Commit 403298317f0035be27a812dae9c5090a51c11faa

Authored by dosire
2 parents 77dc5de9 bbd92f55

Merge branch 'master' into styleguide

Conflicts:
	CONTRIBUTING.md
Showing 507 changed files with 5713 additions and 165556 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 507 files displayed.

CHANGELOG
1 1 v 6.6.0
  2 + - Retrieving user ssh keys publically(github style): http://__HOST__/__USERNAME__.keys
2 3 - Permissions: Developer now can manage issue tracker (modify any issue)
  4 + - Improve Code Compare page performance
  5 + - Group avatar
  6 + - Pygments.rb replaced with highlight.js
  7 + - Improve Merge request diff store logic
  8 + - Improve render performnace for MR show page
  9 + - Fixed Assembla hardcoded project name
  10 + - Jira integration documentation
  11 + - Refactored app/services
  12 + - Remove snippet expiration
  13 + - Mobile UI improvements (Drew Blessing)
  14 + - Fix block/remove UI for admin::users#show page
  15 + - Show users' group membership on users' activity page
  16 + - User pages are visible without login if user is authorized to a public project
  17 + - Markdown rendered headers have id derived from their name and link to their id
  18 + - Improve application to work faster with large groups (100+ members)
  19 + - Multiple emails per user
  20 + - Show last commit for file when view file source
  21 + - Restyle Issue#show page and MR#show page
  22 + - Ability to filter by multiple labels for Issues page
  23 + - Rails version to 4.0.3
3 24  
4 25 v 6.5.1
5 26 - Fix branch selectbox when create merge request from fork
... ... @@ -33,7 +54,7 @@ v6.4.3
33 54 v6.4.2
34 55 - Fixed wrong behaviour of script/upgrade.rb
35 56  
36   -v6.4.1
  57 +v6.4.1
37 58 - Fixed bug with repository rename
38 59 - Fixed bug with project transfer
39 60  
... ...
Gemfile
... ... @@ -29,22 +29,19 @@ gem 'omniauth-github'
29 29  
30 30 # Extracting information from a git repository
31 31 # Provide access to Gitlab::Git library
32   -gem "gitlab_git", "~> 4.0.0"
  32 +gem "gitlab_git", '~> 5.4.0'
33 33  
34 34 # Ruby/Rack Git Smart-HTTP Server Handler
35 35 gem 'gitlab-grack', '~> 2.0.0.pre', require: 'grack'
36 36  
37 37 # LDAP Auth
38   -gem 'gitlab_omniauth-ldap', '1.0.3', require: "omniauth-ldap"
39   -
40   -# Syntax highlighter
41   -gem "gitlab-pygments.rb", '~> 0.5.4', require: 'pygments.rb'
  38 +gem 'gitlab_omniauth-ldap', '1.0.4', require: "omniauth-ldap"
42 39  
43 40 # Git Wiki
44   -gem "gitlab-gollum-lib", "~> 1.0.2", require: 'gollum-lib'
  41 +gem "gitlab-gollum-lib", "~> 1.1.0", require: 'gollum-lib'
45 42  
46 43 # Language detection
47   -gem "gitlab-linguist", "~> 2.9.6", require: "linguist"
  44 +gem "gitlab-linguist", "~> 3.0.0", require: "linguist"
48 45  
49 46 # API
50 47 gem "grape", "~> 0.6.1"
... ... @@ -139,6 +136,9 @@ gem "sanitize"
139 136 # Protect against bruteforcing
140 137 gem "rack-attack"
141 138  
  139 +# Ace editor
  140 +gem 'ace-rails-ap'
  141 +
142 142 gem "sass-rails"
143 143 gem "coffee-rails"
144 144 gem "uglifier"
... ... @@ -208,6 +208,10 @@ group :development, :test do
208 208  
209 209 gem 'spork', '~> 1.0rc'
210 210 gem 'jasmine', '2.0.0.rc5'
  211 +
  212 + gem "spring", '1.1.1'
  213 + gem "spring-commands-rspec", '1.0.1'
  214 + gem "spring-commands-spinach", '1.0.0'
211 215 end
212 216  
213 217 group :test do
... ...
Gemfile.lock
... ... @@ -8,11 +8,12 @@ GIT
8 8 GEM
9 9 remote: https://rubygems.org/
10 10 specs:
11   - actionmailer (4.0.2)
12   - actionpack (= 4.0.2)
  11 + ace-rails-ap (2.0.1)
  12 + actionmailer (4.0.3)
  13 + actionpack (= 4.0.3)
13 14 mail (~> 2.5.4)
14   - actionpack (4.0.2)
15   - activesupport (= 4.0.2)
  15 + actionpack (4.0.3)
  16 + activesupport (= 4.0.3)
16 17 builder (~> 3.1.0)
17 18 erubis (~> 2.7.0)
18 19 rack (~> 1.5.2)
... ... @@ -21,16 +22,16 @@ GEM
21 22 actionpack (>= 4.0.0, < 5.0)
22 23 actionpack-page_caching (1.0.2)
23 24 actionpack (>= 4.0.0, < 5)
24   - activemodel (4.0.2)
25   - activesupport (= 4.0.2)
  25 + activemodel (4.0.3)
  26 + activesupport (= 4.0.3)
26 27 builder (~> 3.1.0)
27   - activerecord (4.0.2)
28   - activemodel (= 4.0.2)
  28 + activerecord (4.0.3)
  29 + activemodel (= 4.0.3)
29 30 activerecord-deprecated_finders (~> 1.0.2)
30   - activesupport (= 4.0.2)
  31 + activesupport (= 4.0.3)
31 32 arel (~> 4.0.0)
32 33 activerecord-deprecated_finders (1.0.3)
33   - activesupport (4.0.2)
  34 + activesupport (4.0.3)
34 35 i18n (~> 0.6, >= 0.6.4)
35 36 minitest (~> 4.2)
36 37 multi_json (~> 1.3)
... ... @@ -42,7 +43,7 @@ GEM
42 43 annotate (2.6.0)
43 44 activerecord (>= 2.3.0)
44 45 rake (>= 0.8.7)
45   - arel (4.0.1)
  46 + arel (4.0.2)
46 47 asciidoctor (0.1.4)
47 48 atomic (1.1.14)
48 49 awesome_print (1.2.0)
... ... @@ -158,36 +159,32 @@ GEM
158 159 gitlab-flowdock-git-hook (0.4.2.2)
159 160 gitlab-grit (>= 2.4.1)
160 161 multi_json
161   - gitlab-gollum-lib (1.0.2)
  162 + gitlab-gollum-lib (1.1.0)
162 163 github-markdown (~> 0.5.3)
163 164 github-markup (>= 0.7.5, < 1.0.0)
164 165 gitlab-grit (~> 2.6.1)
165   - gitlab-pygments.rb (~> 0.5.4)
166 166 nokogiri (~> 1.5.9)
167 167 sanitize (~> 2.0.3)
168 168 stringex (~> 1.5.1)
169 169 gitlab-grack (2.0.0.pre)
170 170 rack (~> 1.5.1)
171   - gitlab-grit (2.6.3)
  171 + gitlab-grit (2.6.4)
172 172 charlock_holmes (~> 0.6.9)
173 173 diff-lcs (~> 1.1)
174 174 mime-types (~> 1.15)
175 175 posix-spawn (~> 0.3.6)
176   - gitlab-linguist (2.9.6)
  176 + gitlab-linguist (3.0.0)
177 177 charlock_holmes (~> 0.6.6)
178 178 escape_utils (~> 0.2.4)
179   - gitlab-pygments.rb (~> 0.5.4)
180 179 mime-types (~> 1.19)
181   - gitlab-pygments.rb (0.5.4)
182   - posix-spawn (~> 0.3.6)
183   - yajl-ruby (~> 1.1.0)
184   - gitlab_git (4.0.0)
  180 + gitlab_git (5.4.0)
185 181 activesupport (~> 4.0.0)
  182 + charlock_holmes (~> 0.6.9)
186 183 gitlab-grit (~> 2.6.1)
187   - gitlab-linguist (~> 2.9.5)
188   - gitlab-pygments.rb (~> 0.5.4)
  184 + gitlab-linguist (~> 3.0.0)
  185 + rugged (~> 0.19.0)
189 186 gitlab_meta (6.0)
190   - gitlab_omniauth-ldap (1.0.3)
  187 + gitlab_omniauth-ldap (1.0.4)
191 188 net-ldap (~> 0.3.1)
192 189 omniauth (~> 1.0)
193 190 pyu-ruby-sasl (~> 0.0.3.1)
... ... @@ -323,8 +320,8 @@ GEM
323 320 cliver (~> 0.2.1)
324 321 multi_json (~> 1.0)
325 322 websocket-driver (>= 0.2.0)
326   - polyglot (0.3.3)
327   - posix-spawn (0.3.6)
  323 + polyglot (0.3.4)
  324 + posix-spawn (0.3.8)
328 325 protected_attributes (1.0.5)
329 326 activemodel (>= 4.0.1, < 5.0)
330 327 pry (0.9.12.4)
... ... @@ -349,13 +346,13 @@ GEM
349 346 rack
350 347 rack-test (0.6.2)
351 348 rack (>= 1.0)
352   - rails (4.0.2)
353   - actionmailer (= 4.0.2)
354   - actionpack (= 4.0.2)
355   - activerecord (= 4.0.2)
356   - activesupport (= 4.0.2)
  349 + rails (4.0.3)
  350 + actionmailer (= 4.0.3)
  351 + actionpack (= 4.0.3)
  352 + activerecord (= 4.0.3)
  353 + activesupport (= 4.0.3)
357 354 bundler (>= 1.3.0, < 2.0)
358   - railties (= 4.0.2)
  355 + railties (= 4.0.3)
359 356 sprockets-rails (~> 2.0.0)
360 357 rails-observers (0.1.2)
361 358 activemodel (~> 4.0)
... ... @@ -368,13 +365,13 @@ GEM
368 365 i18n
369 366 require_all
370 367 ruby-progressbar
371   - railties (4.0.2)
372   - actionpack (= 4.0.2)
373   - activesupport (= 4.0.2)
  368 + railties (4.0.3)
  369 + actionpack (= 4.0.3)
  370 + activesupport (= 4.0.3)
374 371 rake (>= 0.8.7)
375 372 thor (>= 0.18.1, < 2.0)
376 373 raindrops (0.12.0)
377   - rake (10.1.0)
  374 + rake (10.1.1)
378 375 raphael-rails (2.1.2)
379 376 rb-fsevent (0.9.3)
380 377 rb-inotify (0.9.2)
... ... @@ -423,6 +420,7 @@ GEM
423 420 ruby-hmac (0.4.0)
424 421 ruby-progressbar (1.2.0)
425 422 rubyntlm (0.1.1)
  423 + rugged (0.19.0)
426 424 safe_yaml (0.9.7)
427 425 sanitize (2.0.6)
428 426 nokogiri (>= 1.4.4)
... ... @@ -472,6 +470,11 @@ GEM
472 470 railties (>= 3)
473 471 spinach (>= 0.4)
474 472 spork (1.0.0rc4)
  473 + spring (1.1.1)
  474 + spring-commands-rspec (1.0.1)
  475 + spring (>= 0.9.1)
  476 + spring-commands-spinach (1.0.0)
  477 + spring (>= 0.9.1)
475 478 sprockets (2.10.1)
476 479 hike (~> 1.2)
477 480 multi_json (~> 1.0)
... ... @@ -543,12 +546,12 @@ GEM
543 546 websocket-driver (0.3.1)
544 547 xpath (2.0.0)
545 548 nokogiri (~> 1.3)
546   - yajl-ruby (1.1.0)
547 549  
548 550 PLATFORMS
549 551 ruby
550 552  
551 553 DEPENDENCIES
  554 + ace-rails-ap
552 555 actionpack-action_caching
553 556 actionpack-page_caching
554 557 acts-as-taggable-on
... ... @@ -578,13 +581,12 @@ DEPENDENCIES
578 581 gemoji (~> 1.3.0)
579 582 github-markup (~> 0.7.4)!
580 583 gitlab-flowdock-git-hook (~> 0.4.2)
581   - gitlab-gollum-lib (~> 1.0.2)
  584 + gitlab-gollum-lib (~> 1.1.0)
582 585 gitlab-grack (~> 2.0.0.pre)
583   - gitlab-linguist (~> 2.9.6)
584   - gitlab-pygments.rb (~> 0.5.4)
585   - gitlab_git (~> 4.0.0)
  586 + gitlab-linguist (~> 3.0.0)
  587 + gitlab_git (~> 5.4.0)
586 588 gitlab_meta (= 6.0)
587   - gitlab_omniauth-ldap (= 1.0.3)
  589 + gitlab_omniauth-ldap (= 1.0.4)
588 590 gon (~> 5.0.0)
589 591 grape (~> 0.6.1)
590 592 grape-entity (~> 0.3.0)
... ... @@ -640,6 +642,9 @@ DEPENDENCIES
640 642 slim
641 643 spinach-rails
642 644 spork (~> 1.0rc)
  645 + spring (= 1.1.1)
  646 + spring-commands-rspec (= 1.0.1)
  647 + spring-commands-spinach (= 1.0.0)
643 648 stamp
644 649 state_machine
645 650 test_after_commit
... ...
LICENSE
1   -Copyright (c) 2011 Dmitriy Zaporozhets
  1 +Copyright (c) 2011-2014 Dmitriy Zaporozhets
2 2  
3 3 Permission is hereby granted, free of charge, to any person obtaining a copy
4 4 of this software and associated documentation files (the "Software"), to deal
... ...
MAINTENANCE.md
... ... @@ -21,3 +21,5 @@ release where the minor version is increased numerically by increments of one
21 21 (eg. `5.0 -> 5.1`).
22 22  
23 23 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.
  24 +
  25 +More information about the release procedures can be found in the doc/release directory.
