Commit 40329831 authored by dosire's avatar dosire

Merge branch 'master' into styleguide

Conflicts:
	CONTRIBUTING.md
parents 77dc5de9 bbd92f55
v 6.6.0 v 6.6.0
- Retrieving user ssh keys publically(github style): http://__HOST__/__USERNAME__.keys
- Permissions: Developer now can manage issue tracker (modify any issue) - Permissions: Developer now can manage issue tracker (modify any issue)
- Improve Code Compare page performance
- Group avatar
- Pygments.rb replaced with highlight.js
- Improve Merge request diff store logic
- Improve render performnace for MR show page
- Fixed Assembla hardcoded project name
- Jira integration documentation
- Refactored app/services
- Remove snippet expiration
- Mobile UI improvements (Drew Blessing)
- Fix block/remove UI for admin::users#show page
- Show users' group membership on users' activity page
- User pages are visible without login if user is authorized to a public project
- Markdown rendered headers have id derived from their name and link to their id
- Improve application to work faster with large groups (100+ members)
- Multiple emails per user
- Show last commit for file when view file source
- Restyle Issue#show page and MR#show page
- Ability to filter by multiple labels for Issues page
- Rails version to 4.0.3
v 6.5.1 v 6.5.1
- Fix branch selectbox when create merge request from fork - Fix branch selectbox when create merge request from fork
......
...@@ -29,22 +29,19 @@ gem 'omniauth-github' ...@@ -29,22 +29,19 @@ gem 'omniauth-github'
# Extracting information from a git repository # Extracting information from a git repository
# Provide access to Gitlab::Git library # Provide access to Gitlab::Git library
gem "gitlab_git", "~> 4.0.0" gem "gitlab_git", '~> 5.4.0'
# Ruby/Rack Git Smart-HTTP Server Handler # Ruby/Rack Git Smart-HTTP Server Handler
gem 'gitlab-grack', '~> 2.0.0.pre', require: 'grack' gem 'gitlab-grack', '~> 2.0.0.pre', require: 'grack'
# LDAP Auth # LDAP Auth
gem 'gitlab_omniauth-ldap', '1.0.3', require: "omniauth-ldap" gem 'gitlab_omniauth-ldap', '1.0.4', require: "omniauth-ldap"
# Syntax highlighter
gem "gitlab-pygments.rb", '~> 0.5.4', require: 'pygments.rb'
# Git Wiki # Git Wiki
gem "gitlab-gollum-lib", "~> 1.0.2", require: 'gollum-lib' gem "gitlab-gollum-lib", "~> 1.1.0", require: 'gollum-lib'
# Language detection # Language detection
gem "gitlab-linguist", "~> 2.9.6", require: "linguist" gem "gitlab-linguist", "~> 3.0.0", require: "linguist"
# API # API
gem "grape", "~> 0.6.1" gem "grape", "~> 0.6.1"
...@@ -139,6 +136,9 @@ gem "sanitize" ...@@ -139,6 +136,9 @@ gem "sanitize"
# Protect against bruteforcing # Protect against bruteforcing
gem "rack-attack" gem "rack-attack"
# Ace editor
gem 'ace-rails-ap'
gem "sass-rails" gem "sass-rails"
gem "coffee-rails" gem "coffee-rails"
gem "uglifier" gem "uglifier"
...@@ -208,6 +208,10 @@ group :development, :test do ...@@ -208,6 +208,10 @@ group :development, :test do
gem 'spork', '~> 1.0rc' gem 'spork', '~> 1.0rc'
gem 'jasmine', '2.0.0.rc5' gem 'jasmine', '2.0.0.rc5'
gem "spring", '1.1.1'
gem "spring-commands-rspec", '1.0.1'
gem "spring-commands-spinach", '1.0.0'
end end
group :test do group :test do
......
...@@ -8,11 +8,12 @@ GIT ...@@ -8,11 +8,12 @@ GIT
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actionmailer (4.0.2) ace-rails-ap (2.0.1)
actionpack (= 4.0.2) actionmailer (4.0.3)
actionpack (= 4.0.3)
mail (~> 2.5.4) mail (~> 2.5.4)
actionpack (4.0.2) actionpack (4.0.3)
activesupport (= 4.0.2) activesupport (= 4.0.3)
builder (~> 3.1.0) builder (~> 3.1.0)
erubis (~> 2.7.0) erubis (~> 2.7.0)
rack (~> 1.5.2) rack (~> 1.5.2)
...@@ -21,16 +22,16 @@ GEM ...@@ -21,16 +22,16 @@ GEM
actionpack (>= 4.0.0, < 5.0) actionpack (>= 4.0.0, < 5.0)
actionpack-page_caching (1.0.2) actionpack-page_caching (1.0.2)
actionpack (>= 4.0.0, < 5) actionpack (>= 4.0.0, < 5)
activemodel (4.0.2) activemodel (4.0.3)
activesupport (= 4.0.2) activesupport (= 4.0.3)
builder (~> 3.1.0) builder (~> 3.1.0)
activerecord (4.0.2) activerecord (4.0.3)
activemodel (= 4.0.2) activemodel (= 4.0.3)
activerecord-deprecated_finders (~> 1.0.2) activerecord-deprecated_finders (~> 1.0.2)
activesupport (= 4.0.2) activesupport (= 4.0.3)
arel (~> 4.0.0) arel (~> 4.0.0)
activerecord-deprecated_finders (1.0.3) activerecord-deprecated_finders (1.0.3)
activesupport (4.0.2) activesupport (4.0.3)
i18n (~> 0.6, >= 0.6.4) i18n (~> 0.6, >= 0.6.4)
minitest (~> 4.2) minitest (~> 4.2)
multi_json (~> 1.3) multi_json (~> 1.3)
...@@ -42,7 +43,7 @@ GEM ...@@ -42,7 +43,7 @@ GEM
annotate (2.6.0) annotate (2.6.0)
activerecord (>= 2.3.0) activerecord (>= 2.3.0)
rake (>= 0.8.7) rake (>= 0.8.7)
arel (4.0.1) arel (4.0.2)
asciidoctor (0.1.4) asciidoctor (0.1.4)
atomic (1.1.14) atomic (1.1.14)
awesome_print (1.2.0) awesome_print (1.2.0)
...@@ -158,36 +159,32 @@ GEM ...@@ -158,36 +159,32 @@ GEM
gitlab-flowdock-git-hook (0.4.2.2) gitlab-flowdock-git-hook (0.4.2.2)
gitlab-grit (>= 2.4.1) gitlab-grit (>= 2.4.1)
multi_json multi_json
gitlab-gollum-lib (1.0.2) gitlab-gollum-lib (1.1.0)
github-markdown (~> 0.5.3) github-markdown (~> 0.5.3)
github-markup (>= 0.7.5, < 1.0.0) github-markup (>= 0.7.5, < 1.0.0)
gitlab-grit (~> 2.6.1) gitlab-grit (~> 2.6.1)
gitlab-pygments.rb (~> 0.5.4)
nokogiri (~> 1.5.9) nokogiri (~> 1.5.9)
sanitize (~> 2.0.3) sanitize (~> 2.0.3)
stringex (~> 1.5.1) stringex (~> 1.5.1)
gitlab-grack (2.0.0.pre) gitlab-grack (2.0.0.pre)
rack (~> 1.5.1) rack (~> 1.5.1)
gitlab-grit (2.6.3) gitlab-grit (2.6.4)
charlock_holmes (~> 0.6.9) charlock_holmes (~> 0.6.9)
diff-lcs (~> 1.1) diff-lcs (~> 1.1)
mime-types (~> 1.15) mime-types (~> 1.15)
posix-spawn (~> 0.3.6) posix-spawn (~> 0.3.6)
gitlab-linguist (2.9.6) gitlab-linguist (3.0.0)
charlock_holmes (~> 0.6.6) charlock_holmes (~> 0.6.6)
escape_utils (~> 0.2.4) escape_utils (~> 0.2.4)
gitlab-pygments.rb (~> 0.5.4)
mime-types (~> 1.19) mime-types (~> 1.19)
gitlab-pygments.rb (0.5.4) gitlab_git (5.4.0)
posix-spawn (~> 0.3.6)
yajl-ruby (~> 1.1.0)
gitlab_git (4.0.0)
activesupport (~> 4.0.0) activesupport (~> 4.0.0)
charlock_holmes (~> 0.6.9)
gitlab-grit (~> 2.6.1) gitlab-grit (~> 2.6.1)
gitlab-linguist (~> 2.9.5) gitlab-linguist (~> 3.0.0)
gitlab-pygments.rb (~> 0.5.4) rugged (~> 0.19.0)
gitlab_meta (6.0) gitlab_meta (6.0)
gitlab_omniauth-ldap (1.0.3) gitlab_omniauth-ldap (1.0.4)
net-ldap (~> 0.3.1) net-ldap (~> 0.3.1)
omniauth (~> 1.0) omniauth (~> 1.0)
pyu-ruby-sasl (~> 0.0.3.1) pyu-ruby-sasl (~> 0.0.3.1)
...@@ -323,8 +320,8 @@ GEM ...@@ -323,8 +320,8 @@ GEM
cliver (~> 0.2.1) cliver (~> 0.2.1)
multi_json (~> 1.0) multi_json (~> 1.0)
websocket-driver (>= 0.2.0) websocket-driver (>= 0.2.0)
polyglot (0.3.3) polyglot (0.3.4)
posix-spawn (0.3.6) posix-spawn (0.3.8)
protected_attributes (1.0.5) protected_attributes (1.0.5)
activemodel (>= 4.0.1, < 5.0) activemodel (>= 4.0.1, < 5.0)
pry (0.9.12.4) pry (0.9.12.4)
...@@ -349,13 +346,13 @@ GEM ...@@ -349,13 +346,13 @@ GEM
rack rack
rack-test (0.6.2) rack-test (0.6.2)
rack (>= 1.0) rack (>= 1.0)
rails (4.0.2) rails (4.0.3)
actionmailer (= 4.0.2) actionmailer (= 4.0.3)
actionpack (= 4.0.2) actionpack (= 4.0.3)
activerecord (= 4.0.2) activerecord (= 4.0.3)
activesupport (= 4.0.2) activesupport (= 4.0.3)
bundler (>= 1.3.0, < 2.0) bundler (>= 1.3.0, < 2.0)
railties (= 4.0.2) railties (= 4.0.3)
sprockets-rails (~> 2.0.0) sprockets-rails (~> 2.0.0)
rails-observers (0.1.2) rails-observers (0.1.2)
activemodel (~> 4.0) activemodel (~> 4.0)
...@@ -368,13 +365,13 @@ GEM ...@@ -368,13 +365,13 @@ GEM
i18n i18n
require_all require_all
ruby-progressbar ruby-progressbar
railties (4.0.2) railties (4.0.3)
actionpack (= 4.0.2) actionpack (= 4.0.3)
activesupport (= 4.0.2) activesupport (= 4.0.3)
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
raindrops (0.12.0) raindrops (0.12.0)
rake (10.1.0) rake (10.1.1)
raphael-rails (2.1.2) raphael-rails (2.1.2)
rb-fsevent (0.9.3) rb-fsevent (0.9.3)
rb-inotify (0.9.2) rb-inotify (0.9.2)
...@@ -423,6 +420,7 @@ GEM ...@@ -423,6 +420,7 @@ GEM
ruby-hmac (0.4.0) ruby-hmac (0.4.0)
ruby-progressbar (1.2.0) ruby-progressbar (1.2.0)
rubyntlm (0.1.1) rubyntlm (0.1.1)
rugged (0.19.0)
safe_yaml (0.9.7) safe_yaml (0.9.7)
sanitize (2.0.6) sanitize (2.0.6)
nokogiri (>= 1.4.4) nokogiri (>= 1.4.4)
...@@ -472,6 +470,11 @@ GEM ...@@ -472,6 +470,11 @@ GEM
railties (>= 3) railties (>= 3)
spinach (>= 0.4) spinach (>= 0.4)
spork (1.0.0rc4) spork (1.0.0rc4)
spring (1.1.1)
spring-commands-rspec (1.0.1)
spring (>= 0.9.1)
spring-commands-spinach (1.0.0)
spring (>= 0.9.1)
sprockets (2.10.1) sprockets (2.10.1)
hike (~> 1.2) hike (~> 1.2)
multi_json (~> 1.0) multi_json (~> 1.0)
...@@ -543,12 +546,12 @@ GEM ...@@ -543,12 +546,12 @@ GEM
websocket-driver (0.3.1) websocket-driver (0.3.1)
xpath (2.0.0) xpath (2.0.0)
nokogiri (~> 1.3) nokogiri (~> 1.3)
yajl-ruby (1.1.0)
PLATFORMS PLATFORMS
ruby ruby
DEPENDENCIES DEPENDENCIES
ace-rails-ap
actionpack-action_caching actionpack-action_caching
actionpack-page_caching actionpack-page_caching
acts-as-taggable-on acts-as-taggable-on
...@@ -578,13 +581,12 @@ DEPENDENCIES ...@@ -578,13 +581,12 @@ DEPENDENCIES
gemoji (~> 1.3.0) gemoji (~> 1.3.0)
github-markup (~> 0.7.4)! github-markup (~> 0.7.4)!
gitlab-flowdock-git-hook (~> 0.4.2) gitlab-flowdock-git-hook (~> 0.4.2)
gitlab-gollum-lib (~> 1.0.2) gitlab-gollum-lib (~> 1.1.0)
gitlab-grack (~> 2.0.0.pre) gitlab-grack (~> 2.0.0.pre)
gitlab-linguist (~> 2.9.6) gitlab-linguist (~> 3.0.0)
gitlab-pygments.rb (~> 0.5.4) gitlab_git (~> 5.4.0)
gitlab_git (~> 4.0.0)
gitlab_meta (= 6.0) gitlab_meta (= 6.0)
gitlab_omniauth-ldap (= 1.0.3) gitlab_omniauth-ldap (= 1.0.4)
gon (~> 5.0.0) gon (~> 5.0.0)
grape (~> 0.6.1) grape (~> 0.6.1)
grape-entity (~> 0.3.0) grape-entity (~> 0.3.0)
...@@ -640,6 +642,9 @@ DEPENDENCIES ...@@ -640,6 +642,9 @@ DEPENDENCIES
slim slim
spinach-rails spinach-rails
spork (~> 1.0rc) spork (~> 1.0rc)
spring (= 1.1.1)
spring-commands-rspec (= 1.0.1)
spring-commands-spinach (= 1.0.0)
stamp stamp
state_machine state_machine
test_after_commit test_after_commit
......
Copyright (c) 2011 Dmitriy Zaporozhets Copyright (c) 2011-2014 Dmitriy Zaporozhets
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
......
...@@ -21,3 +21,5 @@ release where the minor version is increased numerically by increments of one ...@@ -21,3 +21,5 @@ release where the minor version is increased numerically by increments of one
(eg. `5.0 -> 5.1`). (eg. `5.0 -> 5.1`).
We encourage everyone to run the latest stable release to ensure that you can easily upgrade to the most secure and feature rich GitLab experience. In order to make sure you can easily run the most recent stable release, we are working hard to keep the update process simple and reliable. We encourage everyone to run the latest stable release to ensure that you can easily upgrade to the most secure and feature rich GitLab experience. In order to make sure you can easily run the most recent stable release, we are working hard to keep the update process simple and reliable.
More information about the release procedures can be found in the doc/release directory.
...@@ -4,26 +4,21 @@ ...@@ -4,26 +4,21 @@
![animated-screenshots](https://gist.github.com/fnkr/2f9badd56bfe0ed04ee7/raw/4f48806fbae97f556c2f78d8c2d299c04500cb0d/compiled.gif) ![animated-screenshots](https://gist.github.com/fnkr/2f9badd56bfe0ed04ee7/raw/4f48806fbae97f556c2f78d8c2d299c04500cb0d/compiled.gif)
### GitLab allows you to ### Gitlab is open source software to collaborate on code
* keep your code secure on your own server
* manage repositories, users and access permissions
* communicate through issues, line-comments and wiki pages
* perform code review with merge requests
### GitLab is * Manage git repositories with fine grained access controls that keep your code secure
* Perform code reviews and enhance collaboration with merge requests
* powered by Ruby on Rails * Each project can also have an issue tracker and a wiki
* completely free and open source (MIT license) * Used by more than 50,000 organizations, GitLab is the most popular solution to manage git repositories on-premises
* used by more than 25.000 organizations to keep their code secure * Completely free and open source (MIT Expat license)
* Powered by Ruby on Rails
### Code status ### Code status
* [![build status](http://ci.gitlab.org/projects/1/status.png?ref=master)](http://ci.gitlab.org/projects/1?ref=master) on ci.gitlab.org (master branch) * [![build status](https://ci.gitlab.org/projects/1/status.png?ref=master)](https://ci.gitlab.org/projects/1?ref=master) on ci.gitlab.org (master branch)
* [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.png)](https://codeclimate.com/github/gitlabhq/gitlabhq) * [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.png)](https://codeclimate.com/github/gitlabhq/gitlabhq)
* [![Dependency Status](https://gemnasium.com/gitlabhq/gitlabhq.png)](https://gemnasium.com/gitlabhq/gitlabhq) this button can be yellow (small updates are available) but must not be red (a security fix or an important update is available), gems are updated in major releases of GitLab.
* [![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.png?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq) * [![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.png?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq)
### Resources ### Resources
...@@ -36,6 +31,8 @@ ...@@ -36,6 +31,8 @@
* [GitLab CI](https://gitlab.com/gitlab-org/gitlab-ci/blob/master/README.md) is a continuous integration (CI) server that is easy to integrate with GitLab. * [GitLab CI](https://gitlab.com/gitlab-org/gitlab-ci/blob/master/README.md) is a continuous integration (CI) server that is easy to integrate with GitLab.
* Unofficial third-party [iPhone app](http://gitlabcontrol.com/) and [Android app](https://play.google.com/store/apps/details?id=com.bd.gitlab&hl=en) for GitLab
### Requirements ### Requirements
* Ubuntu/Debian** * Ubuntu/Debian**
...@@ -50,13 +47,17 @@ ...@@ -50,13 +47,17 @@
#### Official installation methods #### Official installation methods
* [Manual installation guide for a production server](doc/install/installation.md) * [GitLab packages (beta)](https://www.gitlab.com/downloads/) These packages contain GitLab and all its depencies (PostgreSQL, Redis, Nginx, Unicorn, etc.). They are made with [omnibus-gitlab](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md) that also contains the installation instructions. These packages currently support a reduced selection of GitLab's normal features. For instance, it is not yet possible to create/restore application backups or to use HTTPS.
* [GitLab virtual machine images](https://www.gitlab.com/downloads/) contain an operating system and a preinstalled GitLab. They are made with [GitLab Packer](https://gitlab.com/gitlab-org/gitlab-packer/blob/master/README.md) that also contains the installation instructions.
* [GitLab Chef Cookbook](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/README.md) This cookbook can be used both for development installations and production installations. If you want to [contribute](CONTRIBUTE.md) to GitLab we suggest you follow the [development installation on a virtual machine with Vagrant](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/doc/development.md) instructions to install all testing dependencies. * [GitLab Chef Cookbook](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/README.md) This cookbook can be used both for development installations and production installations. If you want to [contribute](CONTRIBUTE.md) to GitLab we suggest you follow the [development installation on a virtual machine with Vagrant](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/doc/development.md) instructions to install all testing dependencies.
* [Manual installation guide](doc/install/installation.md) This guide to set up a production server offers detailed and complete step-by-step instructions.
#### Third party one-click installers #### Third party one-click installers
* [Digital Ocean 1-Click Application Install](https://www.digitalocean.com/blog_posts/host-your-git-repositories-in-55-seconds-with-gitlab) Have a new server up in 55 seconds. Digital Ocean uses SSD disks which is great for an IO intensive app such as GitLab. * [Digital Ocean 1-Click Application Install](https://www.digitalocean.com/blog_posts/host-your-git-repositories-in-55-seconds-with-gitlab) Have a new server up in 55 seconds. Digital Ocean uses SSD disks which is great for an IO intensive app such as GitLab. We recommend selecting a droplet with [1GB of memory](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/requirements.md).
* [BitNami one-click installers](http://bitnami.com/stack/gitlab) This package contains both GitLab and GitLab CI. It is available as installer, virtual machine or for cloud hosting providers (Amazon Web Services/Azure/etc.). * [BitNami one-click installers](http://bitnami.com/stack/gitlab) This package contains both GitLab and GitLab CI. It is available as installer, virtual machine or for cloud hosting providers (Amazon Web Services/Azure/etc.).
...@@ -68,11 +69,9 @@ ...@@ -68,11 +69,9 @@
### New versions and upgrading ### New versions and upgrading
Since 2011 GitLab is released on the 22nd of every month. Every new release includes an upgrade guide. Since 2011 GitLab is released on the 22nd of every month. Every new release includes an [upgrade guide](doc/update) and new features are detailed in the [Changelog](CHANGELOG).
* [Upgrade guides](doc/update)
* [Changelog](CHANGELOG) It is recommended to follow a monthly upgrade schedule. Security releases come out when needed. For more information about the release process see the documentation for [monthly](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/release/monthly.md) and [security](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/release/security.md) releases.
* Features that will be in the next releases are listed on [the feedback and suggestions forum](http://feedback.gitlab.com/forums/176466-general) with the status [started](http://feedback.gitlab.com/forums/176466-general/status/796456) and [completed](http://feedback.gitlab.com/forums/176466-general/status/796457). * Features that will be in the next releases are listed on [the feedback and suggestions forum](http://feedback.gitlab.com/forums/176466-general) with the status [started](http://feedback.gitlab.com/forums/176466-general/status/796456) and [completed](http://feedback.gitlab.com/forums/176466-general/status/796457).
...@@ -155,6 +154,8 @@ or start each component separately ...@@ -155,6 +154,8 @@ or start each component separately
* [Book](http://www.packtpub.com/gitlab-repository-management/book) written by GitLab enthusiast Jonathan M. Hethey is unofficial but it offers a good overview. * [Book](http://www.packtpub.com/gitlab-repository-management/book) written by GitLab enthusiast Jonathan M. Hethey is unofficial but it offers a good overview.
* [Gitter chat room](https://gitter.im/gitlabhq/gitlabhq#) here you can ask questions when you need help.
### Getting in touch ### Getting in touch
......
6.6.0.pre 6.6.0.rc1
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
user_path: "/api/:version/users/:id.json" user_path: "/api/:version/users/:id.json"
notes_path: "/api/:version/projects/:id/notes.json" notes_path: "/api/:version/projects/:id/notes.json"
namespaces_path: "/api/:version/namespaces.json" namespaces_path: "/api/:version/namespaces.json"
project_users_path: "/api/:version/projects/:id/users.json"
# Get 20 (depends on api) recent notes # Get 20 (depends on api) recent notes
# and sort the ascending from oldest to newest # and sort the ascending from oldest to newest
...@@ -50,6 +51,23 @@ ...@@ -50,6 +51,23 @@
).done (users) -> ).done (users) ->
callback(users) callback(users)
# Return project users list. Filtered by query
# Only active users retrieved
projectUsers: (project_id, query, callback) ->
url = Api.buildUrl(Api.project_users_path)
url = url.replace(':id', project_id)
$.ajax(
url: url
data:
private_token: gon.api_token
search: query
per_page: 20
active: true
dataType: "json"
).done (users) ->
callback(users)
# Return namespaces list. Filtered by query # Return namespaces list. Filtered by query
namespaces: (query, callback) -> namespaces: (query, callback) ->
url = Api.buildUrl(Api.namespaces_path) url = Api.buildUrl(Api.namespaces_path)
......
...@@ -24,7 +24,8 @@ ...@@ -24,7 +24,8 @@
//= require g.raphael-min //= require g.raphael-min
//= require g.bar-min //= require g.bar-min
//= require branch-graph //= require branch-graph
//= require ace-src-noconflict/ace //= require highlightjs.min
//= require ace/ace
//= require_tree . //= require_tree .
//= require d3 //= require d3
//= require underscore //= require underscore
...@@ -64,7 +64,7 @@ class BlobView ...@@ -64,7 +64,7 @@ class BlobView
nodes.attr("id", hash) nodes.attr("id", hash)
# initialize multi-line select # initialize multi-line select
$("#tree-content-holder .line_numbers a[id^=L]").on("click", handleMultiSelect) $("#tree-content-holder .line-numbers a[id^=L]").on("click", handleMultiSelect)
# Highlight the correct lines on load # Highlight the correct lines on load
highlightBlobLines() highlightBlobLines()
......
...@@ -4,6 +4,7 @@ $ -> ...@@ -4,6 +4,7 @@ $ ->
class Dispatcher class Dispatcher
constructor: () -> constructor: () ->
@initSearch() @initSearch()
@initHighlight()
@initPageScripts() @initPageScripts()
initPageScripts: -> initPageScripts: ->
...@@ -18,6 +19,8 @@ class Dispatcher ...@@ -18,6 +19,8 @@ class Dispatcher
switch page switch page
when 'projects:issues:index' when 'projects:issues:index'
Issues.init() Issues.init()
when 'projects:issues:show'
new Issue()
when 'projects:issues:new', 'projects:merge_requests:new' when 'projects:issues:new', 'projects:merge_requests:new'
GitLab.GfmAutoComplete.setup() GitLab.GfmAutoComplete.setup()
when 'dashboard:show' when 'dashboard:show'
...@@ -53,3 +56,10 @@ class Dispatcher ...@@ -53,3 +56,10 @@ class Dispatcher
project_ref = opts.data('autocomplete-project-ref') project_ref = opts.data('autocomplete-project-ref')
new SearchAutocomplete(path, project_id, project_ref) new SearchAutocomplete(path, project_id, project_ref)
initHighlight: ->
$('.highlight pre code').each (i, e) ->
hljs.highlightBlock(e)
$(e).html($.map($(e).html().split("\n"), (line, i) ->
"<div class='line' id='LC" + (i + 1) + "'>" + line + "</div>"
).join("\n"))
...@@ -4,3 +4,14 @@ class GroupMembers ...@@ -4,3 +4,14 @@ class GroupMembers
$(this).fadeOut() $(this).fadeOut()
@GroupMembers = GroupMembers @GroupMembers = GroupMembers
$ ->
# avatar
$('.js-choose-group-avatar-button').bind "click", ->
form = $(this).closest("form")
form.find(".js-group-avatar-input").click()
$('.js-group-avatar-input').bind "change", ->
form = $(this).closest("form")
filename = $(this).val().replace(/^.*[\\\/]/, '')
form.find(".js-avatar-filename").text(filename)
\ No newline at end of file
class Issue
constructor: ->
$('.edit-issue.inline-update input[type="submit"]').hide()
$(".issue-box .inline-update").on "change", "select", ->
$(this).submit()
$(".issue-box .inline-update").on "change", "#issue_assignee_id", ->
$(this).submit()
@Issue = Issue
...@@ -77,9 +77,3 @@ ...@@ -77,9 +77,3 @@
$("#update_issues_ids").val [] $("#update_issues_ids").val []
$(".issues_bulk_update").hide() $(".issues_bulk_update").hide()
$(".issues-filters").show() $(".issues-filters").show()
$ ->
$('.edit-issue.inline-update input[type="submit"]').hide();
$("body").on "change", ".edit-issue.inline-update select", ->
$(this).submit()
class MergeRequest
constructor: (@opts) ->
@initContextWidget()
this.$el = $('.merge-request')
@diffs_loaded = if @opts.action == 'diffs' then true else false
@commits_loaded = false
this.activateTab(@opts.action)
this.bindEvents()
this.initMergeWidget()
this.$('.show-all-commits').on 'click', =>
this.showAllCommits()
modal = $('#modal_merge_info').modal(show: false)
disableButtonIfEmptyField '#merge_commit_message', '.accept_merge_request'
# Local jQuery finder
$: (selector) ->
this.$el.find(selector)
initContextWidget: ->
$('.edit-merge_request.inline-update input[type="submit"]').hide()
$(".issue-box .inline-update").on "change", "select", ->
$(this).submit()
$(".issue-box .inline-update").on "change", "#merge_request_assignee_id", ->
$(this).submit()
initMergeWidget: ->
this.showState( @opts.current_status )
if this.$('.automerge_widget').length and @opts.check_enable
$.get @opts.url_to_automerge_check, (data) =>
this.showState( data.merge_status )
, 'json'
if @opts.ci_enable
$.get @opts.url_to_ci_check, (data) =>
this.showCiState data.status
, 'json'
bindEvents: ->
this.$('.nav-tabs').on 'click', 'a', (event) =>
a = $(event.currentTarget)
href = a.attr('href')
History.replaceState {path: href}, document.title, href
event.preventDefault()
this.$('.nav-tabs').on 'click', 'li', (event) =>
this.activateTab($(event.currentTarget).data('action'))
this.$('.accept_merge_request').on 'click', ->
$('.automerge_widget.can_be_merged').hide()
$('.merge-in-progress').show()
activateTab: (action) ->
this.$('.nav-tabs li').removeClass 'active'
this.$('.tab-content').hide()
switch action
when 'diffs'
this.$('.nav-tabs .diffs-tab').addClass 'active'
this.loadDiff() unless @diffs_loaded
this.$('.diffs').show()
else
this.$('.nav-tabs .notes-tab').addClass 'active'
this.$('.notes').show()
showState: (state) ->
$('.automerge_widget').hide()
$('.automerge_widget.' + state).show()
showCiState: (state) ->
$('.ci_widget').hide()
$('.ci_widget.ci-' + state).show()
loadDiff: (event) ->
$.ajax
type: 'GET'
url: this.$('.nav-tabs .diffs-tab a').attr('href')
beforeSend: =>
this.$('.status').addClass 'loading'
complete: =>
@diffs_loaded = true
this.$('.status').removeClass 'loading'
success: (data) =>
this.$(".diffs").html(data.html)
dataType: 'json'
showAllCommits: ->
this.$('.first-commits').remove()
this.$('.all-commits').removeClass 'hide'
alreadyOrCannotBeMerged: ->
this.$('.automerge_widget').hide()
this.$('.merge-in-progress').hide()
this.$('.automerge_widget.already_cannot_be_merged').show()
this.MergeRequest = MergeRequest
...@@ -6,99 +6,3 @@ ...@@ -6,99 +6,3 @@
$('#milestone_id').select2() $('#milestone_id').select2()
$('#milestone_id, #assignee_id').on 'change', -> $('#milestone_id, #assignee_id').on 'change', ->
$(this).closest('form').submit() $(this).closest('form').submit()
class MergeRequest
constructor: (@opts) ->
this.$el = $('.merge-request')
@diffs_loaded = if @opts.action == 'diffs' then true else false
@commits_loaded = false
this.activateTab(@opts.action)
this.bindEvents()
this.initMergeWidget()
this.$('.show-all-commits').on 'click', =>
this.showAllCommits()
modal = $('#modal_merge_info').modal(show: false)
disableButtonIfEmptyField '#merge_commit_message', '.accept_merge_request'
# Local jQuery finder
$: (selector) ->
this.$el.find(selector)
initMergeWidget: ->
this.showState( @opts.current_status )
if this.$('.automerge_widget').length and @opts.check_enable
$.get @opts.url_to_automerge_check, (data) =>
this.showState( data.merge_status )
, 'json'
if @opts.ci_enable
$.get @opts.url_to_ci_check, (data) =>
this.showCiState data.status
, 'json'
bindEvents: ->
this.$('.nav-tabs').on 'click', 'a', (event) =>
a = $(event.currentTarget)
href = a.attr('href')
History.replaceState {path: href}, document.title, href
event.preventDefault()
this.$('.nav-tabs').on 'click', 'li', (event) =>
this.activateTab($(event.currentTarget).data('action'))
this.$('.accept_merge_request').on 'click', ->
$('.automerge_widget.can_be_merged').hide()
$('.merge-in-progress').show()
activateTab: (action) ->
this.$('.nav-tabs li').removeClass 'active'
this.$('.tab-content').hide()
switch action
when 'diffs'
this.$('.nav-tabs .diffs-tab').addClass 'active'
this.loadDiff() unless @diffs_loaded
this.$('.diffs').show()
else
this.$('.nav-tabs .notes-tab').addClass 'active'
this.$('.notes').show()
showState: (state) ->
$('.automerge_widget').hide()
$('.automerge_widget.' + state).show()
showCiState: (state) ->
$('.ci_widget').hide()
$('.ci_widget.ci-' + state).show()
loadDiff: (event) ->
$.ajax
type: 'GET'
url: this.$('.nav-tabs .diffs-tab a').attr('href')
beforeSend: =>
this.$('.status').addClass 'loading'
complete: =>
@diffs_loaded = true
this.$('.status').removeClass 'loading'
success: (data) =>
this.$(".diffs").html(data.html)
dataType: 'json'
showAllCommits: ->
this.$('.first-commits').remove()
this.$('.all-commits').removeClass 'hide'
alreadyOrCannotBeMerged: ->
this.$('.automerge_widget').hide()
this.$('.merge-in-progress').hide()
this.$('.automerge_widget.already_cannot_be_merged').show()
this.MergeRequest = MergeRequest
...@@ -94,6 +94,9 @@ class Notes ...@@ -94,6 +94,9 @@ class Notes
if @isNewNote(note) if @isNewNote(note)
@note_ids.push(note.id) @note_ids.push(note.id)
$('ul.main-notes-list').append(note.html) $('ul.main-notes-list').append(note.html)
code = "#note_" + note.id + " .highlight pre code"
$(code).each (i, e) ->
hljs.highlightBlock(e)
### ###
...@@ -253,6 +256,9 @@ class Notes ...@@ -253,6 +256,9 @@ class Notes
updateNote: (xhr, note, status) => updateNote: (xhr, note, status) =>
note_li = $("#note_" + note.id) note_li = $("#note_" + note.id)
note_li.replaceWith(note.html) note_li.replaceWith(note.html)
code = "#note_" + note.id + " .highlight pre code"
$(code).each (i, e) ->
hljs.highlightBlock(e)
### ###
Called in response to clicking the edit note link Called in response to clicking the edit note link
......
...@@ -26,3 +26,5 @@ $ -> ...@@ -26,3 +26,5 @@ $ ->
form = $(this).closest("form") form = $(this).closest("form")
filename = $(this).val().replace(/^.*[\\\/]/, '') filename = $(this).val().replace(/^.*[\\\/]/, '')
form.find(".js-avatar-filename").text(filename) form.find(".js-avatar-filename").text(filename)
$('.profile-groups-avatars').tooltip("placement": "top")
\ No newline at end of file
@projectUsersSelect =
init: ->
$('.ajax-project-users-select').each (i, select) ->
project_id = $('body').data('project-id')
$(select).select2
placeholder: $(select).data('placeholder') || "Search for a user"
multiple: $(select).hasClass('multiselect')
minimumInputLength: 0
query: (query) ->
Api.projectUsers project_id, query.term, (users) ->
data = { results: users }
query.callback(data)
initSelection: (element, callback) ->
id = $(element).val()
if id isnt ""
Api.user(id, callback)
formatResult: projectUsersSelect.projectUserFormatResult
formatSelection: projectUsersSelect.projectUserFormatSelection
dropdownCssClass: "ajax-project-users-dropdown"
dropdownAutoWidth: true
escapeMarkup: (m) -> # we do not want to escape markup since we are displaying html in results
m
projectUserFormatResult: (user) ->
if user.avatar_url
avatar = user.avatar_url
else if gon.gravatar_enabled
avatar = gon.gravatar_url
avatar = avatar.replace('%{hash}', md5(user.email))
avatar = avatar.replace('%{size}', '24')
else
avatar = gon.relative_url_root + "/assets/no_avatar.png"
"<div class='user-result'>
<div class='user-image'><img class='avatar s24' src='#{avatar}'></div>
<div class='user-name'>#{user.name}</div>
<div class='user-username'>#{user.username}</div>
</div>"
projectUserFormatSelection: (user) ->
user.name
$ ->
projectUsersSelect.init()
$ -> $ ->
userFormatResult = (user) -> userFormatResult = (user) ->
if user.avatar if user.avatar_url
avatar = user.avatar.url avatar = user.avatar_url
else else if gon.gravatar_enabled
avatar = gon.gravatar_url avatar = gon.gravatar_url
avatar = avatar.replace('%{hash}', md5(user.email)) avatar = avatar.replace('%{hash}', md5(user.email))
avatar = avatar.replace('%{size}', '24') avatar = avatar.replace('%{size}', '24')
else
avatar = gon.relative_url_root + "/assets/no_avatar.png"
"<div class='user-result'> "<div class='user-result'>
<div class='user-image'><img class='avatar s24' src='#{avatar}'></div> <div class='user-image'><img class='avatar s24' src='#{avatar}'></div>
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
*= require jquery.ui.gitlab *= require jquery.ui.gitlab
*= require jquery.atwho *= require jquery.atwho
*= require select2 *= require select2
*= require highlightjs.min
*= require_self *= require_self
*/ */
...@@ -38,6 +39,7 @@ ...@@ -38,6 +39,7 @@
@import "generic/lists.scss"; @import "generic/lists.scss";
@import "generic/forms.scss"; @import "generic/forms.scss";
@import "generic/selects.scss"; @import "generic/selects.scss";
@import "generic/highlight.scss";
/** /**
* Page specific styles (issues, projects etc): * Page specific styles (issues, projects etc):
...@@ -63,6 +65,7 @@ ...@@ -63,6 +65,7 @@
@import "sections/wall.scss"; @import "sections/wall.scss";
@import "sections/dashboard.scss"; @import "sections/dashboard.scss";
@import "sections/stat_graph.scss"; @import "sections/stat_graph.scss";
@import "sections/groups.scss";
/** /**
* Code ighlight * Code ighlight
......
...@@ -118,7 +118,6 @@ ...@@ -118,7 +118,6 @@
@extend .btn-primary; @extend .btn-primary;
} }
&.btn-close,
&.btn-remove { &.btn-remove {
@extend .btn-danger; @extend .btn-danger;
} }
...@@ -143,6 +142,22 @@ ...@@ -143,6 +142,22 @@
line-height: 16px; line-height: 16px;
margin: 2px; margin: 2px;
} }
&.btn-close {
color: #B94A48;
font-weight: bold;
&:hover {
color: #B94A48;
}
}
&.btn-reopen {
color: #468847;
font-weight: bold;
&:hover {
color: #468847;
}
}
} }
.btn-block { .btn-block {
......
...@@ -88,11 +88,15 @@ pre.well-pre { ...@@ -88,11 +88,15 @@ pre.well-pre {
/** Big Labels **/ /** Big Labels **/
.state-label { .state-label {
font-size: 14px; font-size: 14px;
padding: 6px 25px; padding: 9px 25px;
text-align: center; text-align: center;
@include border-radius(4px);
text-shadow: none; text-shadow: none;
margin-left: 10px; margin-right: 20px;
&.state-label-blue {
background: #31708f;
color: #FFF;
}
&.state-label-green { &.state-label-green {
background: #4A4; background: #4A4;
...@@ -112,6 +116,7 @@ pre.well-pre { ...@@ -112,6 +116,7 @@ pre.well-pre {
.dropdown-menu > li > a:hover, .dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus { .dropdown-menu > li > a:focus {
background: #29b; background: #29b;
color: #FFF
} }
.breadcrumb > li + li:before { .breadcrumb > li + li:before {
...@@ -173,12 +178,10 @@ table a code { ...@@ -173,12 +178,10 @@ table a code {
.loading { .loading {
margin: 20px auto; margin: 20px auto;
background: url(ajax_loader.gif) no-repeat center center;
width: 40px;
height: 40px; height: 40px;
&.loading-gray { color: #555;
background: url(ajax_loader_gray.gif) no-repeat center center; font-size: 32px;
} text-align: center;
} }
span.update-author { span.update-author {
......
...@@ -50,9 +50,9 @@ ...@@ -50,9 +50,9 @@
} }
&.wiki { &.wiki {
padding: 20px;
font-size: 14px; font-size: 14px;
line-height: 1.6; line-height: 1.6;
padding: 25px;
.highlight { .highlight {
margin-bottom: 9px; margin-bottom: 9px;
...@@ -143,75 +143,6 @@ ...@@ -143,75 +143,6 @@
*/ */
&.code { &.code {
padding: 0; padding: 0;
table.lines {
border: none;
box-shadow: none;
margin: 0px;
padding: 0px;
table-layout: fixed;
pre {
border: none;
border-radius: 0;
font-family: $monospace_font;
font-size: 12px !important;
line-height: 16px !important;
margin: 0;
padding: 10px 0;
}
td {
border: none;
margin: 0;
padding: 0;
vertical-align: top;
&:first-child {
background: #eee;
width: 50px;
}
&:last-child {
}
}
tr:hover {
background: none;
}
pre.line_numbers {
color: #666;
padding: 10px 6px 10px 0;
text-align: right;
background: #EEE;
a {
color: #666;
i {
display: none;
font-size: 14px;
line-height: 14px;
}
&:hover i {
display: inherit;
}
}
}
.highlight {
border-left: 1px solid #DEE2E3;
overflow: auto;
overflow-y: hidden;
pre {
white-space: pre;
word-wrap: normal;
.line {
padding: 0 10px;
}
}
}
}
} }
} }
} }
......
...@@ -51,3 +51,27 @@ label { ...@@ -51,3 +51,27 @@ label {
.input-mn-300 { .input-mn-300 {
min-width: 300px; min-width: 300px;
} }
.custom-form-control {
width: 150px;
}
@media (min-width: $screen-sm-min) {
.custom-form-control {
width: 150px;
}
}
/* Medium devices (desktops, 992px and up) */
@media (min-width: $screen-md-min) {
.custom-form-control {
width: 170px;
}
}
/* Large devices (large desktops, 1200px and up) */
@media (min-width: $screen-lg-min) {
.custom-form-control {
width: 200px;
}
}
.highlighted-data {
border: none;
box-shadow: none;
margin: 0px;
padding: 0px;
table-layout: fixed;
pre {
padding: 10px;
border: none;
border-radius: 0;
font-family: $monospace_font;
font-size: 12px !important;
line-height: 16px !important;
margin: 0;
code {
white-space: pre;
word-wrap: normal;
padding: 0;
.line {
display: inline;
}
}
}
.hljs {
padding: 0;
}
.line-numbers {
padding: 10px;
text-align: right;
float: left;
a {
font-family: $monospace_font;
display: block;
font-size: 12px !important;
line-height: 16px !important;
white-space: nowrap;
i {
visibility: hidden;
@extend .pull-left;
}
&:hover i {
visibility: visible;
}
}
}
.highlight {
overflow: auto;
overflow-y: hidden;
pre {
white-space: pre;
word-wrap: normal;
}
}
}
...@@ -11,34 +11,39 @@ ...@@ -11,34 +11,39 @@
color: #666; color: #666;
margin:20px 0; margin:20px 0;
background: #FAFAFA; background: #FAFAFA;
border: 1px solid #DDD; border: 1px solid #EEE;
.control-group { .control-group {
margin-bottom: 0; margin-bottom: 0;
} }
.state {
height: 34px;
border-bottom: 1px solid #DDD;
line-height: 32px;
}
.title { .title {
font-size: 20px; font-size: 22px;
font-weight: 500; font-weight: 500;
line-height: 28px; line-height: 1.5;
margin: 0; margin: 0;
color: #444; color: #333;
padding-bottom: 0;
padding: 15px 25px;
} }
.context { .context {
border: none;
background-color: #f5f5f5;
border: none; border: none;
border-top: 1px solid #eee; border-top: 1px solid #eee;
padding: 15px 25px;
} }
.description { .description {
border-top: 1px solid #eee; padding: 0 25px 15px 25px;
} }
.title, .context, .description { .title, .context, .description {
padding: 15px;
.clearfix { .clearfix {
margin: 0; margin: 0;
} }
......
...@@ -23,6 +23,12 @@ ...@@ -23,6 +23,12 @@
} }
} }
&.warning-row {
background-color: #fcf8e3;
border-color: #faebcc;
color: #8a6d3b;
}
&.smoke { background-color: #f5f5f5; } &.smoke { background-color: #f5f5f5; }
&:hover { &:hover {
......
/** Select2 selectbox style override **/ /** Select2 selectbox style override **/
.select2-container, .select2-container.select2-drop-above { .select2-container, .select2-container.select2-drop-above {
.select2-choice { .select2-choice {
background: #FFF; background: #FFF;
...@@ -12,9 +11,13 @@ ...@@ -12,9 +11,13 @@
} }
.select2-drop-active { .select2-drop-active {
border: 1px solid #BBB; border: 1px solid #BBB !important;
margin-top: 4px; margin-top: 4px;
&.select2-drop-above {
margin-bottom: 8px;
}
.select2-search input { .select2-search input {
background: #fafafa; background: #fafafa;
border-color: #DDD; border-color: #DDD;
...@@ -78,3 +81,9 @@ select { ...@@ -78,3 +81,9 @@ select {
.project-refs-form .select2-container { .project-refs-form .select2-container {
margin-right: 10px; margin-right: 10px;
} }
.ajax-users-dropdown, .ajax-project-users-dropdown {
.select2-search {
padding-top: 4px;
}
}
...@@ -90,9 +90,27 @@ a:focus { ...@@ -90,9 +90,27 @@ a:focus {
font-size: 14px; font-size: 14px;
line-height: 1.6; line-height: 1.6;
.white .highlight pre {
background: #f5f5f5; /* Link to current header. */
h1, h2, h3, h4, h5, h6 {
position: relative;
&:hover > :last-child {
$size: 16px;
position: absolute;
right: 100%;
top: 50%;
margin-top: -$size/2;
margin-right: 0px;
padding-right: 20px;
display: inline-block;
width: $size;
height: $size;
background-image: url("icon-link.png");
background-size: contain;
background-repeat: no-repeat;
}
} }
ul { ul {
padding: 0; padding: 0;
margin: 0 0 9px 25px !important; margin: 0 0 9px 25px !important;
......
...@@ -108,6 +108,8 @@ $pagination-active-bg: $bg_style_color; ...@@ -108,6 +108,8 @@ $pagination-active-bg: $bg_style_color;
// Nav tabs // Nav tabs
.nav.nav-tabs { .nav.nav-tabs {
margin-bottom: 15px;
li { li {
> a { > a {
padding: 8px 20px; padding: 8px 20px;
......
.dark .highlight { .dark {
background-color: #232323;
background-color: #333; .line.hll {
background: #558;
}
.highlight{
border-left: 1px solid #444;
}
.no-highlight {
color: #DDD;
}
.line-numbers a {
color: #666;
}
pre { pre {
background-color: #333; background-color: #232323;
color: #eee; }
}
.hljs {
.hll { display: block; background-color: darken($hover, 65%) } display: block;
.c { color: #888888; font-style: italic } /* Comment */ background: #232323;
.err { color: #a61717; background-color: #e3d2d2 } /* Error */ color: #E6E1DC;
.k { color: #CDA869; font-weight: bold } /* Keyword */ }
.kp { color: #CDA869; font-weight: bold } /* Keyword */
.cm { color: #888888 } /* Comment.Multiline */ .hljs-comment,
.cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .hljs-template_comment,
.c1 { color: #888888 } /* Comment.Single */ .hljs-javadoc,
.cs { color: #cc0000; font-weight: bold; background-color: transparent } /* Comment.Special */ .hljs-shebang {
.gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ color: #BC9458;
.ge { font-style: italic } /* Generic.Emph */ font-style: italic;
.gr { color: #aa0000 } /* Generic.Error */ }
.gh { color: #303030 } /* Generic.Heading */
.gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .hljs-keyword,
.go { color: #888888 } /* Generic.Output */ .ruby .hljs-function .hljs-keyword,
.gp { color: #555555 } /* Generic.Prompt */ .hljs-request,
.gs { font-weight: bold } /* Generic.Strong */ .hljs-status,
.gu { color: #606060 } /* Generic.Subheading */ .nginx .hljs-title,
.gt { color: #aa0000 } /* Generic.Traceback */ .method,
.kc{font-weight: bold;} /* Keyword.Constant */ .hljs-list .hljs-title {
.kd{font-weight: bold;} /* Keyword.Declaration */ color: #C26230;
.kn{font-weight: bold;} /* Keyword.Namespace */ }
.kp{font-weight: bold;} /* Keyword.Pseudo */
.kr{font-weight: bold;} /* Keyword.Reserved */ .hljs-string,
.kt{color: #458;font-weight: bold;} /* Keyword.Type */ .hljs-number,
.m { color: #0000DD; font-weight: bold } /* Literal.Number */ .hljs-regexp,
.p { color: #eee; } .hljs-tag .hljs-value,
.s { color: #0AD; background-color: transparent } /* Literal.String */ .hljs-cdata,
.na{color: #008080;} /* Name.Attribute */ .hljs-filter .hljs-argument,
.nb{color: #0086B3;} /* Name.Builtin */ .hljs-attr_selector,
.nc{color: #ccc;font-weight: bold;} /* Name.Class */ .apache .hljs-cbracket,
.no{color: turquoise;} /* Name.Constant */ .hljs-date,
.ni{color: #800080;} .tex .hljs-command,
.ne{color: #900;font-weight: bold;} /* Name.Exception */ .markdown .hljs-link_label {
.nf{color: #ccc;font-weight: bold;} /* Name.Function */ color: #A5C261;
.nn{color: #79C3E0;font-weight: bold;} /* Name.Namespace */ }
.nt{color: #fc5;} /* Name.Tag */
.nv{color: #FA4;} /* Name.Variable */ .hljs-subst {
.py { color: #336699; font-weight: bold } /* Name.Property */ color: #519F50;
.ow { color: #008800 } /* Operator.Word */ }
.w { color: #bbbbbb } /* Text.Whitespace */
.mf { color: #7AC; font-weight: bold } /* Literal.Number.Float */ .hljs-tag,
.mh { color: #7AC; font-weight: bold } /* Literal.Number.Hex */ .hljs-tag .hljs-keyword,
.mi {color: #099;} /* Literal.Number.Integer */ .hljs-tag .hljs-title,
.mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .hljs-doctype,
.sb { color: #dd2200; background-color: transparent; } /* Literal.String.Backtick */ .hljs-sub .hljs-identifier,
.sc{color: #d14;} /* Literal.String.Char */ .hljs-pi,
.sd { color: #dd2200; background-color: transparent; } /* Literal.String.Doc */ .input_number {
.s2{color: orange;} /* Literal.String.Double */ color: #E8BF6A;
.se{color: orange;} /* Literal.String.Escape */ }
.sh{color: orange;} /* Literal.String.Heredoc */
.si{color: orange;} /* Literal.String.Interpol */ .hljs-identifier {
.sx{color: orange;} /* Literal.String.Other */ color: #D0D0FF;
.sr{color: orange;} /* Literal.String.Regex */ }
.s1{color: orange;} /* Literal.String.Single */
.ss{color: orange;} /* Literal.String.Symbol */ .hljs-class .hljs-title,
.bp { color: #D58 } /* Name.Builtin.Pseudo */ .haskell .hljs-type,
.vc { color: #336699 } /* Name.Variable.Class */ .smalltalk .hljs-class,
.vg { color: #dd7700 } /* Name.Variable.Global */ .hljs-javadoctag,
.vi { color: cyan } .hljs-yardoctag,
} .hljs-phpdoc {
text-decoration: none;
}
.hljs-constant {
color: #DA4939;
}
.hljs-symbol,
.hljs-built_in,
.ruby .hljs-symbol .hljs-string,
.ruby .hljs-symbol .hljs-identifier,
.markdown .hljs-link_url,
.hljs-attribute {
color: #6D9CBE;
}
.markdown .hljs-link_url {
text-decoration: underline;
}
.hljs-params,
.hljs-variable,
.clojure .hljs-attribute {
color: #D0D0FF;
}
.css .hljs-tag,
.hljs-rules .hljs-property,
.hljs-pseudo,
.tex .hljs-special {
color: #CDA869;
}
.css .hljs-class {
color: #9B703F;
}
.hljs-rules .hljs-keyword {
color: #C5AF75;
}
.hljs-rules .hljs-value {
color: #CF6A4C;
}
.css .hljs-id {
color: #8B98AB;
}
.hljs-annotation,
.apache .hljs-sqbracket,
.nginx .hljs-built_in {
color: #9B859D;
}
.hljs-preprocessor,
.hljs-preprocessor *,
.hljs-pragma {
color: #8996A8 !important;
}
.hljs-hexcolor,
.css .hljs-value .hljs-number {
color: #A5C261;
}
.hljs-title,
.hljs-decorator,
.css .hljs-function {
color: #FFC66D;
}
.diff .hljs-header,
.hljs-chunk {
background-color: #2F33AB;
color: #E6E1DC;
display: inline-block;
width: 100%;
}
.diff .hljs-change {
background-color: #4A410D;
color: #F8F8F8;
display: inline-block;
width: 100%;
}
.hljs-addition {
background-color: #144212;
color: #E6E1DC;
display: inline-block;
width: 100%;
}
.hljs-deletion {
background-color: #600;
color: #E6E1DC;
display: inline-block;
width: 100%;
}
.coffeescript .javascript,
.javascript .xml,
.tex .hljs-formula,
.xml .javascript,
.xml .vbscript,
.xml .css,
.xml .hljs-cdata {
opacity: 0.7;
}
}
$monokai-fg: #f8f8f2; .monokai {
$monokai-comment: #75715e; background-color: #272822;
$monokai-pink: #f92672;
$monokai-blue: #66d9ef;
$monokai-green: #a6e22e;
$monokai-gold: #e6db74;
$monokai-dark: #3b3a32;
$monokai-purple: #ae81ff;
.monokai .highlight { .highlight{
border-left: 1px solid #444;
}
background-color: #272822; .line.hll {
background: #558;
}
.no-highlight {
color: #DDD;
}
.line-numbers a {
color: #666;
}
pre { pre {
background-color: #272822; background-color: #272822;
color: $monokai-fg; color: #f8f8f2;
} }
.hll { background-color: darken($hover, 65%) } .hljs {
.c { color: $monokai-comment } /* Comment */ display: block;
.err { color: $monokai-fg } /* Error */ background: #272822;
.g { color: $monokai-fg } /* Generic */ }
.k { color: $monokai-pink } /* Keyword */
.l { color: $monokai-fg } /* Literal */ .hljs-tag,
.n { color: $monokai-blue } /* Name */ .hljs-tag .hljs-title,
.o { color: $monokai-fg } /* Operator */ .hljs-keyword,
.x { color: $monokai-fg } /* Other */ .hljs-literal,
.p { color: $monokai-fg } /* Punctuation */ .hljs-strong,
.cm { color: $monokai-comment } /* Comment.Multiline */ .hljs-change,
.cp { color: $monokai-comment } /* Comment.Preproc */ .hljs-winutils,
.c1 { color: $monokai-comment } /* Comment.Single */ .hljs-flow,
.cs { color: $monokai-comment } /* Comment.Special */ .lisp .hljs-title,
.gd { color: #8b0807 } /* Generic.Deleted */ .clojure .hljs-built_in,
.ge { color: $monokai-fg; text-decoration: underline } /* Generic.Emph */ .nginx .hljs-title,
.gr { color: $monokai-fg } /* Generic.Error */ .tex .hljs-special {
.gh { color: $monokai-fg; font-weight: bold } /* Generic.Heading */ color: #F92672;
.gi { color: $monokai-fg; font-weight: bold; background-color: #46830c } /* Generic.Inserted */ }
.go { color: $monokai-dark; background-color: #31322c } /* Generic.Output */
.gp { color: $monokai-fg } /* Generic.Prompt */ .hljs {
.gs { color: $monokai-fg } /* Generic.Strong */ color: #DDD;
.gu { color: $monokai-fg; font-weight: bold } /* Generic.Subheading */ }
.gt { color: #f8f8f0; background-color: $monokai-pink } /* Generic.Traceback */
.kc { color: $monokai-purple } /* Keyword.Constant */
.kd { color: $monokai-pink } /* Keyword.Declaration */
.kn { color: $monokai-pink } /* Keyword.Namespace */
.kp { color: $monokai-pink } /* Keyword.Pseudo */
.kr { color: $monokai-pink } /* Keyword.Reserved */
.kt { color: $monokai-fg } /* Keyword.Type */
.ld { color: $monokai-fg } /* Literal.Date */
.m { color: $monokai-purple } /* Literal.Number */
.s { color: $monokai-gold } /* Literal.String */
.na { color: $monokai-purple } /* Name.Attribute */
.nb { color: $monokai-blue } /* Name.Builtin */
.nc { color: $monokai-fg } /* Name.Class */
.no { color: $monokai-fg } /* Name.Constant */
.nd { color: $monokai-fg } /* Name.Decorator */
.ni { color: $monokai-fg } /* Name.Entity */
.ne { color: $monokai-fg } /* Name.Exception */
.nf { color: $monokai-green } /* Name.Function */
.nl { color: $monokai-gold } /* Name.Label */
.nn { color: $monokai-fg } /* Name.Namespace */
.nx { color: $monokai-fg } /* Name.Other */
.nt { color: $monokai-pink } /* Name.Tag */
.nv { color: $monokai-blue; font-style: italic } /* Name.Variable */
.py { color: $monokai-fg } /* Name.Property */
.ow { color: $monokai-pink } /* Operator.Word */
.w { color: $monokai-fg } /* Text.Whitespace */
.mf { color: $monokai-purple } /* Literal.Number.Float */
.mh { color: $monokai-purple } /* Literal.Number.Hex */
.mi { color: $monokai-purple } /* Literal.Number.Integer */
.mo { color: $monokai-purple } /* Literal.Number.Oct */
.sb { color: $monokai-gold } /* Literal.String.Backtick */
.sc { color: $monokai-gold } /* Literal.String.Char */
.sd { color: $monokai-gold } /* Literal.String.Doc */
.s2 { color: $monokai-gold } /* Literal.String.Double */
.se { color: $monokai-gold } /* Literal.String.Escape */
.sh { color: $monokai-gold } /* Literal.String.Heredoc */
.si { color: $monokai-gold } /* Literal.String.Interpol */
.sx { color: $monokai-gold } /* Literal.String.Other */
.sr { color: $monokai-gold } /* Literal.String.Regex */
.s1 { color: $monokai-gold } /* Literal.String.Single */
.ss { color: $monokai-gold } /* Literal.String.Symbol */
.bp { color: $monokai-fg } /* Name.Builtin.Pseudo */
.vc { color: $monokai-blue; font-style: italic } /* Name.Variable.Class */
.vg { color: $monokai-blue; font-style: italic } /* Name.Variable.Global */
.vi { color: $monokai-blue; font-style: italic } /* Name.Variable.Instance */
.il { color: $monokai-purple } /* Literal.Number.Integer.Long */
}
.hljs .hljs-constant,
.asciidoc .hljs-code {
color: #66D9EF;
}
.hljs-code,
.hljs-class .hljs-title,
.hljs-header {
color: white;
}
.hljs-link_label,
.hljs-attribute,
.hljs-symbol,
.hljs-symbol .hljs-string,
.hljs-value,
.hljs-regexp {
color: #BF79DB;
}
.hljs-link_url,
.hljs-tag .hljs-value,
.hljs-string,
.hljs-bullet,
.hljs-subst,
.hljs-title,
.hljs-emphasis,
.haskell .hljs-type,
.hljs-preprocessor,
.hljs-pragma,
.ruby .hljs-class .hljs-parent,
.hljs-built_in,
.sql .hljs-aggregate,
.django .hljs-template_tag,
.django .hljs-variable,
.smalltalk .hljs-class,
.hljs-javadoc,
.django .hljs-filter .hljs-argument,
.smalltalk .hljs-localvars,
.smalltalk .hljs-array,
.hljs-attr_selector,
.hljs-pseudo,
.hljs-addition,
.hljs-stream,
.hljs-envvar,
.apache .hljs-tag,
.apache .hljs-cbracket,
.tex .hljs-command,
.hljs-prompt {
color: #A6E22E;
}
.hljs-comment,
.java .hljs-annotation,
.smartquote,
.hljs-blockquote,
.hljs-horizontal_rule,
.python .hljs-decorator,
.hljs-template_comment,
.hljs-pi,
.hljs-doctype,
.hljs-deletion,
.hljs-shebang,
.apache .hljs-sqbracket,
.tex .hljs-formula {
color: #75715E;
}
.hljs-keyword,
.hljs-literal,
.css .hljs-id,
.hljs-phpdoc,
.hljs-title,
.hljs-header,
.haskell .hljs-type,
.vbscript .hljs-built_in,
.sql .hljs-aggregate,
.rsl .hljs-built_in,
.smalltalk .hljs-class,
.diff .hljs-header,
.hljs-chunk,
.hljs-winutils,
.bash .hljs-variable,
.apache .hljs-tag,
.tex .hljs-special,
.hljs-request,
.hljs-status {
font-weight: bold;
}
.coffeescript .javascript,
.javascript .xml,
.tex .hljs-formula,
.xml .javascript,
.xml .vbscript,
.xml .css,
.xml .hljs-cdata {
opacity: 0.5;
}
}
.solarized-dark .highlight { .solarized-dark {
background-color: #002B36; background-color: #002B36;
.highlight{
border-left: 1px solid #113b46;
}
.line.hll {
background: #000;
}
.no-highlight {
color: #DDD;
}
pre { pre {
background-color: #002B36; background-color: #002B36;
color: #eee; color: #eee;
} }
.hll { background-color: #073642 } .line-numbers a {
.c { color: #586E75 } /* Comment */ color: #666;
.err { color: #93A1A1 } /* Error */ }
.g { color: #93A1A1 } /* Generic */
.k { color: #859900 } /* Keyword */ .hljs {
.l { color: #93A1A1 } /* Literal */ display: block;
.n { color: #93A1A1 } /* Name */ background: #002b36;
.o { color: #859900 } /* Operator */ color: #839496;
.x { color: #CB4B16 } /* Other */ }
.p { color: #93A1A1 } /* Punctuation */
.cm { color: #586E75 } /* Comment.Multiline */ .hljs-comment,
.cp { color: #859900 } /* Comment.Preproc */ .hljs-template_comment,
.c1 { color: #586E75 } /* Comment.Single */ .diff .hljs-header,
.cs { color: #859900 } /* Comment.Special */ .hljs-doctype,
.gd { color: #2AA198 } /* Generic.Deleted */ .hljs-pi,
.ge { color: #93A1A1; font-style: italic } /* Generic.Emph */ .lisp .hljs-string,
.gr { color: #DC322F } /* Generic.Error */ .hljs-javadoc {
.gh { color: #CB4B16 } /* Generic.Heading */ color: #586e75;
.gi { color: #859900 } /* Generic.Inserted */ }
.go { color: #93A1A1 } /* Generic.Output */
.gp { color: #93A1A1 } /* Generic.Prompt */ /* Solarized Green */
.gs { color: #93A1A1; font-weight: bold } /* Generic.Strong */ .hljs-keyword,
.gu { color: #CB4B16 } /* Generic.Subheading */ .hljs-winutils,
.gt { color: #93A1A1 } /* Generic.Traceback */ .method,
.kc { color: #CB4B16 } /* Keyword.Constant */ .hljs-addition,
.kd { color: #268BD2 } /* Keyword.Declaration */ .css .hljs-tag,
.kn { color: #859900 } /* Keyword.Namespace */ .hljs-request,
.kp { color: #859900 } /* Keyword.Pseudo */ .hljs-status,
.kr { color: #268BD2 } /* Keyword.Reserved */ .nginx .hljs-title {
.kt { color: #DC322F } /* Keyword.Type */ color: #859900;
.ld { color: #93A1A1 } /* Literal.Date */ }
.m { color: #2AA198 } /* Literal.Number */
.s { color: #2AA198 } /* Literal.String */
.na { color: #93A1A1 } /* Name.Attribute */
.nb { color: #B58900 } /* Name.Builtin */
.nc { color: #268BD2 } /* Name.Class */
.no { color: #CB4B16 } /* Name.Constant */
.nd { color: #268BD2 } /* Name.Decorator */
.ni { color: #CB4B16 } /* Name.Entity */
.ne { color: #CB4B16 } /* Name.Exception */
.nf { color: #268BD2 } /* Name.Function */
.nl { color: #93A1A1 } /* Name.Label */
.nn { color: #93A1A1 } /* Name.Namespace */
.nx { color: #93A1A1 } /* Name.Other */
.py { color: #93A1A1 } /* Name.Property */
.nt { color: #268BD2 } /* Name.Tag */
.nv { color: #268BD2 } /* Name.Variable */
.ow { color: #859900 } /* Operator.Word */
.w { color: #93A1A1 } /* Text.Whitespace */
.mf { color: #2AA198 } /* Literal.Number.Float */
.mh { color: #2AA198 } /* Literal.Number.Hex */
.mi { color: #2AA198 } /* Literal.Number.Integer */
.mo { color: #2AA198 } /* Literal.Number.Oct */
.sb { color: #586E75 } /* Literal.String.Backtick */
.sc { color: #2AA198 } /* Literal.String.Char */
.sd { color: #93A1A1 } /* Literal.String.Doc */
.s2 { color: #2AA198 } /* Literal.String.Double */
.se { color: #CB4B16 } /* Literal.String.Escape */
.sh { color: #93A1A1 } /* Literal.String.Heredoc */
.si { color: #2AA198 } /* Literal.String.Interpol */
.sx { color: #2AA198 } /* Literal.String.Other */
.sr { color: #DC322F } /* Literal.String.Regex */
.s1 { color: #2AA198 } /* Literal.String.Single */
.ss { color: #2AA198 } /* Literal.String.Symbol */
.bp { color: #268BD2 } /* Name.Builtin.Pseudo */
.vc { color: #268BD2 } /* Name.Variable.Class */
.vg { color: #268BD2 } /* Name.Variable.Global */
.vi { color: #268BD2 } /* Name.Variable.Instance */
.il { color: #2AA198 } /* Literal.Number.Integer.Long */
}
/* Solarized Cyan */
.hljs-number,
.hljs-command,
.hljs-string,
.hljs-tag .hljs-value,
.hljs-rules .hljs-value,
.hljs-phpdoc,
.tex .hljs-formula,
.hljs-regexp,
.hljs-hexcolor,
.hljs-link_url {
color: #2aa198;
}
/* Solarized Blue */
.hljs-title,
.hljs-localvars,
.hljs-chunk,
.hljs-decorator,
.hljs-built_in,
.hljs-identifier,
.vhdl .hljs-literal,
.hljs-id,
.css .hljs-function {
color: #268bd2;
}
/* Solarized Yellow */
.hljs-attribute,
.hljs-variable,
.lisp .hljs-body,
.smalltalk .hljs-number,
.hljs-constant,
.hljs-class .hljs-title,
.hljs-parent,
.haskell .hljs-type,
.hljs-link_reference {
color: #b58900;
}
/* Solarized Orange */
.hljs-preprocessor,
.hljs-preprocessor .hljs-keyword,
.hljs-pragma,
.hljs-shebang,
.hljs-symbol,
.hljs-symbol .hljs-string,
.diff .hljs-change,
.hljs-special,
.hljs-attr_selector,
.hljs-subst,
.hljs-cdata,
.clojure .hljs-title,
.css .hljs-pseudo,
.hljs-header {
color: #cb4b16;
}
/* Solarized Red */
.hljs-deletion,
.hljs-important {
color: #dc322f;
}
/* Solarized Violet */
.hljs-link_label {
color: #6c71c4;
}
.tex .hljs-formula {
background: #073642;
}
}
.white .highlight { .white {
background-color: #fff; background-color: #fff;
.line.hll {
background: #FFA;
}
.highlight{
border-left: 1px solid #eee;
}
pre { pre {
background-color: #fff; background-color: #fff;
color: #333; color: #333;
} }
.hll { display: block; background-color: $hover } .hljs {
.c { color: #888888; font-style: italic } /* Comment */ background: #FFF;
.err { color: #a61717; background-color: #e3d2d2 } /* Error */ }
.k { color: #000000; font-weight: bold } /* Keyword */
.cm { color: #888888 } /* Comment.Multiline */ .line-numbers a {
.cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ color: #999;
.c1 { color: #888888 } /* Comment.Single */ }
.cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .hljs {
.ge { font-style: italic } /* Generic.Emph */ display: block;
.gr { color: #aa0000 } /* Generic.Error */ background: #fff; color: black;
.gh { color: #303030 } /* Generic.Heading */ }
.gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.go { color: #888888 } /* Generic.Output */ .hljs-comment,
.gp { color: #555555 } /* Generic.Prompt */ .hljs-template_comment,
.gs { font-weight: bold } /* Generic.Strong */ .hljs-javadoc,
.gu { color: #606060 } /* Generic.Subheading */ .hljs-comment * {
.gt { color: #aa0000 } /* Generic.Traceback */ color: #006a00;
.kc{font-weight: bold;} /* Keyword.Constant */ }
.kd{font-weight: bold;} /* Keyword.Declaration */
.kn{font-weight: bold;} /* Keyword.Namespace */ .hljs-keyword,
.kp{font-weight: bold;} /* Keyword.Pseudo */ .hljs-literal,
.kr{font-weight: bold;} /* Keyword.Reserved */ .nginx .hljs-title {
.kt{color: #458;font-weight: bold;} /* Keyword.Type */ color: #aa0d91;
.m { color: #0000DD; font-weight: bold } /* Literal.Number */ }
.s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .method,
.na{color: #008080;} /* Name.Attribute */ .hljs-list .hljs-title,
.nb{color: #0086B3;} /* Name.Builtin */ .hljs-tag .hljs-title,
.nc{color: #458;font-weight: bold;} /* Name.Class */ .setting .hljs-value,
.no{color: #008080;} /* Name.Constant */ .hljs-winutils,
.ni{color: #800080;} .tex .hljs-command,
.ne{color: #900;font-weight: bold;} /* Name.Exception */ .http .hljs-title,
.nf{color: #900;font-weight: bold;} /* Name.Function */ .hljs-request,
.nn{color: #005;font-weight: bold;} /* Name.Namespace */ .hljs-status {
.nt{color: #000080;} /* Name.Tag */ color: #008;
.nv{color: #008080;} /* Name.Variable */ }
.py { color: #336699; font-weight: bold } /* Name.Property */
.ow { color: #008800 } /* Operator.Word */ .hljs-envvar,
.w { color: #bbbbbb } /* Text.Whitespace */ .tex .hljs-special {
.mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ color: #660;
.mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ }
.mi {color: #099;} /* Literal.Number.Integer */
.mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .hljs-string {
.sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ color: #c41a16;
.sc{color: #d14;} /* Literal.String.Char */ }
.sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .hljs-tag .hljs-value,
.s2{color: #d14;} /* Literal.String.Double */ .hljs-cdata,
.se{color: #d14;} /* Literal.String.Escape */ .hljs-filter .hljs-argument,
.sh{color: #d14;} /* Literal.String.Heredoc */ .hljs-attr_selector,
.si{color: #d14;} /* Literal.String.Interpol */ .apache .hljs-cbracket,
.sx{color: #d14;} /* Literal.String.Other */ .hljs-date,
.sr{color: #d14;} /* Literal.String.Regex */ .hljs-regexp {
.s1{color: #d14;} /* Literal.String.Single */ color: #080;
.ss{color: #d14;} /* Literal.String.Symbol */ }
.bp { color: #003388 } /* Name.Builtin.Pseudo */
.vc { color: #336699 } /* Name.Variable.Class */ .hljs-sub .hljs-identifier,
.vg { color: #dd7700 } /* Name.Variable.Global */ .hljs-pi,
.vi { color: #3333bb } .hljs-tag,
.hljs-tag .hljs-keyword,
.hljs-decorator,
.ini .hljs-title,
.hljs-shebang,
.hljs-prompt,
.hljs-hexcolor,
.hljs-rules .hljs-value,
.hljs-symbol,
.hljs-symbol .hljs-string,
.hljs-number,
.css .hljs-function,
.clojure .hljs-title,
.clojure .hljs-built_in,
.hljs-function .hljs-title,
.coffeescript .hljs-attribute {
color: #1c00cf;
}
.hljs-class .hljs-title,
.haskell .hljs-type,
.smalltalk .hljs-class,
.hljs-javadoctag,
.hljs-yardoctag,
.hljs-phpdoc,
.hljs-typename,
.hljs-tag .hljs-attribute,
.hljs-doctype,
.hljs-class .hljs-id,
.hljs-built_in,
.setting,
.hljs-params,
.clojure .hljs-attribute {
color: #5c2699;
}
.hljs-variable {
color: #3f6e74;
}
.css .hljs-tag,
.hljs-rules .hljs-property,
.hljs-pseudo,
.hljs-subst {
color: #000;
}
.css .hljs-class,
.css .hljs-id {
color: #9B703F;
}
.hljs-value .hljs-important {
color: #ff7700;
font-weight: bold;
}
.hljs-rules .hljs-keyword {
color: #C5AF75;
}
.hljs-annotation,
.apache .hljs-sqbracket,
.nginx .hljs-built_in {
color: #9B859D;
}
.hljs-preprocessor,
.hljs-preprocessor *,
.hljs-pragma {
color: #643820;
}
.tex .hljs-formula {
background-color: #EEE;
font-style: italic;
}
.diff .hljs-header,
.hljs-chunk {
color: #808080;
font-weight: bold;
}
.diff .hljs-change {
background-color: #BCCFF9;
}
.hljs-addition {
background-color: #BAEEBA;
}
.hljs-deletion {
background-color: #FFC8BD;
}
.hljs-comment .hljs-yardoctag {
font-weight: bold;
}
.method .hljs-id {
color: #000;
}
} }
.shadow { .shadow {
......
...@@ -106,12 +106,12 @@ ...@@ -106,12 +106,12 @@
h3 { h3 {
margin-top: 35px; margin-top: 35px;
font-size: 2em; font-size: 1.5em;
} }
h4 { h4 {
margin-top: 30px; margin-top: 30px;
font-size: 1.5em; font-size: 1.2em;
} }
blockquote p { blockquote p {
...@@ -128,7 +128,7 @@ ...@@ -128,7 +128,7 @@
} }
} }
code { p > code {
font-size: inherit; font-size: inherit;
font-weight: inherit; font-weight: inherit;
color: #555; color: #555;
......
...@@ -5,6 +5,7 @@ $primary_color: #2FA0BB; ...@@ -5,6 +5,7 @@ $primary_color: #2FA0BB;
$link_color: #3A89A3; $link_color: #3A89A3;
$style_color: #474D57; $style_color: #474D57;
$bg_style_color: #2299BB; $bg_style_color: #2299BB;
$list-group-active-bg: $bg_style_color;
$hover: #D9EDF7; $hover: #D9EDF7;
/** /**
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* Admin area * Admin area
* *
*/ */
.admin_dash { .admin-dashboard {
.data { .data {
a { a {
h1 { h1 {
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
} }
} }
} }
.str-truncated {
max-width: 60%;
}
} }
.admin-filter form { .admin-filter form {
......
...@@ -153,6 +153,7 @@ ...@@ -153,6 +153,7 @@
img{ img{
border: 1px solid #FFF; border: 1px solid #FFF;
background: url('trans_bg.gif'); background: url('trans_bg.gif');
max-width: 100%;
} }
&.deleted { &.deleted {
border: 1px solid $deleted; border: 1px solid $deleted;
......
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
.dash-sidebar-tabs { .dash-sidebar-tabs {
margin-bottom: 2px; margin-bottom: 2px;
border: none; border: none;
margin: 0; margin: 0 !important;
li { li {
&.active { &.active {
......
...@@ -37,8 +37,8 @@ ...@@ -37,8 +37,8 @@
&.event-inline { &.event-inline {
.avatar { .avatar {
width: 16px; position: relative;
height: 16px; top: -2px;
} }
} }
...@@ -113,6 +113,7 @@ ...@@ -113,6 +113,7 @@
&.commit { &.commit {
background: transparent; background: transparent;
padding: 3px; padding: 3px;
padding-left: 0;
border: none; border: none;
color: #666; color: #666;
.commit-row-title { .commit-row-title {
...@@ -122,6 +123,7 @@ ...@@ -122,6 +123,7 @@
&.commits-stat { &.commits-stat {
display: block; display: block;
padding: 3px; padding: 3px;
padding-left: 0;
&:hover { &:hover {
background: none; background: none;
......
.new-group-member-holder {
margin-top: 50px;
background: #f9f9f9;
padding-top: 20px;
}
.member-search-form {
float: left;
}
...@@ -46,12 +46,17 @@ header { ...@@ -46,12 +46,17 @@ header {
} }
} }
.turbolink-spinner {
font-size: 20px;
margin-right: 10px;
}
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
border-width: 0; border-width: 0;
font-size: 18px; font-size: 18px;
.app_logo { margin-left: -15px; } .app_logo { margin-left: -15px; }
.project_name { .title {
display: inline-block; display: inline-block;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
...@@ -103,7 +108,7 @@ header { ...@@ -103,7 +108,7 @@ header {
h1 { h1 {
margin: 0; margin: 0;
background: url('logo-black.png') no-repeat center center; background: image-url('logo-black.png') no-repeat center center;
background-size: 32px; background-size: 32px;
float: left; float: left;
height: 46px; height: 46px;
...@@ -122,7 +127,7 @@ header { ...@@ -122,7 +127,7 @@ header {
* Project / Area name * Project / Area name
* *
*/ */
.project_name { .title {
position: relative; position: relative;
float: left; float: left;
margin: 0; margin: 0;
...@@ -215,18 +220,18 @@ header { ...@@ -215,18 +220,18 @@ header {
.app_logo { .app_logo {
a { a {
h1 { h1 {
background: url('logo-white.png') no-repeat center center; background: image-url('logo-white.png') no-repeat center center;
background-size: 32px; background-size: 32px;
color: #fff; color: #fff;
text-shadow: 0 1px 1px #444; text-shadow: 0 1px 1px #444;
} }
} }
} }
.project_name { .title {
a { a {
color: #BBB;
&:hover {
color: #FFF; color: #FFF;
&:hover {
text-decoration: underline;
} }
} }
color: #fff; color: #fff;
......
...@@ -14,8 +14,8 @@ ...@@ -14,8 +14,8 @@
.issue-check { .issue-check {
float: left; float: left;
padding: 8px 0;
padding-right: 8px; padding-right: 8px;
margin-bottom: 10px;
min-width: 15px; min-width: 15px;
} }
...@@ -38,13 +38,21 @@ ...@@ -38,13 +38,21 @@
} }
} }
input.check_all_issues { .check-all-holder {
height: 32px;
float: left; float: left;
margin-right: 12px;
padding: 6px 10px;
border: 1px solid #ccc;
@include border-radius(4px);
input.check_all_issues {
padding: 0; padding: 0;
margin: 0; margin: 0;
margin-right: 10px;
position: relative; position: relative;
top: 13px; top: 3px;
}
} }
.issues_content { .issues_content {
...@@ -57,23 +65,6 @@ input.check_all_issues { ...@@ -57,23 +65,6 @@ input.check_all_issues {
} }
} }
.btn.close_issue {
color: #B94A48;
font-weight: bold;
@include shade;
&:hover {
color: #B94A48;
}
}
.btn.reopen_issue {
color: #468847;
font-weight: bold;
@include shade;
&:hover {
color: #468847;
}
}
@media (min-width: 800px) { .issues_filters select { width: 160px; } } @media (min-width: 800px) { .issues_filters select { width: 160px; } }
@media (min-width: 1200px) { .issues_filters select { width: 220px; } } @media (min-width: 1200px) { .issues_filters select { width: 220px; } }
...@@ -93,6 +84,13 @@ input.check_all_issues { ...@@ -93,6 +84,13 @@ input.check_all_issues {
.update_selected_issues { .update_selected_issues {
margin-left: 4px; margin-left: 4px;
} }
.select2-container .select2-choice {
height: 32px;
line-height: 28px;
color: #444 !important;
font-weight: 500;
}
} }
} }
......
...@@ -31,10 +31,10 @@ ...@@ -31,10 +31,10 @@
.mr_source_commit, .mr_source_commit,
.mr_target_commit { .mr_target_commit {
margin-top: 10px;
.commit { .commit {
margin: 0; margin: 0;
padding: 0; padding: 2px 0;
padding: 5px 0;
list-style: none; list-style: none;
&:hover { &:hover {
background: none; background: none;
......
...@@ -35,9 +35,8 @@ ...@@ -35,9 +35,8 @@
width: 1%; width: 1%;
&.active { &.active {
a { a {
color: $style_color; color: #333;
font-weight: bolder; font-weight: bold;
&:after { &:after {
content: ''; content: '';
display: block; display: block;
...@@ -46,7 +45,7 @@ ...@@ -46,7 +45,7 @@
left: 50%; left: 50%;
width: 0; width: 0;
height: 0; height: 0;
border-color: transparent transparent #777 transparent; border-color: transparent transparent #333 transparent;
border-style: solid; border-style: solid;
border-width: 6px; border-width: 6px;
margin-left: -6px; margin-left: -6px;
...@@ -56,7 +55,20 @@ ...@@ -56,7 +55,20 @@
&:hover { &:hover {
a { a {
color: $style_color; color: $link_color;
&:after {
content: '';
display: block;
position: relative;
bottom: 8px;
left: 50%;
width: 0;
height: 0;
border-color: transparent transparent #29b transparent;
border-style: solid;
border-width: 6px;
margin-left: -6px;
}
} }
} }
...@@ -73,7 +85,7 @@ ...@@ -73,7 +85,7 @@
a { a {
display: block; display: block;
text-align: center; text-align: center;
font-weight: normal; font-weight: 500;
height: 38px; height: 38px;
line-height: 34px; line-height: 34px;
color: #777; color: #777;
......
...@@ -92,10 +92,6 @@ ul.notes { ...@@ -92,10 +92,6 @@ ul.notes {
.note-body { .note-body {
@include md-typography; @include md-typography;
margin-left: 45px; margin-left: 45px;
.highlight {
@include border-radius(4px);
}
} }
.note-header { .note-header {
padding-bottom: 5px; padding-bottom: 5px;
...@@ -292,7 +288,7 @@ ul.notes { ...@@ -292,7 +288,7 @@ ul.notes {
box-shadow: none; box-shadow: none;
font-size: 14px; font-size: 14px;
height: 80px; height: 80px;
width: 98.6%; width: 100%;
} }
} }
} }
...@@ -341,7 +337,7 @@ ul.notes { ...@@ -341,7 +337,7 @@ ul.notes {
box-shadow: none; box-shadow: none;
font-size: 14px; font-size: 14px;
height: 80px; height: 80px;
width: 98.6%; width: 100%;
} }
.form-actions { .form-actions {
......
...@@ -105,3 +105,23 @@ ...@@ -105,3 +105,23 @@
} }
} }
} }
.profile-groups-avatars {
margin: 0 5px 10px 0;
img {
width: 50px;
height: 50px;
}
}
.global-notifications-form .level-title {
font-size: 15px;
color: #333;
font-weight: bold;
}
.notification-icon-holder {
width: 20px;
float: left;
}
...@@ -123,14 +123,9 @@ ...@@ -123,14 +123,9 @@
} }
.save-project-loader { .save-project-loader {
img {
margin-top: 50px; margin-top: 50px;
margin-bottom: 50px; margin-bottom: 50px;
} color: #555;
h3 {
@extend .page-title;
}
} }
ul.nav.nav-projects-tabs { ul.nav.nav-projects-tabs {
......
...@@ -127,9 +127,27 @@ ...@@ -127,9 +127,27 @@
border-top: 1px dashed #CCC; border-top: 1px dashed #CCC;
padding-top: 10px; padding-top: 10px;
h4 { .readme-file-title {
font-size: 14px; font-size: 14px;
margin-bottom: 20px; margin-bottom: 20px;
color: #777; color: #777;
} }
} }
.blob-commit-info {
list-style: none;
margin: 0;
padding: 0;
margin-bottom: 10px;
.commit {
.commit-row-title {
font-size: 13px;
.commit-row-message {
font-weight: normal;
color: #555;
}
}
}
}
...@@ -36,4 +36,8 @@ ...@@ -36,4 +36,8 @@
} }
} }
} }
.nav-pills > li.active > a, .nav-pills > li.active > a:hover, .nav-pills > li.active > a:focus {
background: #769;
}
} }
...@@ -135,12 +135,12 @@ class ApplicationController < ActionController::Base ...@@ -135,12 +135,12 @@ class ApplicationController < ActionController::Base
end end
end end
def render_404 def render_403
render file: Rails.root.join("public", "404"), layout: false, status: "404" head :forbidden
end end
def render_403 def render_404
render file: Rails.root.join("public", "403"), layout: false, status: "403" render file: Rails.root.join("public", "404"), layout: false, status: "404"
end end
def require_non_empty_project def require_non_empty_project
...@@ -171,6 +171,7 @@ class ApplicationController < ActionController::Base ...@@ -171,6 +171,7 @@ class ApplicationController < ActionController::Base
gon.api_token = current_user.private_token if current_user gon.api_token = current_user.private_token if current_user
gon.gravatar_url = request.ssl? || Gitlab.config.gitlab.https ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url gon.gravatar_url = request.ssl? || Gitlab.config.gitlab.https ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url
gon.relative_url_root = Gitlab.config.gitlab.relative_url_root gon.relative_url_root = Gitlab.config.gitlab.relative_url_root
gon.gravatar_enabled = Gitlab.config.gravatar.enabled
end end
def check_password_expiration def check_password_expiration
......
...@@ -54,12 +54,12 @@ class DashboardController < ApplicationController ...@@ -54,12 +54,12 @@ class DashboardController < ApplicationController
def merge_requests def merge_requests
@merge_requests = FilteringService.new.execute(MergeRequest, current_user, params) @merge_requests = FilteringService.new.execute(MergeRequest, current_user, params)
@merge_requests = @merge_requests.recent.page(params[:page]).per(20) @merge_requests = @merge_requests.page(params[:page]).per(20)
end end
def issues def issues
@issues = FilteringService.new.execute(Issue, current_user, params) @issues = FilteringService.new.execute(Issue, current_user, params)
@issues = @issues.recent.page(params[:page]).per(20) @issues = @issues.page(params[:page]).per(20)
@issues = @issues.includes(:author, :project) @issues = @issues.includes(:author, :project)
respond_to do |format| respond_to do |format|
......
class Groups::AvatarsController < ApplicationController
layout "profile"
def destroy
@group = Group.find_by(path: params[:group_id])
@group.remove_avatar!
@group.save
redirect_to edit_group_path(@group)
end
end
...@@ -63,7 +63,14 @@ class GroupsController < ApplicationController ...@@ -63,7 +63,14 @@ class GroupsController < ApplicationController
def members def members
@project = group.projects.find(params[:project_id]) if params[:project_id] @project = group.projects.find(params[:project_id]) if params[:project_id]
@members = group.users_groups.order('group_access DESC') @members = group.users_groups
if params[:search].present?
users = group.users.search(params[:search])
@members = @members.where(user_id: users)
end
@members = @members.order('group_access DESC').page(params[:page]).per(50)
@users_group = UsersGroup.new @users_group = UsersGroup.new
end end
......
class Profiles::EmailsController < ApplicationController
layout "profile"
def index
@primary = current_user.email
@emails = current_user.emails
end
def create
@email = current_user.emails.new(params[:email])
flash[:alert] = @email.errors.full_messages.first unless @email.save
redirect_to profile_emails_url
end
def destroy
@email = current_user.emails.find(params[:id])
@email.destroy
respond_to do |format|
format.html { redirect_to profile_emails_url }
format.js { render nothing: true }
end
end
end
...@@ -7,12 +7,11 @@ class Profiles::GroupsController < ApplicationController ...@@ -7,12 +7,11 @@ class Profiles::GroupsController < ApplicationController
def leave def leave
@users_group = group.users_groups.where(user_id: current_user.id).first @users_group = group.users_groups.where(user_id: current_user.id).first
if can?(current_user, :destroy, @users_group)
if group.last_owner?(current_user)
redirect_to(profile_groups_path, alert: "You can't leave group. You must add at least one more owner to it.")
else
@users_group.destroy @users_group.destroy
redirect_to(profile_groups_path, info: "You left #{group.name} group.") redirect_to(profile_groups_path, info: "You left #{group.name} group.")
else
return render_403
end end
end end
......
class Profiles::KeysController < ApplicationController class Profiles::KeysController < ApplicationController
layout "profile" layout "profile"
skip_before_filter :authenticate_user!, only: [:get_keys]
def index def index
@keys = current_user.keys.order('id DESC') @keys = current_user.keys.order('id DESC')
...@@ -32,4 +33,24 @@ class Profiles::KeysController < ApplicationController ...@@ -32,4 +33,24 @@ class Profiles::KeysController < ApplicationController
format.js { render nothing: true } format.js { render nothing: true }
end end
end end
# Get all keys of a user(params[:username]) in a text format
# Helpful for sysadmins to put in respective servers
def get_keys
if params[:username].present?
begin
user = User.find_by_username(params[:username])
if user.present?
render text: user.all_ssh_keys.join("\n")
else
render_404 and return
end
rescue => e
render text: e.message
end
else
render_404 and return
end
end
end end
...@@ -8,13 +8,14 @@ class Projects::CompareController < Projects::ApplicationController ...@@ -8,13 +8,14 @@ class Projects::CompareController < Projects::ApplicationController
end end
def show def show
compare = Gitlab::Git::Compare.new(@repository.raw_repository, params[:from], params[:to]) compare = Gitlab::Git::Compare.new(@repository.raw_repository, params[:from], params[:to], MergeRequestDiff::COMMITS_SAFE_SIZE)
@commits = compare.commits @commits = compare.commits
@commit = compare.commit @commit = compare.commit
@diffs = compare.diffs @diffs = compare.diffs
@refs_are_same = compare.same @refs_are_same = compare.same
@line_notes = [] @line_notes = []
@timeout = compare.timeout
diff_line_count = Commit::diff_line_count(@diffs) diff_line_count = Commit::diff_line_count(@diffs)
@suppress_diff = Commit::diff_suppress?(@diffs, diff_line_count) && !params[:force_show_diff] @suppress_diff = Commit::diff_suppress?(@diffs, diff_line_count) && !params[:force_show_diff]
......
...@@ -9,7 +9,10 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -9,7 +9,10 @@ class Projects::IssuesController < Projects::ApplicationController
before_filter :authorize_write_issue!, only: [:new, :create] before_filter :authorize_write_issue!, only: [:new, :create]
# Allow modify issue # Allow modify issue
before_filter :authorize_modify_issue!, only: [:edit, :update, :bulk_update] before_filter :authorize_modify_issue!, only: [:edit, :update]
# Allow issues bulk update
before_filter :authorize_admin_issues!, only: [:bulk_update]
respond_to :html respond_to :html
...@@ -25,7 +28,7 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -25,7 +28,7 @@ class Projects::IssuesController < Projects::ApplicationController
@milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero? @milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero?
sort_param = params[:sort] || 'newest' sort_param = params[:sort] || 'newest'
@sort = sort_param.humanize unless sort_param.empty? @sort = sort_param.humanize unless sort_param.empty?
@assignees = User.where(id: @project.issues.pluck(:assignee_id))
respond_to do |format| respond_to do |format|
format.html format.html
...@@ -107,8 +110,8 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -107,8 +110,8 @@ class Projects::IssuesController < Projects::ApplicationController
return render_404 unless can?(current_user, :modify_issue, @issue) return render_404 unless can?(current_user, :modify_issue, @issue)
end end
def authorize_admin_issue! def authorize_admin_issues!
return render_404 unless can?(current_user, :admin_issue, @issue) return render_404 unless can?(current_user, :admin_issue, @project)
end end
def module_enabled def module_enabled
......
...@@ -28,6 +28,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -28,6 +28,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
assignee_id, milestone_id = params[:assignee_id], params[:milestone_id] assignee_id, milestone_id = params[:assignee_id], params[:milestone_id]
@assignee = @project.team.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero? @assignee = @project.team.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero?
@milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero? @milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero?
@assignees = User.where(id: @project.merge_requests.pluck(:assignee_id))
end end
def show def show
...@@ -60,7 +61,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -60,7 +61,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@merge_request = MergeRequest.new(params[:merge_request]) @merge_request = MergeRequest.new(params[:merge_request])
@merge_request.source_project = @project unless @merge_request.source_project @merge_request.source_project = @project unless @merge_request.source_project
@merge_request.target_project = @project unless @merge_request.target_project @merge_request.target_project = @project unless @merge_request.target_project
@target_branches = @merge_request.target_project.nil? ? [] : @merge_request.target_project.repository.branch_names
@source_project = @merge_request.source_project @source_project = @merge_request.source_project
@merge_request @merge_request
end end
...@@ -106,10 +106,14 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -106,10 +106,14 @@ class Projects::MergeRequestsController < Projects::ApplicationController
params[:merge_request].delete(:target_project_id) params[:merge_request].delete(:target_project_id)
if @merge_request.update_attributes(params[:merge_request].merge(author_id_of_changes: current_user.id)) if @merge_request.update_attributes(params[:merge_request].merge(author_id_of_changes: current_user.id))
@merge_request.reload_code
@merge_request.mark_as_unchecked
@merge_request.reset_events_cache @merge_request.reset_events_cache
respond_to do |format|
format.js
format.html do
redirect_to [@merge_request.target_project, @merge_request], notice: 'Merge request was successfully updated.' redirect_to [@merge_request.target_project, @merge_request], notice: 'Merge request was successfully updated.'
end
end
else else
render "edit" render "edit"
end end
...@@ -167,7 +171,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -167,7 +171,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
protected protected
def selected_target_project def selected_target_project
((@project.id.to_s == params[:target_project_id]) || @project.forked_project_link.nil?) ? @project : @project.forked_project_link.forked_from_project if @project.id.to_s == params[:target_project_id] || @project.forked_project_link.nil?
@project
else
@project.forked_project_link.forked_from_project
end
end end
def merge_request def merge_request
......
...@@ -11,11 +11,7 @@ class Projects::RawController < Projects::ApplicationController ...@@ -11,11 +11,7 @@ class Projects::RawController < Projects::ApplicationController
@blob = @repository.blob_at(@commit.id, @path) @blob = @repository.blob_at(@commit.id, @path)
if @blob if @blob
type = if @blob.mime_type =~ /html|javascript/ type = get_blob_type
'text/plain; charset=utf-8'
else
@blob.mime_type
end
headers['X-Content-Type-Options'] = 'nosniff' headers['X-Content-Type-Options'] = 'nosniff'
...@@ -29,5 +25,17 @@ class Projects::RawController < Projects::ApplicationController ...@@ -29,5 +25,17 @@ class Projects::RawController < Projects::ApplicationController
not_found! not_found!
end end
end end
private
def get_blob_type
if @blob.mime_type =~ /html|javascript/
'text/plain; charset=utf-8'
elsif @blob.name =~ /(?:msi|exe|rar|r0\d|7z|7zip|zip)$/
'application/octet-stream'
else
@blob.mime_type
end
end
end end
...@@ -34,7 +34,7 @@ class Projects::RefsController < Projects::ApplicationController ...@@ -34,7 +34,7 @@ class Projects::RefsController < Projects::ApplicationController
contents = tree.entries contents = tree.entries
@logs = contents.map do |content| @logs = contents.map do |content|
file = params[:path] ? File.join(params[:path], content.name) : content.name file = params[:path] ? File.join(params[:path], content.name) : content.name
last_commit = @repo.commits(@commit.id, file, 1).last last_commit = @repo.last_commit_for_path(@commit.id, file)
{ {
file_name: content.name, file_name: content.name,
commit: last_commit commit: last_commit
......
...@@ -8,7 +8,7 @@ class Projects::TagsController < Projects::ApplicationController ...@@ -8,7 +8,7 @@ class Projects::TagsController < Projects::ApplicationController
before_filter :authorize_admin_project!, only: [:destroy] before_filter :authorize_admin_project!, only: [:destroy]
def index def index
@tags = Kaminari.paginate_array(@repository.tags).page(params[:page]).per(30) @tags = Kaminari.paginate_array(@repository.tags.reverse).page(params[:page]).per(30)
end end
def create def create
......
class UsersController < ApplicationController class UsersController < ApplicationController
layout 'navless'
skip_before_filter :authenticate_user!, only: [:show]
layout :determine_layout
def show def show
@user = User.find_by!(username: params[:username]) @user = User.find_by_username!(params[:username])
@projects = @user.authorized_projects.where(id: current_user.authorized_projects.pluck(:id)).includes(:namespace) @projects = @user.authorized_projects.includes(:namespace).select {|project| can?(current_user, :read_project, project)}
if !current_user && @projects.empty?
return authenticate_user!
end
@events = @user.recent_events.where(project_id: @projects.map(&:id)).limit(20) @events = @user.recent_events.where(project_id: @projects.map(&:id)).limit(20)
@title = @user.name @title = @user.name
end end
def determine_layout
if current_user
'navless'
else
'public_users'
end
end
end end
...@@ -19,12 +19,15 @@ class UsersGroupsController < ApplicationController ...@@ -19,12 +19,15 @@ class UsersGroupsController < ApplicationController
def destroy def destroy
@users_group = @group.users_groups.find(params[:id]) @users_group = @group.users_groups.find(params[:id])
if can?(current_user, :destroy, @users_group) # May fail if last owner.
@users_group.destroy @users_group.destroy
respond_to do |format| respond_to do |format|
format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' } format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' }
format.js { render nothing: true } format.js { render nothing: true }
end end
else
return render_403
end
end end
protected protected
......
...@@ -49,6 +49,15 @@ module ApplicationHelper ...@@ -49,6 +49,15 @@ module ApplicationHelper
args.any? { |v| v.to_s.downcase == action_name } args.any? { |v| v.to_s.downcase == action_name }
end end
def group_icon(group_path)
group = Group.find_by(path: group_path)
if group && group.avatar.present?
group.avatar.url
else
'/assets/no_group_avatar.png'
end
end
def avatar_icon(user_email = '', size = nil) def avatar_icon(user_email = '', size = nil)
user = User.find_by(email: user_email) user = User.find_by(email: user_email)
if user && user.avatar.present? if user && user.avatar.present?
...@@ -153,15 +162,6 @@ module ApplicationHelper ...@@ -153,15 +162,6 @@ module ApplicationHelper
alias_method :url_to_image, :image_url alias_method :url_to_image, :image_url
def users_select_tag(id, opts = {})
css_class = "ajax-users-select "
css_class << "multiselect " if opts[:multiple]
css_class << (opts[:class] || '')
value = opts[:selected] || ''
hidden_field_tag(id, value, class: css_class)
end
def body_data_page def body_data_page
path = controller.controller_path.split('/') path = controller.controller_path.split('/')
namespace = path.first if path.second namespace = path.first if path.second
...@@ -203,8 +203,14 @@ module ApplicationHelper ...@@ -203,8 +203,14 @@ module ApplicationHelper
def highlight_js(&block) def highlight_js(&block)
string = capture(&block) string = capture(&block)
content_tag :div, class: user_color_scheme_class do content_tag :div, class: "highlighted-data #{user_color_scheme_class}" do
Pygments::Lexer[:js].highlight(string).html_safe content_tag :div, class: 'highlight' do
content_tag :pre do
content_tag :code do
string.html_safe
end
end
end
end end
end end
...@@ -221,4 +227,10 @@ module ApplicationHelper ...@@ -221,4 +227,10 @@ module ApplicationHelper
def render_markup(file_name, file_content) def render_markup(file_name, file_content)
GitHub::Markup.render(file_name, file_content).html_safe GitHub::Markup.render(file_name, file_content).html_safe
end end
def spinner(text = nil)
content_tag :div, class: 'loading hide' do
content_tag(:i, nil, class: 'icon-spinner icon-spin') + text
end
end
end end
...@@ -122,17 +122,18 @@ module CommitsHelper ...@@ -122,17 +122,18 @@ module CommitsHelper
def commit_person_link(commit, options = {}) def commit_person_link(commit, options = {})
source_name = commit.send "#{options[:source]}_name".to_sym source_name = commit.send "#{options[:source]}_name".to_sym
source_email = commit.send "#{options[:source]}_email".to_sym source_email = commit.send "#{options[:source]}_email".to_sym
user = User.find_for_commit(source_email, source_name)
person_name = user.nil? ? source_name : user.name
person_email = user.nil? ? source_email : user.email
text = if options[:avatar] text = if options[:avatar]
avatar = image_tag(avatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "") avatar = image_tag(avatar_icon(person_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>} %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{person_name}</span>}
else else
source_name person_name
end end
# Prefer email match over name match
user = User.where(email: source_email).first
user ||= User.where(name: source_name).first
options = { options = {
class: "commit-#{options[:source]}-link has_tooltip", class: "commit-#{options[:source]}-link has_tooltip",
data: { :'original-title' => sanitize(source_email) } data: { :'original-title' => sanitize(source_email) }
......
...@@ -28,14 +28,16 @@ module GitlabMarkdownHelper ...@@ -28,14 +28,16 @@ module GitlabMarkdownHelper
link_to(gfm_body.html_safe, url, html_options) link_to(gfm_body.html_safe, url, html_options)
end end
def markdown(text) def markdown(text, options={})
unless @markdown unless (@markdown and options == @options)
gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self, @options = options
gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self, {
# see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch- # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch-
filter_html: true, filter_html: true,
with_toc_data: true, with_toc_data: true,
hard_wrap: true, hard_wrap: true,
safe_links_only: true) safe_links_only: true
}.merge(options))
@markdown = Redcarpet::Markdown.new(gitlab_renderer, @markdown = Redcarpet::Markdown.new(gitlab_renderer,
# see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
no_intra_emphasis: true, no_intra_emphasis: true,
...@@ -47,7 +49,6 @@ module GitlabMarkdownHelper ...@@ -47,7 +49,6 @@ module GitlabMarkdownHelper
space_after_headers: true, space_after_headers: true,
superscript: true) superscript: true)
end end
@markdown.render(text).html_safe @markdown.render(text).html_safe
end end
...@@ -166,18 +167,27 @@ module GitlabMarkdownHelper ...@@ -166,18 +167,27 @@ module GitlabMarkdownHelper
def file_exists?(path) def file_exists?(path)
return false if path.nil? || path.empty? return false if path.nil? || path.empty?
File.exists?(path_on_fs(path)) return @repository.blob_at(current_sha, path).present? || @repository.tree(current_sha, path).entries.any?
end end
# Check if the path is pointing to a directory(tree) or a file(blob) # Check if the path is pointing to a directory(tree) or a file(blob)
# eg. doc/api is directory and doc/README.md is file # eg. doc/api is directory and doc/README.md is file
def local_path(path) def local_path(path)
File.directory?(path_on_fs(path)) ? "tree" : "blob" return "tree" if @repository.tree(current_sha, path).entries.any?
return "raw" if @repository.blob_at(current_sha, path).image?
return "blob"
end
def current_ref
@commit.nil? ? "master" : @commit.id
end end
# Path to the file in the satellites repository on the filesystem def current_sha
def path_on_fs(path) if @commit
[@path_to_satellite, path].join("/") @commit.id
else
@repository.head_commit.sha
end
end end
# We will assume that if no ref exists we can point to master # We will assume that if no ref exists we can point to master
......
module GroupsHelper module GroupsHelper
def remove_user_from_group_message(group, user) def remove_user_from_group_message(group, user)
"You are going to remove #{user.name} from #{group.name} Group. Are you sure?" "Are you sure you want to remove \"#{user.name}\" from \"#{group.name}\"?"
end
def leave_group_message(group)
"Are you sure you want to leave \"#{group}\" group?"
end end
def group_head_title def group_head_title
......
...@@ -70,11 +70,11 @@ module IssuesHelper ...@@ -70,11 +70,11 @@ module IssuesHelper
end end
def bulk_update_milestone_options def bulk_update_milestone_options
options_for_select(["None (backlog)", nil]) + options_from_collection_for_select(project_active_milestones, "id", "title", params[:milestone_id]) options_for_select(["None (backlog)"]) + options_from_collection_for_select(project_active_milestones, "id", "title", params[:milestone_id])
end end
def bulk_update_assignee_options def bulk_update_assignee_options
options_for_select(["None (unassigned)", nil]) + options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id]) options_for_select(["None (unassigned)"]) + options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id])
end end
def assignee_options object def assignee_options object
...@@ -84,4 +84,12 @@ module IssuesHelper ...@@ -84,4 +84,12 @@ module IssuesHelper
def milestone_options object def milestone_options object
options_from_collection_for_select(@project.milestones.active, 'id', 'title', object.milestone_id) options_from_collection_for_select(@project.milestones.active, 'id', 'title', object.milestone_id)
end end
def issue_alert_class(issue)
if issue.closed?
'alert-danger'
else
'alert-success'
end
end
end end
...@@ -41,4 +41,14 @@ module MergeRequestsHelper ...@@ -41,4 +41,14 @@ module MergeRequestsHelper
"Branches: #{@merge_request.source_branch} #{separator} #{@merge_request.target_branch}" "Branches: #{@merge_request.source_branch} #{separator} #{@merge_request.target_branch}"
end end
end end
def merge_request_alert_class(merge_request)
if merge_request.merged?
'alert-info'
elsif merge_request.closed?
'alert-danger'
else
'alert-success'
end
end
end end
...@@ -17,7 +17,7 @@ module NotesHelper ...@@ -17,7 +17,7 @@ module NotesHelper
def link_to_merge_request_diff_line_note(note) def link_to_merge_request_diff_line_note(note)
if note.for_merge_request_diff_line? and note.diff if note.for_merge_request_diff_line? and note.diff
link_to "#{note.diff_file_name}:L#{note.diff_new_line}", diffs_project_merge_request_path(note.project, note.noteable_id, anchor: note.line_code) link_to "#{note.diff_file_name}:L#{note.diff_new_line}", diffs_project_merge_request_path(note.project, note.noteable, anchor: note.line_code)
end end
end end
......
module NotificationsHelper module NotificationsHelper
def notification_icon(notification) def notification_icon(notification)
if notification.disabled? if notification.disabled?
content_tag :i, nil, class: 'icon-circle cred' content_tag :i, nil, class: 'icon-volume-off cred'
elsif notification.participating? elsif notification.participating?
content_tag :i, nil, class: 'icon-circle cblue' content_tag :i, nil, class: 'icon-volume-down cblue'
elsif notification.watch? elsif notification.watch?
content_tag :i, nil, class: 'icon-circle cgreen' content_tag :i, nil, class: 'icon-volume-up cgreen'
else else
content_tag :i, nil, class: 'icon-circle-blank cblue' content_tag :i, nil, class: 'icon-circle-blank cblue'
end end
......
...@@ -64,6 +64,31 @@ module ProjectsHelper ...@@ -64,6 +64,31 @@ module ProjectsHelper
project_nav_tabs.include? name project_nav_tabs.include? name
end end
def selected_label?(label_name)
params[:label_name].to_s.split(',').include?(label_name)
end
def labels_filter_path(label_name)
label_name =
if selected_label?(label_name)
params[:label_name].split(',').reject { |l| l == label_name }.join(',')
elsif params[:label_name].present?
"#{params[:label_name]},#{label_name}"
else
label_name
end
project_filter_path(label_name: label_name)
end
def label_filter_class(label_name)
if selected_label?(label_name)
'label-filter-item active'
else
'label-filter-item light'
end
end
def project_filter_path(options={}) def project_filter_path(options={})
exist_opts = { exist_opts = {
state: params[:state], state: params[:state],
......
module SelectsHelper
def users_select_tag(id, opts = {})
css_class = "ajax-users-select "
css_class << "multiselect " if opts[:multiple]
css_class << (opts[:class] || '')
value = opts[:selected] || ''
hidden_field_tag(id, value, class: css_class)
end
def project_users_select_tag(id, opts = {})
css_class = "ajax-project-users-select "
css_class << "multiselect " if opts[:multiple]
css_class << (opts[:class] || '')
value = opts[:selected] || ''
placeholder = opts[:placeholder] || 'Select user'
hidden_field_tag(id, value, class: css_class, 'data-placeholder' => placeholder)
end
end
module SubmoduleHelper
include Gitlab::ShellAdapter
# links to files listing for submodule if submodule is a project on this server
def submodule_links(submodule_item)
url = @repository.submodule_url_for(@ref, submodule_item.path)
return url, nil unless url =~ /([^\/:]+\/[^\/]+\.git)\Z/
project = $1
project.chomp!('.git')
if self_url?(url, project)
return project_path(project), project_tree_path(project, submodule_item.id)
elsif github_dot_com_url?(url)
standard_links('github.com', project, submodule_item.id)
elsif gitlab_dot_com_url?(url)
standard_links('gitlab.com', project, submodule_item.id)
else
return url, nil
end
end
protected
def github_dot_com_url?(url)
url =~ /github\.com[\/:][^\/]+\/[^\/]+\Z/
end
def gitlab_dot_com_url?(url)
url =~ /gitlab\.com[\/:][^\/]+\/[^\/]+\Z/
end
def self_url?(url, project)
return true if url == [ Gitlab.config.gitlab.url, '/', project, '.git' ].join('')
url == gitlab_shell.url_to_repo(project)
end
def standard_links(host, project, commit)
base = [ 'https://', host, '/', project ].join('')
return base, [ base, '/tree/', commit ].join('')
end
end
...@@ -6,6 +6,12 @@ module Emails ...@@ -6,6 +6,12 @@ module Emails
mail(to: @user.email, subject: subject("Account was created for you")) mail(to: @user.email, subject: subject("Account was created for you"))
end end
def new_email_email(email_id)
@email = Email.find(email_id)
@user = @email.user
mail(to: @user.email, subject: subject("Email was added to your account"))
end
def new_ssh_key_email(key_id) def new_ssh_key_email(key_id)
@key = Key.find(key_id) @key = Key.find(key_id)
@user = @key.user @user = @key.user
......
...@@ -17,6 +17,7 @@ module Emails ...@@ -17,6 +17,7 @@ module Emails
def repository_push_email(project_id, recipient, author_id, branch, compare) def repository_push_email(project_id, recipient, author_id, branch, compare)
@project = Project.find(project_id) @project = Project.find(project_id)
@author = User.find(author_id) @author = User.find(author_id)
@compare = compare
@commits = Commit.decorate(compare.commits) @commits = Commit.decorate(compare.commits)
@diffs = compare.diffs @diffs = compare.diffs
@branch = branch @branch = branch
......
...@@ -14,6 +14,7 @@ class Ability ...@@ -14,6 +14,7 @@ class Ability
when "MergeRequest" then merge_request_abilities(user, subject) when "MergeRequest" then merge_request_abilities(user, subject)
when "Group" then group_abilities(user, subject) when "Group" then group_abilities(user, subject)
when "Namespace" then namespace_abilities(user, subject) when "Namespace" then namespace_abilities(user, subject)
when "UsersGroup" then users_group_abilities(user, subject)
else [] else []
end.concat(global_abilities(user)) end.concat(global_abilities(user))
end end
...@@ -126,6 +127,7 @@ class Ability ...@@ -126,6 +127,7 @@ class Ability
:write_merge_request, :write_merge_request,
:write_wiki, :write_wiki,
:modify_issue, :modify_issue,
:admin_issue,
:push_code :push_code
] ]
end end
...@@ -218,5 +220,19 @@ class Ability ...@@ -218,5 +220,19 @@ class Ability
end end
end end
end end
def users_group_abilities(user, subject)
rules = []
target_user = subject.user
group = subject.group
can_manage = group_abilities(user, group).include?(:manage_group)
if can_manage && (user != target_user)
rules << :modify
end
if !group.last_owner?(user) && (can_manage || (user == target_user))
rules << :destroy
end
rules
end
end end
end end
...@@ -16,16 +16,17 @@ class Commit ...@@ -16,16 +16,17 @@ class Commit
DIFF_HARD_LIMIT_FILES = 500 DIFF_HARD_LIMIT_FILES = 500
DIFF_HARD_LIMIT_LINES = 10000 DIFF_HARD_LIMIT_LINES = 10000
def self.decorate(commits) class << self
def decorate(commits)
commits.map { |c| self.new(c) } commits.map { |c| self.new(c) }
end end
# Calculate number of lines to render for diffs # Calculate number of lines to render for diffs
def self.diff_line_count(diffs) def diff_line_count(diffs)
diffs.reduce(0){|sum, d| sum + d.diff.lines.count} diffs.reduce(0){|sum, d| sum + d.diff.lines.count}
end end
def self.diff_suppress?(diffs, line_count = nil) def diff_suppress?(diffs, line_count = nil)
# optimize - check file count first # optimize - check file count first
return true if diffs.size > DIFF_SAFE_FILES return true if diffs.size > DIFF_SAFE_FILES
...@@ -33,13 +34,14 @@ class Commit ...@@ -33,13 +34,14 @@ class Commit
line_count > DIFF_SAFE_LINES line_count > DIFF_SAFE_LINES
end end
def self.diff_force_suppress?(diffs, line_count = nil) def diff_force_suppress?(diffs, line_count = nil)
# optimize - check file count first # optimize - check file count first
return true if diffs.size > DIFF_HARD_LIMIT_FILES return true if diffs.size > DIFF_HARD_LIMIT_FILES
line_count ||= Commit::diff_line_count(diffs) line_count ||= Commit::diff_line_count(diffs)
line_count > DIFF_HARD_LIMIT_LINES line_count > DIFF_HARD_LIMIT_LINES
end end
end
attr_accessor :raw attr_accessor :raw
......
...@@ -48,13 +48,13 @@ module Issuable ...@@ -48,13 +48,13 @@ module Issuable
def sort(method) def sort(method)
case method.to_s case method.to_s
when 'newest' then reorder('created_at DESC') when 'newest' then reorder("#{table_name}.created_at DESC")
when 'oldest' then reorder('created_at ASC') when 'oldest' then reorder("#{table_name}.created_at ASC")
when 'recently_updated' then reorder('updated_at DESC') when 'recently_updated' then reorder("#{table_name}.updated_at DESC")
when 'last_updated' then reorder('updated_at ASC') when 'last_updated' then reorder("#{table_name}.updated_at ASC")
when 'milestone_due_soon' then joins(:milestone).reorder("milestones.due_date ASC") when 'milestone_due_soon' then joins(:milestone).reorder("milestones.due_date ASC")
when 'milestone_due_later' then joins(:milestone).reorder("milestones.due_date DESC") when 'milestone_due_later' then joins(:milestone).reorder("milestones.due_date DESC")
else reorder('created_at DESC') else reorder("#{table_name}.created_at DESC")
end end
end end
end end
......
# == Schema Information
#
# Table name: emails
#
# id :integer not null, primary key
# user_id :integer not null
# email :string not null
# created_at :datetime not null
class Email < ActiveRecord::Base
attr_accessible :email, :user_id
#
# Relations
#
belongs_to :user
#
# Validations
#
validates :user_id, presence: true
validates :email, presence: true, email: { strict_mode: true }, uniqueness: true
validate :unique_email, if: ->(email) { email.email_changed? }
before_validation :cleanup_email
def cleanup_email
self.email = self.email.downcase.strip
end
def unique_email
self.errors.add(:email, 'has already been taken') if User.exists?(email: self.email)
end
end
\ No newline at end of file
class GollumWiki class GollumWiki
include Gitlab::ShellAdapter
MARKUPS = { MARKUPS = {
"Markdown" => :markdown, "Markdown" => :markdown,
...@@ -113,10 +114,6 @@ class GollumWiki ...@@ -113,10 +114,6 @@ class GollumWiki
"#{@user.username} #{action} page: #{title}" "#{@user.username} #{action} page: #{title}"
end end
def gitlab_shell
@gitlab_shell ||= Gitlab::Shell.new
end
def path_to_repo def path_to_repo
@path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git") @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git")
end end
......
...@@ -12,10 +12,20 @@ ...@@ -12,10 +12,20 @@
# description :string(255) default(""), not null # description :string(255) default(""), not null
# #
require 'carrierwave/orm/activerecord'
require 'file_size_validator'
class Group < Namespace class Group < Namespace
has_many :users_groups, dependent: :destroy has_many :users_groups, dependent: :destroy
has_many :users, through: :users_groups has_many :users, through: :users_groups
attr_accessible :avatar
validate :avatar_type, if: ->(user) { user.avatar_changed? }
validates :avatar, file_size: { maximum: 100.kilobytes.to_i }
mount_uploader :avatar, AttachmentUploader
def human_name def human_name
name name
end end
...@@ -50,4 +60,10 @@ class Group < Namespace ...@@ -50,4 +60,10 @@ class Group < Namespace
def members def members
users_groups users_groups
end end
def avatar_type
unless self.avatar.image?
self.errors.add :avatar, "only images allowed"
end
end
end end
...@@ -32,7 +32,9 @@ class MergeRequest < ActiveRecord::Base ...@@ -32,7 +32,9 @@ class MergeRequest < ActiveRecord::Base
belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project" belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project"
has_one :merge_request_diff, dependent: :destroy has_one :merge_request_diff, dependent: :destroy
after_create :create_merge_request_diff after_create :create_merge_request_diff
after_update :update_merge_request_diff
delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil
...@@ -125,6 +127,13 @@ class MergeRequest < ActiveRecord::Base ...@@ -125,6 +127,13 @@ class MergeRequest < ActiveRecord::Base
end end
end end
def update_merge_request_diff
if source_branch_changed? || target_branch_changed?
reload_code
mark_as_unchecked
end
end
def reload_code def reload_code
if merge_request_diff && opened? if merge_request_diff && opened?
merge_request_diff.reload_content merge_request_diff.reload_content
...@@ -219,6 +228,14 @@ class MergeRequest < ActiveRecord::Base ...@@ -219,6 +228,14 @@ class MergeRequest < ActiveRecord::Base
end end
end end
def source_project_namespace
if source_project && source_project.namespace
source_project.namespace.path
else
"(removed)"
end
end
def source_branch_exists? def source_branch_exists?
return false unless self.source_project return false unless self.source_project
...@@ -253,4 +270,24 @@ class MergeRequest < ActiveRecord::Base ...@@ -253,4 +270,24 @@ class MergeRequest < ActiveRecord::Base
message << description.to_s message << description.to_s
message message
end end
# Return array of possible target branches
# dependes on target project of MR
def target_branches
if target_project.nil?
[]
else
target_project.repository.branch_names
end
end
# Return array of possible source branches
# dependes on source project of MR
def source_branches
if source_project.nil?
[]
else
source_project.repository.branch_names
end
end
end end
...@@ -148,13 +148,11 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -148,13 +148,11 @@ class MergeRequestDiff < ActiveRecord::Base
Gitlab::Git::Diff.between(repository, source_branch, target_branch) Gitlab::Git::Diff.between(repository, source_branch, target_branch)
end end
if diffs == broken_diffs
self.state = :timeout
diffs = []
end
diffs ||= [] diffs ||= []
diffs diffs
rescue Gitlab::Git::Diff::TimeoutError => ex
self.state = :timeout
diffs = []
end end
def repository def repository
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
# updated_at :datetime not null # updated_at :datetime not null
# type :string(255) # type :string(255)
# description :string(255) default(""), not null # description :string(255) default(""), not null
# avatar :string(255)
# #
class Namespace < ActiveRecord::Base class Namespace < ActiveRecord::Base
...@@ -26,7 +27,7 @@ class Namespace < ActiveRecord::Base ...@@ -26,7 +27,7 @@ class Namespace < ActiveRecord::Base
format: { with: Gitlab::Regex.name_regex, format: { with: Gitlab::Regex.name_regex,
message: "only letters, digits, spaces & '_' '-' '.' allowed." } message: "only letters, digits, spaces & '_' '-' '.' allowed." }
validates :description, length: { within: 0..255 } validates :description, length: { within: 0..255 }
validates :path, uniqueness: true, presence: true, length: { within: 1..255 }, validates :path, uniqueness: { case_sensitive: false }, presence: true, length: { within: 1..255 },
exclusion: { in: Gitlab::Blacklist.path }, exclusion: { in: Gitlab::Blacklist.path },
format: { with: Gitlab::Regex.path_regex, format: { with: Gitlab::Regex.path_regex,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
......
...@@ -72,14 +72,20 @@ class Note < ActiveRecord::Base ...@@ -72,14 +72,20 @@ class Note < ActiveRecord::Base
# +noteable+ was referenced from +mentioner+, by including GFM in either +mentioner+'s description or an associated Note. # +noteable+ was referenced from +mentioner+, by including GFM in either +mentioner+'s description or an associated Note.
# Create a system Note associated with +noteable+ with a GFM back-reference to +mentioner+. # Create a system Note associated with +noteable+ with a GFM back-reference to +mentioner+.
def create_cross_reference_note(noteable, mentioner, author, project) def create_cross_reference_note(noteable, mentioner, author, project)
create({ note_options = {
noteable: noteable,
commit_id: (noteable.sha if noteable.respond_to? :sha),
project: project, project: project,
author: author, author: author,
note: "_mentioned in #{mentioner.gfm_reference}_", note: "_mentioned in #{mentioner.gfm_reference}_",
system: true system: true
}, without_protection: true) }
if noteable.kind_of?(Commit)
note_options.merge!(noteable_type: 'Commit', commit_id: noteable.id)
else
note_options.merge!(noteable: noteable)
end
create(note_options, without_protection: true)
end end
def create_assignee_change_note(noteable, project, author, assignee) def create_assignee_change_note(noteable, project, author, assignee)
......
...@@ -9,13 +9,24 @@ class Notification ...@@ -9,13 +9,24 @@ class Notification
attr_accessor :target attr_accessor :target
def self.notification_levels class << self
def notification_levels
[N_DISABLED, N_PARTICIPATING, N_WATCH] [N_DISABLED, N_PARTICIPATING, N_WATCH]
end end
def self.project_notification_levels def options_with_labels
{
disabled: N_DISABLED,
participating: N_PARTICIPATING,
watch: N_WATCH,
global: N_GLOBAL
}
end
def project_notification_levels
[N_DISABLED, N_PARTICIPATING, N_WATCH, N_GLOBAL] [N_DISABLED, N_PARTICIPATING, N_WATCH, N_GLOBAL]
end end
end
def initialize(target) def initialize(target)
@target = target @target = target
...@@ -36,4 +47,8 @@ class Notification ...@@ -36,4 +47,8 @@ class Notification
def global? def global?
target.notification_level == N_GLOBAL target.notification_level == N_GLOBAL
end end
def level
target.notification_level
end
end end
...@@ -40,7 +40,7 @@ class HipchatService < Service ...@@ -40,7 +40,7 @@ class HipchatService < Service
end end
def execute(push_data) def execute(push_data)
gate[room].send('Gitlab', create_message(push_data)) gate[room].send('GitLab', create_message(push_data))
end end
private private
......
...@@ -57,7 +57,7 @@ class Repository ...@@ -57,7 +57,7 @@ class Repository
def recent_branches(limit = 20) def recent_branches(limit = 20)
branches.sort do |a, b| branches.sort do |a, b|
b.commit.committed_date <=> a.commit.committed_date commit(b.target).committed_date <=> commit(a.target).committed_date
end[0..limit] end[0..limit]
end end
...@@ -163,7 +163,49 @@ class Repository ...@@ -163,7 +163,49 @@ class Repository
def readme def readme
Rails.cache.fetch(cache_key(:readme)) do Rails.cache.fetch(cache_key(:readme)) do
Tree.new(self, self.root_ref).readme tree(:head).readme
end end
end end
def head_commit
commit(self.root_ref)
end
def tree(sha = :head, path = nil)
if sha == :head
sha = head_commit.sha
end
Tree.new(self, sha, path)
end
def blob_at_branch(branch_name, path)
last_commit = commit(branch_name)
if last_commit
blob_at(last_commit.sha, path)
else
nil
end
end
# Returns url for submodule
#
# Ex.
# @repository.submodule_url_for('master', 'rack')
# # => git@localhost:rack.git
#
def submodule_url_for(ref, path)
if submodules.any?
submodule = submodules(ref)[path]
if submodule
submodule['url']
end
end
end
def last_commit_for_path(sha, path)
commits(sha, path, 1).last
end
end end
...@@ -23,4 +23,8 @@ class Tree ...@@ -23,4 +23,8 @@ class Tree
def submodules def submodules
@entries.select(&:submodule?) @entries.select(&:submodule?)
end end
def sorted_entries
trees + blobs + submodules
end
end end
...@@ -78,6 +78,7 @@ class User < ActiveRecord::Base ...@@ -78,6 +78,7 @@ class User < ActiveRecord::Base
# Profile # Profile
has_many :keys, dependent: :destroy has_many :keys, dependent: :destroy
has_many :emails, dependent: :destroy
# Groups # Groups
has_many :users_groups, dependent: :destroy has_many :users_groups, dependent: :destroy
...@@ -108,7 +109,7 @@ class User < ActiveRecord::Base ...@@ -108,7 +109,7 @@ class User < ActiveRecord::Base
validates :bio, length: { maximum: 255 }, allow_blank: true validates :bio, length: { maximum: 255 }, allow_blank: true
validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider} validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider}
validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0} validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0}
validates :username, presence: true, uniqueness: true, validates :username, presence: true, uniqueness: { case_sensitive: false },
exclusion: { in: Gitlab::Blacklist.path }, exclusion: { in: Gitlab::Blacklist.path },
format: { with: Gitlab::Regex.username_regex, format: { with: Gitlab::Regex.username_regex,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
...@@ -116,6 +117,7 @@ class User < ActiveRecord::Base ...@@ -116,6 +117,7 @@ class User < ActiveRecord::Base
validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true
validate :namespace_uniq, if: ->(user) { user.username_changed? } validate :namespace_uniq, if: ->(user) { user.username_changed? }
validate :avatar_type, if: ->(user) { user.avatar_changed? } validate :avatar_type, if: ->(user) { user.avatar_changed? }
validate :unique_email, if: ->(user) { user.email_changed? }
validates :avatar, file_size: { maximum: 100.kilobytes.to_i } validates :avatar, file_size: { maximum: 100.kilobytes.to_i }
before_validation :generate_password, on: :create before_validation :generate_password, on: :create
...@@ -184,6 +186,13 @@ class User < ActiveRecord::Base ...@@ -184,6 +186,13 @@ class User < ActiveRecord::Base
end end
end end
def find_for_commit(email, name)
# Prefer email match over name match
User.where(email: email).first ||
User.joins(:emails).where(emails: { email: email }).first ||
User.where(name: name).first
end
def filter filter_name def filter filter_name
case filter_name case filter_name
when "admins"; self.admins when "admins"; self.admins
...@@ -250,6 +259,10 @@ class User < ActiveRecord::Base ...@@ -250,6 +259,10 @@ class User < ActiveRecord::Base
end end
end end
def unique_email
self.errors.add(:email, 'has already been taken') if Email.exists?(email: self.email)
end
# Groups user has access to # Groups user has access to
def authorized_groups def authorized_groups
@authorized_groups ||= begin @authorized_groups ||= begin
...@@ -435,4 +448,8 @@ class User < ActiveRecord::Base ...@@ -435,4 +448,8 @@ class User < ActiveRecord::Base
def short_website_url def short_website_url
website_url.gsub(/https?:\/\//, '') website_url.gsub(/https?:\/\//, '')
end end
def all_ssh_keys
keys.map(&:key)
end
end end
class EmailObserver < BaseObserver
def after_create(email)
notification.new_email(email)
end
end
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment