Merge branch 'master' into discussions
Conflicts: app/assets/stylesheets/main.scss app/models/project.rb app/views/notes/_common_form.html.haml app/views/notes/_per_line_form.html.haml lib/gitlab/markdown.rb spec/models/note_spec.rb
|
@ -1,4 +1,5 @@
|
|||
env:
|
||||
- DB=postgresql
|
||||
- DB=mysql
|
||||
before_install:
|
||||
- sudo apt-get install libicu-dev -y
|
||||
|
@ -18,8 +19,7 @@ services:
|
|||
before_script:
|
||||
- "cp config/database.yml.$DB config/database.yml"
|
||||
- "cp config/gitlab.yml.example config/gitlab.yml"
|
||||
- "bundle exec rake db:create RAILS_ENV=test"
|
||||
- "bundle exec rake db:migrate RAILS_ENV=test"
|
||||
- "bundle exec rake db:setup RAILS_ENV=test"
|
||||
- "bundle exec rake db:seed_fu RAILS_ENV=test"
|
||||
- "sh -e /etc/init.d/xvfb start"
|
||||
script: "bundle exec rake travis --trace"
|
||||
|
|
11
CHANGELOG
|
@ -1,4 +1,15 @@
|
|||
v 4.0.0
|
||||
- Reorganized settings
|
||||
- Fixed commits compare
|
||||
- Refactored scss
|
||||
- Improve status checks
|
||||
- Validates presence of User#name
|
||||
- Fixed postgres support
|
||||
- Removed sqlite support
|
||||
- Modified post-receive hook
|
||||
- Milestones can be closed now
|
||||
- Show comment events on dashboard
|
||||
- Quick add team members via group#people page
|
||||
- [API] expose created date for hooks and SSH keys
|
||||
- [API] list, create issue notes
|
||||
- [API] list, create snippet notes
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
## Contribute to GitLab
|
||||
# Contact & support
|
||||
|
||||
If you want to contribute to GitLab, follow this process:
|
||||
If you want quick help, head over to our [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq).
|
||||
Otherwise you can follow our [Issue Submission Guide](https://github.com/gitlabhq/gitlabhq/wiki/Issue-Submission-Guide) for a more systematic and thorough guide to solving your issues.
|
||||
|
||||
1. Fork the project
|
||||
2. Create a feature branch
|
||||
3. Code
|
||||
4. Create a pull request
|
||||
|
||||
We will only accept pull requests if:
|
||||
|
||||
* Your code has proper tests and all tests pass
|
||||
* Your code can be merged w/o problems
|
||||
* It won't break existing functionality
|
||||
* It's quality code
|
||||
* We like it :)
|
||||
# Contribute to GitLab
|
||||
|
||||
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).
|
||||
## Recipes
|
||||
|
||||
## Installation
|
||||
We collect user submitted installation scripts and config file templates for platforms we don't support officially.
|
||||
We believe there is merit in allowing a certain amount of diversity.
|
||||
You can get and submit your solution to running/configuring GitLab with your favorite OS/distro, database, web server, cloud hoster, configuration management tool, etc.
|
||||
|
||||
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.
|
||||
Help us improve the collection of [GitLab Recipes](https://github.com/gitlabhq/gitlab-recipes/)
|
||||
|
||||
## Running tests
|
||||
|
||||
For more information on running the tests please read the [development tips](https://github.com/gitlabhq/gitlabhq/blob/master/doc/development.md)
|
||||
## Feature suggestions
|
||||
|
||||
Follow the [Issue Submission Guide](https://github.com/gitlabhq/gitlabhq/wiki/Issue-Submission-Guide) and support other peoples ideas or propose your own.
|
||||
|
||||
|
||||
## Code
|
||||
|
||||
Follow our [Developer Guide](https://github.com/gitlabhq/gitlabhq/wiki/Developer-Guide) to set you up for hacking on GitLab.
|
||||
|
|
6
Gemfile
|
@ -32,7 +32,7 @@ gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref:
|
|||
gem "gitolite", '1.1.0'
|
||||
|
||||
# Syntax highlighter
|
||||
gem "pygments.rb", git: "https://github.com/gitlabhq/pygments.rb.git", ref: '4db80c599067e2d5f23c5c243bf85b8ca0368ad4'
|
||||
gem "pygments.rb", git: "https://github.com/gitlabhq/pygments.rb.git", branch: "master"
|
||||
|
||||
# Language detection
|
||||
gem "github-linguist", "~> 2.3.4" , require: "linguist"
|
||||
|
@ -100,7 +100,7 @@ group :assets do
|
|||
gem "therubyracer"
|
||||
|
||||
gem 'chosen-rails', "0.9.8"
|
||||
gem 'jquery-atwho-rails', "0.1.6"
|
||||
gem 'jquery-atwho-rails', "0.1.7"
|
||||
gem "jquery-rails", "2.1.3"
|
||||
gem "jquery-ui-rails", "2.0.2"
|
||||
gem "modernizr", "2.6.2"
|
||||
|
@ -124,7 +124,7 @@ group :development, :test do
|
|||
gem "capybara"
|
||||
gem "pry"
|
||||
gem "awesome_print"
|
||||
gem "database_cleaner"
|
||||
gem "database_cleaner", ref: "f89c34300e114be99532f14c115b2799a3380ac6", git: "https://github.com/bmabey/database_cleaner.git"
|
||||
gem "launchy"
|
||||
gem 'factory_girl_rails'
|
||||
|
||||
|
|
18
Gemfile.lock
|
@ -1,3 +1,10 @@
|
|||
GIT
|
||||
remote: https://github.com/bmabey/database_cleaner.git
|
||||
revision: f89c34300e114be99532f14c115b2799a3380ac6
|
||||
ref: f89c34300e114be99532f14c115b2799a3380ac6
|
||||
specs:
|
||||
database_cleaner (0.9.1)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/ctran/annotate_models.git
|
||||
revision: be4e26825b521f0b2d86b181e2dff89901aa9b1e
|
||||
|
@ -45,8 +52,8 @@ GIT
|
|||
|
||||
GIT
|
||||
remote: https://github.com/gitlabhq/pygments.rb.git
|
||||
revision: 4db80c599067e2d5f23c5c243bf85b8ca0368ad4
|
||||
ref: 4db80c599067e2d5f23c5c243bf85b8ca0368ad4
|
||||
revision: db1da0343adf86b49bdc3add04d02d2e80438d38
|
||||
branch: master
|
||||
specs:
|
||||
pygments.rb (0.3.2)
|
||||
posix-spawn (~> 0.3.6)
|
||||
|
@ -140,7 +147,6 @@ GEM
|
|||
colorize (0.5.8)
|
||||
crack (0.3.1)
|
||||
daemons (1.1.9)
|
||||
database_cleaner (0.9.1)
|
||||
devise (2.1.2)
|
||||
bcrypt-ruby (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
|
@ -227,7 +233,7 @@ GEM
|
|||
httpauth (0.2.0)
|
||||
i18n (0.6.1)
|
||||
journey (1.0.4)
|
||||
jquery-atwho-rails (0.1.6)
|
||||
jquery-atwho-rails (0.1.7)
|
||||
jquery-rails (2.1.3)
|
||||
railties (>= 3.1.0, < 5.0)
|
||||
thor (~> 0.14)
|
||||
|
@ -458,7 +464,7 @@ DEPENDENCIES
|
|||
chosen-rails (= 0.9.8)
|
||||
coffee-rails (~> 3.2.2)
|
||||
colored
|
||||
database_cleaner
|
||||
database_cleaner!
|
||||
devise (~> 2.1.0)
|
||||
draper (~> 0.18.0)
|
||||
email_spec
|
||||
|
@ -481,7 +487,7 @@ DEPENDENCIES
|
|||
guard-spinach
|
||||
haml-rails (~> 0.3.5)
|
||||
httparty
|
||||
jquery-atwho-rails (= 0.1.6)
|
||||
jquery-atwho-rails (= 0.1.7)
|
||||
jquery-rails (= 2.1.3)
|
||||
jquery-ui-rails (= 2.0.2)
|
||||
kaminari (~> 0.14.1)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Welcome to GitLab [![build status](https://secure.travis-ci.org/gitlabhq/gitlabhq.png)](https://secure.travis-ci.org/gitlabhq/gitlabhq) [![build status](https://secure.travis-ci.org/gitlabhq/grit.png)](https://secure.travis-ci.org/gitlabhq/grit) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/gitlabhq/gitlabhq)
|
||||
# Welcome to GitLab [![build status](https://secure.travis-ci.org/gitlabhq/gitlabhq.png)](https://travis-ci.org/gitlabhq/gitlabhq) [![build status](https://secure.travis-ci.org/gitlabhq/grit.png)](https://travis-ci.org/gitlabhq/grit) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/gitlabhq/gitlabhq) [![Dependency Status](https://gemnasium.com/gitlabhq/gitlabhq.png)](https://gemnasium.com/gitlabhq/gitlabhq)
|
||||
|
||||
GitLab is a free project and repository management application
|
||||
|
||||
|
|
2
VERSION
|
@ -1 +1 @@
|
|||
4.0.0pre
|
||||
4.0.0rc1
|
||||
|
|
BIN
app/assets/images/ajax_loader_gray.gif
Normal file
After Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.3 KiB |
BIN
app/assets/images/switch_icon.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
|
@ -1,52 +1,38 @@
|
|||
# Creates the variables for setting up GFM auto-completion
|
||||
|
||||
window.GitLab ?= {}
|
||||
GitLab.GfmAutoComplete ?= {}
|
||||
|
||||
# Emoji
|
||||
data = []
|
||||
template = "<li data-value='${insert}'>${name} <img alt='${name}' height='20' src='${image}' width='20' /></li>"
|
||||
GitLab.GfmAutoComplete.Emoji = {data, template}
|
||||
|
||||
# Team Members
|
||||
data = []
|
||||
url = '';
|
||||
params = {private_token: '', page: 1}
|
||||
GitLab.GfmAutoComplete.Members = {data, url, params}
|
||||
|
||||
# Add GFM auto-completion to all input fields, that accept GFM input.
|
||||
GitLab.GfmAutoComplete.setup = ->
|
||||
input = $('.js-gfm-input')
|
||||
|
||||
GitLab.GfmAutoComplete =
|
||||
# Emoji
|
||||
input.atWho ':',
|
||||
data: GitLab.GfmAutoComplete.Emoji.data,
|
||||
tpl: GitLab.GfmAutoComplete.Emoji.template
|
||||
Emoji:
|
||||
data: []
|
||||
template: '<li data-value="${insert}">${name} <img alt="${name}" height="20" src="${image}" width="20" /></li>'
|
||||
|
||||
# Team Members
|
||||
input.atWho '@', (query, callback) ->
|
||||
(getMoreMembers = ->
|
||||
$.getJSON(GitLab.GfmAutoComplete.Members.url, GitLab.GfmAutoComplete.Members.params)
|
||||
.success (members) ->
|
||||
# pick the data we need
|
||||
newMembersData = $.map(members, (m) -> m.name )
|
||||
Members:
|
||||
data: []
|
||||
url: ''
|
||||
params:
|
||||
private_token: ''
|
||||
template: '<li data-value="${username}">${username} <small>${name}</small></li>'
|
||||
|
||||
# add the new page of data to the rest
|
||||
$.merge(GitLab.GfmAutoComplete.Members.data, newMembersData)
|
||||
# Add GFM auto-completion to all input fields, that accept GFM input.
|
||||
setup: ->
|
||||
input = $('.js-gfm-input')
|
||||
|
||||
# show the pop-up with a copy of the current data
|
||||
callback(GitLab.GfmAutoComplete.Members.data[..])
|
||||
# Emoji
|
||||
input.atWho ':',
|
||||
data: @Emoji.data
|
||||
tpl: @Emoji.template
|
||||
|
||||
# are we past the last page?
|
||||
if newMembersData.length is 0
|
||||
# set static data and stop callbacks
|
||||
input.atWho '@',
|
||||
data: GitLab.GfmAutoComplete.Members.data
|
||||
callback: null
|
||||
else
|
||||
# get next page
|
||||
getMoreMembers()
|
||||
# Team Members
|
||||
input.atWho '@',
|
||||
tpl: @Members.template
|
||||
callback: (query, callback) =>
|
||||
request_params = $.extend({}, @Members.params, query: query)
|
||||
$.getJSON(@Members.url, request_params).done (members) =>
|
||||
new_members_data = $.map(members, (m) ->
|
||||
username: m.username,
|
||||
name: m.name
|
||||
)
|
||||
callback(new_members_data)
|
||||
|
||||
# so the next request gets the next page
|
||||
GitLab.GfmAutoComplete.Members.params.page += 1
|
||||
).call()
|
||||
|
|
|
@ -1,43 +1,3 @@
|
|||
function switchToNewIssue(){
|
||||
$(".issues_content").hide("fade", { direction: "left" }, 150, function(){
|
||||
$('select#issue_assignee_id').chosen();
|
||||
$('select#issue_milestone_id').chosen();
|
||||
$("#new_issue_dialog").show("fade", { direction: "right" }, 150);
|
||||
$('.top-tabs .add_new').hide();
|
||||
disableButtonIfEmptyField("#issue_title", ".save-btn");
|
||||
GitLab.GfmAutoComplete.setup();
|
||||
});
|
||||
}
|
||||
|
||||
function switchToEditIssue(){
|
||||
$(".issues_content").hide("fade", { direction: "left" }, 150, function(){
|
||||
$('select#issue_assignee_id').chosen();
|
||||
$('select#issue_milestone_id').chosen();
|
||||
$("#edit_issue_dialog").show("fade", { direction: "right" }, 150);
|
||||
$('.add_new').hide();
|
||||
disableButtonIfEmptyField("#issue_title", ".save-btn");
|
||||
GitLab.GfmAutoComplete.setup();
|
||||
});
|
||||
}
|
||||
|
||||
function switchFromNewIssue(){
|
||||
backToIssues();
|
||||
}
|
||||
|
||||
function switchFromEditIssue(){
|
||||
backToIssues();
|
||||
}
|
||||
|
||||
function backToIssues(){
|
||||
$("#edit_issue_dialog, #new_issue_dialog").hide("fade", { direction: "right" }, 150, function(){
|
||||
$(".issues_content").show("fade", { direction: "left" }, 150, function() {
|
||||
$("#edit_issue_dialog").html("");
|
||||
$("#new_issue_dialog").html("");
|
||||
$('.add_new').show();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function initIssuesSearch() {
|
||||
var href = $('#issue_search_form').attr('action');
|
||||
var last_terms = '';
|
||||
|
@ -76,23 +36,15 @@ function issuesPage(){
|
|||
$(this).closest("form").submit();
|
||||
});
|
||||
|
||||
$("#new_issue_link").click(function(){
|
||||
updateNewIssueURL();
|
||||
});
|
||||
|
||||
$('body').on('ajax:success', '.close_issue, .reopen_issue, #new_issue', function(){
|
||||
$('body').on('ajax:success', '.close_issue, .reopen_issue', function(){
|
||||
var t = $(this),
|
||||
totalIssues,
|
||||
reopen = t.hasClass('reopen_issue'),
|
||||
newIssue = false;
|
||||
if( this.id == 'new_issue' ){
|
||||
newIssue = true;
|
||||
}
|
||||
$('.issue_counter, #new_issue').each(function(){
|
||||
reopen = t.hasClass('reopen_issue');
|
||||
$('.issue_counter').each(function(){
|
||||
var issue = $(this);
|
||||
totalIssues = parseInt( $(this).html(), 10 );
|
||||
|
||||
if( newIssue || ( reopen && issue.closest('.main_menu').length ) ){
|
||||
if( reopen && issue.closest('.main_menu').length ){
|
||||
$(this).html( totalIssues+1 );
|
||||
}else {
|
||||
$(this).html( totalIssues-1 );
|
||||
|
@ -126,20 +78,3 @@ function issuesCheckChanged() {
|
|||
$('.issues_filters').show();
|
||||
}
|
||||
}
|
||||
|
||||
function updateNewIssueURL(){
|
||||
var new_issue_link = $("#new_issue_link");
|
||||
var milestone_id = $("#milestone_id").val();
|
||||
var assignee_id = $("#assignee_id").val();
|
||||
var new_href = "";
|
||||
if(milestone_id){
|
||||
new_href = "issue[milestone_id]=" + milestone_id + "&";
|
||||
}
|
||||
if(assignee_id){
|
||||
new_href = new_href + "issue[assignee_id]=" + assignee_id;
|
||||
}
|
||||
if(new_href.length){
|
||||
new_href = new_issue_link.attr("href") + "?" + new_href;
|
||||
new_issue_link.attr("href", new_href);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,6 +7,18 @@ window.slugify = (text) ->
|
|||
window.ajaxGet = (url) ->
|
||||
$.ajax({type: "GET", url: url, dataType: "script"})
|
||||
|
||||
window.errorMessage = (message) ->
|
||||
ehtml = $("<p>")
|
||||
ehtml.addClass("error_message")
|
||||
ehtml.html(message)
|
||||
ehtml
|
||||
|
||||
window.split = (val) ->
|
||||
return val.split( /,\s*/ )
|
||||
|
||||
window.extractLast = (term) ->
|
||||
return split( term ).pop()
|
||||
|
||||
# Disable button if text field is empty
|
||||
window.disableButtonIfEmptyField = (field_selector, button_selector) ->
|
||||
field = $(field_selector)
|
||||
|
|
|
@ -26,6 +26,12 @@ var MergeRequest = {
|
|||
self.showState(data.state);
|
||||
}, "json");
|
||||
}
|
||||
|
||||
if(self.opts.ci_enable){
|
||||
$.get(self.opts.url_to_ci_check, function(data){
|
||||
self.showCiState(data.status);
|
||||
}, "json");
|
||||
}
|
||||
},
|
||||
|
||||
initTabs:
|
||||
|
@ -79,6 +85,11 @@ var MergeRequest = {
|
|||
$(".automerge_widget." + state).show();
|
||||
},
|
||||
|
||||
showCiState:
|
||||
function(state){
|
||||
$(".ci_widget").hide();
|
||||
$(".ci_widget.ci-" + state).show();
|
||||
},
|
||||
|
||||
loadDiff:
|
||||
function() {
|
||||
|
|
|
@ -18,10 +18,3 @@ $ ->
|
|||
# Ref switcher
|
||||
$('.project-refs-select').on 'change', ->
|
||||
$(@).parents('form').submit()
|
||||
|
||||
class @GraphNav
|
||||
@init: ->
|
||||
$('.graph svg').css 'position', 'relative'
|
||||
$('body').bind 'keyup', (e) ->
|
||||
$('.graph svg').animate(left: '+=400') if e.keyCode is 37 # left
|
||||
$('.graph svg').animate(left: '-=400') if e.keyCode is 39 # right
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
/*
|
||||
* This is a manifest file that'll automatically include all the stylesheets available in this directory
|
||||
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
|
||||
* the top of the compiled file, but it's generally better to create a new file per style scope.
|
||||
*= require jquery.ui.gitlab
|
||||
*= require jquery.atwho
|
||||
*= require chosen
|
||||
*= require_self
|
||||
*= require main
|
||||
*/
|
52
app/assets/stylesheets/application.scss
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* This is a manifest file that'll automatically include all the stylesheets available in this directory
|
||||
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
|
||||
* the top of the compiled file, but it's generally better to create a new file per style scope.
|
||||
*= require jquery.ui.gitlab
|
||||
*= require jquery.atwho
|
||||
*= require chosen
|
||||
*= require_self
|
||||
*/
|
||||
|
||||
/**
|
||||
* GitLab bootstrap:
|
||||
*/
|
||||
@import "gitlab_bootstrap.scss";
|
||||
|
||||
@import "common.scss";
|
||||
@import "ref_select.scss";
|
||||
|
||||
@import "sections/header.scss";
|
||||
@import "sections/nav.scss";
|
||||
@import "sections/commits.scss";
|
||||
@import "sections/issues.scss";
|
||||
@import "sections/projects.scss";
|
||||
@import "sections/snippets.scss";
|
||||
@import "sections/votes.scss";
|
||||
@import "sections/merge_requests.scss";
|
||||
@import "sections/graph.scss";
|
||||
@import "sections/events.scss";
|
||||
@import "sections/themes.scss";
|
||||
@import "sections/tree.scss";
|
||||
@import "sections/notes.scss";
|
||||
@import "sections/profile.scss";
|
||||
@import "sections/login.scss";
|
||||
@import "sections/editor.scss";
|
||||
|
||||
@import "highlight/white.scss";
|
||||
@import "highlight/dark.scss";
|
||||
|
||||
/**
|
||||
* UI themes:
|
||||
*/
|
||||
@import "themes/ui_basic.scss";
|
||||
@import "themes/ui_mars.scss";
|
||||
@import "themes/ui_modern.scss";
|
||||
@import "themes/ui_gray.scss";
|
||||
@import "themes/ui_color.scss";
|
||||
|
||||
/**
|
||||
* Styles for JS behaviors.
|
||||
*/
|
||||
@import "behaviors.scss";
|
||||
|
|
@ -13,20 +13,12 @@ body {
|
|||
margin: 0 0;
|
||||
}
|
||||
|
||||
.container .sidebar {
|
||||
width: 200px;
|
||||
height: 100%;
|
||||
min-height: 450px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
|
||||
.visible_link,
|
||||
.author_link {
|
||||
color: $link_color;
|
||||
}
|
||||
|
||||
.help li { color:#111 }
|
||||
.help li { color:$style_color; }
|
||||
|
||||
.back_link {
|
||||
text-decoration: underline;
|
||||
|
@ -65,6 +57,9 @@ table a code {
|
|||
background: url(ajax_loader.gif) no-repeat center center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
&.loading-gray {
|
||||
background: url(ajax_loader_gray.gif) no-repeat center center;
|
||||
}
|
||||
}
|
||||
|
||||
/** FLASH message **/
|
||||
|
@ -96,28 +91,17 @@ table a code {
|
|||
margin-right:50px
|
||||
}
|
||||
|
||||
.handle:hover {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
span.update-author {
|
||||
display: block;
|
||||
}
|
||||
span.update-author {
|
||||
color: #999;
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
}
|
||||
span.update-author strong {
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
strong {
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
/** UPDATE ITEM **/
|
||||
span.update-author {
|
||||
display: block;
|
||||
}
|
||||
/** END UPDATE ITEM **/
|
||||
.dashboard-loader {
|
||||
float: left;
|
||||
margin: 10px;
|
||||
|
@ -264,21 +248,6 @@ input.git_clone_url {
|
|||
}
|
||||
|
||||
|
||||
/** bordered list **/
|
||||
ul.bordered-list {
|
||||
margin: 5px 0px;
|
||||
padding: 0px;
|
||||
li {
|
||||
padding: 5px 0;
|
||||
border-bottom: 1px solid #EEE;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
margin: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
ul.bordered-list li:last-child { border:none }
|
||||
|
||||
.line_holder {
|
||||
&:hover {
|
||||
td {
|
||||
|
@ -316,98 +285,6 @@ p.time {
|
|||
}
|
||||
|
||||
|
||||
.ico {
|
||||
background: url("images.png") no-repeat -85px -77px;
|
||||
width: 19px;
|
||||
height: 16px;
|
||||
float: left;
|
||||
position: relative;
|
||||
margin-right: 10px;
|
||||
top: 8px;
|
||||
|
||||
&.project {
|
||||
background-position: -37px -77px;
|
||||
}
|
||||
|
||||
&.activities {
|
||||
background-position:-162px -22px;
|
||||
}
|
||||
&.projects {
|
||||
background-position:-209px -21px;
|
||||
}
|
||||
}
|
||||
|
||||
.leftbar {
|
||||
h5, .title {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 14px;
|
||||
padding: 2px 10px;
|
||||
color: #666;
|
||||
border-bottom: 1px solid #f1f1f1;
|
||||
}
|
||||
a:last-child h4 { border: none; }
|
||||
|
||||
a:hover {
|
||||
h4 {
|
||||
color: #111;
|
||||
background: $hover;
|
||||
border-color: #CCC;
|
||||
.ico.project {
|
||||
background-position:-209px -21px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.bottom {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.votes {
|
||||
font-size: 13px;
|
||||
line-height: 15px;
|
||||
.progress {
|
||||
height: 4px;
|
||||
margin: 0;
|
||||
.bar {
|
||||
float: left;
|
||||
height: 100%;
|
||||
}
|
||||
.bar-success {
|
||||
@include linear-gradient(#62C462, #51A351);
|
||||
background-color: #468847;
|
||||
}
|
||||
.bar-danger {
|
||||
@include linear-gradient(#EE5F5B, #BD362F);
|
||||
background-color: #B94A48;
|
||||
}
|
||||
}
|
||||
.upvotes {
|
||||
display: inline-block;
|
||||
color: #468847;
|
||||
}
|
||||
.downvotes {
|
||||
display: inline-block;
|
||||
color: #B94A48;
|
||||
}
|
||||
}
|
||||
.votes-block {
|
||||
margin: 14px 6px 6px 0;
|
||||
.downvotes {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
.votes-inline {
|
||||
display: inline-block;
|
||||
margin: 0 8px;
|
||||
.progress {
|
||||
display: inline-block;
|
||||
padding: 0 0 2px;
|
||||
width: 45px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fix for readme code (stopped it from being yellow) */
|
||||
.readme {
|
||||
|
@ -420,7 +297,6 @@ p.time {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.highlight_word {
|
||||
background: #EEDC94;
|
||||
}
|
||||
|
@ -428,23 +304,16 @@ p.time {
|
|||
.status_info {
|
||||
font-size: 14px;
|
||||
padding: 5px 15px;
|
||||
line-height: 24px;
|
||||
width: 60px;
|
||||
line-height: 26px;
|
||||
text-align: center;
|
||||
float: left;
|
||||
margin-right: 20px;
|
||||
float: right;
|
||||
position: relative;
|
||||
top: -5px;
|
||||
@include border-radius(4px);
|
||||
|
||||
&.success {
|
||||
background: #5BB75B;
|
||||
color: white;
|
||||
text-shadow: 0 1px #111;
|
||||
border-color: #9A9;
|
||||
}
|
||||
&.error {
|
||||
background: #DA4E49;
|
||||
border-color: #BD362F;
|
||||
color: white;
|
||||
text-shadow: 0 1px #111;
|
||||
color: #FFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,16 +332,6 @@ p.time {
|
|||
height: 150px;
|
||||
}
|
||||
|
||||
.gitlab_pagination {
|
||||
span a { color: $link_color; }
|
||||
.prev, .next, .current, .page a {
|
||||
padding: 10px;
|
||||
}
|
||||
.current {
|
||||
border-bottom: 2px solid $style_color;
|
||||
}
|
||||
}
|
||||
|
||||
// Fixes alignment on notes.
|
||||
.new_note {
|
||||
label {
|
||||
|
@ -647,9 +506,14 @@ pre {
|
|||
}
|
||||
}
|
||||
|
||||
.milestone .progress {
|
||||
margin-bottom: 0;
|
||||
margin-top: 4px;
|
||||
.milestone {
|
||||
&.milestone-closed {
|
||||
background: #eee;
|
||||
}
|
||||
.progress {
|
||||
margin-bottom: 0;
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.float-link {
|
||||
|
|
26
app/assets/stylesheets/gitlab_bootstrap.scss
Normal file
|
@ -0,0 +1,26 @@
|
|||
/** Override bootstrap variables **/
|
||||
$baseFontSize: 13px !default;
|
||||
$baseLineHeight: 18px !default;
|
||||
|
||||
// BOOTSTRAP
|
||||
@import "bootstrap";
|
||||
@import "bootstrap/responsive-utilities";
|
||||
@import "bootstrap/responsive-1200px-min";
|
||||
|
||||
@import "font-awesome";
|
||||
|
||||
/**
|
||||
* GitLab bootstrap.
|
||||
* Overrides some styles of twitter bootstrap.
|
||||
* Also give some common classes for GitLab app
|
||||
*/
|
||||
@import "gitlab_bootstrap/variables.scss";
|
||||
@import "gitlab_bootstrap/fonts.scss";
|
||||
@import "gitlab_bootstrap/mixins.scss";
|
||||
@import "gitlab_bootstrap/common.scss";
|
||||
@import "gitlab_bootstrap/typography.scss";
|
||||
@import "gitlab_bootstrap/buttons.scss";
|
||||
@import "gitlab_bootstrap/blocks.scss";
|
||||
@import "gitlab_bootstrap/files.scss";
|
||||
@import "gitlab_bootstrap/tables.scss";
|
||||
@import "gitlab_bootstrap/lists.scss";
|
|
@ -31,6 +31,7 @@
|
|||
.middle_box_content,
|
||||
.bottom_box_content {
|
||||
padding: 15px;
|
||||
word-wrap: break-word;
|
||||
|
||||
pre {
|
||||
background: none !important;
|
||||
|
@ -40,6 +41,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
.top_box_content {
|
||||
.box-title {
|
||||
color: $style_color;
|
||||
font-size: 18px;
|
||||
font-weight: normal;
|
||||
line-height: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
.middle_box_content {
|
||||
@include border-radius(0);
|
||||
border: none;
|
||||
|
@ -64,7 +74,7 @@
|
|||
|
||||
border: 1px solid #eaeaea;
|
||||
@include border-radius(4px);
|
||||
|
||||
|
||||
border-color: #CCC;
|
||||
@include solid-shade;
|
||||
|
||||
|
@ -83,6 +93,10 @@
|
|||
border-top: 1px solid #eaeaea;
|
||||
border-bottom: 1px solid #bbb;
|
||||
|
||||
> a {
|
||||
text-shadow: 0 1px 1px #fff;
|
||||
}
|
||||
|
||||
&.small {
|
||||
line-height: 28px;
|
||||
font-size: 14px;
|
||||
|
@ -138,19 +152,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
li, .wll {
|
||||
padding: 10px;
|
||||
&:first-child {
|
||||
@include border-radius(4px 4px 0 0);
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
@include border-radius(0 0 4px 4px);
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-box-body {
|
||||
padding: 10px;
|
||||
}
|
||||
|
|
|
@ -10,11 +10,6 @@
|
|||
/** COMMON CLASSES **/
|
||||
.left { float:left }
|
||||
.right { float:right!important }
|
||||
.width-50p { width:50% }
|
||||
.width-49p { width:49% }
|
||||
.width-30p { width:30% }
|
||||
.width-65p { width:65% }
|
||||
.width-100p { width:100% }
|
||||
.append-bottom-10 { margin-bottom:10px }
|
||||
.append-bottom-20 { margin-bottom:20px }
|
||||
.prepend-top-10 { margin-top:10px }
|
||||
|
@ -30,6 +25,7 @@
|
|||
.borders { border: 1px solid #ccc; @include shade; }
|
||||
.hint { font-style: italic; color: #999; }
|
||||
.light { color: #888 }
|
||||
.tiny { font-weight: normal }
|
||||
|
||||
/** PILLS & TABS**/
|
||||
.nav-pills a:hover { background-color: #888; }
|
||||
|
@ -99,18 +95,21 @@ input[type='search'].search-text-input {
|
|||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
input[type='text'].danger {
|
||||
background: #F2DEDE!important;
|
||||
border-color: #D66;
|
||||
text-shadow: 0 1px 1px #fff
|
||||
}
|
||||
|
||||
fieldset legend { font-size: 17px; }
|
||||
|
||||
ul.nav.nav-projects-tabs {
|
||||
@extend .nav-tabs;
|
||||
|
||||
padding-left: 8px;
|
||||
|
||||
li {
|
||||
a {
|
||||
padding: 4px 20px;
|
||||
margin-top: 2px;
|
||||
border-color: #DDD;
|
||||
}
|
||||
/** PAGINATION **/
|
||||
.gitlab_pagination {
|
||||
span a { color: $link_color; }
|
||||
.prev, .next, .current, .page a {
|
||||
padding: 10px;
|
||||
}
|
||||
.current {
|
||||
border-bottom: 2px solid $style_color;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,11 +43,15 @@
|
|||
padding: 0 4px;
|
||||
}
|
||||
padding: 20px;
|
||||
h1, h2 {
|
||||
line-height: 46px;
|
||||
}
|
||||
h3, h4 {
|
||||
line-height: 40px;
|
||||
|
||||
h1 { font-size: 26px; line-height: 46px; }
|
||||
h2 { font-size: 22px; line-height: 42px; }
|
||||
h3 { font-size: 20px; line-height: 40px; }
|
||||
h4 { font-size: 18px; line-height: 32px; }
|
||||
h5 { font-size: 16px; line-height: 26px; }
|
||||
|
||||
.white .highlight pre {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,23 +1,38 @@
|
|||
/** LISTS **/
|
||||
|
||||
ul {
|
||||
/**
|
||||
* List li block element #1
|
||||
*
|
||||
*/
|
||||
.wll {
|
||||
/**
|
||||
* Well styled list
|
||||
*
|
||||
*/
|
||||
.well-list {
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
li {
|
||||
background-color: #FFF;
|
||||
padding: 10px 5px;
|
||||
padding: 10px;
|
||||
min-height: 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||
|
||||
&.disabled {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
&.smoke { background-color: #f5f5f5; }
|
||||
|
||||
&:hover {
|
||||
background: $hover;
|
||||
border-bottom: 1px solid #ADF;
|
||||
}
|
||||
&:last-child { border:none }
|
||||
|
||||
&:first-child {
|
||||
@include border-radius(4px 4px 0 0);
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
@include border-radius(0 0 4px 4px);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.author { color: #999; }
|
||||
|
||||
p {
|
||||
|
@ -29,6 +44,11 @@ ul {
|
|||
top: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.well-title {
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,3 +59,17 @@ ol, ul {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** light list with border-bottom between li **/
|
||||
ul.bordered-list {
|
||||
margin: 5px 0px;
|
||||
padding: 0px;
|
||||
li {
|
||||
padding: 5px 0;
|
||||
border-bottom: 1px solid #EEE;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
margin: 0px;
|
||||
&:last-child { border:none }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,4 +57,13 @@
|
|||
|
||||
@mixin solid-shade {
|
||||
@include box-shadow(0 0 0 3px #f1f1f1);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin header-font {
|
||||
color: $style_color;
|
||||
text-shadow: 0 1px 1px #FFF;
|
||||
font-family: 'Korolev', sans-serif;
|
||||
font-size: 28px;
|
||||
line-height: 48px;
|
||||
font-weight: normal;
|
||||
}
|
|
@ -2,4 +2,4 @@
|
|||
$primary_color: #2FA0BB;
|
||||
$link_color: #3A89A3;
|
||||
$style_color: #474D57;
|
||||
$hover: #D9EDF7;
|
||||
$hover: #D9EDF7;
|
|
@ -1,7 +1,8 @@
|
|||
.black .highlight {
|
||||
background-color: #333;
|
||||
pre {
|
||||
background-color: #333;
|
||||
color: #eee;
|
||||
background: inherit;
|
||||
}
|
||||
|
||||
.hll { display: block; background-color: darken($hover, 65%) }
|
||||
|
|
113
app/assets/stylesheets/jquery.ui.gitlab.css
vendored
|
@ -1,27 +1,3 @@
|
|||
/*
|
||||
* jQuery UI CSS Framework 1.8.7
|
||||
*
|
||||
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Theming/API
|
||||
*/
|
||||
|
||||
/* Layout helpers
|
||||
----------------------------------*/
|
||||
.ui-helper-hidden { display: none; }
|
||||
.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
|
||||
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
|
||||
.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
|
||||
.ui-helper-clearfix { display: inline-block; }
|
||||
/* required comment for clearfix to work in Opera \*/
|
||||
* html .ui-helper-clearfix { height:1%; }
|
||||
.ui-helper-clearfix { display:block; }
|
||||
/* end clearfix */
|
||||
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
|
||||
|
||||
|
||||
/* Interaction Cues
|
||||
----------------------------------*/
|
||||
.ui-state-disabled { cursor: default !important; }
|
||||
|
@ -140,26 +116,6 @@
|
|||
/* Overlays */
|
||||
.ui-widget-overlay { background: #262b33; opacity: .70;filter:Alpha(Opacity=70); }
|
||||
.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #000000; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }
|
||||
/*
|
||||
* jQuery UI Resizable 1.8.7
|
||||
*
|
||||
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Resizable#theming
|
||||
*/
|
||||
.ui-resizable { position: relative;}
|
||||
.ui-resizable-handle { position: absolute; font-size: 0.1px; z-index: 999; display: block;}
|
||||
.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
|
||||
.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
|
||||
.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
|
||||
.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
|
||||
.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
|
||||
.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
|
||||
.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
|
||||
.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
|
||||
.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}
|
||||
/*
|
||||
* jQuery UI Selectable 1.8.7
|
||||
*
|
||||
|
@ -240,34 +196,7 @@
|
|||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
}
|
||||
/*
|
||||
* jQuery UI Slider 1.8.7
|
||||
*
|
||||
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Slider#theming
|
||||
*/
|
||||
.ui-slider { position: relative; text-align: left; background: #d7d7d7; z-index: 1; }
|
||||
.ui-slider { -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.5) inset; -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.5) inset; box-shadow: 0 1px 2px rgba(0,0,0,0.5) inset; }
|
||||
.ui-slider .ui-slider-handle { background: url(slider_handles.png) 0px -23px no-repeat; position: absolute; z-index: 2; width: 23px; height: 23px; cursor: default; border: none; outline: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; }
|
||||
.ui-slider .ui-state-hover, .ui-slider .ui-state-active { background-position: 0 0; }
|
||||
.ui-slider .ui-slider-range { background: #a3cae0; position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
|
||||
.ui-slider .ui-slider-range { -moz-box-shadow: 0 1px 2px rgba(17,35,45,0.6) inset; -webkit-box-shadow: 0 1px 2px rgba(17,35,45,0.6) inset; box-shadow: 0 1px 2px rgba(17,35,45,0.6) inset; }
|
||||
|
||||
|
||||
.ui-slider-horizontal { height: 5px; }
|
||||
.ui-slider-horizontal .ui-slider-handle { top: -8px; margin-left: -13px; }
|
||||
.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
|
||||
.ui-slider-horizontal .ui-slider-range-min { left: 0; }
|
||||
.ui-slider-horizontal .ui-slider-range-max { right: 0; }
|
||||
|
||||
.ui-slider-vertical { width: 5px; height: 100px; }
|
||||
.ui-slider-vertical .ui-slider-handle { left: -8px; margin-left: 0; margin-bottom: -13px; }
|
||||
.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
|
||||
.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
|
||||
.ui-slider-vertical .ui-slider-range-max { top: 0; }
|
||||
/*
|
||||
* jQuery UI Datepicker 1.8.7
|
||||
*
|
||||
|
@ -326,45 +255,3 @@
|
|||
.ui-datepicker table .ui-state-highlight { border-color: #ADE; }
|
||||
.ui-datepicker-calendar .ui-state-default { background: transparent; border-color: #FFF; }
|
||||
.ui-datepicker-calendar .ui-state-active { background: #D9EDF7; border-color: #ADE; color: #3A89A3; font-weight: bold; text-shadow: 0 1px 1px #fff; }
|
||||
|
||||
/* with multiple calendars */
|
||||
.ui-datepicker.ui-datepicker-multi { width:auto; }
|
||||
.ui-datepicker-multi .ui-datepicker-group { float:left; }
|
||||
.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
|
||||
.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
|
||||
.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
|
||||
.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
|
||||
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
|
||||
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
|
||||
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
|
||||
.ui-datepicker-row-break { clear:both; width:100%; }
|
||||
|
||||
|
||||
/* Extra Input Field Styling */
|
||||
.ui-form textarea, .ui-form input:not([type="submit"]):not([type="button"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]) {
|
||||
padding: 3px;
|
||||
-webkit-border-radius: 2px;
|
||||
-moz-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #cecece;
|
||||
outline: none;
|
||||
-webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.1) inset, 0 1px 0 rgba(255,255,255,0.2);
|
||||
-moz-box-shadow: 0 1px 3px rgba(0,0,0,0.1) inset, 0 1px 0 rgba(255,255,255,0.2);
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1) inset, 0 1px 0 rgba(255,255,255,0.2);
|
||||
-webkit-transition: all 250ms ease-in-out;
|
||||
-moz-transition: all 250ms ease-in-out;
|
||||
-o-transition: all 250ms ease-in-out;
|
||||
transition: all 250ms ease-in-out;
|
||||
}
|
||||
.ui-form textarea:hover, .ui-form input:not([type="submit"]):not([type="button"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]):hover {
|
||||
border: 1px solid #bdbdbd;
|
||||
-webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.2) inset, 0 1px 0 rgba(255,255,255,0.2);
|
||||
-moz-box-shadow: 0 1px 3px rgba(0,0,0,0.2) inset, 0 1px 0 rgba(255,255,255,0.2);
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.2) inset, 0 1px 0 rgba(255,255,255,0.2);
|
||||
}
|
||||
.ui-form textarea:focus, .ui-form input:not([type="submit"]):not([type="button"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]):focus {
|
||||
border: 1px solid #95bdd4;
|
||||
-webkit-box-shadow: 0 2px 3px rgba(161,202,226,0.5) inset, 0 1px 0 rgba(255,255,255,0.2);
|
||||
-moz-box-shadow: 0 2px 3px rgba(161,202,226,0.5) inset, 0 1px 0 rgba(255,255,255,0.2);
|
||||
box-shadow: 0 2px 3px rgba(161,202,226,0.5) inset, 0 1px 0 rgba(255,255,255,0.2);
|
||||
}
|
||||
|
|
|
@ -1,144 +0,0 @@
|
|||
/** Override bootstrap variables **/
|
||||
$baseFontSize: 13px !default;
|
||||
$baseLineHeight: 18px !default;
|
||||
|
||||
// BOOTSTRAP
|
||||
@import "bootstrap";
|
||||
@import "bootstrap/responsive-utilities";
|
||||
@import "bootstrap/responsive-1200px-min";
|
||||
|
||||
// FONT AWESOME
|
||||
@import "font-awesome";
|
||||
|
||||
/**
|
||||
* Variables
|
||||
* Contains colors
|
||||
*/
|
||||
@import "variables.scss";
|
||||
|
||||
/**
|
||||
* Custom fonts
|
||||
* Contains @font-face font Korolev and default $monotype
|
||||
*/
|
||||
@import "fonts.scss";
|
||||
|
||||
/**
|
||||
* General mixins.
|
||||
* Contains rounded borders, gradients and shades
|
||||
*/
|
||||
@import "mixins.scss";
|
||||
|
||||
/**
|
||||
* Header of application.
|
||||
* Contain application logo, search panel, profile icon
|
||||
*/
|
||||
@import "sections/header.scss";
|
||||
|
||||
/**
|
||||
* Navigation menu of application.
|
||||
* Panel with links to pages depends on project, profile or admin area
|
||||
*/
|
||||
@import "sections/nav.scss";
|
||||
|
||||
/**
|
||||
* This file represent some UI that can be changed
|
||||
* during web app restyle or theme select.
|
||||
*
|
||||
* Next items should be placed there
|
||||
* - link, button colors
|
||||
* - header restyles
|
||||
* - main menu restyles
|
||||
*
|
||||
*/
|
||||
@import "themes/ui_basic.scss";
|
||||
|
||||
/**
|
||||
* UI themes:
|
||||
*/
|
||||
@import "themes/ui_mars.scss";
|
||||
@import "themes/ui_modern.scss";
|
||||
@import "themes/ui_gray.scss";
|
||||
@import "themes/ui_color.scss";
|
||||
|
||||
/**
|
||||
* GitLab bootstrap.
|
||||
* Overrides some styles of twitter bootstrap.
|
||||
* Also give some common classes for GitLab app
|
||||
*/
|
||||
@import "gitlab_bootstrap/common.scss";
|
||||
@import "gitlab_bootstrap/typography.scss";
|
||||
@import "gitlab_bootstrap/buttons.scss";
|
||||
@import "gitlab_bootstrap/blocks.scss";
|
||||
@import "gitlab_bootstrap/files.scss";
|
||||
@import "gitlab_bootstrap/tables.scss";
|
||||
@import "gitlab_bootstrap/lists.scss";
|
||||
|
||||
|
||||
/**
|
||||
* Most of application styles placed here.
|
||||
* This file represent common UI that should not be changed between themes
|
||||
* or project restyling like form width or user avatar class or commit title
|
||||
*
|
||||
* TODO: clean it
|
||||
*/
|
||||
@import "common.scss";
|
||||
|
||||
/**
|
||||
* Styles necessary to support JS behaviours.
|
||||
*/
|
||||
@import "behaviors.scss";
|
||||
|
||||
/**
|
||||
* Styles related to specific part of app
|
||||
*/
|
||||
@import "sections/commits.scss";
|
||||
@import "sections/issues.scss";
|
||||
@import "sections/projects.scss";
|
||||
@import "sections/merge_requests.scss";
|
||||
@import "sections/graph.scss";
|
||||
@import "sections/events.scss";
|
||||
@import "sections/themes.scss";
|
||||
|
||||
/**
|
||||
* This scss file redefine chozen selectbox styles for
|
||||
* project Branch/Tag select element
|
||||
*/
|
||||
@import "ref_select.scss";
|
||||
|
||||
/**
|
||||
* Code (files list) styles. Browsing project files there
|
||||
*/
|
||||
@import "sections/tree.scss";
|
||||
|
||||
/**
|
||||
* This file represent notes(comments) styles
|
||||
*/
|
||||
@import "sections/notes.scss";
|
||||
|
||||
/**
|
||||
* This file represent profile styles
|
||||
*/
|
||||
@import "sections/profile.scss";
|
||||
|
||||
/**
|
||||
* Devise styles
|
||||
*/
|
||||
@import "sections/login.scss";
|
||||
|
||||
/**
|
||||
* CODE HIGHTLIGHT BASE
|
||||
*
|
||||
*/
|
||||
@import "highlight/white.scss";
|
||||
|
||||
/**
|
||||
* CODE HIGHTLIGHT DARK schema
|
||||
*
|
||||
*/
|
||||
@import "highlight/dark.scss";
|
||||
|
||||
/**
|
||||
* File Editor styles
|
||||
*
|
||||
*/
|
||||
@import "sections/editor.scss";
|
|
@ -232,8 +232,6 @@
|
|||
|
||||
/** COMMIT ROW **/
|
||||
.commit {
|
||||
@extend .wll;
|
||||
|
||||
.browse_code_link_holder {
|
||||
@extend .span2;
|
||||
float: right;
|
||||
|
@ -305,3 +303,17 @@
|
|||
color: #fff;
|
||||
font-family: $monospace;
|
||||
}
|
||||
|
||||
|
||||
.commits-compare-switch{
|
||||
background: url("switch_icon.png") no-repeat center center;
|
||||
width: 16px;
|
||||
height: 18px;
|
||||
text-indent: -9999px;
|
||||
float: left;
|
||||
margin-right: 9px;
|
||||
border: 1px solid #DDD;
|
||||
@include border-radius(4px);
|
||||
padding: 4px;
|
||||
background-color: #EEE;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
*
|
||||
*/
|
||||
.event-item {
|
||||
min-height: 40px;
|
||||
border-bottom: 1px solid #eee;
|
||||
.event-title {
|
||||
color: #333;
|
||||
|
@ -50,14 +49,18 @@
|
|||
}
|
||||
}
|
||||
.avatar {
|
||||
width: 32px;
|
||||
position: relative;
|
||||
top: -3px;
|
||||
}
|
||||
.event_icon {
|
||||
position: relative;
|
||||
float: right;
|
||||
border: 1px solid #EEE;
|
||||
padding: 5px;
|
||||
@include border-radius(5px);
|
||||
background: #F9F9F9;
|
||||
margin-left: 10px;
|
||||
top: -6px;
|
||||
img {
|
||||
width: 20px;
|
||||
}
|
||||
|
@ -71,9 +74,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
padding: 15px 5px;
|
||||
padding: 16px 5px;
|
||||
&:last-child { border:none }
|
||||
.wll:hover { background:none }
|
||||
|
||||
.event_commits {
|
||||
margin-top: 5px;
|
||||
|
|
|
@ -44,14 +44,9 @@ header {
|
|||
background: url('logo_dark.png') no-repeat 0px 2px;
|
||||
float: left;
|
||||
margin-left: 2px;
|
||||
font-size: 30px;
|
||||
line-height: 48px;
|
||||
font-weight: normal;
|
||||
color: $style_color;
|
||||
text-shadow: 0 1px 1px #FFF;
|
||||
padding-left: 45px;
|
||||
height: 40px;
|
||||
font-family: 'Korolev', sans-serif;
|
||||
@include header-font;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,12 +61,7 @@ header {
|
|||
float: left;
|
||||
margin: 0;
|
||||
margin-right: 30px;
|
||||
font-size: 30px;
|
||||
line-height: 48px;
|
||||
font-weight: normal;
|
||||
color: $style_color;
|
||||
text-shadow: 0 1px 1px #FFF;
|
||||
font-family: 'Korolev', sans-serif;
|
||||
@include header-font;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -172,7 +162,7 @@ header {
|
|||
display: none;
|
||||
z-index: 100000;
|
||||
@include border-radius(4px);
|
||||
width: 100px;
|
||||
width: 130px;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 38px;
|
||||
|
@ -181,7 +171,7 @@ header {
|
|||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
|
||||
a {
|
||||
color: #fff;
|
||||
padding: 7px 10px;
|
||||
padding: 12px 15px;
|
||||
display: block;
|
||||
text-shadow: none;
|
||||
border-bottom: 1px solid #666;
|
||||
|
@ -204,8 +194,8 @@ header {
|
|||
}
|
||||
&:last-child {
|
||||
@include border-radius(0 0 5px 5px);
|
||||
border-bottom: 0;
|
||||
}
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -121,12 +121,3 @@ input.check_all_issues {
|
|||
#update_status {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Milestones list
|
||||
*
|
||||
*/
|
||||
.milestone {
|
||||
@extend .wll;
|
||||
}
|
||||
|
|
|
@ -136,9 +136,3 @@ li.merge_request {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
height: 32px;
|
||||
width: 100%;
|
||||
@include border-radius(5px);
|
||||
}
|
||||
|
|
|
@ -3,15 +3,13 @@
|
|||
*
|
||||
*/
|
||||
ul.main_menu {
|
||||
@include border-radius(4px);
|
||||
margin: auto;
|
||||
margin: 30px 0;
|
||||
border: 1px solid #BBB;
|
||||
margin-top: 10px;
|
||||
border-bottom: 1px solid #DDD;
|
||||
height: 37px;
|
||||
@include bg-gray-gradient;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
@include shade;
|
||||
.count {
|
||||
position: relative;
|
||||
top: -1px;
|
||||
|
@ -24,9 +22,6 @@ ul.main_menu {
|
|||
line-height: 14px;
|
||||
text-align: center;
|
||||
color: #777;
|
||||
background: #f2f2f2;
|
||||
border-top: 1px solid #CCC;
|
||||
@include border-radius(8px);
|
||||
}
|
||||
.label {
|
||||
background: $hover;
|
||||
|
@ -38,23 +33,10 @@ ul.main_menu {
|
|||
margin: 0;
|
||||
display: table-cell;
|
||||
width: 1%;
|
||||
border-right: 1px solid #DDD;
|
||||
border-left: 1px solid #EEE;
|
||||
border-bottom: 2px solid #CFCFCF;
|
||||
|
||||
&:first-child{
|
||||
@include border-radius(5px 0 0 5px);
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #D5D5D5;
|
||||
border-right: 1px solid #BBB;
|
||||
border-left: 1px solid #BBB;
|
||||
@include border-radius(0 0 1px 1px);
|
||||
&:first-child{
|
||||
border-bottom: none;
|
||||
border-left: none;
|
||||
border-bottom: 2px solid #474D57;
|
||||
a {
|
||||
color: $style_color;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,10 +55,10 @@ ul.main_menu {
|
|||
a {
|
||||
display: block;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-weight: normal;
|
||||
height: 35px;
|
||||
line-height: 36px;
|
||||
color: $style_color;
|
||||
color: #777;
|
||||
text-shadow: 0 1px 1px white;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
|
|
@ -4,12 +4,11 @@
|
|||
}
|
||||
|
||||
.side {
|
||||
@extend .span4;
|
||||
@extend .right;
|
||||
|
||||
.groups_box,
|
||||
.projects_box {
|
||||
h5 {
|
||||
> h5 {
|
||||
color: $style_color;
|
||||
font-size: 16px;
|
||||
text-shadow: 0 1px 1px #fff;
|
||||
|
@ -17,37 +16,22 @@
|
|||
line-height: 32px;
|
||||
font-size: 14px;
|
||||
}
|
||||
ul {
|
||||
li {
|
||||
padding: 0;
|
||||
a {
|
||||
display: block;
|
||||
.group_name {
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
}
|
||||
.project_name {
|
||||
color: #4fa2bd;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
}
|
||||
.arrow {
|
||||
float: right;
|
||||
padding: 10px;
|
||||
margin: 0;
|
||||
}
|
||||
.last_activity {
|
||||
padding-top: 5px;
|
||||
display: block;
|
||||
span, strong {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
.nav-projects-tabs li { padding: 0; }
|
||||
.well-list {
|
||||
.arrow {
|
||||
float: right;
|
||||
padding: 10px;
|
||||
margin: 0;
|
||||
}
|
||||
.last_activity {
|
||||
padding-top: 5px;
|
||||
display: block;
|
||||
span, strong {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
@extend .leftbar;
|
||||
@extend .ui-box;
|
||||
}
|
||||
}
|
||||
|
@ -117,3 +101,25 @@
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
ul.nav.nav-projects-tabs {
|
||||
@extend .nav-tabs;
|
||||
|
||||
padding-left: 8px;
|
||||
|
||||
li {
|
||||
a {
|
||||
padding: 4px 20px;
|
||||
margin-top: 2px;
|
||||
border-color: #DDD;
|
||||
background-color: #EEE;
|
||||
text-shadow: 0 1px 1px white;
|
||||
color: #555;
|
||||
}
|
||||
&.active {
|
||||
a {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
9
app/assets/stylesheets/sections/snippets.scss
Normal file
|
@ -0,0 +1,9 @@
|
|||
.snippet.file_holder {
|
||||
.file_title {
|
||||
.snippet-file-name {
|
||||
position: relative;
|
||||
top: -4px;
|
||||
left: -4px;
|
||||
}
|
||||
}
|
||||
}
|
43
app/assets/stylesheets/sections/votes.scss
Normal file
|
@ -0,0 +1,43 @@
|
|||
.votes {
|
||||
font-size: 13px;
|
||||
line-height: 15px;
|
||||
.progress {
|
||||
height: 4px;
|
||||
margin: 0;
|
||||
.bar {
|
||||
float: left;
|
||||
height: 100%;
|
||||
}
|
||||
.bar-success {
|
||||
@include linear-gradient(#62C462, #51A351);
|
||||
background-color: #468847;
|
||||
}
|
||||
.bar-danger {
|
||||
@include linear-gradient(#EE5F5B, #BD362F);
|
||||
background-color: #B94A48;
|
||||
}
|
||||
}
|
||||
.upvotes {
|
||||
display: inline-block;
|
||||
color: #468847;
|
||||
}
|
||||
.downvotes {
|
||||
display: inline-block;
|
||||
color: #B94A48;
|
||||
}
|
||||
}
|
||||
.votes-block {
|
||||
margin: 14px 6px 6px 0;
|
||||
.downvotes {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
.votes-inline {
|
||||
display: inline-block;
|
||||
margin: 0 8px;
|
||||
.progress {
|
||||
display: inline-block;
|
||||
padding: 0 0 2px;
|
||||
width: 45px;
|
||||
}
|
||||
}
|
|
@ -4,18 +4,6 @@
|
|||
*
|
||||
*/
|
||||
.ui_basic {
|
||||
/*
|
||||
* Common styles
|
||||
*
|
||||
*/
|
||||
a {
|
||||
color: $link_color;
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
color: $primary_color;
|
||||
}
|
||||
}
|
||||
|
||||
.app_logo {
|
||||
.separator {
|
||||
margin-left: 0;
|
||||
|
|
|
@ -2,7 +2,9 @@ class ProjectUpdateContext < BaseContext
|
|||
def execute(role = :default)
|
||||
namespace_id = params[:project].delete(:namespace_id)
|
||||
|
||||
if namespace_id.present?
|
||||
allowed_transfer = can?(current_user, :change_namespace, project) || role == :admin
|
||||
|
||||
if allowed_transfer && namespace_id.present?
|
||||
if namespace_id == Namespace.global_id
|
||||
if project.namespace.present?
|
||||
# Transfer to global namespace from anyone
|
||||
|
|
|
@ -2,7 +2,7 @@ class Admin::GroupsController < AdminController
|
|||
before_filter :group, only: [:edit, :show, :update, :destroy, :project_update]
|
||||
|
||||
def index
|
||||
@groups = Group.scoped
|
||||
@groups = Group.order('name ASC')
|
||||
@groups = @groups.search(params[:name]) if params[:name].present?
|
||||
@groups = @groups.page(params[:page]).per(20)
|
||||
end
|
||||
|
@ -11,6 +11,7 @@ class Admin::GroupsController < AdminController
|
|||
@projects = Project.scoped
|
||||
@projects = @projects.not_in_group(@group) if @group.projects.present?
|
||||
@projects = @projects.all
|
||||
@projects.reject!(&:empty_repo?)
|
||||
end
|
||||
|
||||
def new
|
||||
|
|
|
@ -4,12 +4,13 @@ class Admin::ProjectsController < AdminController
|
|||
def index
|
||||
@projects = Project.scoped
|
||||
@projects = @projects.where(namespace_id: params[:namespace_id]) if params[:namespace_id].present?
|
||||
@projects = @projects.where(namespace_id: nil) if params[:namespace_id] == Namespace.global_id
|
||||
@projects = @projects.search(params[:name]) if params[:name].present?
|
||||
@projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20)
|
||||
end
|
||||
|
||||
def show
|
||||
@users = User.scoped
|
||||
@users = User.active
|
||||
@users = @users.not_in_project(@project) if @project.users.present?
|
||||
@users = @users.all
|
||||
end
|
||||
|
|
|
@ -3,7 +3,7 @@ class Admin::UsersController < AdminController
|
|||
@admin_users = User.scoped
|
||||
@admin_users = @admin_users.filter(params[:filter])
|
||||
@admin_users = @admin_users.search(params[:name]) if params[:name].present?
|
||||
@admin_users = @admin_users.order("updated_at DESC").page(params[:page])
|
||||
@admin_users = @admin_users.order("name ASC").page(params[:page])
|
||||
end
|
||||
|
||||
def show
|
||||
|
@ -30,7 +30,7 @@ class Admin::UsersController < AdminController
|
|||
|
||||
|
||||
def new
|
||||
@admin_user = User.new({ projects_limit: Gitlab.config.default_projects_limit }, as: :admin)
|
||||
@admin_user = User.new({ projects_limit: Gitlab.config.gitlab.default_projects_limit }, as: :admin)
|
||||
end
|
||||
|
||||
def edit
|
||||
|
|
|
@ -112,6 +112,10 @@ class ApplicationController < ActionController::Base
|
|||
render file: Rails.root.join("public", "404"), layout: false, status: "404"
|
||||
end
|
||||
|
||||
def render_403
|
||||
render file: Rails.root.join("public", "403"), layout: false, status: "403"
|
||||
end
|
||||
|
||||
def require_non_empty_project
|
||||
redirect_to @project if @project.empty_repo?
|
||||
end
|
||||
|
|
|
@ -7,6 +7,8 @@ class DashboardController < ApplicationController
|
|||
def index
|
||||
@groups = current_user.authorized_groups
|
||||
|
||||
@has_authorized_projects = @projects.count > 0
|
||||
|
||||
@projects = case params[:scope]
|
||||
when 'personal' then
|
||||
@projects.personal(current_user)
|
||||
|
|
|
@ -21,7 +21,7 @@ class GroupsController < ApplicationController
|
|||
|
||||
# Get authored or assigned open merge requests
|
||||
def merge_requests
|
||||
@merge_requests = current_user.cared_merge_requests
|
||||
@merge_requests = current_user.cared_merge_requests.opened
|
||||
@merge_requests = @merge_requests.of_group(@group).recent.page(params[:page]).per(20)
|
||||
end
|
||||
|
||||
|
@ -49,6 +49,7 @@ class GroupsController < ApplicationController
|
|||
def people
|
||||
@project = group.projects.find(params[:project_id]) if params[:project_id]
|
||||
@users = @project ? @project.users : group.users
|
||||
@users.sort_by!(&:name)
|
||||
|
||||
if @project
|
||||
@team_member = @project.users_projects.new
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class IssuesController < ProjectResourceController
|
||||
before_filter :module_enabled
|
||||
before_filter :issue, only: [:edit, :update, :destroy, :show]
|
||||
before_filter :issue, only: [:edit, :update, :show]
|
||||
|
||||
# Allow read any issue
|
||||
before_filter :authorize_read_issue!
|
||||
|
@ -11,9 +11,6 @@ class IssuesController < ProjectResourceController
|
|||
# Allow modify issue
|
||||
before_filter :authorize_modify_issue!, only: [:edit, :update]
|
||||
|
||||
# Allow destroy issue
|
||||
before_filter :authorize_admin_issue!, only: [:destroy]
|
||||
|
||||
respond_to :js, :html
|
||||
|
||||
def index
|
||||
|
@ -79,15 +76,6 @@ class IssuesController < ProjectResourceController
|
|||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@issue.destroy
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to project_issues_path }
|
||||
format.js { render nothing: true }
|
||||
end
|
||||
end
|
||||
|
||||
def sort
|
||||
return render_404 unless can?(current_user, :admin_issue, @project)
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class MergeRequestsController < ProjectResourceController
|
||||
before_filter :module_enabled
|
||||
before_filter :merge_request, only: [:edit, :update, :destroy, :show, :commits, :diffs, :automerge, :automerge_check]
|
||||
before_filter :merge_request, only: [:edit, :update, :show, :commits, :diffs, :automerge, :automerge_check, :ci_status]
|
||||
before_filter :validates_merge_request, only: [:show, :diffs]
|
||||
before_filter :define_show_vars, only: [:show, :diffs]
|
||||
|
||||
|
@ -13,9 +13,6 @@ class MergeRequestsController < ProjectResourceController
|
|||
# Allow modify merge_request
|
||||
before_filter :authorize_modify_merge_request!, only: [:close, :edit, :update, :sort]
|
||||
|
||||
# Allow destroy merge_request
|
||||
before_filter :authorize_admin_merge_request!, only: [:destroy]
|
||||
|
||||
def index
|
||||
@merge_requests = MergeRequestsLoadContext.new(project, current_user, params).execute
|
||||
end
|
||||
|
@ -90,14 +87,6 @@ class MergeRequestsController < ProjectResourceController
|
|||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@merge_request.destroy
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to project_merge_requests_url(@project) }
|
||||
end
|
||||
end
|
||||
|
||||
def branch_from
|
||||
@commit = project.commit(params[:ref])
|
||||
@commit = CommitDecorator.decorate(@commit)
|
||||
|
@ -108,6 +97,13 @@ class MergeRequestsController < ProjectResourceController
|
|||
@commit = CommitDecorator.decorate(@commit)
|
||||
end
|
||||
|
||||
def ci_status
|
||||
status = project.gitlab_ci_service.commit_status(merge_request.last_commit.sha)
|
||||
response = { status: status }
|
||||
|
||||
render json: response
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def merge_request
|
||||
|
|
|
@ -12,11 +12,12 @@ class MilestonesController < ProjectResourceController
|
|||
|
||||
def index
|
||||
@milestones = case params[:f]
|
||||
when 'all'; @project.milestones
|
||||
else @project.milestones.active
|
||||
when 'all'; @project.milestones.order("closed, due_date DESC")
|
||||
when 'closed'; @project.milestones.closed.order("due_date DESC")
|
||||
else @project.milestones.active.order("due_date ASC")
|
||||
end
|
||||
|
||||
@milestones = @milestones.includes(:project).order("due_date")
|
||||
@milestones = @milestones.includes(:project)
|
||||
@milestones = @milestones.page(params[:page]).per(20)
|
||||
end
|
||||
|
||||
|
@ -42,6 +43,7 @@ class MilestonesController < ProjectResourceController
|
|||
|
||||
def create
|
||||
@milestone = @project.milestones.new(params[:milestone])
|
||||
@milestone.author_id_of_changes = current_user.id
|
||||
|
||||
if @milestone.save
|
||||
redirect_to project_milestone_path(@project, @milestone)
|
||||
|
@ -51,7 +53,7 @@ class MilestonesController < ProjectResourceController
|
|||
end
|
||||
|
||||
def update
|
||||
@milestone.update_attributes(params[:milestone])
|
||||
@milestone.update_attributes(params[:milestone].merge(author_id_of_changes: current_user.id))
|
||||
|
||||
respond_to do |format|
|
||||
format.js
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||
Gitlab.config.omniauth_providers.each do |provider|
|
||||
Gitlab.config.omniauth.providers.each do |provider|
|
||||
define_method provider['name'] do
|
||||
handle_omniauth
|
||||
end
|
||||
|
|
|
@ -46,6 +46,10 @@ class ProjectsController < ProjectResourceController
|
|||
format.js
|
||||
end
|
||||
end
|
||||
|
||||
rescue Project::TransferError => ex
|
||||
@error = ex
|
||||
render :update_failed
|
||||
end
|
||||
|
||||
def show
|
||||
|
@ -54,12 +58,12 @@ class ProjectsController < ProjectResourceController
|
|||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
unless @project.empty_repo?
|
||||
@last_push = current_user.recent_push(@project.id)
|
||||
render :show
|
||||
else
|
||||
render "projects/empty"
|
||||
end
|
||||
unless @project.empty_repo?
|
||||
@last_push = current_user.recent_push(@project.id)
|
||||
render :show
|
||||
else
|
||||
render "projects/empty"
|
||||
end
|
||||
end
|
||||
format.js
|
||||
end
|
||||
|
@ -86,12 +90,18 @@ class ProjectsController < ProjectResourceController
|
|||
end
|
||||
|
||||
def graph
|
||||
graph = Gitlab::Graph::JsonBuilder.new(project)
|
||||
|
||||
@days_json, @commits_json = graph.days_json, graph.commits_json
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json do
|
||||
graph = Gitlab::Graph::JsonBuilder.new(project)
|
||||
render :json => graph.to_json
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
return access_denied! unless can?(current_user, :remove_project, project)
|
||||
|
||||
# Disable the UsersProject update_repository call, otherwise it will be
|
||||
# called once for every person removed from the project
|
||||
UsersProject.skip_callback(:destroy, :after, :update_repository)
|
||||
|
|
|
@ -16,7 +16,7 @@ class SnippetsController < ProjectResourceController
|
|||
respond_to :html
|
||||
|
||||
def index
|
||||
@snippets = @project.snippets
|
||||
@snippets = @project.snippets.fresh
|
||||
end
|
||||
|
||||
def new
|
||||
|
@ -62,7 +62,7 @@ class SnippetsController < ProjectResourceController
|
|||
redirect_to project_snippets_path(@project)
|
||||
end
|
||||
|
||||
def raw
|
||||
def raw
|
||||
send_data(
|
||||
@snippet.content,
|
||||
type: "text/plain",
|
||||
|
|
|
@ -76,7 +76,7 @@ class CommitDecorator < ApplicationDecorator
|
|||
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]
|
||||
avatar = h.image_tag h.gravatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: ""
|
||||
%Q{#{avatar} <span class="commit-#{options[:source]}-name">#{source_name}</span>}
|
||||
else
|
||||
source_name
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
require 'digest/md5'
|
||||
require 'uri'
|
||||
|
||||
module ApplicationHelper
|
||||
|
||||
|
@ -30,13 +31,15 @@ module ApplicationHelper
|
|||
args.any? { |v| v.to_s.downcase == action_name }
|
||||
end
|
||||
|
||||
def gravatar_icon(user_email = '', size = 40)
|
||||
if Gitlab.config.disable_gravatar? || user_email.blank?
|
||||
def gravatar_icon(user_email = '', size = nil)
|
||||
size = 40 if size.nil? || size <= 0
|
||||
|
||||
if !Gitlab.config.gravatar.enabled || user_email.blank?
|
||||
'no_avatar.png'
|
||||
else
|
||||
gravatar_prefix = request.ssl? ? "https://secure" : "http://www"
|
||||
gravatar_url = request.ssl? ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url
|
||||
user_email.strip!
|
||||
"#{gravatar_prefix}.gravatar.com/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=mm"
|
||||
sprintf(gravatar_url, {:hash => Digest::MD5.hexdigest(user_email.downcase), :email => URI.escape(user_email), :size => size})
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -45,7 +48,7 @@ module ApplicationHelper
|
|||
end
|
||||
|
||||
def web_app_url
|
||||
"#{request_protocol}://#{Gitlab.config.web_host}/"
|
||||
"#{request_protocol}://#{Gitlab.config.gitlab.host}/"
|
||||
end
|
||||
|
||||
def last_commit(project)
|
||||
|
@ -92,6 +95,7 @@ module ApplicationHelper
|
|||
{ label: "API Help", url: help_api_path },
|
||||
{ label: "Markdown Help", url: help_markdown_path },
|
||||
{ label: "SSH Keys Help", url: help_ssh_path },
|
||||
{ label: "Gitlab Rake Tasks Help", url: help_raketasks_path },
|
||||
]
|
||||
|
||||
project_nav = []
|
||||
|
|
|
@ -4,28 +4,6 @@ module IssuesHelper
|
|||
project_issues_path project, params
|
||||
end
|
||||
|
||||
def link_to_issue_assignee(issue)
|
||||
project = issue.project
|
||||
|
||||
tm = project.team_member_by_id(issue.assignee_id)
|
||||
if tm
|
||||
link_to issue.assignee_name, project_team_member_path(project, tm), class: "author_link"
|
||||
else
|
||||
issue.assignee_name
|
||||
end
|
||||
end
|
||||
|
||||
def link_to_issue_author(issue)
|
||||
project = issue.project
|
||||
|
||||
tm = project.team_member_by_id(issue.author_id)
|
||||
if tm
|
||||
link_to issue.author_name, project_team_member_path(project, tm), class: "author_link"
|
||||
else
|
||||
issue.author_name
|
||||
end
|
||||
end
|
||||
|
||||
def issue_css_classes issue
|
||||
classes = "issue"
|
||||
classes << " closed" if issue.closed
|
||||
|
@ -52,4 +30,14 @@ module IssuesHelper
|
|||
open: "open"
|
||||
}
|
||||
end
|
||||
|
||||
def labels_autocomplete_source
|
||||
labels = @project.issues_labels.order('count DESC')
|
||||
labels = labels.map{ |l| { label: l.name, value: l.name } }
|
||||
labels.to_json
|
||||
end
|
||||
|
||||
def issues_active_milestones
|
||||
@project.milestones.active.order("id desc").all
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,26 +1,4 @@
|
|||
module MergeRequestsHelper
|
||||
def link_to_merge_request_assignee(merge_request)
|
||||
project = merge_request.project
|
||||
|
||||
tm = project.team_member_by_id(merge_request.assignee_id)
|
||||
if tm
|
||||
link_to merge_request.assignee_name, project_team_member_path(project, tm), class: "author_link"
|
||||
else
|
||||
merge_request.assignee_name
|
||||
end
|
||||
end
|
||||
|
||||
def link_to_merge_request_author(merge_request)
|
||||
project = merge_request.project
|
||||
|
||||
tm = project.team_member_by_id(merge_request.author_id)
|
||||
if tm
|
||||
link_to merge_request.author_name, project_team_member_path(project, tm), class: "author_link"
|
||||
else
|
||||
merge_request.author_name
|
||||
end
|
||||
end
|
||||
|
||||
def new_mr_path_from_push_event(event)
|
||||
new_project_merge_request_path(
|
||||
event.project,
|
||||
|
@ -39,7 +17,7 @@ module MergeRequestsHelper
|
|||
classes
|
||||
end
|
||||
|
||||
def ci_status_path
|
||||
@project.gitlab_ci_service.commit_badge_path(@merge_request.last_commit.sha)
|
||||
def ci_build_details_path merge_request
|
||||
merge_request.project.gitlab_ci_service.build_page(merge_request.last_commit.sha)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,11 +8,49 @@ module ProjectsHelper
|
|||
end
|
||||
|
||||
def link_to_project project
|
||||
link_to project.name, project
|
||||
link_to project do
|
||||
title = content_tag(:strong, project.name)
|
||||
|
||||
if project.namespace
|
||||
namespace = content_tag(:span, "#{project.namespace.human_name} / ", class: 'tiny')
|
||||
title = namespace + title
|
||||
end
|
||||
|
||||
title
|
||||
end
|
||||
end
|
||||
|
||||
def link_to_member(project, author)
|
||||
return "(deleted)" unless author
|
||||
|
||||
# Build avatar image tag
|
||||
avatar = image_tag(gravatar_icon(author.try(:email)), width: 16, class: "lil_av")
|
||||
|
||||
# Build name strong tag
|
||||
name = content_tag :strong, author.name, class: 'author'
|
||||
|
||||
author_html = avatar + name
|
||||
|
||||
tm = project.team_member_by_id(author)
|
||||
|
||||
content_tag :span, class: 'member-link' do
|
||||
if tm
|
||||
link_to author_html, project_team_member_path(project, tm), class: "author_link"
|
||||
else
|
||||
author_html
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def tm_path team_member
|
||||
project_team_member_path(@project, team_member)
|
||||
end
|
||||
end
|
||||
|
||||
def project_title project
|
||||
if project.group
|
||||
project.name_with_namespace
|
||||
else
|
||||
project.name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -72,7 +72,7 @@ module TabHelper
|
|||
return "active" if current_page?(controller: "projects", action: action, id: @project)
|
||||
end
|
||||
|
||||
if ['snippets', 'hooks', 'deploy_keys', 'team_members'].include? controller.controller_name
|
||||
if ['snippets', 'services', 'hooks', 'deploy_keys', 'team_members'].include? controller.controller_name
|
||||
"active"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,11 +3,11 @@ class Notify < ActionMailer::Base
|
|||
add_template_helper ApplicationHelper
|
||||
add_template_helper GitlabMarkdownHelper
|
||||
|
||||
default_url_options[:host] = Gitlab.config.web_host
|
||||
default_url_options[:protocol] = Gitlab.config.web_protocol
|
||||
default_url_options[:port] = Gitlab.config.web_port if Gitlab.config.web_custom_port?
|
||||
default_url_options[:host] = Gitlab.config.gitlab.host
|
||||
default_url_options[:protocol] = Gitlab.config.gitlab.protocol
|
||||
default_url_options[:port] = Gitlab.config.gitlab.port if Gitlab.config.gitlab_on_non_standard_port?
|
||||
|
||||
default from: Gitlab.config.email_from
|
||||
default from: Gitlab.config.gitlab.email_from
|
||||
|
||||
|
||||
|
||||
|
@ -31,6 +31,7 @@ class Notify < ActionMailer::Base
|
|||
def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id)
|
||||
@issue = Issue.find issue_id
|
||||
@issue_status = status
|
||||
@project = @issue.project
|
||||
@updated_by = User.find updated_by_user_id
|
||||
mail(to: recipient(recipient_id),
|
||||
subject: subject("changed issue ##{@issue.id}", @issue.title))
|
||||
|
@ -102,6 +103,12 @@ class Notify < ActionMailer::Base
|
|||
end
|
||||
|
||||
|
||||
def project_was_moved_email(user_project_id)
|
||||
@users_project = UsersProject.find user_project_id
|
||||
@project = @users_project.project
|
||||
mail(to: @users_project.user.email,
|
||||
subject: subject("project was moved"))
|
||||
end
|
||||
|
||||
#
|
||||
# User
|
||||
|
|
|
@ -17,9 +17,7 @@ class Ability
|
|||
|
||||
# Rules based on role in project
|
||||
if project.master_access_for?(user)
|
||||
# TODO: replace with master rules.
|
||||
# Only allow project administration for namespace owners
|
||||
rules << project_admin_rules
|
||||
rules << project_master_rules
|
||||
|
||||
elsif project.dev_access_for?(user)
|
||||
rules << project_dev_rules
|
||||
|
@ -93,13 +91,16 @@ class Ability
|
|||
:admin_merge_request,
|
||||
:admin_note,
|
||||
:accept_mr,
|
||||
:admin_wiki
|
||||
:admin_wiki,
|
||||
:admin_project
|
||||
]
|
||||
end
|
||||
|
||||
def project_admin_rules
|
||||
project_master_rules + [
|
||||
:admin_project
|
||||
:change_namespace,
|
||||
:rename_project,
|
||||
:remove_project
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
@ -87,14 +87,10 @@ class Commit
|
|||
last = project.commit(from.try(:strip))
|
||||
|
||||
if first && last
|
||||
commits = [first, last].sort_by(&:created_at)
|
||||
younger = commits.first
|
||||
older = commits.last
|
||||
|
||||
result[:same] = (younger.id == older.id)
|
||||
result[:commits] = project.repo.commits_between(younger.id, older.id).map {|c| Commit.new(c)}
|
||||
result[:diffs] = project.repo.diff(younger.id, older.id) rescue []
|
||||
result[:commit] = Commit.new(older)
|
||||
result[:same] = (first.id == last.id)
|
||||
result[:commits] = project.repo.commits_between(last.id, first.id).map {|c| Commit.new(c)}
|
||||
result[:diffs] = project.repo.diff(last.id, first.id) rescue []
|
||||
result[:commit] = Commit.new(first)
|
||||
end
|
||||
|
||||
result
|
||||
|
@ -163,6 +159,8 @@ class Commit
|
|||
while !lines.first.start_with?("diff --git") do
|
||||
lines.shift
|
||||
end
|
||||
lines.pop if lines.last =~ /^[\d.]+$/ # Git version
|
||||
lines.pop if lines.last == "-- " # end of diff
|
||||
lines.join("\n")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#
|
||||
|
||||
class Event < ActiveRecord::Base
|
||||
include NoteEvent
|
||||
include PushEvent
|
||||
|
||||
attr_accessible :project, :action, :data, :author_id, :project_id,
|
||||
|
@ -58,12 +59,14 @@ class Event < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
# Next events currently enabled for system
|
||||
# - push
|
||||
# - new issue
|
||||
# - merge request
|
||||
def allowed?
|
||||
push? || issue? || merge_request? || membership_changed?
|
||||
def proper?
|
||||
if push?
|
||||
true
|
||||
elsif membership_changed?
|
||||
true
|
||||
else
|
||||
(issue? || merge_request? || note? || milestone?) && target
|
||||
end
|
||||
end
|
||||
|
||||
def project_name
|
||||
|
@ -94,6 +97,14 @@ class Event < ActiveRecord::Base
|
|||
action == self.class::Reopened
|
||||
end
|
||||
|
||||
def milestone?
|
||||
target_type == "Milestone"
|
||||
end
|
||||
|
||||
def note?
|
||||
target_type == "Note"
|
||||
end
|
||||
|
||||
def issue?
|
||||
target_type == "Issue"
|
||||
end
|
||||
|
|
|
@ -36,4 +36,22 @@ class GitlabCiService < Service
|
|||
def commit_badge_path sha
|
||||
project_url + "/status?sha=#{sha}"
|
||||
end
|
||||
|
||||
def commit_status_path sha
|
||||
project_url + "/builds/#{sha}/status.json?token=#{token}"
|
||||
end
|
||||
|
||||
def commit_status sha
|
||||
response = HTTParty.get(commit_status_path(sha))
|
||||
|
||||
if response.code == 200 and response["status"]
|
||||
response["status"]
|
||||
else
|
||||
:error
|
||||
end
|
||||
end
|
||||
|
||||
def build_page sha
|
||||
project_url + "/builds/#{sha}"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -204,7 +204,7 @@ class MergeRequest < ActiveRecord::Base
|
|||
|
||||
def mr_and_commit_notes
|
||||
commit_ids = commits.map(&:id)
|
||||
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 commit_id IN (:commit_ids))", mr_id: id, commit_ids: commit_ids)
|
||||
end
|
||||
|
||||
# Returns the raw diff for this merge request
|
||||
|
@ -220,4 +220,8 @@ class MergeRequest < ActiveRecord::Base
|
|||
def to_patch
|
||||
project.repo.git.format_patch({timeout: 30, raise: true, stdout: true}, "#{target_branch}..#{source_branch}")
|
||||
end
|
||||
|
||||
def last_commit_short_sha
|
||||
@last_commit_short_sha ||= last_commit.sha[0..10]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,18 +13,26 @@
|
|||
#
|
||||
|
||||
class Milestone < ActiveRecord::Base
|
||||
attr_accessible :title, :description, :due_date, :closed
|
||||
attr_accessible :title, :description, :due_date, :closed, :author_id_of_changes
|
||||
attr_accessor :author_id_of_changes
|
||||
|
||||
belongs_to :project
|
||||
has_many :issues
|
||||
has_many :merge_requests
|
||||
|
||||
scope :active, where(closed: false)
|
||||
scope :closed, where(closed: true)
|
||||
|
||||
validates :title, presence: true
|
||||
validates :project, presence: true
|
||||
validates :closed, inclusion: { in: [true, false] }
|
||||
|
||||
def self.active
|
||||
where("due_date > ? OR due_date IS NULL", Date.today)
|
||||
def expired?
|
||||
if due_date
|
||||
due_date < Date.today
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def participants
|
||||
|
@ -52,4 +60,20 @@ class Milestone < ActiveRecord::Base
|
|||
def expires_at
|
||||
"expires at #{due_date.stamp("Aug 21, 2011")}" if due_date
|
||||
end
|
||||
|
||||
def can_be_closed?
|
||||
open? && issues.opened.count.zero?
|
||||
end
|
||||
|
||||
def is_empty?
|
||||
total_items_count.zero?
|
||||
end
|
||||
|
||||
def open?
|
||||
!closed
|
||||
end
|
||||
|
||||
def author_id
|
||||
author_id_of_changes
|
||||
end
|
||||
end
|
||||
|
|
|
@ -48,23 +48,30 @@ class Namespace < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def ensure_dir_exist
|
||||
namespace_dir_path = File.join(Gitlab.config.git_base_path, path)
|
||||
namespace_dir_path = File.join(Gitlab.config.gitolite.repos_path, path)
|
||||
system("mkdir -m 770 #{namespace_dir_path}") unless File.exists?(namespace_dir_path)
|
||||
end
|
||||
|
||||
def move_dir
|
||||
if path_changed?
|
||||
old_path = File.join(Gitlab.config.git_base_path, path_was)
|
||||
new_path = File.join(Gitlab.config.git_base_path, path)
|
||||
old_path = File.join(Gitlab.config.gitolite.repos_path, path_was)
|
||||
new_path = File.join(Gitlab.config.gitolite.repos_path, path)
|
||||
if File.exists?(new_path)
|
||||
raise "Already exists"
|
||||
end
|
||||
system("mv #{old_path} #{new_path}")
|
||||
|
||||
if system("mv #{old_path} #{new_path}")
|
||||
send_update_instructions
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def rm_dir
|
||||
dir_path = File.join(Gitlab.config.git_base_path, path)
|
||||
dir_path = File.join(Gitlab.config.gitolite.repos_path, path)
|
||||
system("rm -rf #{dir_path}")
|
||||
end
|
||||
|
||||
def send_update_instructions
|
||||
projects.each(&:send_move_instructions)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,7 +19,7 @@ require 'file_size_validator'
|
|||
|
||||
class Note < ActiveRecord::Base
|
||||
attr_accessible :note, :noteable, :noteable_id, :noteable_type, :project_id,
|
||||
:attachment, :line_code
|
||||
:attachment, :line_code, :commit_id
|
||||
|
||||
attr_accessor :notify
|
||||
attr_accessor :notify_author
|
||||
|
@ -35,10 +35,14 @@ class Note < ActiveRecord::Base
|
|||
validates :line_code, format: { with: /\A\d+_\d+_\d+\Z/ }, allow_blank: true
|
||||
validates :attachment, file_size: { maximum: 10.megabytes.to_i }
|
||||
|
||||
validates :noteable_id, presence: true, if: ->(n) { n.noteable_type.present? && n.noteable_type != 'Commit' }
|
||||
validates :commit_id, presence: true, if: ->(n) { n.noteable_type == 'Commit' }
|
||||
|
||||
mount_uploader :attachment, AttachmentUploader
|
||||
|
||||
# Scopes
|
||||
scope :common, ->{ where(noteable_id: nil) }
|
||||
scope :for_commits, ->{ where(noteable_type: "Commit") }
|
||||
scope :common, ->{ where(noteable_id: nil, commit_id: nil) }
|
||||
scope :today, ->{ where("created_at >= :date", date: Date.today) }
|
||||
scope :last_week, ->{ where("created_at >= :date", date: (Date.today - 7.days)) }
|
||||
scope :since, ->(day) { where("created_at >= :date", date: (day)) }
|
||||
|
@ -122,7 +126,7 @@ class Note < ActiveRecord::Base
|
|||
# override to return commits, which are not active record
|
||||
def noteable
|
||||
if for_commit?
|
||||
project.commit(noteable_id)
|
||||
project.commit(commit_id)
|
||||
else
|
||||
super
|
||||
end
|
||||
|
@ -151,4 +155,12 @@ class Note < ActiveRecord::Base
|
|||
def votable?
|
||||
for_issue? || (for_merge_request? && !for_diff_line?)
|
||||
end
|
||||
|
||||
def noteable_type_name
|
||||
if noteable_type.present?
|
||||
noteable_type.downcase
|
||||
else
|
||||
"wall"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -25,6 +25,9 @@ class Project < ActiveRecord::Base
|
|||
include PushObserver
|
||||
include Authority
|
||||
include Team
|
||||
include NamespacedProject
|
||||
|
||||
class TransferError < StandardError; end
|
||||
|
||||
attr_accessible :name, :path, :description, :default_branch, :issues_enabled,
|
||||
:wall_enabled, :merge_requests_enabled, :wiki_enabled, as: [:default, :admin]
|
||||
|
@ -36,6 +39,10 @@ class Project < ActiveRecord::Base
|
|||
# Relations
|
||||
belongs_to :group, foreign_key: "namespace_id", conditions: "type = 'Group'"
|
||||
belongs_to :namespace
|
||||
|
||||
# TODO: replace owner with creator.
|
||||
# With namespaces a project owner will be a namespace owner
|
||||
# so this field makes sense only for global projects
|
||||
belongs_to :owner, class_name: "User"
|
||||
has_many :users, through: :users_projects
|
||||
has_many :events, dependent: :destroy
|
||||
|
@ -97,7 +104,7 @@ class Project < ActiveRecord::Base
|
|||
namespace_id = Namespace.find_by_path(id.first).id
|
||||
where(namespace_id: namespace_id).find_by_path(id.last)
|
||||
else
|
||||
find_by_path(id)
|
||||
where(path: id, namespace_id: nil).last
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -172,7 +179,7 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def repo_name
|
||||
denied_paths = %w(gitolite-admin groups projects dashboard)
|
||||
denied_paths = %w(gitolite-admin admin dashboard groups help profile projects search)
|
||||
|
||||
if denied_paths.include?(path)
|
||||
errors.add(:path, "like #{path} is not allowed")
|
||||
|
@ -188,7 +195,7 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def web_url
|
||||
[Gitlab.config.url, path].join("/")
|
||||
[Gitlab.config.gitlab.url, path_with_namespace].join("/")
|
||||
end
|
||||
|
||||
def common_notes
|
||||
|
@ -196,15 +203,15 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def build_commit_note(commit)
|
||||
notes.new(noteable_id: commit.id, noteable_type: "Commit")
|
||||
notes.new(commit_id: commit.id, noteable_type: "Commit")
|
||||
end
|
||||
|
||||
def commit_notes(commit)
|
||||
notes.where(noteable_id: commit.id, noteable_type: "Commit").where('line_code IS NULL OR line_code = ""')
|
||||
notes.where(commit_id: commit.id, noteable_type: "Commit").where('line_code IS NULL OR line_code = ""')
|
||||
end
|
||||
|
||||
def commit_line_notes(commit)
|
||||
notes.where(noteable_id: commit.id, noteable_type: "Commit").where("line_code IS NOT NULL")
|
||||
notes.where(commit_id: commit.id, noteable_type: "Commit").where("line_code IS NOT NULL")
|
||||
end
|
||||
|
||||
def public?
|
||||
|
@ -239,51 +246,11 @@ class Project < ActiveRecord::Base
|
|||
gitlab_ci_service && gitlab_ci_service.active
|
||||
end
|
||||
|
||||
def path_with_namespace
|
||||
if namespace
|
||||
namespace.path + '/' + path
|
||||
else
|
||||
path
|
||||
end
|
||||
end
|
||||
|
||||
# For compatibility with old code
|
||||
def code
|
||||
path
|
||||
end
|
||||
|
||||
def transfer(new_namespace)
|
||||
Project.transaction do
|
||||
old_namespace = namespace
|
||||
self.namespace = new_namespace
|
||||
|
||||
old_dir = old_namespace.try(:path) || ''
|
||||
new_dir = new_namespace.try(:path) || ''
|
||||
|
||||
old_repo = if old_dir.present?
|
||||
File.join(old_dir, self.path)
|
||||
else
|
||||
self.path
|
||||
end
|
||||
|
||||
Gitlab::ProjectMover.new(self, old_dir, new_dir).execute
|
||||
|
||||
git_host.move_repository(old_repo, self)
|
||||
|
||||
save!
|
||||
end
|
||||
end
|
||||
|
||||
def name_with_namespace
|
||||
@name_with_namespace ||= begin
|
||||
if namespace
|
||||
namespace.human_name + " / " + name
|
||||
else
|
||||
name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def items_for entity
|
||||
case entity
|
||||
when 'issue' then
|
||||
|
@ -293,7 +260,9 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def namespace_owner
|
||||
namespace.try(:owner)
|
||||
def send_move_instructions
|
||||
self.users_projects.each do |member|
|
||||
Notify.project_was_moved_email(member.id).deliver
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -22,7 +22,7 @@ class Snippet < ActiveRecord::Base
|
|||
belongs_to :author, class_name: "User"
|
||||
has_many :notes, as: :noteable, dependent: :destroy
|
||||
|
||||
delegate :name, :email, to: :author, prefix: true
|
||||
delegate :name, :email, to: :author, prefix: true, allow_nil: true
|
||||
|
||||
validates :author, presence: true
|
||||
validates :project, presence: true
|
||||
|
|
|
@ -56,12 +56,12 @@ class User < ActiveRecord::Base
|
|||
has_many :issues, foreign_key: :author_id, dependent: :destroy
|
||||
has_many :notes, foreign_key: :author_id, dependent: :destroy
|
||||
has_many :merge_requests, foreign_key: :author_id, dependent: :destroy
|
||||
has_many :my_own_projects, class_name: "Project", foreign_key: :owner_id
|
||||
has_many :events, class_name: "Event", foreign_key: :author_id, dependent: :destroy
|
||||
has_many :recent_events, class_name: "Event", foreign_key: :author_id, order: "id DESC"
|
||||
has_many :assigned_issues, class_name: "Issue", foreign_key: :assignee_id, dependent: :destroy
|
||||
has_many :assigned_merge_requests, class_name: "MergeRequest", foreign_key: :assignee_id, dependent: :destroy
|
||||
|
||||
validates :name, presence: true
|
||||
validates :bio, length: { within: 0..255 }
|
||||
validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider}
|
||||
validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0}
|
||||
|
@ -123,16 +123,4 @@ class User < ActiveRecord::Base
|
|||
self.password = self.password_confirmation = Devise.friendly_token.first(8)
|
||||
end
|
||||
end
|
||||
|
||||
def authorized_groups
|
||||
@authorized_groups ||= begin
|
||||
groups = Group.where(id: self.projects.pluck(:namespace_id)).all
|
||||
groups = groups + self.groups
|
||||
groups.uniq
|
||||
end
|
||||
end
|
||||
|
||||
def authorized_projects
|
||||
Project.authorized_for(self)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -28,6 +28,7 @@ class UsersProject < ActiveRecord::Base
|
|||
|
||||
validates :user, presence: true
|
||||
validates :user_id, uniqueness: { :scope => [:project_id], message: "already exists in project" }
|
||||
validates :project_access, inclusion: { in: [GUEST, REPORTER, DEVELOPER, MASTER] }, presence: true
|
||||
validates :project, presence: true
|
||||
|
||||
delegate :name, :email, to: :user, prefix: true
|
||||
|
|
|
@ -1,18 +1,27 @@
|
|||
class ActivityObserver < ActiveRecord::Observer
|
||||
observe :issue, :merge_request
|
||||
observe :issue, :merge_request, :note, :milestone
|
||||
|
||||
def after_create(record)
|
||||
Event.create(
|
||||
project: record.project,
|
||||
target_id: record.id,
|
||||
target_type: record.class.name,
|
||||
action: Event.determine_action(record),
|
||||
author_id: record.author_id
|
||||
)
|
||||
event_author_id = record.author_id
|
||||
|
||||
# Skip status notes
|
||||
if record.kind_of?(Note) && record.note.include?("_Status changed to ")
|
||||
return true
|
||||
end
|
||||
|
||||
if event_author_id
|
||||
Event.create(
|
||||
project: record.project,
|
||||
target_id: record.id,
|
||||
target_type: record.class.name,
|
||||
action: Event.determine_action(record),
|
||||
author_id: event_author_id
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def after_save(record)
|
||||
if record.changed.include?("closed")
|
||||
if record.changed.include?("closed") && record.author_id_of_changes
|
||||
Event.create(
|
||||
project: record.project,
|
||||
target_id: record.id,
|
||||
|
|
|
@ -16,7 +16,7 @@ class IssueObserver < ActiveRecord::Observer
|
|||
if status
|
||||
Note.create_status_change_note(issue, current_user, status)
|
||||
[issue.author, issue.assignee].compact.each do |recipient|
|
||||
Notify.issue_status_changed_email(recipient.id, issue.id, status, current_user)
|
||||
Notify.issue_status_changed_email(recipient.id, issue.id, status, current_user.id).deliver
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,7 +21,7 @@ class NoteObserver < ActiveRecord::Observer
|
|||
# Notifies the whole team except the author of note
|
||||
def notify_team(note)
|
||||
# Note: wall posts are not "attached" to anything, so fall back to "Wall"
|
||||
noteable_type = note.noteable_type || "Wall"
|
||||
noteable_type = note.noteable_type.presence || "Wall"
|
||||
notify_method = "note_#{noteable_type.underscore}_email".to_sym
|
||||
|
||||
if Notify.respond_to? notify_method
|
||||
|
|
|
@ -3,7 +3,8 @@ class ProjectObserver < ActiveRecord::Observer
|
|||
project.update_repository
|
||||
end
|
||||
|
||||
def after_save(project)
|
||||
def after_update(project)
|
||||
project.send_move_instructions if project.namespace_id_changed?
|
||||
end
|
||||
|
||||
def after_destroy(project)
|
||||
|
|
|
@ -47,7 +47,7 @@ module Account
|
|||
end
|
||||
|
||||
def cared_merge_requests
|
||||
MergeRequest.where("author_id = :id or assignee_id = :id", id: self.id).opened
|
||||
MergeRequest.where("author_id = :id or assignee_id = :id", id: self.id)
|
||||
end
|
||||
|
||||
def project_ids
|
||||
|
@ -105,4 +105,20 @@ module Account
|
|||
def namespace_id
|
||||
namespace.try :id
|
||||
end
|
||||
|
||||
def authorized_groups
|
||||
@authorized_groups ||= begin
|
||||
groups = Group.where(id: self.projects.pluck(:namespace_id)).all
|
||||
groups = groups + self.groups
|
||||
groups.uniq
|
||||
end
|
||||
end
|
||||
|
||||
def authorized_projects
|
||||
Project.authorized_for(self)
|
||||
end
|
||||
|
||||
def my_own_projects
|
||||
Project.personal(self)
|
||||
end
|
||||
end
|
||||
|
|
59
app/roles/namespaced_project.rb
Normal file
|
@ -0,0 +1,59 @@
|
|||
module NamespacedProject
|
||||
def transfer(new_namespace)
|
||||
Project.transaction do
|
||||
old_namespace = namespace
|
||||
self.namespace = new_namespace
|
||||
|
||||
old_dir = old_namespace.try(:path) || ''
|
||||
new_dir = new_namespace.try(:path) || ''
|
||||
|
||||
old_repo = if old_dir.present?
|
||||
File.join(old_dir, self.path)
|
||||
else
|
||||
self.path
|
||||
end
|
||||
|
||||
if Project.where(path: self.path, namespace_id: new_namespace.try(:id)).present?
|
||||
raise TransferError.new("Project with same path in target namespace already exists")
|
||||
end
|
||||
|
||||
Gitlab::ProjectMover.new(self, old_dir, new_dir).execute
|
||||
|
||||
git_host.move_repository(old_repo, self)
|
||||
|
||||
save!
|
||||
end
|
||||
rescue Gitlab::ProjectMover::ProjectMoveError => ex
|
||||
raise TransferError.new(ex.message)
|
||||
end
|
||||
|
||||
def name_with_namespace
|
||||
@name_with_namespace ||= begin
|
||||
if namespace
|
||||
namespace.human_name + " / " + name
|
||||
else
|
||||
name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def namespace_owner
|
||||
namespace.try(:owner)
|
||||
end
|
||||
|
||||
def chief
|
||||
if namespace
|
||||
namespace_owner
|
||||
else
|
||||
owner
|
||||
end
|
||||
end
|
||||
|
||||
def path_with_namespace
|
||||
if namespace
|
||||
namespace.path + '/' + path
|
||||
else
|
||||
path
|
||||
end
|
||||
end
|
||||
end
|
37
app/roles/note_event.rb
Normal file
|
@ -0,0 +1,37 @@
|
|||
module NoteEvent
|
||||
def note_commit_id
|
||||
target.commit_id
|
||||
end
|
||||
|
||||
def note_short_commit_id
|
||||
note_commit_id[0..8]
|
||||
end
|
||||
|
||||
def note_commit?
|
||||
target.noteable_type == "Commit"
|
||||
end
|
||||
|
||||
def note_target
|
||||
target.noteable
|
||||
end
|
||||
|
||||
def note_target_id
|
||||
if note_commit?
|
||||
target.commit_id
|
||||
else
|
||||
target.noteable_id.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def wall_note?
|
||||
target.noteable_type.blank?
|
||||
end
|
||||
|
||||
def note_target_type
|
||||
if target.noteable_type.present?
|
||||
target.noteable_type.titleize
|
||||
else
|
||||
"Wall"
|
||||
end.downcase
|
||||
end
|
||||
end
|
|
@ -114,7 +114,7 @@ module PushObserver
|
|||
id: commit.id,
|
||||
message: commit.safe_message,
|
||||
timestamp: commit.date.xmlschema,
|
||||
url: "#{Gitlab.config.url}/#{path}/commits/#{commit.id}",
|
||||
url: "#{Gitlab.config.gitlab.url}/#{path_with_namespace}/commit/#{commit.id}",
|
||||
author: {
|
||||
name: commit.author_name,
|
||||
email: commit.author_email
|
||||
|
|
|
@ -45,8 +45,22 @@ module Repository
|
|||
end
|
||||
|
||||
def has_post_receive_file?
|
||||
hook_file = File.join(path_to_repo, 'hooks', 'post-receive')
|
||||
File.exists?(hook_file)
|
||||
!!hook_file
|
||||
end
|
||||
|
||||
def valid_post_receive_file?
|
||||
valid_hook_file == hook_file
|
||||
end
|
||||
|
||||
def valid_hook_file
|
||||
@valid_hook_file ||= File.read(Rails.root.join('lib', 'hooks', 'post-receive'))
|
||||
end
|
||||
|
||||
def hook_file
|
||||
@hook_file ||= begin
|
||||
hook_path = File.join(path_to_repo, 'hooks', 'post-receive')
|
||||
File.read(hook_path) if File.exists?(hook_path)
|
||||
end
|
||||
end
|
||||
|
||||
# Returns an Array of branch names
|
||||
|
@ -83,7 +97,7 @@ module Repository
|
|||
end
|
||||
|
||||
def path_to_repo
|
||||
File.join(Gitlab.config.git_base_path, "#{path_with_namespace}.git")
|
||||
File.join(Gitlab.config.gitolite.repos_path, "#{path_with_namespace}.git")
|
||||
end
|
||||
|
||||
def namespace_dir
|
||||
|
@ -185,7 +199,7 @@ module Repository
|
|||
end
|
||||
|
||||
def http_url_to_repo
|
||||
http_url = [Gitlab.config.url, "/", path_with_namespace, ".git"].join('')
|
||||
http_url = [Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('')
|
||||
end
|
||||
|
||||
# Check if current branch name is marked as protected in the system
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
= form_for [:admin, @group] do |f|
|
||||
- if @group.errors.any?
|
||||
.alert-message.block-message.error
|
||||
%span= @group.errors.full_messages.first
|
||||
.clearfix.group_name_holder
|
||||
= f.label :name do
|
||||
Group name is
|
||||
.input
|
||||
= f.text_field :name, placeholder: "Example Group", class: "xxlarge"
|
||||
|
||||
.form-actions
|
||||
= f.submit 'Save group', class: "btn save-btn"
|
|
@ -1,3 +1,28 @@
|
|||
%h3.page_title Edit Group
|
||||
%br
|
||||
= render 'form'
|
||||
%h3.page_title Rename Group
|
||||
%hr
|
||||
= form_for [:admin, @group] do |f|
|
||||
- if @group.errors.any?
|
||||
.alert-message.block-message.error
|
||||
%span= @group.errors.full_messages.first
|
||||
.clearfix.group_name_holder
|
||||
= f.label :name do
|
||||
Group name is
|
||||
.input
|
||||
= f.text_field :name, placeholder: "Example Group", class: "xxlarge"
|
||||
|
||||
|
||||
|
||||
.clearfix.group_name_holder
|
||||
= f.label :path do
|
||||
%span.cred Group path is
|
||||
.input
|
||||
= f.text_field :path, placeholder: "example-group", class: "xxlarge danger"
|
||||
%ul.cred
|
||||
%li Changing group path can have unintended side effects.
|
||||
%li Renaming group path will rename directory for all related projects
|
||||
%li It will change web url for access group and group projects.
|
||||
%li It will change the git path to repositories under this group.
|
||||
|
||||
.form-actions
|
||||
= f.submit 'Rename group', class: "btn danger"
|
||||
= link_to 'Cancel', admin_groups_path, class: "btn cancel-btn"
|
||||
|
|
|
@ -12,17 +12,24 @@
|
|||
|
||||
%table
|
||||
%thead
|
||||
%th Name
|
||||
%th Path
|
||||
%th Projects
|
||||
%th Edit
|
||||
%th.cred Danger Zone!
|
||||
%tr
|
||||
%th
|
||||
Name
|
||||
%i.icon-sort-down
|
||||
%th Path
|
||||
%th Projects
|
||||
%th Owner
|
||||
%th.cred Danger Zone!
|
||||
|
||||
- @groups.each do |group|
|
||||
%tr
|
||||
%td= link_to group.name, [:admin, group]
|
||||
%td
|
||||
%strong= link_to group.name, [:admin, group]
|
||||
%td= group.path
|
||||
%td= group.projects.count
|
||||
%td= link_to 'Edit', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn small"
|
||||
%td.bgred= link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn small danger"
|
||||
%td
|
||||
= link_to group.owner_name, admin_user_path(group.owner_id)
|
||||
%td.bgred
|
||||
= link_to 'Rename', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn small"
|
||||
= link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn small danger"
|
||||
= paginate @groups, theme: "admin"
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
%h3.page_title
|
||||
Group: #{@group.name}
|
||||
= link_to edit_admin_group_path(@group), class: "btn right" do
|
||||
%i.icon-edit
|
||||
Edit
|
||||
|
||||
%br
|
||||
%table.zebra-striped
|
||||
|
@ -16,36 +13,64 @@
|
|||
Name:
|
||||
%td
|
||||
= @group.name
|
||||
|
||||
= link_to edit_admin_group_path(@group), class: "btn btn-small right" do
|
||||
%i.icon-edit
|
||||
Rename
|
||||
%tr
|
||||
%td
|
||||
%b
|
||||
Path:
|
||||
%td
|
||||
%span.monospace= File.join(Gitlab.config.git_base_path, @group.path)
|
||||
%span.monospace= File.join(Gitlab.config.gitolite.repos_path, @group.path)
|
||||
%tr
|
||||
%td
|
||||
%b
|
||||
Owner:
|
||||
%td
|
||||
= @group.owner_name
|
||||
.ui-box
|
||||
%h5
|
||||
Projects
|
||||
%small
|
||||
(#{@group.projects.count})
|
||||
%ul.unstyled
|
||||
.right
|
||||
= link_to "#", class: "btn btn-small change-owner-link" do
|
||||
%i.icon-edit
|
||||
Change owner
|
||||
|
||||
%tr.change-owner-holder.hide
|
||||
%td.bgred
|
||||
%b.cred
|
||||
New Owner:
|
||||
%td.bgred
|
||||
= form_for [:admin, @group] do |f|
|
||||
= f.select :owner_id, User.all.map { |user| [user.name, user.id] }, {}, {class: 'chosen'}
|
||||
%div
|
||||
= f.submit 'Change Owner', class: "btn danger"
|
||||
= link_to "Cancel", "#", class: "btn change-owner-cancel-link"
|
||||
%fieldset
|
||||
%legend Projects (#{@group.projects.count})
|
||||
%table
|
||||
%thead
|
||||
%tr
|
||||
%th Project name
|
||||
%th Path
|
||||
%th Users
|
||||
%th.cred Danger Zone!
|
||||
- @group.projects.each do |project|
|
||||
%li.wll
|
||||
%strong
|
||||
= link_to project.name, [:admin, project]
|
||||
.right
|
||||
= link_to 'Remove from group', remove_project_admin_group_path(@group, project_id: project.id), confirm: 'Are you sure?', method: :delete, class: "btn danger small"
|
||||
.clearfix
|
||||
%tr
|
||||
%td
|
||||
= link_to project.name_with_namespace, [:admin, project]
|
||||
%td
|
||||
%span.monospace= project.path_with_namespace + ".git"
|
||||
%td= project.users.count
|
||||
%td.bgred
|
||||
= link_to 'Transfer project to global namespace', remove_project_admin_group_path(@group, project_id: project.id), confirm: 'Remove project from group and move to global namespace. Are you sure?', method: :delete, class: "btn danger small"
|
||||
|
||||
|
||||
= form_tag project_update_admin_group_path(@group), class: "bulk_import", method: :put do
|
||||
%fieldset
|
||||
%legend Move projects to group
|
||||
.alert
|
||||
You can move only projects with existing repos
|
||||
%br
|
||||
Group projects will be moved in group directory and will not be accessible by old path
|
||||
.clearfix
|
||||
= label_tag :project_ids do
|
||||
Projects
|
||||
|
@ -53,3 +78,17 @@
|
|||
= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5'
|
||||
.form-actions
|
||||
= submit_tag 'Add', class: "btn primary"
|
||||
|
||||
:javascript
|
||||
$(function(){
|
||||
var modal = $('.change-owner-holder');
|
||||
$('.change-owner-link').bind("click", function(){
|
||||
$(this).hide();
|
||||
modal.show();
|
||||
});
|
||||
$('.change-owner-cancel-link').bind("click", function(){
|
||||
modal.hide();
|
||||
$('.change-owner-link').show();
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
= link_to "githost.log", "#githost", 'data-toggle' => 'tab'
|
||||
%li
|
||||
= link_to "application.log", "#application", 'data-toggle' => 'tab'
|
||||
%li
|
||||
= link_to "production.log", "#production", 'data-toggle' => 'tab'
|
||||
|
||||
%p.light To prevent perfomance issues admin logs output the last 2000 lines
|
||||
.tab-content
|
||||
|
@ -34,3 +36,17 @@
|
|||
- Gitlab::AppLogger.read_latest.each do |line|
|
||||
%li
|
||||
%p= line
|
||||
.tab-pane#production
|
||||
.file_holder#README
|
||||
.file_title
|
||||
%i.icon-file
|
||||
production.log
|
||||
.right
|
||||
= link_to '#', class: 'log-bottom' do
|
||||
%i.icon-arrow-down
|
||||
Scroll down
|
||||
.file_content.logs
|
||||
%ol
|
||||
- Gitlab::Logger.read_latest_for('production.log').each do |line|
|
||||
%li
|
||||
%p= line
|
||||
|
|
|
@ -19,40 +19,47 @@
|
|||
.input
|
||||
= text_field_tag :ppath, @project.path_to_repo, class: "xlarge", disabled: true
|
||||
|
||||
- unless project.new_record?
|
||||
- if project.repo_exists?
|
||||
.clearfix
|
||||
= f.label :namespace_id
|
||||
.input= f.select :namespace_id, namespaces_options(@project.namespace_id), {}, {class: 'chosen'}
|
||||
= f.label :default_branch, "Default Branch"
|
||||
.input= f.select(:default_branch, project.heads.map(&:name), {}, style: "width:210px;")
|
||||
|
||||
- if project.repo_exists?
|
||||
.clearfix
|
||||
= f.label :default_branch, "Default Branch"
|
||||
.input= f.select(:default_branch, project.heads.map(&:name), {}, style: "width:210px;")
|
||||
%fieldset.adv_settings
|
||||
%legend Features:
|
||||
|
||||
- unless project.new_record?
|
||||
%fieldset.adv_settings
|
||||
%legend Features:
|
||||
.clearfix
|
||||
= f.label :issues_enabled, "Issues"
|
||||
.input= f.check_box :issues_enabled
|
||||
|
||||
.clearfix
|
||||
= f.label :issues_enabled, "Issues"
|
||||
.input= f.check_box :issues_enabled
|
||||
.clearfix
|
||||
= f.label :merge_requests_enabled, "Merge Requests"
|
||||
.input= f.check_box :merge_requests_enabled
|
||||
|
||||
.clearfix
|
||||
= f.label :merge_requests_enabled, "Merge Requests"
|
||||
.input= f.check_box :merge_requests_enabled
|
||||
.clearfix
|
||||
= f.label :wall_enabled, "Wall"
|
||||
.input= f.check_box :wall_enabled
|
||||
|
||||
.clearfix
|
||||
= f.label :wall_enabled, "Wall"
|
||||
.input= f.check_box :wall_enabled
|
||||
.clearfix
|
||||
= f.label :wiki_enabled, "Wiki"
|
||||
.input= f.check_box :wiki_enabled
|
||||
|
||||
.clearfix
|
||||
= f.label :wiki_enabled, "Wiki"
|
||||
.input= f.check_box :wiki_enabled
|
||||
%fieldset.features
|
||||
%legend Transfer:
|
||||
.control-group
|
||||
= f.label :namespace_id do
|
||||
%span Namespace
|
||||
.controls
|
||||
= f.select :namespace_id, namespaces_options(@project.namespace_id, :all), {}, {class: 'chosen'}
|
||||
%br
|
||||
%ul.prepend-top-10.cred
|
||||
%li Be careful. Changing project namespace can have unintended side effects
|
||||
%li You can transfer project only to namespaces you can manage
|
||||
%li You will need to update your local repositories to point to the new location.
|
||||
|
||||
- unless project.new_record?
|
||||
.actions
|
||||
= f.submit 'Save Project', class: "btn save-btn"
|
||||
= link_to 'Cancel', admin_projects_path, class: "btn cancel-btn"
|
||||
|
||||
.actions
|
||||
= f.submit 'Save Project', class: "btn save-btn"
|
||||
= link_to 'Cancel', admin_projects_path, class: "btn cancel-btn"
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%h3.page_title
|
||||
Projects
|
||||
Projects (#{@projects.count})
|
||||
= link_to 'New Project', new_project_path, class: "btn small right"
|
||||
%br
|
||||
= form_tag admin_projects_path, method: :get, class: 'form-inline' do
|
||||
|
@ -9,12 +9,15 @@
|
|||
|
||||
%table
|
||||
%thead
|
||||
%th Name
|
||||
%th Path
|
||||
%th Team Members
|
||||
%th Last Commit
|
||||
%th Edit
|
||||
%th.cred Danger Zone!
|
||||
%tr
|
||||
%th
|
||||
Name
|
||||
%i.icon-sort-down
|
||||
%th Path
|
||||
%th Team Members
|
||||
%th Last Commit
|
||||
%th Edit
|
||||
%th.cred Danger Zone!
|
||||
|
||||
- @projects.each do |project|
|
||||
%tr
|
||||
|
|
|
@ -4,14 +4,24 @@
|
|||
%i.icon-edit
|
||||
Edit
|
||||
|
||||
- if !@project.has_post_receive_file? && @project.has_commits?
|
||||
%br
|
||||
.alert.alert-error
|
||||
%span
|
||||
%strong Important!
|
||||
Project has commits but missing post-receive file.
|
||||
%br
|
||||
If you exported project manually - copy post-receive hook to bare repository
|
||||
- if @project.has_commits?
|
||||
- if !@project.has_post_receive_file?
|
||||
%br
|
||||
.alert.alert-error
|
||||
%span
|
||||
%strong Project has commits but missing post-receive file.
|
||||
%br
|
||||
If you exported project manually - make a link of post-receive hook file from gitolite to project repository
|
||||
- elsif !@project.valid_post_receive_file?
|
||||
%br
|
||||
.alert.alert-error
|
||||
%span
|
||||
%strong Project has invalid post-receive file.
|
||||
%br
|
||||
1. Make sure your gitolite instace has latest post-receive file.
|
||||
%br
|
||||
2. Make a link of post-receive hook file from gitolite to project repository
|
||||
|
||||
|
||||
%br
|
||||
%table.zebra-striped
|
||||
|
@ -37,23 +47,63 @@
|
|||
%tr
|
||||
%td
|
||||
%b
|
||||
Path:
|
||||
Owned by:
|
||||
%td
|
||||
%code= @project.path_to_repo
|
||||
- if @project.chief
|
||||
= link_to @project.chief.name, admin_user_path(@project.chief)
|
||||
- else
|
||||
(deleted)
|
||||
%tr
|
||||
%td
|
||||
%b
|
||||
Created by:
|
||||
%td
|
||||
= @project.owner_name || '(deleted)'
|
||||
%tr
|
||||
%td
|
||||
%b
|
||||
Created at:
|
||||
%td
|
||||
= @project.created_at.stamp("March 1, 1999")
|
||||
|
||||
%table.zebra-striped
|
||||
%thead
|
||||
%tr
|
||||
%th Repository
|
||||
%th
|
||||
%tr
|
||||
%td
|
||||
%b
|
||||
FS Path:
|
||||
%td
|
||||
%code= @project.path_to_repo
|
||||
%tr
|
||||
%td
|
||||
%b
|
||||
Smart HTTP:
|
||||
%td
|
||||
= link_to @project.http_url_to_repo
|
||||
%tr
|
||||
%td
|
||||
%b
|
||||
SSH:
|
||||
%td
|
||||
= link_to @project.ssh_url_to_repo
|
||||
%tr
|
||||
%td
|
||||
%b
|
||||
Last commit at:
|
||||
%td
|
||||
= last_commit(@project)
|
||||
%tr
|
||||
%td
|
||||
%b
|
||||
Post Receive File:
|
||||
%td
|
||||
= check_box_tag :post_receive_file, 1, @project.has_post_receive_file?, disabled: true
|
||||
|
||||
%br
|
||||
%h3
|
||||
%h5
|
||||
Team
|
||||
%small
|
||||
(#{@project.users_projects.count})
|
||||
|
@ -75,7 +125,7 @@
|
|||
%td= link_to 'Remove from team', admin_team_member_path(tm), confirm: 'Are you sure?', method: :delete, class: "btn danger small"
|
||||
|
||||
%br
|
||||
%h3 Add new team member
|
||||
%h5 Add new team member
|
||||
%br
|
||||
= form_tag team_update_admin_project_path(@project), class: "bulk_import", method: :put do
|
||||
%table.zebra-striped
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%h3.page_title
|
||||
Users
|
||||
Users (#{@admin_users.count})
|
||||
= link_to 'New User', new_admin_user_path, class: "btn small right"
|
||||
%br
|
||||
|
||||
|
@ -21,13 +21,16 @@
|
|||
|
||||
%table
|
||||
%thead
|
||||
%th Admin
|
||||
%th Name
|
||||
%th Username
|
||||
%th Email
|
||||
%th Projects
|
||||
%th Edit
|
||||
%th.cred Danger Zone!
|
||||
%tr
|
||||
%th Admin
|
||||
%th
|
||||
Name
|
||||
%i.icon-sort-down
|
||||
%th Username
|
||||
%th Email
|
||||
%th Projects
|
||||
%th Edit
|
||||
%th.cred Danger Zone!
|
||||
|
||||
- @admin_users.each do |user|
|
||||
%tr
|
||||
|
@ -38,10 +41,13 @@
|
|||
%td= user.users_projects.count
|
||||
%td= link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn small"
|
||||
%td.bgred
|
||||
- if user.blocked
|
||||
= link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn small success"
|
||||
- if user == current_user
|
||||
%span.cred It's you!
|
||||
- else
|
||||
= link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small danger"
|
||||
= link_to 'Destroy', [:admin, user], confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn small danger"
|
||||
- if user.blocked
|
||||
= link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn small success"
|
||||
- else
|
||||
= link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small danger"
|
||||
= link_to 'Destroy', [:admin, user], confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn small danger"
|
||||
|
||||
= paginate @admin_users, theme: "admin"
|
||||
|
|
|
@ -37,6 +37,12 @@
|
|||
%b
|
||||
Blocked:
|
||||
%td= check_box_tag "blocked", 1, @admin_user.blocked, disabled: :disabled
|
||||
%tr
|
||||
%td
|
||||
%b
|
||||
Created at:
|
||||
%td
|
||||
= @admin_user.created_at.stamp("March 1, 1999")
|
||||
%tr
|
||||
%td
|
||||
%b
|
||||
|
@ -66,7 +72,7 @@
|
|||
= @admin_user.twitter
|
||||
|
||||
%br
|
||||
%h3 Add User to Projects
|
||||
%h5 Add User to Projects
|
||||
%br
|
||||
= form_tag team_update_admin_user_path(@admin_user), class: "bulk_import", method: :put do
|
||||
%table
|
||||
|
@ -76,7 +82,7 @@
|
|||
%th Project Access:
|
||||
|
||||
%tr
|
||||
%td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5'
|
||||
%td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5'
|
||||
%td= select_tag :project_access, options_for_select(Project.access_options), class: "project-access-select chosen span3"
|
||||
|
||||
%tr
|
||||
|
@ -86,8 +92,22 @@
|
|||
%strong= link_to "here", help_permissions_path, class: "vlink"
|
||||
%br
|
||||
|
||||
- if @admin_user.groups.present?
|
||||
%h5 Owner of groups:
|
||||
%br
|
||||
|
||||
%table.zebra-striped
|
||||
%thead
|
||||
%tr
|
||||
%th Name
|
||||
|
||||
- @admin_user.groups.each do |group|
|
||||
%tr
|
||||
%td= link_to group.name, admin_group_path(group)
|
||||
|
||||
|
||||
- if @admin_user.projects.present?
|
||||
%h3 Projects
|
||||
%h5 Projects:
|
||||
%br
|
||||
|
||||
%table.zebra-striped
|
||||
|
@ -101,7 +121,7 @@
|
|||
- @admin_user.users_projects.each do |tm|
|
||||
- project = tm.project
|
||||
%tr
|
||||
%td= link_to project.name, admin_project_path(project)
|
||||
%td= link_to project.name_with_namespace, admin_project_path(project)
|
||||
%td= tm.project_access_human
|
||||
%td= link_to 'Edit Access', edit_admin_team_member_path(tm), class: "btn small"
|
||||
%td= link_to 'Remove from team', admin_team_member_path(tm), confirm: 'Are you sure?', method: :delete, class: "btn small danger"
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
%h5.small
|
||||
%i.icon-calendar
|
||||
= day.stamp("28 Aug, 2010")
|
||||
%ul.unstyled= render commits
|
||||
%ul.well-list= render commits
|
||||
|
|
|
@ -1,23 +1,30 @@
|
|||
%div
|
||||
%p.slead
|
||||
Fill input field with commit id like
|
||||
%code.label_branch 4eedf23
|
||||
or branch/tag name like
|
||||
%code.label_branch master
|
||||
and press compare button for commits list, code diff.
|
||||
- unless params[:to]
|
||||
%p.slead
|
||||
Fill input field with commit id like
|
||||
%code.label_branch 4eedf23
|
||||
or branch/tag name like
|
||||
%code.label_branch master
|
||||
and press compare button for commits list, code diff.
|
||||
|
||||
%br
|
||||
%br
|
||||
|
||||
= form_tag project_compare_index_path(@project), method: :post do
|
||||
.clearfix
|
||||
= text_field_tag :from, params[:from], placeholder: "master", class: "xlarge"
|
||||
= "..."
|
||||
= text_field_tag :to, params[:to], placeholder: "aa8b4ef", class: "xlarge"
|
||||
.pull-left
|
||||
- if params[:to] && params[:from]
|
||||
= link_to 'switch', {from: params[:to], to: params[:from]}, {class: 'commits-compare-switch has_tooltip', title: 'Switch base of comparison'}
|
||||
= text_field_tag :from, params[:from], placeholder: "master", class: "xlarge"
|
||||
= "..."
|
||||
= text_field_tag :to, params[:to], placeholder: "aa8b4ef", class: "xlarge"
|
||||
.pull-left
|
||||
|
||||
= submit_tag "Compare", class: "btn primary wide commits-compare-btn"
|
||||
- if @refs_are_same
|
||||
.alert
|
||||
%span Refs are the same
|
||||
.actions
|
||||
= submit_tag "Compare", class: "btn primary wide commits-compare-btn"
|
||||
|
||||
|
||||
|
||||
:javascript
|
||||
$(function() {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
- if @commits.present?
|
||||
%div.ui-box
|
||||
%h5.small Commits (#{@commits.count})
|
||||
%ul.unstyled= render @commits
|
||||
%ul.well-list= render @commits
|
||||
|
||||
- unless @diffs.empty?
|
||||
%h4 Diff
|
||||
|
|