... ...
README.md
... ... @@ -4,26 +4,21 @@
4 4  
5 5 ![animated-screenshots](https://gist.github.com/fnkr/2f9badd56bfe0ed04ee7/raw/4f48806fbae97f556c2f78d8c2d299c04500cb0d/compiled.gif)
6 6  
7   -### GitLab allows you to
8   - * keep your code secure on your own server
9   - * manage repositories, users and access permissions
10   - * communicate through issues, line-comments and wiki pages
11   - * perform code review with merge requests
  7 +### Gitlab is open source software to collaborate on code
12 8  
13   -### GitLab is
14   -
15   -* powered by Ruby on Rails
16   -* completely free and open source (MIT license)
17   -* used by more than 25.000 organizations to keep their code secure
  9 +* Manage git repositories with fine grained access controls that keep your code secure
  10 +* Perform code reviews and enhance collaboration with merge requests
  11 +* Each project can also have an issue tracker and a wiki
  12 +* Used by more than 50,000 organizations, GitLab is the most popular solution to manage git repositories on-premises
  13 +* Completely free and open source (MIT Expat license)
  14 +* Powered by Ruby on Rails
18 15  
19 16 ### Code status
20 17  
21   -* [![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)
  18 +* [![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)
22 19  
23 20 * [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.png)](https://codeclimate.com/github/gitlabhq/gitlabhq)
24 21  
25   -* [![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.
26   -
27 22 * [![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.png?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq)
28 23  
29 24 ### Resources
... ... @@ -36,6 +31,8 @@
36 31  
37 32 * [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.
38 33  
  34 +* 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
  35 +
39 36 ### Requirements
40 37  
41 38 * Ubuntu/Debian**
... ... @@ -50,13 +47,17 @@
50 47  
51 48 #### Official installation methods
52 49  
53   -* [Manual installation guide for a production server](doc/install/installation.md)
  50 +* [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.
  51 +
  52 +* [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.
54 53  
55 54 * [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.
56 55  
  56 +* [Manual installation guide](doc/install/installation.md) This guide to set up a production server offers detailed and complete step-by-step instructions.
  57 +
57 58 #### Third party one-click installers
58 59  
59   -* [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.
  60 +* [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).
60 61  
61 62 * [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.).
62 63  
... ... @@ -68,11 +69,9 @@
68 69  
69 70 ### New versions and upgrading
70 71  
71   -Since 2011 GitLab is released on the 22nd of every month. Every new release includes an upgrade guide.
72   -
73   -* [Upgrade guides](doc/update)
  72 +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).
74 73  
75   -* [Changelog](CHANGELOG)
  74 +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.
76 75  
77 76 * 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).
78 77  
... ... @@ -155,6 +154,8 @@ or start each component separately
155 154  
156 155 * [Book](http://www.packtpub.com/gitlab-repository-management/book) written by GitLab enthusiast Jonathan M. Hethey is unofficial but it offers a good overview.
157 156  
  157 +* [Gitter chat room](https://gitter.im/gitlabhq/gitlabhq#) here you can ask questions when you need help.
  158 +
158 159  
159 160 ### Getting in touch
160 161  
... ...
VERSION
1   -6.6.0.pre
  1 +6.6.0.rc1
... ...
app/assets/images/ajax_loader.gif

7.73 KB

app/assets/images/ajax_loader_gray.gif

7.6 KB

app/assets/images/ajax_loader_tree.gif

3.09 KB

app/assets/images/icon-link.png 0 → 100644

1019 Bytes

app/assets/images/no_group_avatar.png 0 → 100644

4.77 KB

app/assets/javascripts/api.js.coffee
... ... @@ -3,6 +3,7 @@
3 3 user_path: "/api/:version/users/:id.json"
4 4 notes_path: "/api/:version/projects/:id/notes.json"
5 5 namespaces_path: "/api/:version/namespaces.json"
  6 + project_users_path: "/api/:version/projects/:id/users.json"
6 7  
7 8 # Get 20 (depends on api) recent notes
8 9 # and sort the ascending from oldest to newest
... ... @@ -50,6 +51,23 @@
50 51 ).done (users) ->
51 52 callback(users)
52 53  
  54 + # Return project users list. Filtered by query
  55 + # Only active users retrieved
  56 + projectUsers: (project_id, query, callback) ->
  57 + url = Api.buildUrl(Api.project_users_path)
  58 + url = url.replace(':id', project_id)
  59 +
  60 + $.ajax(
  61 + url: url
  62 + data:
  63 + private_token: gon.api_token
  64 + search: query
  65 + per_page: 20
  66 + active: true
  67 + dataType: "json"
  68 + ).done (users) ->
  69 + callback(users)
  70 +
53 71 # Return namespaces list. Filtered by query
54 72 namespaces: (query, callback) ->
55 73 url = Api.buildUrl(Api.namespaces_path)
... ...
app/assets/javascripts/application.js
... ... @@ -24,7 +24,8 @@
24 24 //= require g.raphael-min
25 25 //= require g.bar-min
26 26 //= require branch-graph
27   -//= require ace-src-noconflict/ace
  27 +//= require highlightjs.min
  28 +//= require ace/ace
28 29 //= require_tree .
29 30 //= require d3
30 31 //= require underscore
... ...
app/assets/javascripts/blob.js.coffee
... ... @@ -17,7 +17,7 @@ class BlobView
17 17  
18 18 setHash(hash)
19 19 e.preventDefault()
20   -
  20 +
21 21 # See if there are lines selected
22 22 # "#L12" and "#L34-56" supported
23 23 highlightBlobLines = (e) ->
... ... @@ -64,7 +64,7 @@ class BlobView
64 64 nodes.attr("id", hash)
65 65  
66 66 # initialize multi-line select
67   - $("#tree-content-holder .line_numbers a[id^=L]").on("click", handleMultiSelect)
  67 + $("#tree-content-holder .line-numbers a[id^=L]").on("click", handleMultiSelect)
68 68  
69 69 # Highlight the correct lines on load
70 70 highlightBlobLines()
... ...
app/assets/javascripts/dispatcher.js.coffee
... ... @@ -4,6 +4,7 @@ $ -&gt;
4 4 class Dispatcher
5 5 constructor: () ->
6 6 @initSearch()
  7 + @initHighlight()
7 8 @initPageScripts()
8 9  
9 10 initPageScripts: ->
... ... @@ -18,6 +19,8 @@ class Dispatcher
18 19 switch page
19 20 when 'projects:issues:index'
20 21 Issues.init()
  22 + when 'projects:issues:show'
  23 + new Issue()
21 24 when 'projects:issues:new', 'projects:merge_requests:new'
22 25 GitLab.GfmAutoComplete.setup()
23 26 when 'dashboard:show'
... ... @@ -53,3 +56,10 @@ class Dispatcher
53 56 project_ref = opts.data('autocomplete-project-ref')
54 57  
55 58 new SearchAutocomplete(path, project_id, project_ref)
  59 +
  60 + initHighlight: ->
  61 + $('.highlight pre code').each (i, e) ->
  62 + hljs.highlightBlock(e)
  63 + $(e).html($.map($(e).html().split("\n"), (line, i) ->
  64 + "<div class='line' id='LC" + (i + 1) + "'>" + line + "</div>"
  65 + ).join("\n"))
... ...
app/assets/javascripts/groups.js.coffee
... ... @@ -4,3 +4,14 @@ class GroupMembers
4 4 $(this).fadeOut()
5 5  
6 6 @GroupMembers = GroupMembers
  7 +
  8 +$ ->
  9 + # avatar
  10 + $('.js-choose-group-avatar-button').bind "click", ->
  11 + form = $(this).closest("form")
  12 + form.find(".js-group-avatar-input").click()
  13 +
  14 + $('.js-group-avatar-input').bind "change", ->
  15 + form = $(this).closest("form")
  16 + filename = $(this).val().replace(/^.*[\\\/]/, '')
  17 + form.find(".js-avatar-filename").text(filename)
7 18 \ No newline at end of file
... ...
app/assets/javascripts/issue.js.coffee 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class Issue
  2 + constructor: ->
  3 + $('.edit-issue.inline-update input[type="submit"]').hide()
  4 + $(".issue-box .inline-update").on "change", "select", ->
  5 + $(this).submit()
  6 + $(".issue-box .inline-update").on "change", "#issue_assignee_id", ->
  7 + $(this).submit()
  8 +
  9 +@Issue = Issue
... ...
app/assets/javascripts/issues.js.coffee
... ... @@ -77,9 +77,3 @@
77 77 $("#update_issues_ids").val []
78 78 $(".issues_bulk_update").hide()
79 79 $(".issues-filters").show()
80   -
81   -$ ->
82   - $('.edit-issue.inline-update input[type="submit"]').hide();
83   - $("body").on "change", ".edit-issue.inline-update select", ->
84   - $(this).submit()
85   -
... ...
app/assets/javascripts/merge_request.js.coffee 0 → 100644
... ... @@ -0,0 +1,103 @@
  1 +class MergeRequest
  2 + constructor: (@opts) ->
  3 + @initContextWidget()
  4 + this.$el = $('.merge-request')
  5 + @diffs_loaded = if @opts.action == 'diffs' then true else false
  6 + @commits_loaded = false
  7 +
  8 + this.activateTab(@opts.action)
  9 +
  10 + this.bindEvents()
  11 +
  12 + this.initMergeWidget()
  13 + this.$('.show-all-commits').on 'click', =>
  14 + this.showAllCommits()
  15 +
  16 + modal = $('#modal_merge_info').modal(show: false)
  17 +
  18 + disableButtonIfEmptyField '#merge_commit_message', '.accept_merge_request'
  19 +
  20 +
  21 + # Local jQuery finder
  22 + $: (selector) ->
  23 + this.$el.find(selector)
  24 +
  25 + initContextWidget: ->
  26 + $('.edit-merge_request.inline-update input[type="submit"]').hide()
  27 + $(".issue-box .inline-update").on "change", "select", ->
  28 + $(this).submit()
  29 + $(".issue-box .inline-update").on "change", "#merge_request_assignee_id", ->
  30 + $(this).submit()
  31 +
  32 + initMergeWidget: ->
  33 + this.showState( @opts.current_status )
  34 +
  35 + if this.$('.automerge_widget').length and @opts.check_enable
  36 + $.get @opts.url_to_automerge_check, (data) =>
  37 + this.showState( data.merge_status )
  38 + , 'json'
  39 +
  40 + if @opts.ci_enable
  41 + $.get @opts.url_to_ci_check, (data) =>
  42 + this.showCiState data.status
  43 + , 'json'
  44 +
  45 + bindEvents: ->
  46 + this.$('.nav-tabs').on 'click', 'a', (event) =>
  47 + a = $(event.currentTarget)
  48 +
  49 + href = a.attr('href')
  50 + History.replaceState {path: href}, document.title, href
  51 +
  52 + event.preventDefault()
  53 +
  54 + this.$('.nav-tabs').on 'click', 'li', (event) =>
  55 + this.activateTab($(event.currentTarget).data('action'))
  56 +
  57 + this.$('.accept_merge_request').on 'click', ->
  58 + $('.automerge_widget.can_be_merged').hide()
  59 + $('.merge-in-progress').show()
  60 +
  61 + activateTab: (action) ->
  62 + this.$('.nav-tabs li').removeClass 'active'
  63 + this.$('.tab-content').hide()
  64 + switch action
  65 + when 'diffs'
  66 + this.$('.nav-tabs .diffs-tab').addClass 'active'
  67 + this.loadDiff() unless @diffs_loaded
  68 + this.$('.diffs').show()
  69 + else
  70 + this.$('.nav-tabs .notes-tab').addClass 'active'
  71 + this.$('.notes').show()
  72 +
  73 + showState: (state) ->
  74 + $('.automerge_widget').hide()
  75 + $('.automerge_widget.' + state).show()
  76 +
  77 + showCiState: (state) ->
  78 + $('.ci_widget').hide()
  79 + $('.ci_widget.ci-' + state).show()
  80 +
  81 + loadDiff: (event) ->
  82 + $.ajax
  83 + type: 'GET'
  84 + url: this.$('.nav-tabs .diffs-tab a').attr('href')
  85 + beforeSend: =>
  86 + this.$('.status').addClass 'loading'
  87 + complete: =>
  88 + @diffs_loaded = true
  89 + this.$('.status').removeClass 'loading'
  90 + success: (data) =>
  91 + this.$(".diffs").html(data.html)
  92 + dataType: 'json'
  93 +
  94 + showAllCommits: ->
  95 + this.$('.first-commits').remove()
  96 + this.$('.all-commits').removeClass 'hide'
  97 +
  98 + alreadyOrCannotBeMerged: ->
  99 + this.$('.automerge_widget').hide()
  100 + this.$('.merge-in-progress').hide()
  101 + this.$('.automerge_widget.already_cannot_be_merged').show()
  102 +
  103 +this.MergeRequest = MergeRequest
... ...
app/assets/javascripts/merge_requests.js.coffee
... ... @@ -6,99 +6,3 @@
6 6 $('#milestone_id').select2()
7 7 $('#milestone_id, #assignee_id').on 'change', ->
8 8 $(this).closest('form').submit()
9   -
10   -class MergeRequest
11   -
12   - constructor: (@opts) ->
13   - this.$el = $('.merge-request')
14   - @diffs_loaded = if @opts.action == 'diffs' then true else false
15   - @commits_loaded = false
16   -
17   - this.activateTab(@opts.action)
18   -
19   - this.bindEvents()
20   -
21   - this.initMergeWidget()
22   - this.$('.show-all-commits').on 'click', =>
23   - this.showAllCommits()
24   -
25   - modal = $('#modal_merge_info').modal(show: false)
26   -
27   - disableButtonIfEmptyField '#merge_commit_message', '.accept_merge_request'
28   -
29   - # Local jQuery finder
30   - $: (selector) ->
31   - this.$el.find(selector)
32   -
33   - initMergeWidget: ->
34   - this.showState( @opts.current_status )
35   -
36   - if this.$('.automerge_widget').length and @opts.check_enable
37   - $.get @opts.url_to_automerge_check, (data) =>
38   - this.showState( data.merge_status )
39   - , 'json'
40   -
41   - if @opts.ci_enable
42   - $.get @opts.url_to_ci_check, (data) =>
43   - this.showCiState data.status
44   - , 'json'
45   -
46   - bindEvents: ->
47   - this.$('.nav-tabs').on 'click', 'a', (event) =>
48   - a = $(event.currentTarget)
49   -
50   - href = a.attr('href')
51   - History.replaceState {path: href}, document.title, href
52   -
53   - event.preventDefault()
54   -
55   - this.$('.nav-tabs').on 'click', 'li', (event) =>
56   - this.activateTab($(event.currentTarget).data('action'))
57   -
58   - this.$('.accept_merge_request').on 'click', ->
59   - $('.automerge_widget.can_be_merged').hide()
60   - $('.merge-in-progress').show()
61   -
62   - activateTab: (action) ->
63   - this.$('.nav-tabs li').removeClass 'active'
64   - this.$('.tab-content').hide()
65   - switch action
66   - when 'diffs'
67   - this.$('.nav-tabs .diffs-tab').addClass 'active'
68   - this.loadDiff() unless @diffs_loaded
69   - this.$('.diffs').show()
70   - else
71   - this.$('.nav-tabs .notes-tab').addClass 'active'
72   - this.$('.notes').show()
73   -
74   - showState: (state) ->
75   - $('.automerge_widget').hide()
76   - $('.automerge_widget.' + state).show()
77   -
78   - showCiState: (state) ->
79   - $('.ci_widget').hide()
80   - $('.ci_widget.ci-' + state).show()
81   -
82   - loadDiff: (event) ->
83   - $.ajax
84   - type: 'GET'
85   - url: this.$('.nav-tabs .diffs-tab a').attr('href')
86   - beforeSend: =>
87   - this.$('.status').addClass 'loading'
88   - complete: =>
89   - @diffs_loaded = true
90   - this.$('.status').removeClass 'loading'
91   - success: (data) =>
92   - this.$(".diffs").html(data.html)
93   - dataType: 'json'
94   -
95   - showAllCommits: ->
96   - this.$('.first-commits').remove()
97   - this.$('.all-commits').removeClass 'hide'
98   -
99   - alreadyOrCannotBeMerged: ->
100   - this.$('.automerge_widget').hide()
101   - this.$('.merge-in-progress').hide()
102   - this.$('.automerge_widget.already_cannot_be_merged').show()
103   -
104   -this.MergeRequest = MergeRequest
... ...
app/assets/javascripts/notes.js.coffee
... ... @@ -94,6 +94,9 @@ class Notes
94 94 if @isNewNote(note)
95 95 @note_ids.push(note.id)
96 96 $('ul.main-notes-list').append(note.html)
  97 + code = "#note_" + note.id + " .highlight pre code"
  98 + $(code).each (i, e) ->
  99 + hljs.highlightBlock(e)
97 100  
98 101  
99 102 ###
... ... @@ -253,6 +256,9 @@ class Notes
253 256 updateNote: (xhr, note, status) =>
254 257 note_li = $("#note_" + note.id)
255 258 note_li.replaceWith(note.html)
  259 + code = "#note_" + note.id + " .highlight pre code"
  260 + $(code).each (i, e) ->
  261 + hljs.highlightBlock(e)
256 262  
257 263 ###
258 264 Called in response to clicking the edit note link
... ...
app/assets/javascripts/profile.js.coffee
... ... @@ -26,3 +26,5 @@ $ -&gt;
26 26 form = $(this).closest("form")
27 27 filename = $(this).val().replace(/^.*[\\\/]/, '')
28 28 form.find(".js-avatar-filename").text(filename)
  29 +
  30 + $('.profile-groups-avatars').tooltip("placement": "top")
29 31 \ No newline at end of file
... ...
app/assets/javascripts/project_users_select.js.coffee 0 → 100644
... ... @@ -0,0 +1,48 @@
  1 +@projectUsersSelect =
  2 + init: ->
  3 + $('.ajax-project-users-select').each (i, select) ->
  4 + project_id = $('body').data('project-id')
  5 +
  6 + $(select).select2
  7 + placeholder: $(select).data('placeholder') || "Search for a user"
  8 + multiple: $(select).hasClass('multiselect')
  9 + minimumInputLength: 0
  10 + query: (query) ->
  11 + Api.projectUsers project_id, query.term, (users) ->
  12 + data = { results: users }
  13 + query.callback(data)
  14 +
  15 + initSelection: (element, callback) ->
  16 + id = $(element).val()
  17 + if id isnt ""
  18 + Api.user(id, callback)
  19 +
  20 +
  21 + formatResult: projectUsersSelect.projectUserFormatResult
  22 + formatSelection: projectUsersSelect.projectUserFormatSelection
  23 + dropdownCssClass: "ajax-project-users-dropdown"
  24 + dropdownAutoWidth: true
  25 + escapeMarkup: (m) -> # we do not want to escape markup since we are displaying html in results
  26 + m
  27 +
  28 + projectUserFormatResult: (user) ->
  29 + if user.avatar_url
  30 + avatar = user.avatar_url
  31 + else if gon.gravatar_enabled
  32 + avatar = gon.gravatar_url
  33 + avatar = avatar.replace('%{hash}', md5(user.email))
  34 + avatar = avatar.replace('%{size}', '24')
  35 + else
  36 + avatar = gon.relative_url_root + "/assets/no_avatar.png"
  37 +
  38 + "<div class='user-result'>
  39 + <div class='user-image'><img class='avatar s24' src='#{avatar}'></div>
  40 + <div class='user-name'>#{user.name}</div>
  41 + <div class='user-username'>#{user.username}</div>
  42 + </div>"
  43 +
  44 + projectUserFormatSelection: (user) ->
  45 + user.name
  46 +
  47 +$ ->
  48 + projectUsersSelect.init()
... ...
app/assets/javascripts/users_select.js.coffee
1 1 $ ->
2 2 userFormatResult = (user) ->
3   - if user.avatar
4   - avatar = user.avatar.url
5   - else
  3 + if user.avatar_url
  4 + avatar = user.avatar_url
  5 + else if gon.gravatar_enabled
6 6 avatar = gon.gravatar_url
7 7 avatar = avatar.replace('%{hash}', md5(user.email))
8 8 avatar = avatar.replace('%{size}', '24')
  9 + else
  10 + avatar = gon.relative_url_root + "/assets/no_avatar.png"
9 11  
10 12 "<div class='user-result'>
11 13 <div class='user-image'><img class='avatar s24' src='#{avatar}'></div>
... ...
app/assets/stylesheets/application.scss
... ... @@ -5,6 +5,7 @@
5 5 *= require jquery.ui.gitlab
6 6 *= require jquery.atwho
7 7 *= require select2
  8 + *= require highlightjs.min
8 9 *= require_self
9 10 */
10 11  
... ... @@ -38,6 +39,7 @@
38 39 @import "generic/lists.scss";
39 40 @import "generic/forms.scss";
40 41 @import "generic/selects.scss";
  42 +@import "generic/highlight.scss";
41 43  
42 44 /**
43 45 * Page specific styles (issues, projects etc):
... ... @@ -63,6 +65,7 @@
63 65 @import "sections/wall.scss";
64 66 @import "sections/dashboard.scss";
65 67 @import "sections/stat_graph.scss";
  68 +@import "sections/groups.scss";
66 69  
67 70 /**
68 71 * Code ighlight
... ...
app/assets/stylesheets/generic/buttons.scss
... ... @@ -118,7 +118,6 @@
118 118 @extend .btn-primary;
119 119 }
120 120  
121   - &.btn-close,
122 121 &.btn-remove {
123 122 @extend .btn-danger;
124 123 }
... ... @@ -143,6 +142,22 @@
143 142 line-height: 16px;
144 143 margin: 2px;
145 144 }
  145 +
  146 + &.btn-close {
  147 + color: #B94A48;
  148 + font-weight: bold;
  149 + &:hover {
  150 + color: #B94A48;
  151 + }
  152 + }
  153 +
  154 + &.btn-reopen {
  155 + color: #468847;
  156 + font-weight: bold;
  157 + &:hover {
  158 + color: #468847;
  159 + }
  160 + }
146 161 }
147 162  
148 163 .btn-block {
... ...
app/assets/stylesheets/generic/common.scss
... ... @@ -88,11 +88,15 @@ pre.well-pre {
88 88 /** Big Labels **/
89 89 .state-label {
90 90 font-size: 14px;
91   - padding: 6px 25px;
  91 + padding: 9px 25px;
92 92 text-align: center;
93   - @include border-radius(4px);
94 93 text-shadow: none;
95   - margin-left: 10px;
  94 + margin-right: 20px;
  95 +
  96 + &.state-label-blue {
  97 + background: #31708f;
  98 + color: #FFF;
  99 + }
96 100  
97 101 &.state-label-green {
98 102 background: #4A4;
... ... @@ -112,6 +116,7 @@ pre.well-pre {
112 116 .dropdown-menu > li > a:hover,
113 117 .dropdown-menu > li > a:focus {
114 118 background: #29b;
  119 + color: #FFF
115 120 }
116 121  
117 122 .breadcrumb > li + li:before {
... ... @@ -173,12 +178,10 @@ table a code {
173 178  
174 179 .loading {
175 180 margin: 20px auto;
176   - background: url(ajax_loader.gif) no-repeat center center;
177   - width: 40px;
178 181 height: 40px;
179   - &.loading-gray {
180   - background: url(ajax_loader_gray.gif) no-repeat center center;
181   - }
  182 + color: #555;
  183 + font-size: 32px;
  184 + text-align: center;
182 185 }
183 186  
184 187 span.update-author {
... ...
app/assets/stylesheets/generic/files.scss
... ... @@ -50,9 +50,9 @@
50 50 }
51 51  
52 52 &.wiki {
53   - padding: 20px;
54 53 font-size: 14px;
55 54 line-height: 1.6;
  55 + padding: 25px;
56 56  
57 57 .highlight {
58 58 margin-bottom: 9px;
... ... @@ -143,75 +143,6 @@
143 143 */
144 144 &.code {
145 145 padding: 0;
146   -
147   - table.lines {
148   - border: none;
149   - box-shadow: none;
150   - margin: 0px;
151   - padding: 0px;
152   - table-layout: fixed;
153   -
154   - pre {
155   - border: none;
156   - border-radius: 0;
157   - font-family: $monospace_font;
158   - font-size: 12px !important;
159   - line-height: 16px !important;
160   - margin: 0;
161   - padding: 10px 0;
162   - }
163   - td {
164   - border: none;
165   - margin: 0;
166   - padding: 0;
167   - vertical-align: top;
168   -
169   - &:first-child {
170   - background: #eee;
171   - width: 50px;
172   - }
173   - &:last-child {
174   - }
175   - }
176   - tr:hover {
177   - background: none;
178   - }
179   -
180   - pre.line_numbers {
181   - color: #666;
182   - padding: 10px 6px 10px 0;
183   - text-align: right;
184   - background: #EEE;
185   -
186   - a {
187   - color: #666;
188   -
189   - i {
190   - display: none;
191   - font-size: 14px;
192   - line-height: 14px;
193   - }
194   - &:hover i {
195   - display: inherit;
196   - }
197   - }
198   - }
199   -
200   - .highlight {
201   - border-left: 1px solid #DEE2E3;
202   - overflow: auto;
203   - overflow-y: hidden;
204   -
205   - pre {
206   - white-space: pre;
207   - word-wrap: normal;
208   -
209   - .line {
210   - padding: 0 10px;
211   - }
212   - }
213   - }
214   - }
215 146 }
216 147 }
217 148 }
... ...
app/assets/stylesheets/generic/forms.scss
... ... @@ -51,3 +51,27 @@ label {
51 51 .input-mn-300 {
52 52 min-width: 300px;
53 53 }
  54 +
  55 +.custom-form-control {
  56 + width: 150px;
  57 +}
  58 +
  59 +@media (min-width: $screen-sm-min) {
  60 + .custom-form-control {
  61 + width: 150px;
  62 + }
  63 +}
  64 +
  65 +/* Medium devices (desktops, 992px and up) */
  66 +@media (min-width: $screen-md-min) {
  67 + .custom-form-control {
  68 + width: 170px;
  69 + }
  70 +}
  71 +
  72 +/* Large devices (large desktops, 1200px and up) */
  73 +@media (min-width: $screen-lg-min) {
  74 + .custom-form-control {
  75 + width: 200px;
  76 + }
  77 +}
... ...
app/assets/stylesheets/generic/highlight.scss 0 → 100644
... ... @@ -0,0 +1,64 @@
  1 +.highlighted-data {
  2 + border: none;
  3 + box-shadow: none;
  4 + margin: 0px;
  5 + padding: 0px;
  6 + table-layout: fixed;
  7 +
  8 + pre {
  9 + padding: 10px;
  10 + border: none;
  11 + border-radius: 0;
  12 + font-family: $monospace_font;
  13 + font-size: 12px !important;
  14 + line-height: 16px !important;
  15 + margin: 0;
  16 +
  17 + code {
  18 + white-space: pre;
  19 + word-wrap: normal;
  20 + padding: 0;
  21 +
  22 + .line {
  23 + display: inline;
  24 + }
  25 + }
  26 + }
  27 +
  28 + .hljs {
  29 + padding: 0;
  30 + }
  31 +
  32 + .line-numbers {
  33 + padding: 10px;
  34 + text-align: right;
  35 + float: left;
  36 +
  37 + a {
  38 + font-family: $monospace_font;
  39 + display: block;
  40 + font-size: 12px !important;
  41 + line-height: 16px !important;
  42 + white-space: nowrap;
  43 +
  44 + i {
  45 + visibility: hidden;
  46 + @extend .pull-left;
  47 + }
  48 +
  49 + &:hover i {
  50 + visibility: visible;
  51 + }
  52 + }
  53 + }
  54 +
  55 + .highlight {
  56 + overflow: auto;
  57 + overflow-y: hidden;
  58 +
  59 + pre {
  60 + white-space: pre;
  61 + word-wrap: normal;
  62 + }
  63 + }
  64 +}
... ...
app/assets/stylesheets/generic/issue_box.scss
... ... @@ -11,34 +11,39 @@
11 11 color: #666;
12 12 margin:20px 0;
13 13 background: #FAFAFA;
14   - border: 1px solid #DDD;
  14 + border: 1px solid #EEE;
15 15  
16 16 .control-group {
17 17 margin-bottom: 0;
18 18 }
19 19  
  20 + .state {
  21 + height: 34px;
  22 + border-bottom: 1px solid #DDD;
  23 + line-height: 32px;
  24 + }
  25 +
20 26 .title {
21   - font-size: 20px;
  27 + font-size: 22px;
22 28 font-weight: 500;
23   - line-height: 28px;
  29 + line-height: 1.5;
24 30 margin: 0;
25   - color: #444;
  31 + color: #333;
  32 + padding-bottom: 0;
  33 + padding: 15px 25px;
26 34 }
27 35  
28 36 .context {
29 37 border: none;
30   - background-color: #f5f5f5;
31   - border: none;
32 38 border-top: 1px solid #eee;
  39 + padding: 15px 25px;
33 40 }
34 41  
35 42 .description {
36   - border-top: 1px solid #eee;
  43 + padding: 0 25px 15px 25px;
37 44 }
38 45  
39 46 .title, .context, .description {
40   - padding: 15px;
41   -
42 47 .clearfix {
43 48 margin: 0;
44 49 }
... ...
app/assets/stylesheets/generic/lists.scss
... ... @@ -23,6 +23,12 @@
23 23 }
24 24 }
25 25  
  26 + &.warning-row {
  27 + background-color: #fcf8e3;
  28 + border-color: #faebcc;
  29 + color: #8a6d3b;
  30 + }
  31 +
26 32 &.smoke { background-color: #f5f5f5; }
27 33  
28 34 &:hover {
... ...
app/assets/stylesheets/generic/selects.scss
1 1 /** Select2 selectbox style override **/
2   -
3 2 .select2-container, .select2-container.select2-drop-above {
4 3 .select2-choice {
5 4 background: #FFF;
... ... @@ -12,9 +11,13 @@
12 11 }
13 12  
14 13 .select2-drop-active {
15   - border: 1px solid #BBB;
  14 + border: 1px solid #BBB !important;
16 15 margin-top: 4px;
17 16  
  17 + &.select2-drop-above {
  18 + margin-bottom: 8px;
  19 + }
  20 +
18 21 .select2-search input {
19 22 background: #fafafa;
20 23 border-color: #DDD;
... ... @@ -78,3 +81,9 @@ select {
78 81 .project-refs-form .select2-container {
79 82 margin-right: 10px;
80 83 }
  84 +
  85 +.ajax-users-dropdown, .ajax-project-users-dropdown {
  86 + .select2-search {
  87 + padding-top: 4px;
  88 + }
  89 +}
... ...
app/assets/stylesheets/generic/typography.scss
... ... @@ -90,9 +90,27 @@ a:focus {
90 90  
91 91 font-size: 14px;
92 92 line-height: 1.6;
93   - .white .highlight pre {
94   - background: #f5f5f5;
  93 +
  94 + /* Link to current header. */
  95 + h1, h2, h3, h4, h5, h6 {
  96 + position: relative;
  97 + &:hover > :last-child {
  98 + $size: 16px;
  99 + position: absolute;
  100 + right: 100%;
  101 + top: 50%;
  102 + margin-top: -$size/2;
  103 + margin-right: 0px;
  104 + padding-right: 20px;
  105 + display: inline-block;
  106 + width: $size;
  107 + height: $size;
  108 + background-image: url("icon-link.png");
  109 + background-size: contain;
  110 + background-repeat: no-repeat;
  111 + }
95 112 }
  113 +
96 114 ul {
97 115 padding: 0;
98 116 margin: 0 0 9px 25px !important;
... ...
app/assets/stylesheets/gl_bootstrap.scss
... ... @@ -108,6 +108,8 @@ $pagination-active-bg: $bg_style_color;
108 108  
109 109 // Nav tabs
110 110 .nav.nav-tabs {
  111 + margin-bottom: 15px;
  112 +
111 113 li {
112 114 > a {
113 115 padding: 8px 20px;
... ...
app/assets/stylesheets/highlight/dark.scss
1   -.dark .highlight {
  1 +.dark {
  2 + background-color: #232323;
2 3  
3   - background-color: #333;
  4 + .line.hll {
  5 + background: #558;
  6 + }
  7 +
  8 + .highlight{
  9 + border-left: 1px solid #444;
  10 + }
  11 +
  12 + .no-highlight {
  13 + color: #DDD;
  14 + }
  15 +
  16 + .line-numbers a {
  17 + color: #666;
  18 + }
4 19  
5 20 pre {
6   - background-color: #333;
7   - color: #eee;
8   - }
9   -
10   - .hll { display: block; background-color: darken($hover, 65%) }
11   - .c { color: #888888; font-style: italic } /* Comment */
12   - .err { color: #a61717; background-color: #e3d2d2 } /* Error */
13   - .k { color: #CDA869; font-weight: bold } /* Keyword */
14   - .kp { color: #CDA869; font-weight: bold } /* Keyword */
15   - .cm { color: #888888 } /* Comment.Multiline */
16   - .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
17   - .c1 { color: #888888 } /* Comment.Single */
18   - .cs { color: #cc0000; font-weight: bold; background-color: transparent } /* Comment.Special */
19   - .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
20   - .ge { font-style: italic } /* Generic.Emph */
21   - .gr { color: #aa0000 } /* Generic.Error */
22   - .gh { color: #303030 } /* Generic.Heading */
23   - .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
24   - .go { color: #888888 } /* Generic.Output */
25   - .gp { color: #555555 } /* Generic.Prompt */
26   - .gs { font-weight: bold } /* Generic.Strong */
27   - .gu { color: #606060 } /* Generic.Subheading */
28   - .gt { color: #aa0000 } /* Generic.Traceback */
29   - .kc{font-weight: bold;} /* Keyword.Constant */
30   - .kd{font-weight: bold;} /* Keyword.Declaration */
31   - .kn{font-weight: bold;} /* Keyword.Namespace */
32   - .kp{font-weight: bold;} /* Keyword.Pseudo */
33   - .kr{font-weight: bold;} /* Keyword.Reserved */
34   - .kt{color: #458;font-weight: bold;} /* Keyword.Type */
35   - .m { color: #0000DD; font-weight: bold } /* Literal.Number */
36   - .p { color: #eee; }
37   - .s { color: #0AD; background-color: transparent } /* Literal.String */
38   - .na{color: #008080;} /* Name.Attribute */
39   - .nb{color: #0086B3;} /* Name.Builtin */
40   - .nc{color: #ccc;font-weight: bold;} /* Name.Class */
41   - .no{color: turquoise;} /* Name.Constant */
42   - .ni{color: #800080;}
43   - .ne{color: #900;font-weight: bold;} /* Name.Exception */
44   - .nf{color: #ccc;font-weight: bold;} /* Name.Function */
45   - .nn{color: #79C3E0;font-weight: bold;} /* Name.Namespace */
46   - .nt{color: #fc5;} /* Name.Tag */
47   - .nv{color: #FA4;} /* Name.Variable */
48   - .py { color: #336699; font-weight: bold } /* Name.Property */
49   - .ow { color: #008800 } /* Operator.Word */
50   - .w { color: #bbbbbb } /* Text.Whitespace */
51   - .mf { color: #7AC; font-weight: bold } /* Literal.Number.Float */
52   - .mh { color: #7AC; font-weight: bold } /* Literal.Number.Hex */
53   - .mi {color: #099;} /* Literal.Number.Integer */
54   - .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
55   - .sb { color: #dd2200; background-color: transparent; } /* Literal.String.Backtick */
56   - .sc{color: #d14;} /* Literal.String.Char */
57   - .sd { color: #dd2200; background-color: transparent; } /* Literal.String.Doc */
58   - .s2{color: orange;} /* Literal.String.Double */
59   - .se{color: orange;} /* Literal.String.Escape */
60   - .sh{color: orange;} /* Literal.String.Heredoc */
61   - .si{color: orange;} /* Literal.String.Interpol */
62   - .sx{color: orange;} /* Literal.String.Other */
63   - .sr{color: orange;} /* Literal.String.Regex */
64   - .s1{color: orange;} /* Literal.String.Single */
65   - .ss{color: orange;} /* Literal.String.Symbol */
66   - .bp { color: #D58 } /* Name.Builtin.Pseudo */
67   - .vc { color: #336699 } /* Name.Variable.Class */
68   - .vg { color: #dd7700 } /* Name.Variable.Global */
69   - .vi { color: cyan }
70   -}
  21 + background-color: #232323;
  22 + }
  23 +
  24 + .hljs {
  25 + display: block;
  26 + background: #232323;
  27 + color: #E6E1DC;
  28 + }
  29 +
  30 + .hljs-comment,
  31 + .hljs-template_comment,
  32 + .hljs-javadoc,
  33 + .hljs-shebang {
  34 + color: #BC9458;
  35 + font-style: italic;
  36 + }
  37 +
  38 + .hljs-keyword,
  39 + .ruby .hljs-function .hljs-keyword,
  40 + .hljs-request,
  41 + .hljs-status,
  42 + .nginx .hljs-title,
  43 + .method,
  44 + .hljs-list .hljs-title {
  45 + color: #C26230;
  46 + }
  47 +
  48 + .hljs-string,
  49 + .hljs-number,
  50 + .hljs-regexp,
  51 + .hljs-tag .hljs-value,
  52 + .hljs-cdata,
  53 + .hljs-filter .hljs-argument,
  54 + .hljs-attr_selector,
  55 + .apache .hljs-cbracket,
  56 + .hljs-date,
  57 + .tex .hljs-command,
  58 + .markdown .hljs-link_label {
  59 + color: #A5C261;
  60 + }
  61 +
  62 + .hljs-subst {
  63 + color: #519F50;
  64 + }
  65 +
  66 + .hljs-tag,
  67 + .hljs-tag .hljs-keyword,
  68 + .hljs-tag .hljs-title,
  69 + .hljs-doctype,
  70 + .hljs-sub .hljs-identifier,
  71 + .hljs-pi,
  72 + .input_number {
  73 + color: #E8BF6A;
  74 + }
  75 +
  76 + .hljs-identifier {
  77 + color: #D0D0FF;
  78 + }
  79 +
  80 + .hljs-class .hljs-title,
  81 + .haskell .hljs-type,
  82 + .smalltalk .hljs-class,
  83 + .hljs-javadoctag,
  84 + .hljs-yardoctag,
  85 + .hljs-phpdoc {
  86 + text-decoration: none;
  87 + }
  88 +
  89 + .hljs-constant {
  90 + color: #DA4939;
  91 + }
  92 +
  93 +
  94 + .hljs-symbol,
  95 + .hljs-built_in,
  96 + .ruby .hljs-symbol .hljs-string,
  97 + .ruby .hljs-symbol .hljs-identifier,
  98 + .markdown .hljs-link_url,
  99 + .hljs-attribute {
  100 + color: #6D9CBE;
  101 + }
  102 +
  103 + .markdown .hljs-link_url {
  104 + text-decoration: underline;
  105 + }
71 106  
  107 +
  108 +
  109 + .hljs-params,
  110 + .hljs-variable,
  111 + .clojure .hljs-attribute {
  112 + color: #D0D0FF;
  113 + }
  114 +
  115 + .css .hljs-tag,
  116 + .hljs-rules .hljs-property,
  117 + .hljs-pseudo,
  118 + .tex .hljs-special {
  119 + color: #CDA869;
  120 + }
  121 +
  122 + .css .hljs-class {
  123 + color: #9B703F;
  124 + }
  125 +
  126 + .hljs-rules .hljs-keyword {
  127 + color: #C5AF75;
  128 + }
  129 +
  130 + .hljs-rules .hljs-value {
  131 + color: #CF6A4C;
  132 + }
  133 +
  134 + .css .hljs-id {
  135 + color: #8B98AB;
  136 + }
  137 +
  138 + .hljs-annotation,
  139 + .apache .hljs-sqbracket,
  140 + .nginx .hljs-built_in {
  141 + color: #9B859D;
  142 + }
  143 +
  144 + .hljs-preprocessor,
  145 + .hljs-preprocessor *,
  146 + .hljs-pragma {
  147 + color: #8996A8 !important;
  148 + }
  149 +
  150 + .hljs-hexcolor,
  151 + .css .hljs-value .hljs-number {
  152 + color: #A5C261;
  153 + }
  154 +
  155 + .hljs-title,
  156 + .hljs-decorator,
  157 + .css .hljs-function {
  158 + color: #FFC66D;
  159 + }
  160 +
  161 + .diff .hljs-header,
  162 + .hljs-chunk {
  163 + background-color: #2F33AB;
  164 + color: #E6E1DC;
  165 + display: inline-block;
  166 + width: 100%;
  167 + }
  168 +
  169 + .diff .hljs-change {
  170 + background-color: #4A410D;
  171 + color: #F8F8F8;
  172 + display: inline-block;
  173 + width: 100%;
  174 + }
  175 +
  176 + .hljs-addition {
  177 + background-color: #144212;
  178 + color: #E6E1DC;
  179 + display: inline-block;
  180 + width: 100%;
  181 + }
  182 +
  183 + .hljs-deletion {
  184 + background-color: #600;
  185 + color: #E6E1DC;
  186 + display: inline-block;
  187 + width: 100%;
  188 + }
  189 +
  190 + .coffeescript .javascript,
  191 + .javascript .xml,
  192 + .tex .hljs-formula,
  193 + .xml .javascript,
  194 + .xml .vbscript,
  195 + .xml .css,
  196 + .xml .hljs-cdata {
  197 + opacity: 0.7;
  198 + }
  199 +}
... ...
app/assets/stylesheets/highlight/monokai.scss
1   -$monokai-fg: #f8f8f2;
2   -$monokai-comment: #75715e;
3   -$monokai-pink: #f92672;
4   -$monokai-blue: #66d9ef;
5   -$monokai-green: #a6e22e;
6   -$monokai-gold: #e6db74;
7   -$monokai-dark: #3b3a32;
8   -$monokai-purple: #ae81ff;
  1 +.monokai {
  2 + background-color: #272822;
9 3  
10   -.monokai .highlight {
  4 + .highlight{
  5 + border-left: 1px solid #444;
  6 + }
11 7  
12   - background-color: #272822;
  8 + .line.hll {
  9 + background: #558;
  10 + }
  11 +
  12 + .no-highlight {
  13 + color: #DDD;
  14 + }
  15 +
  16 + .line-numbers a {
  17 + color: #666;
  18 + }
13 19  
14 20 pre {
15 21 background-color: #272822;
16   - color: $monokai-fg;
  22 + color: #f8f8f2;
17 23 }
18 24  
19   - .hll { background-color: darken($hover, 65%) }
20   - .c { color: $monokai-comment } /* Comment */
21   - .err { color: $monokai-fg } /* Error */
22   - .g { color: $monokai-fg } /* Generic */
23   - .k { color: $monokai-pink } /* Keyword */
24   - .l { color: $monokai-fg } /* Literal */
25   - .n { color: $monokai-blue } /* Name */
26   - .o { color: $monokai-fg } /* Operator */
27   - .x { color: $monokai-fg } /* Other */
28   - .p { color: $monokai-fg } /* Punctuation */
29   - .cm { color: $monokai-comment } /* Comment.Multiline */
30   - .cp { color: $monokai-comment } /* Comment.Preproc */
31   - .c1 { color: $monokai-comment } /* Comment.Single */
32   - .cs { color: $monokai-comment } /* Comment.Special */
33   - .gd { color: #8b0807 } /* Generic.Deleted */
34   - .ge { color: $monokai-fg; text-decoration: underline } /* Generic.Emph */
35   - .gr { color: $monokai-fg } /* Generic.Error */
36   - .gh { color: $monokai-fg; font-weight: bold } /* Generic.Heading */
37   - .gi { color: $monokai-fg; font-weight: bold; background-color: #46830c } /* Generic.Inserted */
38   - .go { color: $monokai-dark; background-color: #31322c } /* Generic.Output */
39   - .gp { color: $monokai-fg } /* Generic.Prompt */
40   - .gs { color: $monokai-fg } /* Generic.Strong */
41   - .gu { color: $monokai-fg; font-weight: bold } /* Generic.Subheading */
42   - .gt { color: #f8f8f0; background-color: $monokai-pink } /* Generic.Traceback */
43   - .kc { color: $monokai-purple } /* Keyword.Constant */
44   - .kd { color: $monokai-pink } /* Keyword.Declaration */
45   - .kn { color: $monokai-pink } /* Keyword.Namespace */
46   - .kp { color: $monokai-pink } /* Keyword.Pseudo */
47   - .kr { color: $monokai-pink } /* Keyword.Reserved */
48   - .kt { color: $monokai-fg } /* Keyword.Type */
49   - .ld { color: $monokai-fg } /* Literal.Date */
50   - .m { color: $monokai-purple } /* Literal.Number */
51   - .s { color: $monokai-gold } /* Literal.String */
52   - .na { color: $monokai-purple } /* Name.Attribute */
53   - .nb { color: $monokai-blue } /* Name.Builtin */
54   - .nc { color: $monokai-fg } /* Name.Class */
55   - .no { color: $monokai-fg } /* Name.Constant */
56   - .nd { color: $monokai-fg } /* Name.Decorator */
57   - .ni { color: $monokai-fg } /* Name.Entity */
58   - .ne { color: $monokai-fg } /* Name.Exception */
59   - .nf { color: $monokai-green } /* Name.Function */
60   - .nl { color: $monokai-gold } /* Name.Label */
61   - .nn { color: $monokai-fg } /* Name.Namespace */
62   - .nx { color: $monokai-fg } /* Name.Other */
63   - .nt { color: $monokai-pink } /* Name.Tag */
64   - .nv { color: $monokai-blue; font-style: italic } /* Name.Variable */
65   - .py { color: $monokai-fg } /* Name.Property */
66   - .ow { color: $monokai-pink } /* Operator.Word */
67   - .w { color: $monokai-fg } /* Text.Whitespace */
68   - .mf { color: $monokai-purple } /* Literal.Number.Float */
69   - .mh { color: $monokai-purple } /* Literal.Number.Hex */
70   - .mi { color: $monokai-purple } /* Literal.Number.Integer */
71   - .mo { color: $monokai-purple } /* Literal.Number.Oct */
72   - .sb { color: $monokai-gold } /* Literal.String.Backtick */
73   - .sc { color: $monokai-gold } /* Literal.String.Char */
74   - .sd { color: $monokai-gold } /* Literal.String.Doc */
75   - .s2 { color: $monokai-gold } /* Literal.String.Double */
76   - .se { color: $monokai-gold } /* Literal.String.Escape */
77   - .sh { color: $monokai-gold } /* Literal.String.Heredoc */
78   - .si { color: $monokai-gold } /* Literal.String.Interpol */
79   - .sx { color: $monokai-gold } /* Literal.String.Other */
80   - .sr { color: $monokai-gold } /* Literal.String.Regex */
81   - .s1 { color: $monokai-gold } /* Literal.String.Single */
82   - .ss { color: $monokai-gold } /* Literal.String.Symbol */
83   - .bp { color: $monokai-fg } /* Name.Builtin.Pseudo */
84   - .vc { color: $monokai-blue; font-style: italic } /* Name.Variable.Class */
85   - .vg { color: $monokai-blue; font-style: italic } /* Name.Variable.Global */
86   - .vi { color: $monokai-blue; font-style: italic } /* Name.Variable.Instance */
87   - .il { color: $monokai-purple } /* Literal.Number.Integer.Long */
88   -}
  25 + .hljs {
  26 + display: block;
  27 + background: #272822;
  28 + }
  29 +
  30 + .hljs-tag,
  31 + .hljs-tag .hljs-title,
  32 + .hljs-keyword,
  33 + .hljs-literal,
  34 + .hljs-strong,
  35 + .hljs-change,
  36 + .hljs-winutils,
  37 + .hljs-flow,
  38 + .lisp .hljs-title,
  39 + .clojure .hljs-built_in,
  40 + .nginx .hljs-title,
  41 + .tex .hljs-special {
  42 + color: #F92672;
  43 + }
  44 +
  45 + .hljs {
  46 + color: #DDD;
  47 + }
89 48  
  49 + .hljs .hljs-constant,
  50 + .asciidoc .hljs-code {
  51 + color: #66D9EF;
  52 + }
  53 +
  54 + .hljs-code,
  55 + .hljs-class .hljs-title,
  56 + .hljs-header {
  57 + color: white;
  58 + }
  59 +
  60 + .hljs-link_label,
  61 + .hljs-attribute,
  62 + .hljs-symbol,
  63 + .hljs-symbol .hljs-string,
  64 + .hljs-value,
  65 + .hljs-regexp {
  66 + color: #BF79DB;
  67 + }
  68 +
  69 + .hljs-link_url,
  70 + .hljs-tag .hljs-value,
  71 + .hljs-string,
  72 + .hljs-bullet,
  73 + .hljs-subst,
  74 + .hljs-title,
  75 + .hljs-emphasis,
  76 + .haskell .hljs-type,
  77 + .hljs-preprocessor,
  78 + .hljs-pragma,
  79 + .ruby .hljs-class .hljs-parent,
  80 + .hljs-built_in,
  81 + .sql .hljs-aggregate,
  82 + .django .hljs-template_tag,
  83 + .django .hljs-variable,
  84 + .smalltalk .hljs-class,
  85 + .hljs-javadoc,
  86 + .django .hljs-filter .hljs-argument,
  87 + .smalltalk .hljs-localvars,
  88 + .smalltalk .hljs-array,
  89 + .hljs-attr_selector,
  90 + .hljs-pseudo,
  91 + .hljs-addition,
  92 + .hljs-stream,
  93 + .hljs-envvar,
  94 + .apache .hljs-tag,
  95 + .apache .hljs-cbracket,
  96 + .tex .hljs-command,
  97 + .hljs-prompt {
  98 + color: #A6E22E;
  99 + }
  100 +
  101 + .hljs-comment,
  102 + .java .hljs-annotation,
  103 + .smartquote,
  104 + .hljs-blockquote,
  105 + .hljs-horizontal_rule,
  106 + .python .hljs-decorator,
  107 + .hljs-template_comment,
  108 + .hljs-pi,
  109 + .hljs-doctype,
  110 + .hljs-deletion,
  111 + .hljs-shebang,
  112 + .apache .hljs-sqbracket,
  113 + .tex .hljs-formula {
  114 + color: #75715E;
  115 + }
  116 +
  117 + .hljs-keyword,
  118 + .hljs-literal,
  119 + .css .hljs-id,
  120 + .hljs-phpdoc,
  121 + .hljs-title,
  122 + .hljs-header,
  123 + .haskell .hljs-type,
  124 + .vbscript .hljs-built_in,
  125 + .sql .hljs-aggregate,
  126 + .rsl .hljs-built_in,
  127 + .smalltalk .hljs-class,
  128 + .diff .hljs-header,
  129 + .hljs-chunk,
  130 + .hljs-winutils,
  131 + .bash .hljs-variable,
  132 + .apache .hljs-tag,
  133 + .tex .hljs-special,
  134 + .hljs-request,
  135 + .hljs-status {
  136 + font-weight: bold;
  137 + }
  138 +
  139 + .coffeescript .javascript,
  140 + .javascript .xml,
  141 + .tex .hljs-formula,
  142 + .xml .javascript,
  143 + .xml .vbscript,
  144 + .xml .css,
  145 + .xml .hljs-cdata {
  146 + opacity: 0.5;
  147 + }
  148 +}
... ...
app/assets/stylesheets/highlight/solarized_dark.scss
1   -.solarized-dark .highlight {
2   -
  1 +.solarized-dark {
3 2 background-color: #002B36;
4   -
  3 +
  4 + .highlight{
  5 + border-left: 1px solid #113b46;
  6 + }
  7 +
  8 + .line.hll {
  9 + background: #000;
  10 + }
  11 +
  12 + .no-highlight {
  13 + color: #DDD;
  14 + }
  15 +
5 16 pre {
6 17 background-color: #002B36;
7 18 color: #eee;
8 19 }
9 20  
10   - .hll { background-color: #073642 }
11   - .c { color: #586E75 } /* Comment */
12   - .err { color: #93A1A1 } /* Error */
13   - .g { color: #93A1A1 } /* Generic */
14   - .k { color: #859900 } /* Keyword */
15   - .l { color: #93A1A1 } /* Literal */
16   - .n { color: #93A1A1 } /* Name */
17   - .o { color: #859900 } /* Operator */
18   - .x { color: #CB4B16 } /* Other */
19   - .p { color: #93A1A1 } /* Punctuation */
20   - .cm { color: #586E75 } /* Comment.Multiline */
21   - .cp { color: #859900 } /* Comment.Preproc */
22   - .c1 { color: #586E75 } /* Comment.Single */
23   - .cs { color: #859900 } /* Comment.Special */
24   - .gd { color: #2AA198 } /* Generic.Deleted */
25   - .ge { color: #93A1A1; font-style: italic } /* Generic.Emph */
26   - .gr { color: #DC322F } /* Generic.Error */
27   - .gh { color: #CB4B16 } /* Generic.Heading */
28   - .gi { color: #859900 } /* Generic.Inserted */
29   - .go { color: #93A1A1 } /* Generic.Output */
30   - .gp { color: #93A1A1 } /* Generic.Prompt */
31   - .gs { color: #93A1A1; font-weight: bold } /* Generic.Strong */
32   - .gu { color: #CB4B16 } /* Generic.Subheading */
33   - .gt { color: #93A1A1 } /* Generic.Traceback */
34   - .kc { color: #CB4B16 } /* Keyword.Constant */
35   - .kd { color: #268BD2 } /* Keyword.Declaration */
36   - .kn { color: #859900 } /* Keyword.Namespace */
37   - .kp { color: #859900 } /* Keyword.Pseudo */
38   - .kr { color: #268BD2 } /* Keyword.Reserved */
39   - .kt { color: #DC322F } /* Keyword.Type */
40   - .ld { color: #93A1A1 } /* Literal.Date */
41   - .m { color: #2AA198 } /* Literal.Number */
42   - .s { color: #2AA198 } /* Literal.String */
43   - .na { color: #93A1A1 } /* Name.Attribute */
44   - .nb { color: #B58900 } /* Name.Builtin */
45   - .nc { color: #268BD2 } /* Name.Class */
46   - .no { color: #CB4B16 } /* Name.Constant */
47   - .nd { color: #268BD2 } /* Name.Decorator */
48   - .ni { color: #CB4B16 } /* Name.Entity */
49   - .ne { color: #CB4B16 } /* Name.Exception */
50   - .nf { color: #268BD2 } /* Name.Function */
51   - .nl { color: #93A1A1 } /* Name.Label */
52   - .nn { color: #93A1A1 } /* Name.Namespace */
53   - .nx { color: #93A1A1 } /* Name.Other */
54   - .py { color: #93A1A1 } /* Name.Property */
55   - .nt { color: #268BD2 } /* Name.Tag */
56   - .nv { color: #268BD2 } /* Name.Variable */
57   - .ow { color: #859900 } /* Operator.Word */
58   - .w { color: #93A1A1 } /* Text.Whitespace */
59   - .mf { color: #2AA198 } /* Literal.Number.Float */
60   - .mh { color: #2AA198 } /* Literal.Number.Hex */
61   - .mi { color: #2AA198 } /* Literal.Number.Integer */
62   - .mo { color: #2AA198 } /* Literal.Number.Oct */
63   - .sb { color: #586E75 } /* Literal.String.Backtick */
64   - .sc { color: #2AA198 } /* Literal.String.Char */
65   - .sd { color: #93A1A1 } /* Literal.String.Doc */
66   - .s2 { color: #2AA198 } /* Literal.String.Double */
67   - .se { color: #CB4B16 } /* Literal.String.Escape */
68   - .sh { color: #93A1A1 } /* Literal.String.Heredoc */
69   - .si { color: #2AA198 } /* Literal.String.Interpol */
70   - .sx { color: #2AA198 } /* Literal.String.Other */
71   - .sr { color: #DC322F } /* Literal.String.Regex */
72   - .s1 { color: #2AA198 } /* Literal.String.Single */
73   - .ss { color: #2AA198 } /* Literal.String.Symbol */
74   - .bp { color: #268BD2 } /* Name.Builtin.Pseudo */
75   - .vc { color: #268BD2 } /* Name.Variable.Class */
76   - .vg { color: #268BD2 } /* Name.Variable.Global */
77   - .vi { color: #268BD2 } /* Name.Variable.Instance */
78   - .il { color: #2AA198 } /* Literal.Number.Integer.Long */
79   -}
  21 + .line-numbers a {
  22 + color: #666;
  23 + }
  24 +
  25 + .hljs {
  26 + display: block;
  27 + background: #002b36;
  28 + color: #839496;
  29 + }
  30 +
  31 + .hljs-comment,
  32 + .hljs-template_comment,
  33 + .diff .hljs-header,
  34 + .hljs-doctype,
  35 + .hljs-pi,
  36 + .lisp .hljs-string,
  37 + .hljs-javadoc {
  38 + color: #586e75;
  39 + }
  40 +
  41 + /* Solarized Green */
  42 + .hljs-keyword,
  43 + .hljs-winutils,
  44 + .method,
  45 + .hljs-addition,
  46 + .css .hljs-tag,
  47 + .hljs-request,
  48 + .hljs-status,
  49 + .nginx .hljs-title {
  50 + color: #859900;
  51 + }
80 52  
  53 + /* Solarized Cyan */
  54 + .hljs-number,
  55 + .hljs-command,
  56 + .hljs-string,
  57 + .hljs-tag .hljs-value,
  58 + .hljs-rules .hljs-value,
  59 + .hljs-phpdoc,
  60 + .tex .hljs-formula,
  61 + .hljs-regexp,
  62 + .hljs-hexcolor,
  63 + .hljs-link_url {
  64 + color: #2aa198;
  65 + }
  66 +
  67 + /* Solarized Blue */
  68 + .hljs-title,
  69 + .hljs-localvars,
  70 + .hljs-chunk,
  71 + .hljs-decorator,
  72 + .hljs-built_in,
  73 + .hljs-identifier,
  74 + .vhdl .hljs-literal,
  75 + .hljs-id,
  76 + .css .hljs-function {
  77 + color: #268bd2;
  78 + }
  79 +
  80 + /* Solarized Yellow */
  81 + .hljs-attribute,
  82 + .hljs-variable,
  83 + .lisp .hljs-body,
  84 + .smalltalk .hljs-number,
  85 + .hljs-constant,
  86 + .hljs-class .hljs-title,
  87 + .hljs-parent,
  88 + .haskell .hljs-type,
  89 + .hljs-link_reference {
  90 + color: #b58900;
  91 + }
  92 +
  93 + /* Solarized Orange */
  94 + .hljs-preprocessor,
  95 + .hljs-preprocessor .hljs-keyword,
  96 + .hljs-pragma,
  97 + .hljs-shebang,
  98 + .hljs-symbol,
  99 + .hljs-symbol .hljs-string,
  100 + .diff .hljs-change,
  101 + .hljs-special,
  102 + .hljs-attr_selector,
  103 + .hljs-subst,
  104 + .hljs-cdata,
  105 + .clojure .hljs-title,
  106 + .css .hljs-pseudo,
  107 + .hljs-header {
  108 + color: #cb4b16;
  109 + }
  110 +
  111 + /* Solarized Red */
  112 + .hljs-deletion,
  113 + .hljs-important {
  114 + color: #dc322f;
  115 + }
  116 +
  117 + /* Solarized Violet */
  118 + .hljs-link_label {
  119 + color: #6c71c4;
  120 + }
  121 +
  122 + .tex .hljs-formula {
  123 + background: #073642;
  124 + }
  125 +}
... ...
app/assets/stylesheets/highlight/white.scss
1   -.white .highlight {
2   -
  1 +.white {
3 2 background-color: #fff;
4   -
  3 +
  4 + .line.hll {
  5 + background: #FFA;
  6 + }
  7 +
  8 + .highlight{
  9 + border-left: 1px solid #eee;
  10 + }
  11 +
5 12 pre {
6 13 background-color: #fff;
7 14 color: #333;
8 15 }
9 16  
10   - .hll { display: block; background-color: $hover }
11   - .c { color: #888888; font-style: italic } /* Comment */
12   - .err { color: #a61717; background-color: #e3d2d2 } /* Error */
13   - .k { color: #000000; font-weight: bold } /* Keyword */
14   - .cm { color: #888888 } /* Comment.Multiline */
15   - .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
16   - .c1 { color: #888888 } /* Comment.Single */
17   - .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
18   - .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
19   - .ge { font-style: italic } /* Generic.Emph */
20   - .gr { color: #aa0000 } /* Generic.Error */
21   - .gh { color: #303030 } /* Generic.Heading */
22   - .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
23   - .go { color: #888888 } /* Generic.Output */
24   - .gp { color: #555555 } /* Generic.Prompt */
25   - .gs { font-weight: bold } /* Generic.Strong */
26   - .gu { color: #606060 } /* Generic.Subheading */
27   - .gt { color: #aa0000 } /* Generic.Traceback */
28   - .kc{font-weight: bold;} /* Keyword.Constant */
29   - .kd{font-weight: bold;} /* Keyword.Declaration */
30   - .kn{font-weight: bold;} /* Keyword.Namespace */
31   - .kp{font-weight: bold;} /* Keyword.Pseudo */
32   - .kr{font-weight: bold;} /* Keyword.Reserved */
33   - .kt{color: #458;font-weight: bold;} /* Keyword.Type */
34   - .m { color: #0000DD; font-weight: bold } /* Literal.Number */
35   - .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
36   - .na{color: #008080;} /* Name.Attribute */
37   - .nb{color: #0086B3;} /* Name.Builtin */
38   - .nc{color: #458;font-weight: bold;} /* Name.Class */
39   - .no{color: #008080;} /* Name.Constant */
40   - .ni{color: #800080;}
41   - .ne{color: #900;font-weight: bold;} /* Name.Exception */
42   - .nf{color: #900;font-weight: bold;} /* Name.Function */
43   - .nn{color: #005;font-weight: bold;} /* Name.Namespace */
44   - .nt{color: #000080;} /* Name.Tag */
45   - .nv{color: #008080;} /* Name.Variable */
46   - .py { color: #336699; font-weight: bold } /* Name.Property */
47   - .ow { color: #008800 } /* Operator.Word */
48   - .w { color: #bbbbbb } /* Text.Whitespace */
49   - .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
50   - .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
51   - .mi {color: #099;} /* Literal.Number.Integer */
52   - .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
53   - .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
54   - .sc{color: #d14;} /* Literal.String.Char */
55   - .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
56   - .s2{color: #d14;} /* Literal.String.Double */
57   - .se{color: #d14;} /* Literal.String.Escape */
58   - .sh{color: #d14;} /* Literal.String.Heredoc */
59   - .si{color: #d14;} /* Literal.String.Interpol */
60   - .sx{color: #d14;} /* Literal.String.Other */
61   - .sr{color: #d14;} /* Literal.String.Regex */
62   - .s1{color: #d14;} /* Literal.String.Single */
63   - .ss{color: #d14;} /* Literal.String.Symbol */
64   - .bp { color: #003388 } /* Name.Builtin.Pseudo */
65   - .vc { color: #336699 } /* Name.Variable.Class */
66   - .vg { color: #dd7700 } /* Name.Variable.Global */
67   - .vi { color: #3333bb }
  17 + .hljs {
  18 + background: #FFF;
  19 + }
  20 +
  21 + .line-numbers a {
  22 + color: #999;
  23 + }
  24 +
  25 + .hljs {
  26 + display: block;
  27 + background: #fff; color: black;
  28 + }
  29 +
  30 + .hljs-comment,
  31 + .hljs-template_comment,
  32 + .hljs-javadoc,
  33 + .hljs-comment * {
  34 + color: #006a00;
  35 + }
  36 +
  37 + .hljs-keyword,
  38 + .hljs-literal,
  39 + .nginx .hljs-title {
  40 + color: #aa0d91;
  41 + }
  42 + .method,
  43 + .hljs-list .hljs-title,
  44 + .hljs-tag .hljs-title,
  45 + .setting .hljs-value,
  46 + .hljs-winutils,
  47 + .tex .hljs-command,
  48 + .http .hljs-title,
  49 + .hljs-request,
  50 + .hljs-status {
  51 + color: #008;
  52 + }
  53 +
  54 + .hljs-envvar,
  55 + .tex .hljs-special {
  56 + color: #660;
  57 + }
  58 +
  59 + .hljs-string {
  60 + color: #c41a16;
  61 + }
  62 + .hljs-tag .hljs-value,
  63 + .hljs-cdata,
  64 + .hljs-filter .hljs-argument,
  65 + .hljs-attr_selector,
  66 + .apache .hljs-cbracket,
  67 + .hljs-date,
  68 + .hljs-regexp {
  69 + color: #080;
  70 + }
  71 +
  72 + .hljs-sub .hljs-identifier,
  73 + .hljs-pi,
  74 + .hljs-tag,
  75 + .hljs-tag .hljs-keyword,
  76 + .hljs-decorator,
  77 + .ini .hljs-title,
  78 + .hljs-shebang,
  79 + .hljs-prompt,
  80 + .hljs-hexcolor,
  81 + .hljs-rules .hljs-value,
  82 + .hljs-symbol,
  83 + .hljs-symbol .hljs-string,
  84 + .hljs-number,
  85 + .css .hljs-function,
  86 + .clojure .hljs-title,
  87 + .clojure .hljs-built_in,
  88 + .hljs-function .hljs-title,
  89 + .coffeescript .hljs-attribute {
  90 + color: #1c00cf;
  91 + }
  92 +
  93 + .hljs-class .hljs-title,
  94 + .haskell .hljs-type,
  95 + .smalltalk .hljs-class,
  96 + .hljs-javadoctag,
  97 + .hljs-yardoctag,
  98 + .hljs-phpdoc,
  99 + .hljs-typename,
  100 + .hljs-tag .hljs-attribute,
  101 + .hljs-doctype,
  102 + .hljs-class .hljs-id,
  103 + .hljs-built_in,
  104 + .setting,
  105 + .hljs-params,
  106 + .clojure .hljs-attribute {
  107 + color: #5c2699;
  108 + }
  109 +
  110 + .hljs-variable {
  111 + color: #3f6e74;
  112 + }
  113 + .css .hljs-tag,
  114 + .hljs-rules .hljs-property,
  115 + .hljs-pseudo,
  116 + .hljs-subst {
  117 + color: #000;
  118 + }
  119 +
  120 + .css .hljs-class,
  121 + .css .hljs-id {
  122 + color: #9B703F;
  123 + }
  124 +
  125 + .hljs-value .hljs-important {
  126 + color: #ff7700;
  127 + font-weight: bold;
  128 + }
  129 +
  130 + .hljs-rules .hljs-keyword {
  131 + color: #C5AF75;
  132 + }
  133 +
  134 + .hljs-annotation,
  135 + .apache .hljs-sqbracket,
  136 + .nginx .hljs-built_in {
  137 + color: #9B859D;
  138 + }
  139 +
  140 + .hljs-preprocessor,
  141 + .hljs-preprocessor *,
  142 + .hljs-pragma {
  143 + color: #643820;
  144 + }
  145 +
  146 + .tex .hljs-formula {
  147 + background-color: #EEE;
  148 + font-style: italic;
  149 + }
  150 +
  151 + .diff .hljs-header,
  152 + .hljs-chunk {
  153 + color: #808080;
  154 + font-weight: bold;
  155 + }
  156 +
  157 + .diff .hljs-change {
  158 + background-color: #BCCFF9;
  159 + }
  160 +
  161 + .hljs-addition {
  162 + background-color: #BAEEBA;
  163 + }
  164 +
  165 + .hljs-deletion {
  166 + background-color: #FFC8BD;
  167 + }
  168 +
  169 + .hljs-comment .hljs-yardoctag {
  170 + font-weight: bold;
  171 + }
  172 +
  173 + .method .hljs-id {
  174 + color: #000;
  175 + }
68 176 }
69 177  
70 178 .shadow {
... ...
app/assets/stylesheets/main/mixins.scss
... ... @@ -106,12 +106,12 @@
106 106  
107 107 h3 {
108 108 margin-top: 35px;
109   - font-size: 2em;
  109 + font-size: 1.5em;
110 110 }
111 111  
112 112 h4 {
113 113 margin-top: 30px;
114   - font-size: 1.5em;
  114 + font-size: 1.2em;
115 115 }
116 116  
117 117 blockquote p {
... ... @@ -128,7 +128,7 @@
128 128 }
129 129 }
130 130  
131   - code {
  131 + p > code {
132 132 font-size: inherit;
133 133 font-weight: inherit;
134 134 color: #555;
... ...
app/assets/stylesheets/main/variables.scss
... ... @@ -5,6 +5,7 @@ $primary_color: #2FA0BB;
5 5 $link_color: #3A89A3;
6 6 $style_color: #474D57;
7 7 $bg_style_color: #2299BB;
  8 +$list-group-active-bg: $bg_style_color;
8 9 $hover: #D9EDF7;
9 10  
10 11 /**
... ...
app/assets/stylesheets/sections/admin.scss
... ... @@ -2,7 +2,7 @@
2 2 * Admin area
3 3 *
4 4 */
5   -.admin_dash {
  5 +.admin-dashboard {
6 6 .data {
7 7 a {
8 8 h1 {
... ... @@ -14,6 +14,10 @@
14 14 }
15 15 }
16 16 }
  17 +
  18 + .str-truncated {
  19 + max-width: 60%;
  20 + }
17 21 }
18 22  
19 23 .admin-filter form {
... ...
app/assets/stylesheets/sections/commits.scss
... ... @@ -153,6 +153,7 @@
153 153 img{
154 154 border: 1px solid #FFF;
155 155 background: url('trans_bg.gif');
  156 + max-width: 100%;
156 157 }
157 158 &.deleted {
158 159 border: 1px solid $deleted;
... ...
app/assets/stylesheets/sections/dashboard.scss
... ... @@ -41,7 +41,7 @@
41 41 .dash-sidebar-tabs {
42 42 margin-bottom: 2px;
43 43 border: none;
44   - margin: 0;
  44 + margin: 0 !important;
45 45  
46 46 li {
47 47 &.active {
... ...
app/assets/stylesheets/sections/events.scss
... ... @@ -37,8 +37,8 @@
37 37  
38 38 &.event-inline {
39 39 .avatar {
40   - width: 16px;
41   - height: 16px;
  40 + position: relative;
  41 + top: -2px;
42 42 }
43 43 }
44 44  
... ... @@ -113,6 +113,7 @@
113 113 &.commit {
114 114 background: transparent;
115 115 padding: 3px;
  116 + padding-left: 0;
116 117 border: none;
117 118 color: #666;
118 119 .commit-row-title {
... ... @@ -122,6 +123,7 @@
122 123 &.commits-stat {
123 124 display: block;
124 125 padding: 3px;
  126 + padding-left: 0;
125 127  
126 128 &:hover {
127 129 background: none;
... ...
app/assets/stylesheets/sections/groups.scss 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +.new-group-member-holder {
  2 + margin-top: 50px;
  3 + background: #f9f9f9;
  4 + padding-top: 20px;
  5 +}
  6 +
  7 +.member-search-form {
  8 + float: left;
  9 +}
... ...
app/assets/stylesheets/sections/header.scss
... ... @@ -46,12 +46,17 @@ header {
46 46 }
47 47 }
48 48  
  49 + .turbolink-spinner {
  50 + font-size: 20px;
  51 + margin-right: 10px;
  52 + }
  53 +
49 54 @media (max-width: $screen-xs-max) {
50 55 border-width: 0;
51 56 font-size: 18px;
52 57  
53 58 .app_logo { margin-left: -15px; }
54   - .project_name {
  59 + .title {
55 60 display: inline-block;
56 61 overflow: hidden;
57 62 text-overflow: ellipsis;
... ... @@ -103,7 +108,7 @@ header {
103 108  
104 109 h1 {
105 110 margin: 0;
106   - background: url('logo-black.png') no-repeat center center;
  111 + background: image-url('logo-black.png') no-repeat center center;
107 112 background-size: 32px;
108 113 float: left;
109 114 height: 46px;
... ... @@ -122,7 +127,7 @@ header {
122 127 * Project / Area name
123 128 *
124 129 */
125   - .project_name {
  130 + .title {
126 131 position: relative;
127 132 float: left;
128 133 margin: 0;
... ... @@ -215,18 +220,18 @@ header {
215 220 .app_logo {
216 221 a {
217 222 h1 {
218   - background: url('logo-white.png') no-repeat center center;
  223 + background: image-url('logo-white.png') no-repeat center center;
219 224 background-size: 32px;
220 225 color: #fff;
221 226 text-shadow: 0 1px 1px #444;
222 227 }
223 228 }
224 229 }
225   - .project_name {
  230 + .title {
226 231 a {
227   - color: #BBB;
  232 + color: #FFF;
228 233 &:hover {
229   - color: #FFF;
  234 + text-decoration: underline;
230 235 }
231 236 }
232 237 color: #fff;
... ...
app/assets/stylesheets/sections/issues.scss
... ... @@ -14,8 +14,8 @@
14 14  
15 15 .issue-check {
16 16 float: left;
17   - padding: 8px 0;
18 17 padding-right: 8px;
  18 + margin-bottom: 10px;
19 19 min-width: 15px;
20 20 }
21 21  
... ... @@ -38,13 +38,21 @@
38 38 }
39 39 }
40 40  
41   -input.check_all_issues {
  41 +.check-all-holder {
  42 + height: 32px;
42 43 float: left;
43   - padding: 0;
44   - margin: 0;
45   - margin-right: 10px;
46   - position: relative;
47   - top: 13px;
  44 + margin-right: 12px;
  45 + padding: 6px 10px;
  46 + border: 1px solid #ccc;
  47 + @include border-radius(4px);
  48 +
  49 +
  50 + input.check_all_issues {
  51 + padding: 0;
  52 + margin: 0;
  53 + position: relative;
  54 + top: 3px;
  55 + }
48 56 }
49 57  
50 58 .issues_content {
... ... @@ -57,23 +65,6 @@ input.check_all_issues {
57 65 }
58 66 }
59 67  
60   -.btn.close_issue {
61   - color: #B94A48;
62   - font-weight: bold;
63   - @include shade;
64   - &:hover {
65   - color: #B94A48;
66   - }
67   -}
68   -.btn.reopen_issue {
69   - color: #468847;
70   - font-weight: bold;
71   - @include shade;
72   - &:hover {
73   - color: #468847;
74   - }
75   -}
76   -
77 68 @media (min-width: 800px) { .issues_filters select { width: 160px; } }
78 69 @media (min-width: 1200px) { .issues_filters select { width: 220px; } }
79 70  
... ... @@ -93,6 +84,13 @@ input.check_all_issues {
93 84 .update_selected_issues {
94 85 margin-left: 4px;
95 86 }
  87 +
  88 + .select2-container .select2-choice {
  89 + height: 32px;
  90 + line-height: 28px;
  91 + color: #444 !important;
  92 + font-weight: 500;
  93 + }
96 94 }
97 95 }
98 96  
... ...
app/assets/stylesheets/sections/merge_requests.scss
... ... @@ -31,10 +31,10 @@
31 31  
32 32 .mr_source_commit,
33 33 .mr_target_commit {
  34 + margin-top: 10px;
34 35 .commit {
35 36 margin: 0;
36   - padding: 0;
37   - padding: 5px 0;
  37 + padding: 2px 0;
38 38 list-style: none;
39 39 &:hover {
40 40 background: none;
... ...
app/assets/stylesheets/sections/nav.scss
... ... @@ -35,9 +35,8 @@
35 35 width: 1%;
36 36 &.active {
37 37 a {
38   - color: $style_color;
39   - font-weight: bolder;
40   -
  38 + color: #333;
  39 + font-weight: bold;
41 40 &:after {
42 41 content: '';
43 42 display: block;
... ... @@ -46,7 +45,7 @@
46 45 left: 50%;
47 46 width: 0;
48 47 height: 0;
49   - border-color: transparent transparent #777 transparent;
  48 + border-color: transparent transparent #333 transparent;
50 49 border-style: solid;
51 50 border-width: 6px;
52 51 margin-left: -6px;
... ... @@ -56,7 +55,20 @@
56 55  
57 56 &:hover {
58 57 a {
59   - color: $style_color;
  58 + color: $link_color;
  59 + &:after {
  60 + content: '';
  61 + display: block;
  62 + position: relative;
  63 + bottom: 8px;
  64 + left: 50%;
  65 + width: 0;
  66 + height: 0;
  67 + border-color: transparent transparent #29b transparent;
  68 + border-style: solid;
  69 + border-width: 6px;
  70 + margin-left: -6px;
  71 + }
60 72 }
61 73 }
62 74  
... ... @@ -73,7 +85,7 @@
73 85 a {
74 86 display: block;
75 87 text-align: center;
76   - font-weight: normal;
  88 + font-weight: 500;
77 89 height: 38px;
78 90 line-height: 34px;
79 91 color: #777;
... ...
app/assets/stylesheets/sections/notes.scss
... ... @@ -92,10 +92,6 @@ ul.notes {
92 92 .note-body {
93 93 @include md-typography;
94 94 margin-left: 45px;
95   -
96   - .highlight {
97   - @include border-radius(4px);
98   - }
99 95 }
100 96 .note-header {
101 97 padding-bottom: 5px;
... ... @@ -292,7 +288,7 @@ ul.notes {
292 288 box-shadow: none;
293 289 font-size: 14px;
294 290 height: 80px;
295   - width: 98.6%;
  291 + width: 100%;
296 292 }
297 293 }
298 294 }
... ... @@ -341,7 +337,7 @@ ul.notes {
341 337 box-shadow: none;
342 338 font-size: 14px;
343 339 height: 80px;
344   - width: 98.6%;
  340 + width: 100%;
345 341 }
346 342  
347 343 .form-actions {
... ...
app/assets/stylesheets/sections/profile.scss
... ... @@ -105,3 +105,23 @@
105 105 }
106 106 }
107 107 }
  108 +
  109 +.profile-groups-avatars {
  110 + margin: 0 5px 10px 0;
  111 +
  112 + img {
  113 + width: 50px;
  114 + height: 50px;
  115 + }
  116 +}
  117 +
  118 +.global-notifications-form .level-title {
  119 + font-size: 15px;
  120 + color: #333;
  121 + font-weight: bold;
  122 +}
  123 +
  124 +.notification-icon-holder {
  125 + width: 20px;
  126 + float: left;
  127 +}
... ...
app/assets/stylesheets/sections/projects.scss
... ... @@ -123,14 +123,9 @@
123 123 }
124 124  
125 125 .save-project-loader {
126   - img {
127   - margin-top: 50px;
128   - margin-bottom: 50px;
129   - }
130   - h3 {
131   - @extend .page-title;
132   - }
133   -
  126 + margin-top: 50px;
  127 + margin-bottom: 50px;
  128 + color: #555;
134 129 }
135 130  
136 131 ul.nav.nav-projects-tabs {
... ...
app/assets/stylesheets/sections/tree.scss
... ... @@ -127,9 +127,27 @@
127 127 border-top: 1px dashed #CCC;
128 128 padding-top: 10px;
129 129  
130   - h4 {
  130 + .readme-file-title {
131 131 font-size: 14px;
132 132 margin-bottom: 20px;
133 133 color: #777;
134 134 }
135 135 }
  136 +
  137 +.blob-commit-info {
  138 + list-style: none;
  139 + margin: 0;
  140 + padding: 0;
  141 + margin-bottom: 10px;
  142 +
  143 + .commit {
  144 + .commit-row-title {
  145 + font-size: 13px;
  146 +
  147 + .commit-row-message {
  148 + font-weight: normal;
  149 + color: #555;
  150 + }
  151 + }
  152 + }
  153 +}
... ...
app/assets/stylesheets/themes/ui_color.scss
... ... @@ -36,4 +36,8 @@
36 36 }
37 37 }
38 38 }
  39 +
  40 + .nav-pills > li.active > a, .nav-pills > li.active > a:hover, .nav-pills > li.active > a:focus {
  41 + background: #769;
  42 + }
39 43 }
... ...
app/controllers/application_controller.rb
... ... @@ -135,12 +135,12 @@ class ApplicationController &lt; ActionController::Base
135 135 end
136 136 end
137 137  
138   - def render_404
139   - render file: Rails.root.join("public", "404"), layout: false, status: "404"
  138 + def render_403
  139 + head :forbidden
140 140 end
141 141  
142   - def render_403
143   - render file: Rails.root.join("public", "403"), layout: false, status: "403"
  142 + def render_404
  143 + render file: Rails.root.join("public", "404"), layout: false, status: "404"
144 144 end
145 145  
146 146 def require_non_empty_project
... ... @@ -171,6 +171,7 @@ class ApplicationController &lt; ActionController::Base
171 171 gon.api_token = current_user.private_token if current_user
172 172 gon.gravatar_url = request.ssl? || Gitlab.config.gitlab.https ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url
173 173 gon.relative_url_root = Gitlab.config.gitlab.relative_url_root
  174 + gon.gravatar_enabled = Gitlab.config.gravatar.enabled
174 175 end
175 176  
176 177 def check_password_expiration
... ...
app/controllers/dashboard_controller.rb
... ... @@ -54,12 +54,12 @@ class DashboardController &lt; ApplicationController
54 54  
55 55 def merge_requests
56 56 @merge_requests = FilteringService.new.execute(MergeRequest, current_user, params)
57   - @merge_requests = @merge_requests.recent.page(params[:page]).per(20)
  57 + @merge_requests = @merge_requests.page(params[:page]).per(20)
58 58 end
59 59  
60 60 def issues
61 61 @issues = FilteringService.new.execute(Issue, current_user, params)
62   - @issues = @issues.recent.page(params[:page]).per(20)
  62 + @issues = @issues.page(params[:page]).per(20)
63 63 @issues = @issues.includes(:author, :project)
64 64  
65 65 respond_to do |format|
... ...
app/controllers/groups/avatars_controller.rb 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +class Groups::AvatarsController < ApplicationController
  2 + layout "profile"
  3 +
  4 + def destroy
  5 + @group = Group.find_by(path: params[:group_id])
  6 + @group.remove_avatar!
  7 +
  8 + @group.save
  9 +
  10 + redirect_to edit_group_path(@group)
  11 + end
  12 +end
... ...
app/controllers/groups_controller.rb
... ... @@ -63,7 +63,14 @@ class GroupsController &lt; ApplicationController
63 63  
64 64 def members
65 65 @project = group.projects.find(params[:project_id]) if params[:project_id]
66   - @members = group.users_groups.order('group_access DESC')
  66 + @members = group.users_groups
  67 +
  68 + if params[:search].present?
  69 + users = group.users.search(params[:search])
  70 + @members = @members.where(user_id: users)
  71 + end
  72 +
  73 + @members = @members.order('group_access DESC').page(params[:page]).per(50)
67 74 @users_group = UsersGroup.new
68 75 end
69 76  
... ...
app/controllers/profiles/emails_controller.rb 0 → 100644
... ... @@ -0,0 +1,26 @@
  1 +class Profiles::EmailsController < ApplicationController
  2 + layout "profile"
  3 +
  4 + def index
  5 + @primary = current_user.email
  6 + @emails = current_user.emails
  7 + end
  8 +
  9 + def create
  10 + @email = current_user.emails.new(params[:email])
  11 +
  12 + flash[:alert] = @email.errors.full_messages.first unless @email.save
  13 +
  14 + redirect_to profile_emails_url
  15 + end
  16 +
  17 + def destroy
  18 + @email = current_user.emails.find(params[:id])
  19 + @email.destroy
  20 +
  21 + respond_to do |format|
  22 + format.html { redirect_to profile_emails_url }
  23 + format.js { render nothing: true }
  24 + end
  25 + end
  26 +end
... ...
app/controllers/profiles/groups_controller.rb
... ... @@ -7,12 +7,11 @@ class Profiles::GroupsController &lt; ApplicationController
7 7  
8 8 def leave
9 9 @users_group = group.users_groups.where(user_id: current_user.id).first
10   -
11   - if group.last_owner?(current_user)
12   - redirect_to(profile_groups_path, alert: "You can't leave group. You must add at least one more owner to it.")
13   - else
  10 + if can?(current_user, :destroy, @users_group)
14 11 @users_group.destroy
15 12 redirect_to(profile_groups_path, info: "You left #{group.name} group.")
  13 + else
  14 + return render_403
16 15 end
17 16 end
18 17  
... ...
app/controllers/profiles/keys_controller.rb
1 1 class Profiles::KeysController < ApplicationController
2 2 layout "profile"
  3 + skip_before_filter :authenticate_user!, only: [:get_keys]
3 4  
4 5 def index
5 6 @keys = current_user.keys.order('id DESC')
... ... @@ -32,4 +33,24 @@ class Profiles::KeysController &lt; ApplicationController
32 33 format.js { render nothing: true }
33 34 end
34 35 end
  36 +
  37 + # Get all keys of a user(params[:username]) in a text format
  38 + # Helpful for sysadmins to put in respective servers
  39 + def get_keys
  40 + if params[:username].present?
  41 + begin
  42 + user = User.find_by_username(params[:username])
  43 + if user.present?
  44 + render text: user.all_ssh_keys.join("\n")
  45 + else
  46 + render_404 and return
  47 + end
  48 + rescue => e
  49 + render text: e.message
  50 + end
  51 + else
  52 + render_404 and return
  53 + end
  54 + end
  55 +
35 56 end
... ...
app/controllers/projects/compare_controller.rb
... ... @@ -8,13 +8,14 @@ class Projects::CompareController &lt; Projects::ApplicationController
8 8 end
9 9  
10 10 def show
11   - compare = Gitlab::Git::Compare.new(@repository.raw_repository, params[:from], params[:to])
  11 + compare = Gitlab::Git::Compare.new(@repository.raw_repository, params[:from], params[:to], MergeRequestDiff::COMMITS_SAFE_SIZE)
12 12  
13 13 @commits = compare.commits
14 14 @commit = compare.commit
15 15 @diffs = compare.diffs
16 16 @refs_are_same = compare.same
17 17 @line_notes = []
  18 + @timeout = compare.timeout
18 19  
19 20 diff_line_count = Commit::diff_line_count(@diffs)
20 21 @suppress_diff = Commit::diff_suppress?(@diffs, diff_line_count) && !params[:force_show_diff]
... ...
app/controllers/projects/issues_controller.rb
... ... @@ -9,7 +9,10 @@ class Projects::IssuesController &lt; Projects::ApplicationController
9 9 before_filter :authorize_write_issue!, only: [:new, :create]
10 10  
11 11 # Allow modify issue
12   - before_filter :authorize_modify_issue!, only: [:edit, :update, :bulk_update]
  12 + before_filter :authorize_modify_issue!, only: [:edit, :update]
  13 +
  14 + # Allow issues bulk update
  15 + before_filter :authorize_admin_issues!, only: [:bulk_update]
13 16  
14 17 respond_to :html
15 18  
... ... @@ -25,7 +28,7 @@ class Projects::IssuesController &lt; Projects::ApplicationController
25 28 @milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero?
26 29 sort_param = params[:sort] || 'newest'
27 30 @sort = sort_param.humanize unless sort_param.empty?
28   -
  31 + @assignees = User.where(id: @project.issues.pluck(:assignee_id))
29 32  
30 33 respond_to do |format|
31 34 format.html
... ... @@ -107,8 +110,8 @@ class Projects::IssuesController &lt; Projects::ApplicationController
107 110 return render_404 unless can?(current_user, :modify_issue, @issue)
108 111 end
109 112  
110   - def authorize_admin_issue!
111   - return render_404 unless can?(current_user, :admin_issue, @issue)
  113 + def authorize_admin_issues!
  114 + return render_404 unless can?(current_user, :admin_issue, @project)
112 115 end
113 116  
114 117 def module_enabled
... ...
app/controllers/projects/merge_requests_controller.rb
... ... @@ -28,6 +28,7 @@ class Projects::MergeRequestsController &lt; Projects::ApplicationController
28 28 assignee_id, milestone_id = params[:assignee_id], params[:milestone_id]
29 29 @assignee = @project.team.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero?
30 30 @milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero?
  31 + @assignees = User.where(id: @project.merge_requests.pluck(:assignee_id))
31 32 end
32 33  
33 34 def show
... ... @@ -60,7 +61,6 @@ class Projects::MergeRequestsController &lt; Projects::ApplicationController
60 61 @merge_request = MergeRequest.new(params[:merge_request])
61 62 @merge_request.source_project = @project unless @merge_request.source_project
62 63 @merge_request.target_project = @project unless @merge_request.target_project
63   - @target_branches = @merge_request.target_project.nil? ? [] : @merge_request.target_project.repository.branch_names
64 64 @source_project = @merge_request.source_project
65 65 @merge_request
66 66 end
... ... @@ -106,10 +106,14 @@ class Projects::MergeRequestsController &lt; Projects::ApplicationController
106 106 params[:merge_request].delete(:target_project_id)
107 107  
108 108 if @merge_request.update_attributes(params[:merge_request].merge(author_id_of_changes: current_user.id))
109   - @merge_request.reload_code
110   - @merge_request.mark_as_unchecked
111 109 @merge_request.reset_events_cache
112   - redirect_to [@merge_request.target_project, @merge_request], notice: 'Merge request was successfully updated.'
  110 +
  111 + respond_to do |format|
  112 + format.js
  113 + format.html do
  114 + redirect_to [@merge_request.target_project, @merge_request], notice: 'Merge request was successfully updated.'
  115 + end
  116 + end
113 117 else
114 118 render "edit"
115 119 end
... ... @@ -167,7 +171,11 @@ class Projects::MergeRequestsController &lt; Projects::ApplicationController
167 171 protected
168 172  
169 173 def selected_target_project
170   - ((@project.id.to_s == params[:target_project_id]) || @project.forked_project_link.nil?) ? @project : @project.forked_project_link.forked_from_project
  174 + if @project.id.to_s == params[:target_project_id] || @project.forked_project_link.nil?
  175 + @project
  176 + else
  177 + @project.forked_project_link.forked_from_project
  178 + end
171 179 end
172 180  
173 181 def merge_request
... ...
app/controllers/projects/raw_controller.rb
... ... @@ -11,11 +11,7 @@ class Projects::RawController &lt; Projects::ApplicationController
11 11 @blob = @repository.blob_at(@commit.id, @path)
12 12  
13 13 if @blob
14   - type = if @blob.mime_type =~ /html|javascript/
15   - 'text/plain; charset=utf-8'
16   - else
17   - @blob.mime_type
18   - end
  14 + type = get_blob_type
19 15  
20 16 headers['X-Content-Type-Options'] = 'nosniff'
21 17  
... ... @@ -29,5 +25,17 @@ class Projects::RawController &lt; Projects::ApplicationController
29 25 not_found!
30 26 end
31 27 end
  28 +
  29 + private
  30 +
  31 + def get_blob_type
  32 + if @blob.mime_type =~ /html|javascript/
  33 + 'text/plain; charset=utf-8'
  34 + elsif @blob.name =~ /(?:msi|exe|rar|r0\d|7z|7zip|zip)$/
  35 + 'application/octet-stream'
  36 + else
  37 + @blob.mime_type
  38 + end
  39 + end
32 40 end
33 41  
... ...
app/controllers/projects/refs_controller.rb
... ... @@ -34,7 +34,7 @@ class Projects::RefsController &lt; Projects::ApplicationController
34 34 contents = tree.entries
35 35 @logs = contents.map do |content|
36 36 file = params[:path] ? File.join(params[:path], content.name) : content.name
37   - last_commit = @repo.commits(@commit.id, file, 1).last
  37 + last_commit = @repo.last_commit_for_path(@commit.id, file)
38 38 {
39 39 file_name: content.name,
40 40 commit: last_commit
... ...
app/controllers/projects/tags_controller.rb
... ... @@ -8,7 +8,7 @@ class Projects::TagsController &lt; Projects::ApplicationController
8 8 before_filter :authorize_admin_project!, only: [:destroy]
9 9  
10 10 def index
11   - @tags = Kaminari.paginate_array(@repository.tags).page(params[:page]).per(30)
  11 + @tags = Kaminari.paginate_array(@repository.tags.reverse).page(params[:page]).per(30)
12 12 end
13 13  
14 14 def create
... ...
app/controllers/users_controller.rb
1 1 class UsersController < ApplicationController
2   - layout 'navless'
  2 +
  3 + skip_before_filter :authenticate_user!, only: [:show]
  4 + layout :determine_layout
3 5  
4 6 def show
5   - @user = User.find_by!(username: params[:username])
6   - @projects = @user.authorized_projects.where(id: current_user.authorized_projects.pluck(:id)).includes(:namespace)
  7 + @user = User.find_by_username!(params[:username])
  8 + @projects = @user.authorized_projects.includes(:namespace).select {|project| can?(current_user, :read_project, project)}
  9 + if !current_user && @projects.empty?
  10 + return authenticate_user!
  11 + end
7 12 @events = @user.recent_events.where(project_id: @projects.map(&:id)).limit(20)
8   -
9 13 @title = @user.name
10 14 end
  15 +
  16 + def determine_layout
  17 + if current_user
  18 + 'navless'
  19 + else
  20 + 'public_users'
  21 + end
  22 + end
11 23 end
... ...
app/controllers/users_groups_controller.rb
... ... @@ -19,11 +19,14 @@ class UsersGroupsController &lt; ApplicationController
19 19  
20 20 def destroy
21 21 @users_group = @group.users_groups.find(params[:id])
22   - @users_group.destroy
23   -
24   - respond_to do |format|
25   - format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' }
26   - format.js { render nothing: true }
  22 + if can?(current_user, :destroy, @users_group) # May fail if last owner.
  23 + @users_group.destroy
  24 + respond_to do |format|
  25 + format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' }
  26 + format.js { render nothing: true }
  27 + end
  28 + else
  29 + return render_403
27 30 end
28 31 end
29 32  
... ...
app/helpers/application_helper.rb
... ... @@ -49,6 +49,15 @@ module ApplicationHelper
49 49 args.any? { |v| v.to_s.downcase == action_name }
50 50 end
51 51  
  52 + def group_icon(group_path)
  53 + group = Group.find_by(path: group_path)
  54 + if group && group.avatar.present?
  55 + group.avatar.url
  56 + else
  57 + '/assets/no_group_avatar.png'
  58 + end
  59 + end
  60 +
52 61 def avatar_icon(user_email = '', size = nil)
53 62 user = User.find_by(email: user_email)
54 63 if user && user.avatar.present?
... ... @@ -153,15 +162,6 @@ module ApplicationHelper
153 162  
154 163 alias_method :url_to_image, :image_url
155 164  
156   - def users_select_tag(id, opts = {})
157   - css_class = "ajax-users-select "
158   - css_class << "multiselect " if opts[:multiple]
159   - css_class << (opts[:class] || '')
160   - value = opts[:selected] || ''
161   -
162   - hidden_field_tag(id, value, class: css_class)
163   - end
164   -
165 165 def body_data_page
166 166 path = controller.controller_path.split('/')
167 167 namespace = path.first if path.second
... ... @@ -203,8 +203,14 @@ module ApplicationHelper
203 203 def highlight_js(&block)
204 204 string = capture(&block)
205 205  
206   - content_tag :div, class: user_color_scheme_class do
207   - Pygments::Lexer[:js].highlight(string).html_safe
  206 + content_tag :div, class: "highlighted-data #{user_color_scheme_class}" do
  207 + content_tag :div, class: 'highlight' do
  208 + content_tag :pre do
  209 + content_tag :code do
  210 + string.html_safe
  211 + end
  212 + end
  213 + end
208 214 end
209 215 end
210 216  
... ... @@ -221,4 +227,10 @@ module ApplicationHelper
221 227 def render_markup(file_name, file_content)
222 228 GitHub::Markup.render(file_name, file_content).html_safe
223 229 end
  230 +
  231 + def spinner(text = nil)
  232 + content_tag :div, class: 'loading hide' do
  233 + content_tag(:i, nil, class: 'icon-spinner icon-spin') + text
  234 + end
  235 + end
224 236 end
... ...
app/helpers/commits_helper.rb
... ... @@ -122,17 +122,18 @@ module CommitsHelper
122 122 def commit_person_link(commit, options = {})
123 123 source_name = commit.send "#{options[:source]}_name".to_sym
124 124 source_email = commit.send "#{options[:source]}_email".to_sym
  125 +
  126 + user = User.find_for_commit(source_email, source_name)
  127 + person_name = user.nil? ? source_name : user.name
  128 + person_email = user.nil? ? source_email : user.email
  129 +
125 130 text = if options[:avatar]
126   - avatar = image_tag(avatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "")
127   - %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{source_name}</span>}
  131 + avatar = image_tag(avatar_icon(person_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "")
  132 + %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{person_name}</span>}
128 133 else
129   - source_name
  134 + person_name
130 135 end
131 136  
132   - # Prefer email match over name match
133   - user = User.where(email: source_email).first
134   - user ||= User.where(name: source_name).first
135   -
136 137 options = {
137 138 class: "commit-#{options[:source]}-link has_tooltip",
138 139 data: { :'original-title' => sanitize(source_email) }
... ...
app/helpers/gitlab_markdown_helper.rb
... ... @@ -28,14 +28,16 @@ module GitlabMarkdownHelper
28 28 link_to(gfm_body.html_safe, url, html_options)
29 29 end
30 30  
31   - def markdown(text)
32   - unless @markdown
33   - gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self,
34   - # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch-
35   - filter_html: true,
36   - with_toc_data: true,
37   - hard_wrap: true,
38   - safe_links_only: true)
  31 + def markdown(text, options={})
  32 + unless (@markdown and options == @options)
  33 + @options = options
  34 + gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self, {
  35 + # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch-
  36 + filter_html: true,
  37 + with_toc_data: true,
  38 + hard_wrap: true,
  39 + safe_links_only: true
  40 + }.merge(options))
39 41 @markdown = Redcarpet::Markdown.new(gitlab_renderer,
40 42 # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
41 43 no_intra_emphasis: true,
... ... @@ -47,7 +49,6 @@ module GitlabMarkdownHelper
47 49 space_after_headers: true,
48 50 superscript: true)
49 51 end
50   -
51 52 @markdown.render(text).html_safe
52 53 end
53 54  
... ... @@ -166,18 +167,27 @@ module GitlabMarkdownHelper
166 167  
167 168 def file_exists?(path)
168 169 return false if path.nil? || path.empty?
169   - File.exists?(path_on_fs(path))
  170 + return @repository.blob_at(current_sha, path).present? || @repository.tree(current_sha, path).entries.any?
170 171 end
171 172  
172 173 # Check if the path is pointing to a directory(tree) or a file(blob)
173 174 # eg. doc/api is directory and doc/README.md is file
174 175 def local_path(path)
175   - File.directory?(path_on_fs(path)) ? "tree" : "blob"
  176 + return "tree" if @repository.tree(current_sha, path).entries.any?
  177 + return "raw" if @repository.blob_at(current_sha, path).image?
  178 + return "blob"
  179 + end
  180 +
  181 + def current_ref
  182 + @commit.nil? ? "master" : @commit.id
176 183 end
177 184  
178   - # Path to the file in the satellites repository on the filesystem
179   - def path_on_fs(path)
180   - [@path_to_satellite, path].join("/")
  185 + def current_sha
  186 + if @commit
  187 + @commit.id
  188 + else
  189 + @repository.head_commit.sha
  190 + end
181 191 end
182 192  
183 193 # We will assume that if no ref exists we can point to master
... ...
app/helpers/groups_helper.rb
1 1 module GroupsHelper
2 2 def remove_user_from_group_message(group, user)
3   - "You are going to remove #{user.name} from #{group.name} Group. Are you sure?"
  3 + "Are you sure you want to remove \"#{user.name}\" from \"#{group.name}\"?"
  4 + end
  5 +
  6 + def leave_group_message(group)
  7 + "Are you sure you want to leave \"#{group}\" group?"
4 8 end
5 9  
6 10 def group_head_title
... ...
app/helpers/issues_helper.rb
... ... @@ -70,11 +70,11 @@ module IssuesHelper
70 70 end
71 71  
72 72 def bulk_update_milestone_options
73   - options_for_select(["None (backlog)", nil]) + options_from_collection_for_select(project_active_milestones, "id", "title", params[:milestone_id])
  73 + options_for_select(["None (backlog)"]) + options_from_collection_for_select(project_active_milestones, "id", "title", params[:milestone_id])
74 74 end
75 75  
76 76 def bulk_update_assignee_options
77   - options_for_select(["None (unassigned)", nil]) + options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id])
  77 + options_for_select(["None (unassigned)"]) + options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id])
78 78 end
79 79  
80 80 def assignee_options object
... ... @@ -84,4 +84,12 @@ module IssuesHelper
84 84 def milestone_options object
85 85 options_from_collection_for_select(@project.milestones.active, 'id', 'title', object.milestone_id)
86 86 end
  87 +
  88 + def issue_alert_class(issue)
  89 + if issue.closed?
  90 + 'alert-danger'
  91 + else
  92 + 'alert-success'
  93 + end
  94 + end
87 95 end
... ...
app/helpers/merge_requests_helper.rb
... ... @@ -41,4 +41,14 @@ module MergeRequestsHelper
41 41 "Branches: #{@merge_request.source_branch} #{separator} #{@merge_request.target_branch}"
42 42 end
43 43 end
  44 +
  45 + def merge_request_alert_class(merge_request)
  46 + if merge_request.merged?
  47 + 'alert-info'
  48 + elsif merge_request.closed?
  49 + 'alert-danger'
  50 + else
  51 + 'alert-success'
  52 + end
  53 + end
44 54 end
... ...
app/helpers/notes_helper.rb
... ... @@ -17,7 +17,7 @@ module NotesHelper
17 17  
18 18 def link_to_merge_request_diff_line_note(note)
19 19 if note.for_merge_request_diff_line? and note.diff
20   - 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)
  20 + link_to "#{note.diff_file_name}:L#{note.diff_new_line}", diffs_project_merge_request_path(note.project, note.noteable, anchor: note.line_code)
21 21 end
22 22 end
23 23  
... ...
app/helpers/notifications_helper.rb
1 1 module NotificationsHelper
2 2 def notification_icon(notification)
3 3 if notification.disabled?
4   - content_tag :i, nil, class: 'icon-circle cred'
  4 + content_tag :i, nil, class: 'icon-volume-off cred'
5 5 elsif notification.participating?
6   - content_tag :i, nil, class: 'icon-circle cblue'
  6 + content_tag :i, nil, class: 'icon-volume-down cblue'
7 7 elsif notification.watch?
8   - content_tag :i, nil, class: 'icon-circle cgreen'
  8 + content_tag :i, nil, class: 'icon-volume-up cgreen'
9 9 else
10 10 content_tag :i, nil, class: 'icon-circle-blank cblue'
11 11 end
... ...
app/helpers/projects_helper.rb
... ... @@ -64,6 +64,31 @@ module ProjectsHelper
64 64 project_nav_tabs.include? name
65 65 end
66 66  
  67 + def selected_label?(label_name)
  68 + params[:label_name].to_s.split(',').include?(label_name)
  69 + end
  70 +
  71 + def labels_filter_path(label_name)
  72 + label_name =
  73 + if selected_label?(label_name)
  74 + params[:label_name].split(',').reject { |l| l == label_name }.join(',')
  75 + elsif params[:label_name].present?
  76 + "#{params[:label_name]},#{label_name}"
  77 + else
  78 + label_name
  79 + end
  80 +
  81 + project_filter_path(label_name: label_name)
  82 + end
  83 +
  84 + def label_filter_class(label_name)
  85 + if selected_label?(label_name)
  86 + 'label-filter-item active'
  87 + else
  88 + 'label-filter-item light'
  89 + end
  90 + end
  91 +
67 92 def project_filter_path(options={})
68 93 exist_opts = {
69 94 state: params[:state],
... ...
app/helpers/selects_helper.rb 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +module SelectsHelper
  2 + def users_select_tag(id, opts = {})
  3 + css_class = "ajax-users-select "
  4 + css_class << "multiselect " if opts[:multiple]
  5 + css_class << (opts[:class] || '')
  6 + value = opts[:selected] || ''
  7 +
  8 + hidden_field_tag(id, value, class: css_class)
  9 + end
  10 +
  11 + def project_users_select_tag(id, opts = {})
  12 + css_class = "ajax-project-users-select "
  13 + css_class << "multiselect " if opts[:multiple]
  14 + css_class << (opts[:class] || '')
  15 + value = opts[:selected] || ''
  16 + placeholder = opts[:placeholder] || 'Select user'
  17 +
  18 + hidden_field_tag(id, value, class: css_class, 'data-placeholder' => placeholder)
  19 + end
  20 +end
... ...
app/helpers/submodule_helper.rb 0 → 100644
... ... @@ -0,0 +1,43 @@
  1 +module SubmoduleHelper
  2 + include Gitlab::ShellAdapter
  3 +
  4 + # links to files listing for submodule if submodule is a project on this server
  5 + def submodule_links(submodule_item)
  6 + url = @repository.submodule_url_for(@ref, submodule_item.path)
  7 +
  8 + return url, nil unless url =~ /([^\/:]+\/[^\/]+\.git)\Z/
  9 +
  10 + project = $1
  11 + project.chomp!('.git')
  12 +
  13 + if self_url?(url, project)
  14 + return project_path(project), project_tree_path(project, submodule_item.id)
  15 + elsif github_dot_com_url?(url)
  16 + standard_links('github.com', project, submodule_item.id)
  17 + elsif gitlab_dot_com_url?(url)
  18 + standard_links('gitlab.com', project, submodule_item.id)
  19 + else
  20 + return url, nil
  21 + end
  22 + end
  23 +
  24 + protected
  25 +
  26 + def github_dot_com_url?(url)
  27 + url =~ /github\.com[\/:][^\/]+\/[^\/]+\Z/
  28 + end
  29 +
  30 + def gitlab_dot_com_url?(url)
  31 + url =~ /gitlab\.com[\/:][^\/]+\/[^\/]+\Z/
  32 + end
  33 +
  34 + def self_url?(url, project)
  35 + return true if url == [ Gitlab.config.gitlab.url, '/', project, '.git' ].join('')
  36 + url == gitlab_shell.url_to_repo(project)
  37 + end
  38 +
  39 + def standard_links(host, project, commit)
  40 + base = [ 'https://', host, '/', project ].join('')
  41 + return base, [ base, '/tree/', commit ].join('')
  42 + end
  43 +end
... ...
app/mailers/emails/profile.rb
... ... @@ -6,6 +6,12 @@ module Emails
6 6 mail(to: @user.email, subject: subject("Account was created for you"))
7 7 end
8 8  
  9 + def new_email_email(email_id)
  10 + @email = Email.find(email_id)
  11 + @user = @email.user
  12 + mail(to: @user.email, subject: subject("Email was added to your account"))
  13 + end
  14 +
9 15 def new_ssh_key_email(key_id)
10 16 @key = Key.find(key_id)
11 17 @user = @key.user
... ...
app/mailers/emails/projects.rb
... ... @@ -17,6 +17,7 @@ module Emails
17 17 def repository_push_email(project_id, recipient, author_id, branch, compare)
18 18 @project = Project.find(project_id)
19 19 @author = User.find(author_id)
  20 + @compare = compare
20 21 @commits = Commit.decorate(compare.commits)
21 22 @diffs = compare.diffs
22 23 @branch = branch
... ...
app/models/ability.rb
... ... @@ -14,6 +14,7 @@ class Ability
14 14 when "MergeRequest" then merge_request_abilities(user, subject)
15 15 when "Group" then group_abilities(user, subject)
16 16 when "Namespace" then namespace_abilities(user, subject)
  17 + when "UsersGroup" then users_group_abilities(user, subject)
17 18 else []
18 19 end.concat(global_abilities(user))
19 20 end
... ... @@ -126,6 +127,7 @@ class Ability
126 127 :write_merge_request,
127 128 :write_wiki,
128 129 :modify_issue,
  130 + :admin_issue,
129 131 :push_code
130 132 ]
131 133 end
... ... @@ -218,5 +220,19 @@ class Ability
218 220 end
219 221 end
220 222 end
  223 +
  224 + def users_group_abilities(user, subject)
  225 + rules = []
  226 + target_user = subject.user
  227 + group = subject.group
  228 + can_manage = group_abilities(user, group).include?(:manage_group)
  229 + if can_manage && (user != target_user)
  230 + rules << :modify
  231 + end
  232 + if !group.last_owner?(user) && (can_manage || (user == target_user))
  233 + rules << :destroy
  234 + end
  235 + rules
  236 + end
221 237 end
222 238 end
... ...
app/models/commit.rb
... ... @@ -16,29 +16,31 @@ class Commit
16 16 DIFF_HARD_LIMIT_FILES = 500
17 17 DIFF_HARD_LIMIT_LINES = 10000
18 18  
19   - def self.decorate(commits)
20   - commits.map { |c| self.new(c) }
21   - end
  19 + class << self
  20 + def decorate(commits)
  21 + commits.map { |c| self.new(c) }
  22 + end
22 23  
23   - # Calculate number of lines to render for diffs
24   - def self.diff_line_count(diffs)
25   - diffs.reduce(0){|sum, d| sum + d.diff.lines.count}
26   - end
  24 + # Calculate number of lines to render for diffs
  25 + def diff_line_count(diffs)
  26 + diffs.reduce(0){|sum, d| sum + d.diff.lines.count}
  27 + end
27 28  
28   - def self.diff_suppress?(diffs, line_count = nil)
29   - # optimize - check file count first
30   - return true if diffs.size > DIFF_SAFE_FILES
  29 + def diff_suppress?(diffs, line_count = nil)
  30 + # optimize - check file count first
  31 + return true if diffs.size > DIFF_SAFE_FILES
31 32  
32   - line_count ||= Commit::diff_line_count(diffs)
33   - line_count > DIFF_SAFE_LINES
34   - end
  33 + line_count ||= Commit::diff_line_count(diffs)
  34 + line_count > DIFF_SAFE_LINES
  35 + end
35 36  
36   - def self.diff_force_suppress?(diffs, line_count = nil)
37   - # optimize - check file count first
38   - return true if diffs.size > DIFF_HARD_LIMIT_FILES
  37 + def diff_force_suppress?(diffs, line_count = nil)
  38 + # optimize - check file count first
  39 + return true if diffs.size > DIFF_HARD_LIMIT_FILES
39 40  
40   - line_count ||= Commit::diff_line_count(diffs)
41   - line_count > DIFF_HARD_LIMIT_LINES
  41 + line_count ||= Commit::diff_line_count(diffs)
  42 + line_count > DIFF_HARD_LIMIT_LINES
  43 + end
42 44 end
43 45  
44 46 attr_accessor :raw
... ...
app/models/concerns/issuable.rb
... ... @@ -48,13 +48,13 @@ module Issuable
48 48  
49 49 def sort(method)
50 50 case method.to_s
51   - when 'newest' then reorder('created_at DESC')
52   - when 'oldest' then reorder('created_at ASC')
53   - when 'recently_updated' then reorder('updated_at DESC')
54   - when 'last_updated' then reorder('updated_at ASC')
  51 + when 'newest' then reorder("#{table_name}.created_at DESC")
  52 + when 'oldest' then reorder("#{table_name}.created_at ASC")
  53 + when 'recently_updated' then reorder("#{table_name}.updated_at DESC")
  54 + when 'last_updated' then reorder("#{table_name}.updated_at ASC")
55 55 when 'milestone_due_soon' then joins(:milestone).reorder("milestones.due_date ASC")
56 56 when 'milestone_due_later' then joins(:milestone).reorder("milestones.due_date DESC")
57   - else reorder('created_at DESC')
  57 + else reorder("#{table_name}.created_at DESC")
58 58 end
59 59 end
60 60 end
... ...
app/models/email.rb 0 → 100644
... ... @@ -0,0 +1,33 @@
  1 +# == Schema Information
  2 +#
  3 +# Table name: emails
  4 +#
  5 +# id :integer not null, primary key
  6 +# user_id :integer not null
  7 +# email :string not null
  8 +# created_at :datetime not null
  9 +class Email < ActiveRecord::Base
  10 + attr_accessible :email, :user_id
  11 +
  12 + #
  13 + # Relations
  14 + #
  15 + belongs_to :user
  16 +
  17 + #
  18 + # Validations
  19 + #
  20 + validates :user_id, presence: true
  21 + validates :email, presence: true, email: { strict_mode: true }, uniqueness: true
  22 + validate :unique_email, if: ->(email) { email.email_changed? }
  23 +
  24 + before_validation :cleanup_email
  25 +
  26 + def cleanup_email
  27 + self.email = self.email.downcase.strip
  28 + end
  29 +
  30 + def unique_email
  31 + self.errors.add(:email, 'has already been taken') if User.exists?(email: self.email)
  32 + end
  33 +end
0 34 \ No newline at end of file
... ...
app/models/gollum_wiki.rb
1 1 class GollumWiki
  2 + include Gitlab::ShellAdapter
2 3  
3 4 MARKUPS = {
4 5 "Markdown" => :markdown,
... ... @@ -113,10 +114,6 @@ class GollumWiki
113 114 "#{@user.username} #{action} page: #{title}"
114 115 end
115 116  
116   - def gitlab_shell
117   - @gitlab_shell ||= Gitlab::Shell.new
118   - end
119   -
120 117 def path_to_repo
121 118 @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git")
122 119 end
... ...
app/models/group.rb
... ... @@ -12,10 +12,20 @@
12 12 # description :string(255) default(""), not null
13 13 #
14 14  
  15 +require 'carrierwave/orm/activerecord'
  16 +require 'file_size_validator'
  17 +
15 18 class Group < Namespace
16 19 has_many :users_groups, dependent: :destroy
17 20 has_many :users, through: :users_groups
18 21  
  22 + attr_accessible :avatar
  23 +
  24 + validate :avatar_type, if: ->(user) { user.avatar_changed? }
  25 + validates :avatar, file_size: { maximum: 100.kilobytes.to_i }
  26 +
  27 + mount_uploader :avatar, AttachmentUploader
  28 +
19 29 def human_name
20 30 name
21 31 end
... ... @@ -50,4 +60,10 @@ class Group &lt; Namespace
50 60 def members
51 61 users_groups
52 62 end
  63 +
  64 + def avatar_type
  65 + unless self.avatar.image?
  66 + self.errors.add :avatar, "only images allowed"
  67 + end
  68 + end
53 69 end
... ...
app/models/merge_request.rb
... ... @@ -32,7 +32,9 @@ class MergeRequest &lt; ActiveRecord::Base
32 32 belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project"
33 33  
34 34 has_one :merge_request_diff, dependent: :destroy
  35 +
35 36 after_create :create_merge_request_diff
  37 + after_update :update_merge_request_diff
36 38  
37 39 delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil
38 40  
... ... @@ -125,6 +127,13 @@ class MergeRequest &lt; ActiveRecord::Base
125 127 end
126 128 end
127 129  
  130 + def update_merge_request_diff
  131 + if source_branch_changed? || target_branch_changed?
  132 + reload_code
  133 + mark_as_unchecked
  134 + end
  135 + end
  136 +
128 137 def reload_code
129 138 if merge_request_diff && opened?
130 139 merge_request_diff.reload_content
... ... @@ -219,6 +228,14 @@ class MergeRequest &lt; ActiveRecord::Base
219 228 end
220 229 end
221 230  
  231 + def source_project_namespace
  232 + if source_project && source_project.namespace
  233 + source_project.namespace.path
  234 + else
  235 + "(removed)"
  236 + end
  237 + end
  238 +
222 239 def source_branch_exists?
223 240 return false unless self.source_project
224 241  
... ... @@ -253,4 +270,24 @@ class MergeRequest &lt; ActiveRecord::Base
253 270 message << description.to_s
254 271 message
255 272 end
  273 +
  274 + # Return array of possible target branches
  275 + # dependes on target project of MR
  276 + def target_branches
  277 + if target_project.nil?
  278 + []
  279 + else
  280 + target_project.repository.branch_names
  281 + end
  282 + end
  283 +
  284 + # Return array of possible source branches
  285 + # dependes on source project of MR
  286 + def source_branches
  287 + if source_project.nil?
  288 + []
  289 + else
  290 + source_project.repository.branch_names
  291 + end
  292 + end
256 293 end
... ...
app/models/merge_request_diff.rb
... ... @@ -148,13 +148,11 @@ class MergeRequestDiff &lt; ActiveRecord::Base
148 148 Gitlab::Git::Diff.between(repository, source_branch, target_branch)
149 149 end
150 150  
151   - if diffs == broken_diffs
152   - self.state = :timeout
153   - diffs = []
154   - end
155   -
156 151 diffs ||= []
157 152 diffs
  153 + rescue Gitlab::Git::Diff::TimeoutError => ex
  154 + self.state = :timeout
  155 + diffs = []
158 156 end
159 157  
160 158 def repository
... ...
app/models/namespace.rb
... ... @@ -10,6 +10,7 @@
10 10 # updated_at :datetime not null
11 11 # type :string(255)
12 12 # description :string(255) default(""), not null
  13 +# avatar :string(255)
13 14 #
14 15  
15 16 class Namespace < ActiveRecord::Base
... ... @@ -26,7 +27,7 @@ class Namespace &lt; ActiveRecord::Base
26 27 format: { with: Gitlab::Regex.name_regex,
27 28 message: "only letters, digits, spaces & '_' '-' '.' allowed." }
28 29 validates :description, length: { within: 0..255 }
29   - validates :path, uniqueness: true, presence: true, length: { within: 1..255 },
  30 + validates :path, uniqueness: { case_sensitive: false }, presence: true, length: { within: 1..255 },
30 31 exclusion: { in: Gitlab::Blacklist.path },
31 32 format: { with: Gitlab::Regex.path_regex,
32 33 message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
... ...
app/models/note.rb
... ... @@ -72,14 +72,20 @@ class Note &lt; ActiveRecord::Base
72 72 # +noteable+ was referenced from +mentioner+, by including GFM in either +mentioner+'s description or an associated Note.
73 73 # Create a system Note associated with +noteable+ with a GFM back-reference to +mentioner+.
74 74 def create_cross_reference_note(noteable, mentioner, author, project)
75   - create({
76   - noteable: noteable,
77   - commit_id: (noteable.sha if noteable.respond_to? :sha),
  75 + note_options = {
78 76 project: project,
79 77 author: author,
80 78 note: "_mentioned in #{mentioner.gfm_reference}_",
81 79 system: true
82   - }, without_protection: true)
  80 + }
  81 +
  82 + if noteable.kind_of?(Commit)
  83 + note_options.merge!(noteable_type: 'Commit', commit_id: noteable.id)
  84 + else
  85 + note_options.merge!(noteable: noteable)
  86 + end
  87 +
  88 + create(note_options, without_protection: true)
83 89 end
84 90  
85 91 def create_assignee_change_note(noteable, project, author, assignee)
... ...
app/models/notification.rb
... ... @@ -9,12 +9,23 @@ class Notification
9 9  
10 10 attr_accessor :target
11 11  
12   - def self.notification_levels
13   - [N_DISABLED, N_PARTICIPATING, N_WATCH]
14   - end
15   -
16   - def self.project_notification_levels
17   - [N_DISABLED, N_PARTICIPATING, N_WATCH, N_GLOBAL]
  12 + class << self
  13 + def notification_levels
  14 + [N_DISABLED, N_PARTICIPATING, N_WATCH]
  15 + end
  16 +
  17 + def options_with_labels
  18 + {
  19 + disabled: N_DISABLED,
  20 + participating: N_PARTICIPATING,
  21 + watch: N_WATCH,
  22 + global: N_GLOBAL
  23 + }
  24 + end
  25 +
  26 + def project_notification_levels
  27 + [N_DISABLED, N_PARTICIPATING, N_WATCH, N_GLOBAL]
  28 + end
18 29 end
19 30  
20 31 def initialize(target)
... ... @@ -36,4 +47,8 @@ class Notification
36 47 def global?
37 48 target.notification_level == N_GLOBAL
38 49 end
  50 +
  51 + def level
  52 + target.notification_level
  53 + end
39 54 end
... ...
app/models/project_services/hipchat_service.rb
... ... @@ -40,7 +40,7 @@ class HipchatService &lt; Service
40 40 end
41 41  
42 42 def execute(push_data)
43   - gate[room].send('Gitlab', create_message(push_data))
  43 + gate[room].send('GitLab', create_message(push_data))
44 44 end
45 45  
46 46 private
... ...
app/models/repository.rb
... ... @@ -57,7 +57,7 @@ class Repository
57 57  
58 58 def recent_branches(limit = 20)
59 59 branches.sort do |a, b|
60   - b.commit.committed_date <=> a.commit.committed_date
  60 + commit(b.target).committed_date <=> commit(a.target).committed_date
61 61 end[0..limit]
62 62 end
63 63  
... ... @@ -163,7 +163,49 @@ class Repository
163 163  
164 164 def readme
165 165 Rails.cache.fetch(cache_key(:readme)) do
166   - Tree.new(self, self.root_ref).readme
  166 + tree(:head).readme
167 167 end
168 168 end
  169 +
  170 + def head_commit
  171 + commit(self.root_ref)
  172 + end
  173 +
  174 + def tree(sha = :head, path = nil)
  175 + if sha == :head
  176 + sha = head_commit.sha
  177 + end
  178 +
  179 + Tree.new(self, sha, path)
  180 + end
  181 +
  182 + def blob_at_branch(branch_name, path)
  183 + last_commit = commit(branch_name)
  184 +
  185 + if last_commit
  186 + blob_at(last_commit.sha, path)
  187 + else
  188 + nil
  189 + end
  190 + end
  191 +
  192 + # Returns url for submodule
  193 + #
  194 + # Ex.
  195 + # @repository.submodule_url_for('master', 'rack')
  196 + # # => git@localhost:rack.git
  197 + #
  198 + def submodule_url_for(ref, path)
  199 + if submodules.any?
  200 + submodule = submodules(ref)[path]
  201 +
  202 + if submodule
  203 + submodule['url']
  204 + end
  205 + end
  206 + end
  207 +
  208 + def last_commit_for_path(sha, path)
  209 + commits(sha, path, 1).last
  210 + end
169 211 end
... ...
app/models/tree.rb
... ... @@ -23,4 +23,8 @@ class Tree
23 23 def submodules
24 24 @entries.select(&:submodule?)
25 25 end
  26 +
  27 + def sorted_entries
  28 + trees + blobs + submodules
  29 + end
26 30 end
... ...
app/models/user.rb
... ... @@ -78,6 +78,7 @@ class User &lt; ActiveRecord::Base
78 78  
79 79 # Profile
80 80 has_many :keys, dependent: :destroy
  81 + has_many :emails, dependent: :destroy
81 82  
82 83 # Groups
83 84 has_many :users_groups, dependent: :destroy
... ... @@ -108,7 +109,7 @@ class User &lt; ActiveRecord::Base
108 109 validates :bio, length: { maximum: 255 }, allow_blank: true
109 110 validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider}
110 111 validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0}
111   - validates :username, presence: true, uniqueness: true,
  112 + validates :username, presence: true, uniqueness: { case_sensitive: false },
112 113 exclusion: { in: Gitlab::Blacklist.path },
113 114 format: { with: Gitlab::Regex.username_regex,
114 115 message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
... ... @@ -116,6 +117,7 @@ class User &lt; ActiveRecord::Base
116 117 validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true
117 118 validate :namespace_uniq, if: ->(user) { user.username_changed? }
118 119 validate :avatar_type, if: ->(user) { user.avatar_changed? }
  120 + validate :unique_email, if: ->(user) { user.email_changed? }
119 121 validates :avatar, file_size: { maximum: 100.kilobytes.to_i }
120 122  
121 123 before_validation :generate_password, on: :create
... ... @@ -183,6 +185,13 @@ class User &lt; ActiveRecord::Base
183 185 where(conditions).first
184 186 end
185 187 end
  188 +
  189 + def find_for_commit(email, name)
  190 + # Prefer email match over name match
  191 + User.where(email: email).first ||
  192 + User.joins(:emails).where(emails: { email: email }).first ||
  193 + User.where(name: name).first
  194 + end
186 195  
187 196 def filter filter_name
188 197 case filter_name
... ... @@ -250,6 +259,10 @@ class User &lt; ActiveRecord::Base
250 259 end
251 260 end
252 261  
  262 + def unique_email
  263 + self.errors.add(:email, 'has already been taken') if Email.exists?(email: self.email)
  264 + end
  265 +
253 266 # Groups user has access to
254 267 def authorized_groups
255 268 @authorized_groups ||= begin
... ... @@ -435,4 +448,8 @@ class User &lt; ActiveRecord::Base
435 448 def short_website_url
436 449 website_url.gsub(/https?:\/\//, '')
437 450 end
  451 +
  452 + def all_ssh_keys
  453 + keys.map(&:key)
  454 + end
438 455 end
... ...
app/observers/email_observer.rb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +class EmailObserver < BaseObserver
  2 + def after_create(email)
  3 + notification.new_email(email)
  4 + end
  5 +end
... ...