Commit 73e00301 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'master' into admin-edit-identities

Signed-off-by: default avatarDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>

Conflicts:
	app/views/admin/users/show.html.haml
parents 3fe3cbf2 cc9b5c49
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 7.13.0 (unreleased) v 7.13.0 (unreleased)
- Update maintenance documentation to explain no need to recompile asssets for omnibus installations (Stan Hu)
- Support commenting on diffs in side-by-side mode (Stan Hu) - Support commenting on diffs in side-by-side mode (Stan Hu)
- Fix JavaScript error when clicking on the comment button on a diff line that has a comment already (Stan Hu) - Fix JavaScript error when clicking on the comment button on a diff line that has a comment already (Stan Hu)
- Remove project visibility icons from dashboard projects list - Remove project visibility icons from dashboard projects list
...@@ -8,8 +9,12 @@ v 7.13.0 (unreleased) ...@@ -8,8 +9,12 @@ v 7.13.0 (unreleased)
- Allow users to customize their default Dashboard page. - Allow users to customize their default Dashboard page.
- Update ssl_ciphers in Nginx example to remove DHE settings. This will deny forward secrecy for Android 2.3.7, Java 6 and OpenSSL 0.9.8 - Update ssl_ciphers in Nginx example to remove DHE settings. This will deny forward secrecy for Android 2.3.7, Java 6 and OpenSSL 0.9.8
- Admin can edit and remove user identities - Admin can edit and remove user identities
- Convert CRLF newlines to LF when committing using the web editor.
- API request /projects/:project_id/merge_requests?state=closed will return only closed merge requests without merged one. If you need ones that were merged - use state=merged.
v 7.12.0 (unreleased) v 7.12.0 (unreleased)
- Fix Error 500 when one user attempts to access a personal, internal snippet (Stan Hu)
- Disable changing of target branch in new merge request page when a branch has already been specified (Stan Hu)
- Fix post-receive errors on a push when an external issue tracker is configured (Stan Hu) - Fix post-receive errors on a push when an external issue tracker is configured (Stan Hu)
- Update oauth button logos for Twitter and Google to recommended assets - Update oauth button logos for Twitter and Google to recommended assets
- Fix hooks for web based events with external issue references (Daniel Gerhardt) - Fix hooks for web based events with external issue references (Daniel Gerhardt)
...@@ -48,8 +53,8 @@ v 7.12.0 (unreleased) ...@@ -48,8 +53,8 @@ v 7.12.0 (unreleased)
- Add validation to wiki page creation (only [a-zA-Z0-9/_-] are allowed) (Jeroen van Baarsen) - Add validation to wiki page creation (only [a-zA-Z0-9/_-] are allowed) (Jeroen van Baarsen)
- Fix new/empty milestones showing 100% completion value (Jonah Bishop) - Fix new/empty milestones showing 100% completion value (Jonah Bishop)
- Add a note when an Issue or Merge Request's title changes - Add a note when an Issue or Merge Request's title changes
- Consistently refer to MRs as either Accepted or Rejected. - Consistently refer to MRs as either Merged or Closed.
- Add Accepted and Rejected tabs to MR lists. - Add Merged tab to MR lists.
- Prefix EmailsOnPush email subject with `[Git]`. - Prefix EmailsOnPush email subject with `[Git]`.
- Group project contributions by both name and email. - Group project contributions by both name and email.
- Clarify navigation labels for Project Settings and Group Settings. - Clarify navigation labels for Project Settings and Group Settings.
...@@ -61,7 +66,7 @@ v 7.12.0 (unreleased) ...@@ -61,7 +66,7 @@ v 7.12.0 (unreleased)
- Allow to configure a URL to show after sign out - Allow to configure a URL to show after sign out
- Add an option to automatically sign-in with an Omniauth provider - Add an option to automatically sign-in with an Omniauth provider
- Better performance for web editor (switched from satellites to rugged) - Better performance for web editor (switched from satellites to rugged)
- GitLab CI service sends .gitlab-ci.yaml in each push call - GitLab CI service sends .gitlab-ci.yml in each push call
- When remove project - move repository and schedule it removal - When remove project - move repository and schedule it removal
- Improve group removing logic - Improve group removing logic
- Trigger create-hooks on backup restore task - Trigger create-hooks on backup restore task
......
...@@ -167,15 +167,17 @@ If you add a dependency in GitLab (such as an operating system package) please c ...@@ -167,15 +167,17 @@ If you add a dependency in GitLab (such as an operating system package) please c
This is also the style used by linting tools such as [RuboCop](https://github.com/bbatsov/rubocop), [PullReview](https://www.pullreview.com/) and [Hound CI](https://houndci.com). This is also the style used by linting tools such as [RuboCop](https://github.com/bbatsov/rubocop), [PullReview](https://www.pullreview.com/) and [Hound CI](https://houndci.com).
## Code of conduct ## Code of conduct
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion. We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
Instances of abusive, harassing, or otherwise unacceptable behavior can be This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
reported by emailing contact@gitlab.com
Instances of abusive, harassing, or otherwise unacceptable behavior can be reported by emailing contact@gitlab.com
This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/) This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.1.0, available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/)
\ No newline at end of file
...@@ -34,7 +34,7 @@ gem "browser", '~> 0.8.0' ...@@ -34,7 +34,7 @@ gem "browser", '~> 0.8.0'
# Extracting information from a git repository # Extracting information from a git repository
# Provide access to Gitlab::Git library # Provide access to Gitlab::Git library
gem "gitlab_git", '~> 7.2.3' gem "gitlab_git", '~> 7.2.5'
# Ruby/Rack Git Smart-HTTP Server Handler # Ruby/Rack Git Smart-HTTP Server Handler
# GitLab fork with a lot of changes (improved thread-safety, better memory usage etc) # GitLab fork with a lot of changes (improved thread-safety, better memory usage etc)
...@@ -222,16 +222,16 @@ group :development do ...@@ -222,16 +222,16 @@ group :development do
end end
group :development, :test do group :development, :test do
gem 'awesome_print'
gem 'byebug'
gem 'pry-rails'
gem 'coveralls', require: false gem 'coveralls', require: false
gem 'database_cleaner', '~> 1.4.0'
gem 'factory_girl_rails'
gem 'rspec-rails', '~> 3.3.0'
gem 'rubocop', '0.28.0', require: false gem 'rubocop', '0.28.0', require: false
gem 'spinach-rails' gem 'spinach-rails'
gem "rspec-rails", '2.99'
gem 'capybara', '~> 2.2.1'
gem 'capybara-screenshot', '~> 1.0.0'
gem "pry-rails"
gem "awesome_print"
gem "database_cleaner"
gem 'factory_girl_rails'
# Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826) # Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826)
gem 'minitest', '~> 5.3.0' gem 'minitest', '~> 5.3.0'
...@@ -239,8 +239,9 @@ group :development, :test do ...@@ -239,8 +239,9 @@ group :development, :test do
# Generate Fake data # Generate Fake data
gem 'ffaker', '~> 2.0.0' gem 'ffaker', '~> 2.0.0'
# PhantomJS driver for Capybara gem 'capybara', '~> 2.3.0'
gem 'poltergeist', '~> 1.5.1' gem 'capybara-screenshot', '~> 1.0.0'
gem 'poltergeist', '~> 1.6.0'
gem 'teaspoon', '~> 1.0.0' gem 'teaspoon', '~> 1.0.0'
gem 'teaspoon-jasmine' gem 'teaspoon-jasmine'
...@@ -249,14 +250,12 @@ group :development, :test do ...@@ -249,14 +250,12 @@ group :development, :test do
gem 'spring-commands-rspec', '~> 1.0.0' gem 'spring-commands-rspec', '~> 1.0.0'
gem 'spring-commands-spinach', '~> 1.0.0' gem 'spring-commands-spinach', '~> 1.0.0'
gem 'spring-commands-teaspoon', '~> 0.0.2' gem 'spring-commands-teaspoon', '~> 0.0.2'
gem "byebug"
end end
group :test do group :test do
gem 'simplecov', require: false gem 'simplecov', require: false
gem 'shoulda-matchers', '~> 2.8.0', require: false gem 'shoulda-matchers', '~> 2.8.0', require: false
gem 'email_spec' gem 'email_spec', '~> 1.6.0'
gem 'webmock', '~> 1.21.0' gem 'webmock', '~> 1.21.0'
gem 'test_after_commit' gem 'test_after_commit'
end end
......
...@@ -82,7 +82,7 @@ GEM ...@@ -82,7 +82,7 @@ GEM
columnize (~> 0.8) columnize (~> 0.8)
debugger-linecache (~> 1.2) debugger-linecache (~> 1.2)
cal-heatmap-rails (0.0.1) cal-heatmap-rails (0.0.1)
capybara (2.2.1) capybara (2.3.0)
mime-types (>= 1.16) mime-types (>= 1.16)
nokogiri (>= 1.3.3) nokogiri (>= 1.3.3)
rack (>= 1.0.0) rack (>= 1.0.0)
...@@ -125,7 +125,7 @@ GEM ...@@ -125,7 +125,7 @@ GEM
d3_rails (3.5.5) d3_rails (3.5.5)
railties (>= 3.1.0) railties (>= 3.1.0)
daemons (1.1.9) daemons (1.1.9)
database_cleaner (1.3.0) database_cleaner (1.4.1)
debug_inspector (0.0.2) debug_inspector (0.0.2)
debugger-linecache (1.2.0) debugger-linecache (1.2.0)
default_value_for (3.0.0) default_value_for (3.0.0)
...@@ -154,7 +154,7 @@ GEM ...@@ -154,7 +154,7 @@ GEM
dotenv (0.9.0) dotenv (0.9.0)
dropzonejs-rails (0.4.14) dropzonejs-rails (0.4.14)
rails (> 3.1) rails (> 3.1)
email_spec (1.5.0) email_spec (1.6.0)
launchy (~> 2.1) launchy (~> 2.1)
mail (~> 2.2) mail (~> 2.2)
encryptor (1.3.0) encryptor (1.3.0)
...@@ -266,7 +266,7 @@ GEM ...@@ -266,7 +266,7 @@ GEM
mime-types (~> 1.19) mime-types (~> 1.19)
gitlab_emoji (0.1.0) gitlab_emoji (0.1.0)
gemojione (~> 2.0) gemojione (~> 2.0)
gitlab_git (7.2.3) gitlab_git (7.2.5)
activesupport (~> 4.0) activesupport (~> 4.0)
charlock_holmes (~> 0.6) charlock_holmes (~> 0.6)
gitlab-linguist (~> 3.0) gitlab-linguist (~> 3.0)
...@@ -348,7 +348,7 @@ GEM ...@@ -348,7 +348,7 @@ GEM
actionpack (>= 3.0.0) actionpack (>= 3.0.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
kgio (2.9.2) kgio (2.9.2)
launchy (2.4.2) launchy (2.4.3)
addressable (~> 2.3) addressable (~> 2.3)
letter_opener (1.1.2) letter_opener (1.1.2)
launchy (~> 2.2) launchy (~> 2.2)
...@@ -431,8 +431,8 @@ GEM ...@@ -431,8 +431,8 @@ GEM
orm_adapter (0.5.0) orm_adapter (0.5.0)
parser (2.2.0.2) parser (2.2.0.2)
ast (>= 1.1, < 3.0) ast (>= 1.1, < 3.0)
pg (0.15.1) pg (0.18.2)
poltergeist (1.5.1) poltergeist (1.6.0)
capybara (~> 2.1) capybara (~> 2.1)
cliver (~> 0.3.1) cliver (~> 0.3.1)
multi_json (~> 1.0) multi_json (~> 1.0)
...@@ -449,7 +449,7 @@ GEM ...@@ -449,7 +449,7 @@ GEM
quiet_assets (1.0.2) quiet_assets (1.0.2)
railties (>= 3.1, < 5.0) railties (>= 3.1, < 5.0)
racc (1.4.10) racc (1.4.10)
rack (1.5.4) rack (1.5.5)
rack-accept (0.4.5) rack-accept (0.4.5)
rack (>= 0.4) rack (>= 0.4)
rack-attack (4.3.0) rack-attack (4.3.0)
...@@ -530,21 +530,23 @@ GEM ...@@ -530,21 +530,23 @@ GEM
rqrcode (0.4.2) rqrcode (0.4.2)
rqrcode-rails3 (0.1.7) rqrcode-rails3 (0.1.7)
rqrcode (>= 0.4.2) rqrcode (>= 0.4.2)
rspec-collection_matchers (1.1.2) rspec-core (3.3.1)
rspec-expectations (>= 2.99.0.beta1) rspec-support (~> 3.3.0)
rspec-core (2.99.2) rspec-expectations (3.3.0)
rspec-expectations (2.99.2) diff-lcs (>= 1.2.0, < 2.0)
diff-lcs (>= 1.1.3, < 2.0) rspec-support (~> 3.3.0)
rspec-mocks (2.99.3) rspec-mocks (3.3.0)
rspec-rails (2.99.0) diff-lcs (>= 1.2.0, < 2.0)
actionpack (>= 3.0) rspec-support (~> 3.3.0)
activemodel (>= 3.0) rspec-rails (3.3.2)
activesupport (>= 3.0) actionpack (>= 3.0, < 4.3)
railties (>= 3.0) activesupport (>= 3.0, < 4.3)
rspec-collection_matchers railties (>= 3.0, < 4.3)
rspec-core (~> 2.99.0) rspec-core (~> 3.3.0)
rspec-expectations (~> 2.99.0) rspec-expectations (~> 3.3.0)
rspec-mocks (~> 2.99.0) rspec-mocks (~> 3.3.0)
rspec-support (~> 3.3.0)
rspec-support (3.3.0)
rubocop (0.28.0) rubocop (0.28.0)
astrolabe (~> 1.3) astrolabe (~> 1.3)
parser (>= 2.2.0.pre.7, < 3.0) parser (>= 2.2.0.pre.7, < 3.0)
...@@ -707,7 +709,9 @@ GEM ...@@ -707,7 +709,9 @@ GEM
webmock (1.21.0) webmock (1.21.0)
addressable (>= 2.3.6) addressable (>= 2.3.6)
crack (>= 0.3.2) crack (>= 0.3.2)
websocket-driver (0.3.3) websocket-driver (0.5.4)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2)
wikicloth (0.8.1) wikicloth (0.8.1)
builder builder
expression_parser expression_parser
...@@ -735,7 +739,7 @@ DEPENDENCIES ...@@ -735,7 +739,7 @@ DEPENDENCIES
browser (~> 0.8.0) browser (~> 0.8.0)
byebug byebug
cal-heatmap-rails (~> 0.0.1) cal-heatmap-rails (~> 0.0.1)
capybara (~> 2.2.1) capybara (~> 2.3.0)
capybara-screenshot (~> 1.0.0) capybara-screenshot (~> 1.0.0)
carrierwave carrierwave
charlock_holmes charlock_holmes
...@@ -744,7 +748,7 @@ DEPENDENCIES ...@@ -744,7 +748,7 @@ DEPENDENCIES
coveralls coveralls
creole (~> 0.3.6) creole (~> 0.3.6)
d3_rails (~> 3.5.5) d3_rails (~> 3.5.5)
database_cleaner database_cleaner (~> 1.4.0)
default_value_for (~> 3.0.0) default_value_for (~> 3.0.0)
devise (= 3.2.4) devise (= 3.2.4)
devise-async (= 0.9.0) devise-async (= 0.9.0)
...@@ -752,7 +756,7 @@ DEPENDENCIES ...@@ -752,7 +756,7 @@ DEPENDENCIES
diffy (~> 3.0.3) diffy (~> 3.0.3)
doorkeeper (= 2.1.3) doorkeeper (= 2.1.3)
dropzonejs-rails dropzonejs-rails
email_spec email_spec (~> 1.6.0)
enumerize enumerize
factory_girl_rails factory_girl_rails
ffaker (~> 2.0.0) ffaker (~> 2.0.0)
...@@ -765,7 +769,7 @@ DEPENDENCIES ...@@ -765,7 +769,7 @@ DEPENDENCIES
gitlab-grack (~> 2.0.2) gitlab-grack (~> 2.0.2)
gitlab-linguist (~> 3.0.1) gitlab-linguist (~> 3.0.1)
gitlab_emoji (~> 0.1) gitlab_emoji (~> 0.1)
gitlab_git (~> 7.2.3) gitlab_git (~> 7.2.5)
gitlab_meta (= 7.0) gitlab_meta (= 7.0)
gitlab_omniauth-ldap (= 1.2.1) gitlab_omniauth-ldap (= 1.2.1)
gollum-lib (~> 4.0.2) gollum-lib (~> 4.0.2)
...@@ -800,7 +804,7 @@ DEPENDENCIES ...@@ -800,7 +804,7 @@ DEPENDENCIES
omniauth-twitter omniauth-twitter
org-ruby (= 0.9.12) org-ruby (= 0.9.12)
pg pg
poltergeist (~> 1.5.1) poltergeist (~> 1.6.0)
pry-rails pry-rails
quiet_assets (~> 1.0.1) quiet_assets (~> 1.0.1)
rack-attack (~> 4.3.0) rack-attack (~> 4.3.0)
...@@ -815,7 +819,7 @@ DEPENDENCIES ...@@ -815,7 +819,7 @@ DEPENDENCIES
request_store request_store
rerun (~> 0.10.0) rerun (~> 0.10.0)
rqrcode-rails3 rqrcode-rails3
rspec-rails (= 2.99) rspec-rails (~> 3.3.0)
rubocop (= 0.28.0) rubocop (= 0.28.0)
rugments (~> 1.0.0.beta7) rugments (~> 1.0.0.beta7)
sanitize (~> 2.0) sanitize (~> 2.0)
......
app/assets/images/favicon.ico

32.2 KB | W: | H:

app/assets/images/favicon.ico

5.3 KB | W: | H:

app/assets/images/favicon.ico
app/assets/images/favicon.ico
app/assets/images/favicon.ico
app/assets/images/favicon.ico
  • 2-up
  • Swipe
  • Onion skin
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="210px" height="210px" viewBox="0 0 210 210" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.3.2 (12043) - http://www.bohemiancoding.com/sketch -->
<title>Slice 1</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="logo" sketch:type="MSLayerGroup" transform="translate(0.000000, 10.000000)">
<g id="Page-1" sketch:type="MSShapeGroup">
<g id="Fill-1-+-Group-24">
<g id="Group-24">
<g id="Group">
<path d="M105.0614,193.655 L105.0614,193.655 L143.7014,74.734 L66.4214,74.734 L105.0614,193.655 L105.0614,193.655 Z" id="Fill-4" fill="#E24329"></path>
<path d="M105.0614,193.6548 L66.4214,74.7338 L12.2684,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-8" fill="#FC6D26"></path>
<path d="M12.2685,74.7341 L12.2685,74.7341 L0.5265,110.8731 C-0.5445,114.1691 0.6285,117.7801 3.4325,119.8171 L105.0615,193.6551 L12.2685,74.7341 L12.2685,74.7341 Z" id="Fill-12" fill="#FCA326"></path>
<path d="M12.2685,74.7342 L66.4215,74.7342 L43.1485,3.1092 C41.9515,-0.5768 36.7375,-0.5758 35.5405,3.1092 L12.2685,74.7342 L12.2685,74.7342 Z" id="Fill-16" fill="#E24329"></path>
<path d="M105.0614,193.6548 L143.7014,74.7338 L197.8544,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-18" fill="#FC6D26"></path>
<path d="M197.8544,74.7341 L197.8544,74.7341 L209.5964,110.8731 C210.6674,114.1691 209.4944,117.7801 206.6904,119.8171 L105.0614,193.6551 L197.8544,74.7341 L197.8544,74.7341 Z" id="Fill-20" fill="#FCA326"></path>
<path d="M197.8544,74.7342 L143.7014,74.7342 L166.9744,3.1092 C168.1714,-0.5768 173.3854,-0.5758 174.5824,3.1092 L197.8544,74.7342 L197.8544,74.7342 Z" id="Fill-22" fill="#E24329"></path>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="546px" height="194px" viewBox="0 0 546 194" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.3.2 (12043) - http://www.bohemiancoding.com/sketch -->
<title>Fill 1 + Group 24</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="Fill-1-+-Group-24" sketch:type="MSLayerGroup">
<g id="Group-24" sketch:type="MSShapeGroup">
<path d="M316.7906,65.3001 C301.5016,65.3001 292.0046,77.4461 292.0046,97.0001 C292.0046,116.5541 301.5016,128.7001 316.7906,128.7001 C322.5346,128.7001 327.8716,127.0711 332.2226,123.9881 L332.4336,123.8391 L332.4336,101.8711 L310.4336,101.8711 L310.4336,94.0711 L341.4336,94.0711 L341.4336,126.8061 C334.8706,133.1501 326.3546,136.5001 316.7906,136.5001 C296.2666,136.5001 283.0046,120.9951 283.0046,97.0001 C283.0046,73.0051 296.2666,57.5001 316.7906,57.5001 C326.7826,57.5001 335.2176,61.1481 341.2206,68.0561 L335.2246,73.0381 C330.6986,67.9041 324.4986,65.3001 316.7906,65.3001 L316.7906,65.3001 Z M489.8836,135.2501 L482.9356,135.2501 L480.6016,128.8021 L480.0486,129.2991 C479.9716,129.3681 472.2196,136.2501 462.4606,136.2501 C452.6096,136.2501 445.4606,129.6961 445.4606,120.6671 C445.4606,107.5951 456.7446,104.8511 466.2096,104.8511 C473.5836,104.8511 480.1886,106.5111 480.2546,106.5281 L480.8776,106.6871 L480.8776,105.1011 C480.8776,97.9861 476.4356,94.3781 467.6726,94.3781 C462.3646,94.3781 456.7556,95.6891 451.4236,98.1701 L447.8206,91.9581 C452.5266,88.8961 459.6726,85.3781 467.6726,85.3781 C481.5806,85.3781 489.8836,92.9341 489.8836,105.5891 L489.8836,135.2501 Z M470.6886,111.7771 C460.0716,111.7771 454.4606,114.8511 454.4606,120.6671 C454.4606,124.7281 457.5256,127.2501 462.4606,127.2501 C470.5906,127.2501 477.7276,123.9181 480.6626,121.9481 L480.8836,121.8001 L480.8836,112.6201 L480.4676,112.5491 C480.4226,112.5411 475.8766,111.7771 470.6886,111.7771 L470.6886,111.7771 Z M440.4576,127.4501 L440.4576,135.2501 L410.4606,135.2501 L410.4606,61.2501 L419.4606,61.2501 L419.4606,127.4501 L440.4576,127.4501 Z M520.9416,136.5001 C515.0966,136.5001 508.6886,135.6961 501.8926,134.1091 L501.8926,61.2501 L510.8926,61.2501 L510.8926,89.3131 L511.6656,88.8111 C511.7146,88.7791 516.7346,85.5711 523.6536,85.5711 C525.0336,85.5711 526.4146,85.7001 527.7486,85.9521 C539.0936,88.2761 545.8666,97.4301 545.8666,110.4391 C545.8666,125.7831 535.6176,136.5001 520.9416,136.5001 L520.9416,136.5001 Z M521.9426,94.3781 C518.3636,94.3781 514.6196,95.6031 511.1166,97.9191 L510.8926,98.0681 L510.8926,127.9021 L511.3196,127.9651 C514.6986,128.4601 517.9356,128.7121 520.9416,128.7121 C530.3176,128.7121 536.8666,121.1971 536.8666,110.4391 C536.8666,100.2321 531.4266,94.3781 521.9426,94.3781 L521.9426,94.3781 Z M398.4516,86.2501 L398.4516,94.0501 L383.4516,94.0501 L383.4516,116.9501 C383.4516,119.7551 384.5436,122.3921 386.5276,124.3741 C388.5096,126.3581 391.1466,127.4501 393.9516,127.4501 L398.4516,127.4501 L398.4516,135.2501 L393.9516,135.2501 C383.1996,135.2501 374.4516,126.5021 374.4516,115.7501 L374.4516,61.2501 L383.4516,61.2501 L383.4516,86.2501 L398.4516,86.2501 Z M353.4426,66.2501 L362.4426,66.2501 L362.4426,75.2501 L353.4426,75.2501 L353.4426,66.2501 Z M353.4426,86.2501 L362.4426,86.2501 L362.4426,135.2501 L353.4426,135.2501 L353.4426,86.2501 Z" id="Fill-2" fill="#8C929D"></path>
<g id="Group">
<path d="M105.0614,193.655 L105.0614,193.655 L143.7014,74.734 L66.4214,74.734 L105.0614,193.655 L105.0614,193.655 Z" id="Fill-4" fill="#E24329"></path>
<path id="Fill-6" fill="#FC6D26"></path>
<path d="M105.0614,193.6548 L66.4214,74.7338 L12.2684,74.7338 L105.0614,193.6548 Z" id="Fill-8" fill="#FC6D26"></path>
<path id="Fill-10" fill="#FC6D26"></path>
<path d="M12.2685,74.7341 L12.2685,74.7341 L0.5265,110.8731 C-0.5445,114.1691 0.6285,117.7801 3.4325,119.8171 L105.0615,193.6551 L12.2685,74.7341 Z" id="Fill-12" fill="#FCA326"></path>
<path id="Fill-14" fill="#FC6D26"></path>
<path d="M12.2685,74.7342 L66.4215,74.7342 L43.1485,3.1092 C41.9515,-0.5768 36.7375,-0.5758 35.5405,3.1092 L12.2685,74.7342 Z" id="Fill-16" fill="#E24329"></path>
<path d="M105.0614,193.6548 L143.7014,74.7338 L197.8544,74.7338 L105.0614,193.6548 Z" id="Fill-18" fill="#FC6D26"></path>
<path d="M197.8544,74.7341 L197.8544,74.7341 L209.5964,110.8731 C210.6674,114.1691 209.4944,117.7801 206.6904,119.8171 L105.0614,193.6551 L197.8544,74.7341 Z" id="Fill-20" fill="#FCA326"></path>
<path d="M197.8544,74.7342 L143.7014,74.7342 L166.9744,3.1092 C168.1714,-0.5768 173.3854,-0.5758 174.5824,3.1092 L197.8544,74.7342 Z" id="Fill-22" fill="#E24329"></path>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
...@@ -141,8 +141,7 @@ $ -> ...@@ -141,8 +141,7 @@ $ ->
$('.trigger-submit').on 'change', -> $('.trigger-submit').on 'change', ->
$(@).parents('form').submit() $(@).parents('form').submit()
$("abbr.timeago").timeago() $('abbr.timeago, .js-timeago').timeago()
$('.js-timeago').timeago()
# Flash # Flash
if (flash = $(".flash-container")).length > 0 if (flash = $(".flash-container")).length > 0
......
class @BlobView
constructor: ->
# handle multi-line select
handleMultiSelect = (e) ->
[ first_line, last_line ] = parseSelectedLines()
[ line_number ] = parseSelectedLines($(this).attr("id"))
hash = "L#{line_number}"
if e.shiftKey and not isNaN(first_line) and not isNaN(line_number)
if line_number < first_line
last_line = first_line
first_line = line_number
else
last_line = line_number
hash = if first_line == last_line then "L#{first_line}" else "L#{first_line}-#{last_line}"
setHash(hash)
e.preventDefault()
# See if there are lines selected
# "#L12" and "#L34-56" supported
highlightBlobLines = (e) ->
[ first_line, last_line ] = parseSelectedLines()
unless isNaN first_line
$("#tree-content-holder .highlight .line").removeClass("hll")
$("#LC#{line}").addClass("hll") for line in [first_line..last_line]
$.scrollTo("#L#{first_line}", offset: -50) unless e?
# parse selected lines from hash
# always return first and last line (initialized to NaN)
parseSelectedLines = (str) ->
first_line = NaN
last_line = NaN
hash = str || window.location.hash
if hash isnt ""
matches = hash.match(/\#?L(\d+)(\-(\d+))?/)
first_line = parseInt(matches?[1])
last_line = parseInt(matches?[3])
last_line = first_line if isNaN(last_line)
[ first_line, last_line ]
setHash = (hash) ->
hash = hash.replace(/^\#/, "")
nodes = $("#" + hash)
# if any nodes are using this id, they must be temporarily changed
# also, add a temporary div at the top of the screen to prevent scrolling
if nodes.length > 0
scroll_top = $(document).scrollTop()
nodes.attr("id", "")
tmp = $("<div></div>")
.css({ position: "absolute", visibility: "hidden", top: scroll_top + "px" })
.attr("id", hash)
.appendTo(document.body)
window.location.hash = hash
# restore the nodes
if nodes.length > 0
tmp.remove()
nodes.attr("id", hash)
# initialize multi-line select
$("#tree-content-holder .line-numbers a[id^=L]").on("click", handleMultiSelect)
# Highlight the correct lines on load
highlightBlobLines()
# Highlight the correct lines when the hash part of the URL changes
$(window).on("hashchange", highlightBlobLines)
...@@ -87,7 +87,7 @@ class Dispatcher ...@@ -87,7 +87,7 @@ class Dispatcher
new TreeView() new TreeView()
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
when 'projects:blob:show' when 'projects:blob:show'
new BlobView() new LineHighlighter()
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
when 'projects:labels:new', 'projects:labels:edit' when 'projects:labels:new', 'projects:labels:edit'
new Labels() new Labels()
......
# LineHighlighter
#
# Handles single- and multi-line selection and highlight for blob views.
#
#= require jquery.scrollTo
#
# ### Example Markup
#
# <div id="tree-content-holder">
# <div class="file-content">
# <div class="line-numbers">
# <a href="#L1" id="L1" data-line-number="1">1</a>
# <a href="#L2" id="L2" data-line-number="2">2</a>
# <a href="#L3" id="L3" data-line-number="3">3</a>
# <a href="#L4" id="L4" data-line-number="4">4</a>
# <a href="#L5" id="L5" data-line-number="5">5</a>
# </div>
# <pre class="code highlight">
# <code>
# <span id="LC1" class="line">...</span>
# <span id="LC2" class="line">...</span>
# <span id="LC3" class="line">...</span>
# <span id="LC4" class="line">...</span>
# <span id="LC5" class="line">...</span>
# </code>
# </pre>
# </div>
# </div>
#
class @LineHighlighter
# CSS class applied to highlighted lines
highlightClass: 'hll'
# Internal copy of location.hash so we're not dependent on `location` in tests
_hash: ''
# Initialize a LineHighlighter object
#
# hash - String URL hash for dependency injection in tests
constructor: (hash = location.hash) ->
@_hash = hash
@bindEvents()
unless hash == ''
range = @hashToRange(hash)
if range[0]
@highlightRange(range)
# Scroll to the first highlighted line on initial load
# Offset -50 for the sticky top bar, and another -100 for some context
$.scrollTo("#L#{range[0]}", offset: -150)
bindEvents: ->
$('#tree-content-holder').on 'mousedown', 'a[data-line-number]', @clickHandler
# While it may seem odd to bind to the mousedown event and then throw away
# the click event, there is a method to our madness.
#
# If not done this way, the line number anchor will sometimes keep its
# active state even when the event is cancelled, resulting in an ugly border
# around the link and/or a persisted underline text decoration.
$('#tree-content-holder').on 'click', 'a[data-line-number]', (event) ->
event.preventDefault()
clickHandler: (event) =>
event.preventDefault()
@clearHighlight()
lineNumber = $(event.target).data('line-number')
current = @hashToRange(@_hash)
unless current[0] && event.shiftKey
# If there's no current selection, or there is but Shift wasn't held,
# treat this like a single-line selection.
@setHash(lineNumber)
@highlightLine(lineNumber)
else if event.shiftKey
if lineNumber < current[0]
range = [lineNumber, current[0]]
else
range = [current[0], lineNumber]
@setHash(range[0], range[1])
@highlightRange(range)
# Unhighlight previously highlighted lines
clearHighlight: ->
$(".#{@highlightClass}").removeClass(@highlightClass)
# Convert a URL hash String into line numbers
#
# hash - Hash String
#
# Examples:
#
# hashToRange('#L5') # => [5, null]
# hashToRange('#L5-15') # => [5, 15]
# hashToRange('#foo') # => [null, null]
#
# Returns an Array
hashToRange: (hash) ->
matches = hash.match(/^#?L(\d+)(?:-(\d+))?$/)
if matches && matches.length
first = parseInt(matches[1])
last = if matches[2] then parseInt(matches[2]) else null
[first, last]
else
[null, null]
# Highlight a single line
#
# lineNumber - Line number to highlight
highlightLine: (lineNumber) =>
$("#LC#{lineNumber}").addClass(@highlightClass)
# Highlight all lines within a range
#
# range - Array containing the starting and ending line numbers
highlightRange: (range) ->
if range[1]
for lineNumber in [range[0]..range[1]]
@highlightLine(lineNumber)
else
@highlightLine(range[0])
# Set the URL hash string
setHash: (firstLineNumber, lastLineNumber) =>
if lastLineNumber
hash = "#L#{firstLineNumber}-#{lastLineNumber}"
else
hash = "#L#{firstLineNumber}"
@_hash = hash
@__setLocationHash__(hash)
# Make the actual hash change in the browser
#
# This method is stubbed in tests.
__setLocationHash__: (value) ->
# We're using pushState instead of assigning location.hash directly to
# prevent the page from scrolling on the hashchange event
history.pushState({turbolinks: false, url: value}, document.title, value)
#= require jquery.waitforimages #= require jquery.waitforimages
#= require task_list #= require task_list
#= require merge_request_tabs
class @MergeRequest class @MergeRequest
# Initialize MergeRequest behavior # Initialize MergeRequest behavior
# #
# Options: # Options:
# action - String, current controller action # action - String, current controller action
# diffs_loaded - Boolean, have diffs been pre-rendered server-side?
# (default: true if `action` is 'diffs', otherwise false)
# commits_loaded - Boolean, have commits been pre-rendered server-side?
# (default: false)
# #
constructor: (@opts) -> constructor: (@opts) ->
@initContextWidget() @initContextWidget()
this.$el = $('.merge-request') this.$el = $('.merge-request')
@diffs_loaded = @opts.diffs_loaded or @opts.action == 'diffs'
@commits_loaded = @opts.commits_loaded or false
this.bindEvents()
this.activateTabFromPath()
this.$('.show-all-commits').on 'click', => this.$('.show-all-commits').on 'click', =>
this.showAllCommits() this.showAllCommits()
# `MergeRequests#new` has no tab-persisting or lazy-loading behavior
unless @opts.action == 'new'
new MergeRequestTabs(@opts)
# Prevent duplicate event bindings # Prevent duplicate event bindings
@disableTaskList() @disableTaskList()
...@@ -52,83 +48,6 @@ class @MergeRequest ...@@ -52,83 +48,6 @@ class @MergeRequest
$(".context .inline-update").on "change", "#merge_request_assignee_id", -> $(".context .inline-update").on "change", "#merge_request_assignee_id", ->
$(this).submit() $(this).submit()
bindEvents: ->
this.$('.merge-request-tabs a[data-toggle="tab"]').on 'shown.bs.tab', (e) =>
$target = $(e.target)
tab_action = $target.data('action')
# Lazy-load diffs
if tab_action == 'diffs'
this.loadDiff() unless @diffs_loaded
$('.diff-header').trigger('sticky_kit:recalc')
# Skip tab-persisting behavior on MergeRequests#new
unless @opts.action == 'new'
@setCurrentAction(tab_action)
# Activate a tab based on the current URL path
#
# If the current action is 'show' or 'new' (i.e., initial page load),
# activates the first tab, otherwise activates the tab corresponding to the
# current action (diffs, commits).
activateTabFromPath: ->
if @opts.action == 'show' || @opts.action == 'new'
this.$('.merge-request-tabs a[data-toggle="tab"]:first').tab('show')
else
this.$(".merge-request-tabs a[data-action='#{@opts.action}']").tab('show')
# Replaces the current Merge Request-specific action in the URL with a new one
#
# If the action is "notes", the URL is reset to the standard
# `MergeRequests#show` route.
#
# Examples:
#
# location.pathname # => "/namespace/project/merge_requests/1"
# setCurrentAction('diffs')
# location.pathname # => "/namespace/project/merge_requests/1/diffs"
#
# location.pathname # => "/namespace/project/merge_requests/1/diffs"
# setCurrentAction('notes')
# location.pathname # => "/namespace/project/merge_requests/1"
#
# location.pathname # => "/namespace/project/merge_requests/1/diffs"
# setCurrentAction('commits')
# location.pathname # => "/namespace/project/merge_requests/1/commits"
setCurrentAction: (action) ->
# Normalize action, just to be safe
action = 'notes' if action == 'show'
# Remove a trailing '/commits' or '/diffs'
new_state = location.pathname.replace(/\/(commits|diffs)\/?$/, '')
# Append the new action if we're on a tab other than 'notes'
unless action == 'notes'
new_state += "/#{action}"
# Ensure parameters and hash come along for the ride
new_state += location.search + location.hash
# Replace the current history state with the new one without breaking
# Turbolinks' history.
#
# See https://github.com/rails/turbolinks/issues/363
history.replaceState {turbolinks: true, url: new_state}, '', new_state
loadDiff: (event) ->
$.ajax
type: 'GET'
url: this.$('.merge-request-tabs .diffs-tab a').attr('href') + ".json"
beforeSend: =>
this.$('.mr-loading-status .loading').show()
complete: =>
@diffs_loaded = true
this.$('.mr-loading-status .loading').hide()
success: (data) =>
this.$(".diffs").html(data.html)
dataType: 'json'
showAllCommits: -> showAllCommits: ->
this.$('.first-commits').remove() this.$('.first-commits').remove()
this.$('.all-commits').removeClass 'hide' this.$('.all-commits').removeClass 'hide'
......
# MergeRequestTabs
#
# Handles persisting and restoring the current tab selection and lazily-loading
# content on the MergeRequests#show page.
#
# ### Example Markup
#
# <ul class="nav nav-tabs merge-request-tabs">
# <li class="notes-tab active">
# <a data-action="notes" data-target="#notes" data-toggle="tab" href="/foo/bar/merge_requests/1">
# Discussion
# </a>
# </li>
# <li class="commits-tab">
# <a data-action="commits" data-target="#commits" data-toggle="tab" href="/foo/bar/merge_requests/1/commits">
# Commits
# </a>
# </li>
# <li class="diffs-tab">
# <a data-action="diffs" data-target="#diffs" data-toggle="tab" href="/foo/bar/merge_requests/1/diffs">
# Diffs
# </a>
# </li>
# </ul>
#
# <div class="tab-content">
# <div class="notes tab-pane active" id="notes">
# Notes Content
# </div>
# <div class="commits tab-pane" id="commits">
# Commits Content
# </div>
# <div class="diffs tab-pane" id="diffs">
# Diffs Content
# </div>
# </div>
#
# <div class="mr-loading-status">
# <div class="loading">
# Loading Animation
# </div>
# </div>
#
class @MergeRequestTabs
diffsLoaded: false
commitsLoaded: false
constructor: (@opts = {}) ->
# Store the `location` object, allowing for easier stubbing in tests
@_location = location
@bindEvents()
@activateTab(@opts.action)
switch @opts.action
when 'commits' then @commitsLoaded = true
when 'diffs' then @diffsLoaded = true
bindEvents: ->
$(document).on 'shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', @tabShown
tabShown: (event) =>
$target = $(event.target)
action = $target.data('action')
if action == 'commits'
@loadCommits($target.attr('href'))
else if action == 'diffs'
@loadDiff($target.attr('href'))
@setCurrentAction(action)
# Activate a tab based on the current action
activateTab: (action) ->
action = 'notes' if action == 'show'
$(".merge-request-tabs a[data-action='#{action}']").tab('show')
# Replaces the current Merge Request-specific action in the URL with a new one
#
# If the action is "notes", the URL is reset to the standard
# `MergeRequests#show` route.
#
# Examples:
#
# location.pathname # => "/namespace/project/merge_requests/1"
# setCurrentAction('diffs')
# location.pathname # => "/namespace/project/merge_requests/1/diffs"
#
# location.pathname # => "/namespace/project/merge_requests/1/diffs"
# setCurrentAction('notes')
# location.pathname # => "/namespace/project/merge_requests/1"
#
# location.pathname # => "/namespace/project/merge_requests/1/diffs"
# setCurrentAction('commits')
# location.pathname # => "/namespace/project/merge_requests/1/commits"
#
# Returns the new URL String
setCurrentAction: (action) =>
# Normalize action, just to be safe
action = 'notes' if action == 'show'
# Remove a trailing '/commits' or '/diffs'
new_state = @_location.pathname.replace(/\/(commits|diffs)\/?$/, '')
# Append the new action if we're on a tab other than 'notes'
unless action == 'notes'
new_state += "/#{action}"
# Ensure parameters and hash come along for the ride
new_state += @_location.search + @_location.hash
# Replace the current history state with the new one without breaking
# Turbolinks' history.
#
# See https://github.com/rails/turbolinks/issues/363
history.replaceState {turbolinks: true, url: new_state}, document.title, new_state
new_state
loadCommits: (source) ->
return if @commitsLoaded
@_get
url: "#{source}.json"
success: (data) =>
document.getElementById('commits').innerHTML = data.html
$('.js-timeago').timeago()
@commitsLoaded = true
loadDiff: (source) ->
return if @diffsLoaded
@_get
url: "#{source}.json"
success: (data) =>
document.getElementById('diffs').innerHTML = data.html
$('.diff-header').trigger('sticky_kit:recalc')
@diffsLoaded = true
toggleLoading: ->
$('.mr-loading-status .loading').toggle()
_get: (options) ->
defaults = {
beforeSend: @toggleLoading
complete: @toggleLoading
dataType: 'json'
type: 'GET'
}
options = $.extend({}, defaults, options)
$.ajax(options)
...@@ -10,6 +10,10 @@ header { ...@@ -10,6 +10,10 @@ header {
.center-logo { .center-logo {
margin: 8px 0; margin: 8px 0;
text-align: center; text-align: center;
img {
height: 32px;
}
} }
} }
......
class DashboardController < Dashboard::ApplicationController class DashboardController < Dashboard::ApplicationController
before_action :load_projects, except: [:projects] before_action :load_projects
before_action :event_filter, only: :show before_action :event_filter, only: :show
respond_to :html respond_to :html
def show def show
......
...@@ -24,7 +24,7 @@ class PasswordsController < Devise::PasswordsController ...@@ -24,7 +24,7 @@ class PasswordsController < Devise::PasswordsController
super do |resource| super do |resource|
# TODO (rspeicher): In Devise master (> 3.4.1), we can set # TODO (rspeicher): In Devise master (> 3.4.1), we can set
# `Devise.sign_in_after_reset_password = false` and avoid this mess. # `Devise.sign_in_after_reset_password = false` and avoid this mess.
if resource.errors.empty? && resource.try(:otp_required_for_login?) if resource.errors.empty? && resource.try(:two_factor_enabled?)
resource.unlock_access! if unlockable?(resource) resource.unlock_access! if unlockable?(resource)
# Since we are not signing this user in, we use the :updated_not_active # Since we are not signing this user in, we use the :updated_not_active
......
...@@ -10,7 +10,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController ...@@ -10,7 +10,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
def create def create
if current_user.valid_otp?(params[:pin_code]) if current_user.valid_otp?(params[:pin_code])
current_user.otp_required_for_login = true current_user.two_factor_enabled = true
@codes = current_user.generate_otp_backup_codes! @codes = current_user.generate_otp_backup_codes!
current_user.save! current_user.save!
...@@ -30,7 +30,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController ...@@ -30,7 +30,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
def destroy def destroy
current_user.update_attributes({ current_user.update_attributes({
otp_required_for_login: false, two_factor_enabled: false,
encrypted_otp_secret: nil, encrypted_otp_secret: nil,
encrypted_otp_secret_iv: nil, encrypted_otp_secret_iv: nil,
encrypted_otp_secret_salt: nil, encrypted_otp_secret_salt: nil,
......
...@@ -71,7 +71,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -71,7 +71,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def commits def commits
render 'show' respond_to do |format|
format.html { render 'show' }
format.json { render json: { html: view_to_html_string('projects/merge_requests/show/_commits') } }
end
end end
def new def new
......
...@@ -57,7 +57,7 @@ class SessionsController < Devise::SessionsController ...@@ -57,7 +57,7 @@ class SessionsController < Devise::SessionsController
def authenticate_with_two_factor def authenticate_with_two_factor
user = self.resource = find_user user = self.resource = find_user
return unless user && user.otp_required_for_login return unless user && user.two_factor_enabled?
if user_params[:otp_attempt].present? && session[:otp_user_id] if user_params[:otp_attempt].present? && session[:otp_user_id]
if valid_otp_attempt?(user) if valid_otp_attempt?(user)
......
...@@ -45,10 +45,10 @@ class IssuableFinder ...@@ -45,10 +45,10 @@ class IssuableFinder
def group def group
return @group if defined?(@group) return @group if defined?(@group)
@group = @group =
if params[:group_id].present? if params[:group_id].present?
Group.find(params[:group_id]) Group.find(params[:group_id])
else else
nil nil
end end
end end
...@@ -56,10 +56,10 @@ class IssuableFinder ...@@ -56,10 +56,10 @@ class IssuableFinder
def project def project
return @project if defined?(@project) return @project if defined?(@project)
@project = @project =
if params[:project_id].present? if params[:project_id].present?
Project.find(params[:project_id]) Project.find(params[:project_id])
else else
nil nil
end end
end end
...@@ -76,7 +76,7 @@ class IssuableFinder ...@@ -76,7 +76,7 @@ class IssuableFinder
return @milestones if defined?(@milestones) return @milestones if defined?(@milestones)
@milestones = @milestones =
if milestones? && params[:milestone_title] != NONE if milestones? && params[:milestone_title] != NONE
Milestone.where(title: params[:milestone_title]) Milestone.where(title: params[:milestone_title])
else else
nil nil
...@@ -90,7 +90,7 @@ class IssuableFinder ...@@ -90,7 +90,7 @@ class IssuableFinder
def assignee def assignee
return @assignee if defined?(@assignee) return @assignee if defined?(@assignee)
@assignee = @assignee =
if assignee? && params[:assignee_id] != NONE if assignee? && params[:assignee_id] != NONE
User.find(params[:assignee_id]) User.find(params[:assignee_id])
else else
...@@ -105,7 +105,7 @@ class IssuableFinder ...@@ -105,7 +105,7 @@ class IssuableFinder
def author def author
return @author if defined?(@author) return @author if defined?(@author)
@author = @author =
if author? && params[:author_id] != NONE if author? && params[:author_id] != NONE
User.find(params[:author_id]) User.find(params[:author_id])
else else
...@@ -148,8 +148,6 @@ class IssuableFinder ...@@ -148,8 +148,6 @@ class IssuableFinder
case params[:state] case params[:state]
when 'closed' when 'closed'
items.closed items.closed
when 'rejected'
items.respond_to?(:rejected) ? items.rejected : items.closed
when 'merged' when 'merged'
items.respond_to?(:merged) ? items.merged : items.closed items.respond_to?(:merged) ? items.merged : items.closed
when 'all' when 'all'
......
...@@ -16,6 +16,6 @@ module AppearancesHelper ...@@ -16,6 +16,6 @@ module AppearancesHelper
end end
def brand_header_logo def brand_header_logo
image_tag 'logo-white.png' image_tag 'logo.svg'
end end
end end
...@@ -179,14 +179,33 @@ module ApplicationHelper ...@@ -179,14 +179,33 @@ module ApplicationHelper
BroadcastMessage.current BroadcastMessage.current
end end
def time_ago_with_tooltip(date, placement = 'top', html_class = 'time_ago') # Render a `time` element with Javascript-based relative date and tooltip
capture_haml do #
haml_tag :time, date.to_s, # time - Time object
class: html_class, datetime: date.getutc.iso8601, title: date.in_time_zone.stamp('Aug 21, 2011 9:23pm'), # placement - Tooltip placement String (default: "top")
data: { toggle: 'tooltip', placement: placement } # html_class - Custom class for `time` element (default: "time_ago")
# skip_js - When true, exclude the `script` tag (default: false)
haml_tag :script, "$('." + html_class + "').timeago().tooltip()" #
end.html_safe # By default also includes a `script` element with Javascript necessary to
# initialize the `timeago` jQuery extension. If this method is called many
# times, for example rendering hundreds of commits, it's advisable to disable
# this behavior using the `skip_js` argument and re-initializing `timeago`
# manually once all of the elements have been rendered.
#
# A `js-timeago` class is always added to the element, even when a custom
# `html_class` argument is provided.
#
# Returns an HTML-safe String
def time_ago_with_tooltip(time, placement: 'top', html_class: 'time_ago', skip_js: false)
element = content_tag :time, time.to_s,
class: "#{html_class} js-timeago",
datetime: time.getutc.iso8601,
title: time.in_time_zone.stamp('Aug 21, 2011 9:23pm'),
data: { toggle: 'tooltip', placement: placement }
element += javascript_tag "$('.js-timeago').timeago()" unless skip_js
element
end end
def render_markup(file_name, file_content) def render_markup(file_name, file_content)
...@@ -214,39 +233,6 @@ module ApplicationHelper ...@@ -214,39 +233,6 @@ module ApplicationHelper
Gitlab::MarkupHelper.asciidoc?(filename) Gitlab::MarkupHelper.asciidoc?(filename)
end end
# Overrides ActionView::Helpers::UrlHelper#link_to to add `rel="nofollow"` to
# external links
def link_to(name = nil, options = nil, html_options = {})
if options.kind_of?(String)
if !options.start_with?('#', '/')
html_options = add_nofollow(options, html_options)
end
end
super
end
# Add `"rel=nofollow"` to external links
#
# link - String link to check
# html_options - Hash of `html_options` passed to `link_to`
#
# Returns `html_options`, adding `rel: nofollow` for external links
def add_nofollow(link, html_options = {})
begin
uri = URI(link)
if uri && uri.absolute? && uri.host != Gitlab.config.gitlab.host
rel = html_options.fetch(:rel, '')
html_options[:rel] = (rel + ' nofollow').strip
end
rescue URI::Error
# noop
end
html_options
end
def promo_host def promo_host
'about.gitlab.com' 'about.gitlab.com'
end end
...@@ -295,10 +281,9 @@ module ApplicationHelper ...@@ -295,10 +281,9 @@ module ApplicationHelper
def state_filters_text_for(entity, project) def state_filters_text_for(entity, project)
titles = { titles = {
opened: "Open", opened: "Open"
merged: "Accepted"
} }
entity_title = titles[entity] || entity.to_s.humanize entity_title = titles[entity] || entity.to_s.humanize
count = count =
......
module BroadcastMessagesHelper module BroadcastMessagesHelper
def broadcast_styling(broadcast_message) def broadcast_styling(broadcast_message)
if(broadcast_message.color || broadcast_message.font) styling = ''
"background-color:#{broadcast_message.color};color:#{broadcast_message.font}"
else if broadcast_message.color.present?
"" styling << "background-color: #{broadcast_message.color}"
styling << '; ' if broadcast_message.font.present?
end end
if broadcast_message.font.present?
styling << "color: #{broadcast_message.font}"
end
styling
end end
end end
module IconsHelper module IconsHelper
include FontAwesome::Rails::IconHelper
# Creates an icon tag given icon name(s) and possible icon modifiers. # Creates an icon tag given icon name(s) and possible icon modifiers.
# #
# Right now this method simply delegates directly to `fa_icon` from the # Right now this method simply delegates directly to `fa_icon` from the
......
...@@ -45,13 +45,13 @@ module IssuesHelper ...@@ -45,13 +45,13 @@ module IssuesHelper
def issue_timestamp(issue) def issue_timestamp(issue)
# Shows the created at time and the updated at time if different # Shows the created at time and the updated at time if different
ts = "#{time_ago_with_tooltip(issue.created_at, 'bottom', 'note_created_ago')}" ts = time_ago_with_tooltip(issue.created_at, placement: 'bottom', html_class: 'note_created_ago')
if issue.updated_at != issue.created_at if issue.updated_at != issue.created_at
ts << capture_haml do ts << capture_haml do
haml_tag :span do haml_tag :span do
haml_concat '&middot;' haml_concat '&middot;'
haml_concat icon('edit', title: 'edited') haml_concat icon('edit', title: 'edited')
haml_concat time_ago_with_tooltip(issue.updated_at, 'bottom', 'issue_edited_ago') haml_concat time_ago_with_tooltip(issue.updated_at, placement: 'bottom', html_class: 'issue_edited_ago')
end end
end end
end end
......
...@@ -25,13 +25,13 @@ module NotesHelper ...@@ -25,13 +25,13 @@ module NotesHelper
def note_timestamp(note) def note_timestamp(note)
# Shows the created at time and the updated at time if different # Shows the created at time and the updated at time if different
ts = "#{time_ago_with_tooltip(note.created_at, 'bottom', 'note_created_ago')}" ts = time_ago_with_tooltip(note.created_at, placement: 'bottom', html_class: 'note_created_ago')
if note.updated_at != note.created_at if note.updated_at != note.created_at
ts << capture_haml do ts << capture_haml do
haml_tag :span do haml_tag :span do
haml_concat '&middot;' haml_concat '&middot;'
haml_concat icon('edit', title: 'edited') haml_concat icon('edit', title: 'edited')
haml_concat time_ago_with_tooltip(note.updated_at, 'bottom', 'note_edited_ago') haml_concat time_ago_with_tooltip(note.updated_at, placement: 'bottom', html_class: 'note_edited_ago')
end end
end end
end end
......
module NotificationsHelper module NotificationsHelper
include IconsHelper
def notification_icon(notification) def notification_icon(notification)
if notification.disabled? if notification.disabled?
icon('volume-off', class: 'ns-mute') icon('volume-off', class: 'ns-mute')
......
...@@ -211,7 +211,7 @@ module ProjectsHelper ...@@ -211,7 +211,7 @@ module ProjectsHelper
def project_last_activity(project) def project_last_activity(project)
if project.last_activity_at if project.last_activity_at
time_ago_with_tooltip(project.last_activity_at, 'bottom', 'last_activity_time_ago') time_ago_with_tooltip(project.last_activity_at, placement: 'bottom', html_class: 'last_activity_time_ago')
else else
"Never" "Never"
end end
......
...@@ -263,7 +263,7 @@ class Ability ...@@ -263,7 +263,7 @@ class Ability
:"modify_#{name}", :"modify_#{name}",
] ]
else else
if subject.respond_to?(:project) if subject.respond_to?(:project) && subject.project
project_abilities(user, subject.project) project_abilities(user, subject.project)
else else
[] []
......
...@@ -75,7 +75,7 @@ module Mentionable ...@@ -75,7 +75,7 @@ module Mentionable
refs.reject! { |ref| without.include?(ref) } refs.reject! { |ref| without.include?(ref) }
refs.each do |ref| refs.each do |ref|
Note.create_cross_reference_note(ref, local_reference, a) SystemNoteService.cross_reference(ref, local_reference, a)
end end
end end
......
...@@ -125,16 +125,14 @@ class MergeRequest < ActiveRecord::Base ...@@ -125,16 +125,14 @@ class MergeRequest < ActiveRecord::Base
validate :validate_fork validate :validate_fork
scope :of_group, ->(group) { where("source_project_id in (:group_project_ids) OR target_project_id in (:group_project_ids)", group_project_ids: group.project_ids) } scope :of_group, ->(group) { where("source_project_id in (:group_project_ids) OR target_project_id in (:group_project_ids)", group_project_ids: group.project_ids) }
scope :merged, -> { with_state(:merged) }
scope :by_branch, ->(branch_name) { where("(source_branch LIKE :branch) OR (target_branch LIKE :branch)", branch: branch_name) } scope :by_branch, ->(branch_name) { where("(source_branch LIKE :branch) OR (target_branch LIKE :branch)", branch: branch_name) }
scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) } scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) }
scope :by_milestone, ->(milestone) { where(milestone_id: milestone) } scope :by_milestone, ->(milestone) { where(milestone_id: milestone) }
scope :in_projects, ->(project_ids) { where("source_project_id in (:project_ids) OR target_project_id in (:project_ids)", project_ids: project_ids) } scope :in_projects, ->(project_ids) { where("source_project_id in (:project_ids) OR target_project_id in (:project_ids)", project_ids: project_ids) }
scope :of_projects, ->(ids) { where(target_project_id: ids) } scope :of_projects, ->(ids) { where(target_project_id: ids) }
# Closed scope for merge request should return scope :merged, -> { with_state(:merged) }
# both merged and closed mr's scope :closed, -> { with_state(:closed) }
scope :closed, -> { with_states(:closed, :merged) } scope :closed_and_merged, -> { with_states(:closed, :merged) }
scope :rejected, -> { with_states(:closed) }
def self.reference_prefix def self.reference_prefix
'!' '!'
...@@ -417,4 +415,14 @@ class MergeRequest < ActiveRecord::Base ...@@ -417,4 +415,14 @@ class MergeRequest < ActiveRecord::Base
def can_be_merged_by?(user) def can_be_merged_by?(user)
::Gitlab::GitAccess.new(user, project).can_push_to_branch?(target_branch) ::Gitlab::GitAccess.new(user, project).can_push_to_branch?(target_branch)
end end
def state_human_name
if merged?
"Merged"
elsif closed?
"Closed"
else
"Open"
end
end
end end
...@@ -56,7 +56,7 @@ class Milestone < ActiveRecord::Base ...@@ -56,7 +56,7 @@ class Milestone < ActiveRecord::Base
end end
def closed_items_count def closed_items_count
self.issues.closed.count + self.merge_requests.closed.count self.issues.closed.count + self.merge_requests.closed_and_merged.count
end end
def total_items_count def total_items_count
......
...@@ -63,11 +63,6 @@ class Note < ActiveRecord::Base ...@@ -63,11 +63,6 @@ class Note < ActiveRecord::Base
after_update :set_references after_update :set_references
class << self class << self
# TODO (rspeicher): Update usages
def create_cross_reference_note(*args)
SystemNoteService.cross_reference(*args)
end
def discussions_from_notes(notes) def discussions_from_notes(notes)
discussion_ids = [] discussion_ids = []
discussions = [] discussions = []
......
...@@ -5,8 +5,13 @@ class Repository ...@@ -5,8 +5,13 @@ class Repository
def initialize(path_with_namespace, default_branch = nil, project = nil) def initialize(path_with_namespace, default_branch = nil, project = nil)
@path_with_namespace = path_with_namespace @path_with_namespace = path_with_namespace
@raw_repository = Gitlab::Git::Repository.new(path_to_repo) if path_with_namespace
@project = project @project = project
if path_with_namespace
@raw_repository = Gitlab::Git::Repository.new(path_to_repo)
@raw_repository.autocrlf = :input
end
rescue Gitlab::Git::Repository::NoRepository rescue Gitlab::Git::Repository::NoRepository
nil nil
end end
......
...@@ -34,7 +34,6 @@ class Snippet < ActiveRecord::Base ...@@ -34,7 +34,6 @@ class Snippet < ActiveRecord::Base
validates :author, presence: true validates :author, presence: true
validates :title, presence: true, length: { within: 0..255 } validates :title, presence: true, length: { within: 0..255 }
validates :file_name, validates :file_name,
presence: true,
length: { within: 0..255 }, length: { within: 0..255 },
format: { with: Gitlab::Regex.file_name_regex, format: { with: Gitlab::Regex.file_name_regex,
message: Gitlab::Regex.file_name_regex_message } message: Gitlab::Regex.file_name_regex_message }
......
...@@ -172,6 +172,9 @@ class User < ActiveRecord::Base ...@@ -172,6 +172,9 @@ class User < ActiveRecord::Base
after_create :post_create_hook after_create :post_create_hook
after_destroy :post_destroy_hook after_destroy :post_destroy_hook
# User's Dashboard preference
# Note: When adding an option, it MUST go on the end of the array.
enum dashboard: [:projects, :stars]
alias_attribute :private_token, :authentication_token alias_attribute :private_token, :authentication_token
...@@ -220,10 +223,26 @@ class User < ActiveRecord::Base ...@@ -220,10 +223,26 @@ class User < ActiveRecord::Base
end end
def find_for_commit(email, name) def find_for_commit(email, name)
# Prefer email match over name match user_table = arel_table
User.where(email: email).first || email_table = Email.arel_table
User.joins(:emails).where(emails: { email: email }).first ||
User.where(name: name).first # Use ARel to build a query:
query = user_table.
# SELECT "users".* FROM "users"
project(user_table[Arel.star]).
# LEFT OUTER JOIN "emails"
join(email_table, Arel::Nodes::OuterJoin).
# ON "users"."id" = "emails"."user_id"
on(user_table[:id].eq(email_table[:user_id])).
# WHERE ("user"."email" = '<email>' OR "user"."name" = '<name>')
# OR "emails"."email" = '<email>'
where(
user_table[:email].eq(email).
or(user_table[:name].eq(name)).
or(email_table[:email].eq(email))
)
find_by_sql(query.to_sql).first
end end
def filter(filter_name) def filter(filter_name)
...@@ -297,6 +316,18 @@ class User < ActiveRecord::Base ...@@ -297,6 +316,18 @@ class User < ActiveRecord::Base
@reset_token @reset_token
end end
# Check if the user has enabled Two-factor Authentication
def two_factor_enabled?
otp_required_for_login
end
# Set whether or not Two-factor Authentication is enabled for the current user
#
# setting - Boolean
def two_factor_enabled=(setting)
self.otp_required_for_login = setting
end
def namespace_uniq def namespace_uniq
namespace_name = self.username namespace_name = self.username
existing_namespace = Namespace.by_path(namespace_name) existing_namespace = Namespace.by_path(namespace_name)
...@@ -704,8 +735,4 @@ class User < ActiveRecord::Base ...@@ -704,8 +735,4 @@ class User < ActiveRecord::Base
def can_be_removed? def can_be_removed?
!solo_owned_groups.present? !solo_owned_groups.present?
end end
# User's Dashboard preference
# Note: When adding an option, it MUST go on the end of the array.
enum dashboard: [:projects, :stars]
end end
...@@ -105,7 +105,7 @@ class GitPushService ...@@ -105,7 +105,7 @@ class GitPushService
author ||= commit_user(commit) author ||= commit_user(commit)
refs.each do |r| refs.each do |r|
Note.create_cross_reference_note(r, commit, author) SystemNoteService.cross_reference(r, commit, author)
end end
end end
end end
......
...@@ -15,7 +15,7 @@ module Notes ...@@ -15,7 +15,7 @@ module Notes
# Create a cross-reference note if this Note contains GFM that names an # Create a cross-reference note if this Note contains GFM that names an
# issue, merge request, or commit. # issue, merge request, or commit.
note.references.each do |mentioned| note.references.each do |mentioned|
Note.create_cross_reference_note(mentioned, note.noteable, note.author) SystemNoteService.cross_reference(mentioned, note.noteable, note.author)
end end
execute_hooks(note) execute_hooks(note)
......
...@@ -13,7 +13,7 @@ module Notes ...@@ -13,7 +13,7 @@ module Notes
# Create a cross-reference note if this Note contains GFM that # Create a cross-reference note if this Note contains GFM that
# names an issue, merge request, or commit. # names an issue, merge request, or commit.
note.references.each do |mentioned| note.references.each do |mentioned|
Note.create_cross_reference_note(mentioned, note.noteable, note.author) SystemNoteService.cross_reference(mentioned, note.noteable, note.author)
end end
end end
end end
......
...@@ -38,6 +38,14 @@ ...@@ -38,6 +38,14 @@
= link_to remove_email_admin_user_path(@user, email), data: { confirm: "Are you sure you want to remove #{email.email}?" }, method: :delete, class: "btn-xs btn btn-remove pull-right", title: 'Remove secondary email', id: "remove_email_#{email.id}" do = link_to remove_email_admin_user_path(@user, email), data: { confirm: "Are you sure you want to remove #{email.email}?" }, method: :delete, class: "btn-xs btn btn-remove pull-right", title: 'Remove secondary email', id: "remove_email_#{email.id}" do
%i.fa.fa-times %i.fa.fa-times
%li.two-factor-status
%span.light Two-factor Authentication:
%strong{class: @user.two_factor_enabled? ? 'cgreen' : 'cred'}
- if @user.two_factor_enabled?
Enabled
- else
Disabled
%li %li
%span.light Can create groups: %span.light Can create groups:
%strong %strong
......
%header.navbar.navbar-fixed-top.navbar-empty %header.navbar.navbar-fixed-top.navbar-empty
.container .container
.center-logo .center-logo
= image_tag 'logo-white.png', width: 32, height: 32 = brand_header_logo
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
.panel-heading .panel-heading
Two-factor Authentication Two-factor Authentication
.panel-body .panel-body
- if current_user.otp_required_for_login - if current_user.two_factor_enabled?
.pull-right .pull-right
= link_to 'Disable Two-factor Authentication', profile_two_factor_auth_path, method: :delete, class: 'btn btn-close btn-sm', = link_to 'Disable Two-factor Authentication', profile_two_factor_auth_path, method: :delete, class: 'btn btn-close btn-sm',
data: { confirm: 'Are you sure?' } data: { confirm: 'Are you sure?' }
......
...@@ -15,10 +15,10 @@ ...@@ -15,10 +15,10 @@
- if issuable.is_a?(MergeRequest) - if issuable.is_a?(MergeRequest)
%p.help-block %p.help-block
- if issuable.work_in_progress? - if issuable.work_in_progress?
Remove the <code>WIP</code> prefix from the title to allow this Remove the <code>WIP</code> prefix from the title to allow this
<strong>Work In Progress</strong> merge request to be accepted when it's ready. <strong>Work In Progress</strong> merge request to be accepted when it's ready.
- else - else
Start the title with <code>[WIP]</code> or <code>WIP:</code> to prevent a Start the title with <code>[WIP]</code> or <code>WIP:</code> to prevent a
<strong>Work In Progress</strong> merge request from being accepted before it's ready. <strong>Work In Progress</strong> merge request from being accepted before it's ready.
.form-group.issuable-description .form-group.issuable-description
= f.label :description, 'Description', class: 'control-label' = f.label :description, 'Description', class: 'control-label'
...@@ -81,21 +81,22 @@ ...@@ -81,21 +81,22 @@
- if issuable.is_a?(MergeRequest) - if issuable.is_a?(MergeRequest)
%hr %hr
- unless @merge_request.persisted? - if @merge_request.new_record?
.form-group .form-group
= f.label :source_branch, class: 'control-label' do = f.label :source_branch, class: 'control-label' do
%i.fa.fa-code-fork %i.fa.fa-code-fork
Source Branch Source Branch
.col-sm-10 .col-sm-10
= f.select(:source_branch, [@merge_request.source_branch], { }, { class: 'source_branch select2 span2', disabled: true }) = f.select(:source_branch, [@merge_request.source_branch], { }, { class: 'source_branch select2 span2', disabled: true })
%p.help-block
= link_to 'Change source branch', mr_change_branches_path(@merge_request)
.form-group .form-group
= f.label :target_branch, class: 'control-label' do = f.label :target_branch, class: 'control-label' do
%i.fa.fa-code-fork %i.fa.fa-code-fork
Target Branch Target Branch
.col-sm-10 .col-sm-10
= f.select(:target_branch, @merge_request.target_branches, { include_blank: "Select branch" }, { class: 'target_branch select2 span2' }) = f.select(:target_branch, @merge_request.target_branches, { include_blank: "Select branch" }, { class: 'target_branch select2 span2', disabled: @merge_request.new_record? })
- if @merge_request.new_record?
%p.help-block
= link_to 'Change branches', mr_change_branches_path(@merge_request)
.form-actions .form-actions
- if !issuable.project.empty_repo? && (guide_url = contribution_guide_url(issuable.project)) && !issuable.persisted? - if !issuable.project.empty_repo? && (guide_url = contribution_guide_url(issuable.project)) && !issuable.persisted?
......
...@@ -29,5 +29,5 @@ ...@@ -29,5 +29,5 @@
= commit_author_link(commit, avatar: true, size: 24) = commit_author_link(commit, avatar: true, size: 24)
authored authored
.committed_ago .committed_ago
#{time_ago_with_tooltip(commit.committed_date)} &nbsp; #{time_ago_with_tooltip(commit.committed_date, skip_js: true)} &nbsp;
= link_to_browse_code(project, commit) = link_to_browse_code(project, commit)
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
= 0 = 0
.issue-info .issue-info
= "##{issue.iid} opened #{time_ago_with_tooltip(issue.created_at, 'bottom')} by #{link_to_member(@project, issue.author, avatar: false)}".html_safe = "##{issue.iid} opened #{time_ago_with_tooltip(issue.created_at, placement: 'bottom')} by #{link_to_member(@project, issue.author, avatar: false)}".html_safe
- if issue.votes_count > 0 - if issue.votes_count > 0
= render 'votes/votes_inline', votable: issue = render 'votes/votes_inline', votable: issue
- if issue.milestone - if issue.milestone
...@@ -41,4 +41,4 @@ ...@@ -41,4 +41,4 @@
= issue.task_status = issue.task_status
.pull-right.issue-updated-at .pull-right.issue-updated-at
%small updated #{time_ago_with_tooltip(issue.updated_at, 'bottom', 'issue_update_ago')} %small updated #{time_ago_with_tooltip(issue.updated_at, placement: 'bottom', html_class: 'issue_update_ago')}
...@@ -9,11 +9,11 @@ ...@@ -9,11 +9,11 @@
- if merge_request.merged? - if merge_request.merged?
%span %span
%i.fa.fa-check %i.fa.fa-check
ACCEPTED MERGED
- elsif merge_request.closed? - elsif merge_request.closed?
%span %span
%i.fa.fa-ban %i.fa.fa-ban
REJECTED CLOSED
- else - else
%span.hidden-xs.hidden-sm %span.hidden-xs.hidden-sm
%span.label-branch< %span.label-branch<
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
= 0 = 0
.merge-request-info .merge-request-info
= "##{merge_request.iid} opened #{time_ago_with_tooltip(merge_request.created_at, 'bottom')} by #{link_to_member(@project, merge_request.author, avatar: false)}".html_safe = "##{merge_request.iid} opened #{time_ago_with_tooltip(merge_request.created_at, placement: 'bottom')} by #{link_to_member(@project, merge_request.author, avatar: false)}".html_safe
- if merge_request.votes_count > 0 - if merge_request.votes_count > 0
= render 'votes/votes_inline', votable: merge_request = render 'votes/votes_inline', votable: merge_request
- if merge_request.milestone_id? - if merge_request.milestone_id?
...@@ -48,4 +48,4 @@ ...@@ -48,4 +48,4 @@
= merge_request.task_status = merge_request.task_status
.pull-right.hidden-xs .pull-right.hidden-xs
%small updated #{time_ago_with_tooltip(merge_request.updated_at, 'bottom', 'merge_request_updated_ago')} %small updated #{time_ago_with_tooltip(merge_request.updated_at, placement: 'bottom', html_class: 'merge_request_updated_ago')}
...@@ -56,7 +56,8 @@ ...@@ -56,7 +56,8 @@
#notes.notes.tab-pane.voting_notes #notes.notes.tab-pane.voting_notes
= render "projects/merge_requests/discussion" = render "projects/merge_requests/discussion"
#commits.commits.tab-pane #commits.commits.tab-pane
= render "projects/merge_requests/show/commits" - if current_page?(action: 'commits')
= render "projects/merge_requests/show/commits"
#diffs.diffs.tab-pane #diffs.diffs.tab-pane
- if current_page?(action: 'diffs') - if current_page?(action: 'diffs')
= render "projects/merge_requests/show/diffs" = render "projects/merge_requests/show/diffs"
...@@ -64,7 +65,6 @@ ...@@ -64,7 +65,6 @@
.mr-loading-status .mr-loading-status
= spinner = spinner
:javascript :javascript
var merge_request; var merge_request;
......
%h4.page-title %h4.page-title
.issue-box{ class: issue_box_class(@merge_request) } .issue-box{ class: issue_box_class(@merge_request) }
- if @merge_request.merged? = @merge_request.state_human_name
Accepted
- elsif @merge_request.closed?
Rejected
- else
Open
= "Merge Request ##{@merge_request.iid}" = "Merge Request ##{@merge_request.iid}"
%small.creator %small.creator
&middot; &middot;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
= render 'projects/merge_requests/widget/heading' = render 'projects/merge_requests/widget/heading'
.mr-widget-body .mr-widget-body
%h4 %h4
Rejected Closed
- if @merge_request.closed_event - if @merge_request.closed_event
by #{link_to_member(@project, @merge_request.closed_event.author, avatar: true)} by #{link_to_member(@project, @merge_request.closed_event.author, avatar: true)}
#{time_ago_with_tooltip(@merge_request.closed_event.created_at)} #{time_ago_with_tooltip(@merge_request.closed_event.created_at)}
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
= render 'projects/merge_requests/widget/heading' = render 'projects/merge_requests/widget/heading'
.mr-widget-body .mr-widget-body
%h4 %h4
Accepted Merged
- if @merge_request.merge_event - if @merge_request.merge_event
by #{link_to_member(@project, @merge_request.merge_event.author, avatar: true)} by #{link_to_member(@project, @merge_request.merge_event.author, avatar: true)}
#{time_ago_with_tooltip(@merge_request.merge_event.created_at)} #{time_ago_with_tooltip(@merge_request.merge_event.created_at)}
......
...@@ -86,10 +86,10 @@ ...@@ -86,10 +86,10 @@
.col-md-3 .col-md-3
= render('merge_requests', title: 'Waiting for merge (open and assigned)', merge_requests: @merge_requests.opened.assigned, id: 'ongoing') = render('merge_requests', title: 'Waiting for merge (open and assigned)', merge_requests: @merge_requests.opened.assigned, id: 'ongoing')
.col-md-3 .col-md-3
= render('merge_requests', title: 'Rejected (closed)', merge_requests: @merge_requests.rejected, id: 'closed') = render('merge_requests', title: 'Rejected (closed)', merge_requests: @merge_requests.closed, id: 'closed')
.col-md-3 .col-md-3
.panel.panel-primary .panel.panel-primary
.panel-heading Accepted .panel-heading Merged
%ul.well-list %ul.well-list
- @merge_requests.merged.each do |merge_request| - @merge_requests.merged.each do |merge_request|
= render 'merge_request', merge_request: merge_request = render 'merge_request', merge_request: merge_request
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
= link_to_member(@project, last_note.author, avatar: false) = link_to_member(@project, last_note.author, avatar: false)
%span.discussion-last-update %span.discussion-last-update
#{time_ago_with_tooltip(last_note.updated_at, 'bottom', 'discussion_updated_ago')} #{time_ago_with_tooltip(last_note.updated_at, placement: 'bottom', html_class: 'discussion_updated_ago')}
.discussion-body.js-toggle-content .discussion-body.js-toggle-content
= render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note = render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
last updated by last updated by
= link_to_member(@project, last_note.author, avatar: false) = link_to_member(@project, last_note.author, avatar: false)
%span.discussion-last-update %span.discussion-last-update
#{time_ago_with_tooltip(last_note.updated_at, 'bottom', 'discussion_updated_ago')} #{time_ago_with_tooltip(last_note.updated_at, placement: 'bottom', html_class: 'discussion_updated_ago')}
.discussion-body.js-toggle-content .discussion-body.js-toggle-content
- if note.for_diff_line? - if note.for_diff_line?
= render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note = render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note
......
...@@ -14,6 +14,6 @@ ...@@ -14,6 +14,6 @@
last updated by last updated by
= link_to_member(@project, last_note.author, avatar: false) = link_to_member(@project, last_note.author, avatar: false)
%span.discussion-last-update %span.discussion-last-update
#{time_ago_with_tooltip(last_note.updated_at, 'bottom', 'discussion_updated_ago')} #{time_ago_with_tooltip(last_note.updated_at, placement: 'bottom', html_class: 'discussion_updated_ago')}
.discussion-body.js-toggle-content.hide .discussion-body.js-toggle-content.hide
= render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note = render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note
...@@ -11,6 +11,6 @@ ...@@ -11,6 +11,6 @@
#{merge_request.project.name_with_namespace} #{merge_request.project.name_with_namespace}
.pull-right .pull-right
- if merge_request.merged? - if merge_request.merged?
%span.label.label-primary Accepted %span.label.label-primary Merged
- elsif merge_request.closed? - elsif merge_request.closed?
%span.label.label-danger Rejected %span.label.label-danger Closed
.file-content.code{class: user_color_scheme_class} .file-content.code{class: user_color_scheme_class}
.line-numbers .line-numbers
- if blob.data.present? - if blob.data.present?
- blob.data.lines.to_a.size.times do |index| - blob.data.lines.each_index do |index|
- offset = defined?(first_line_number) ? first_line_number : 1 - offset = defined?(first_line_number) ? first_line_number : 1
- i = index + offset - i = index + offset
/ We're not using `link_to` because it is too slow once we get to thousands of lines. -# We're not using `link_to` because it is too slow once we get to thousands of lines.
%a{href: "#L#{i}", id: "L#{i}", rel: "#L#{i}"} %a{href: "#L#{i}", id: "L#{i}", 'data-line-number' => i}
%i.fa.fa-link %i.fa.fa-link
= i = i
:preserve :preserve
......
...@@ -12,10 +12,10 @@ ...@@ -12,10 +12,10 @@
= icon('check-circle') = icon('check-circle')
#{state_filters_text_for(:merged, @project)} #{state_filters_text_for(:merged, @project)}
%li{class: ("active" if params[:state] == 'rejected')} %li{class: ("active" if params[:state] == 'closed')}
= link_to page_filter_path(state: 'rejected') do = link_to page_filter_path(state: 'closed') do
= icon('ban') = icon('ban')
#{state_filters_text_for(:rejected, @project)} #{state_filters_text_for(:closed, @project)}
- else - else
%li{class: ("active" if params[:state] == 'closed')} %li{class: ("active" if params[:state] == 'closed')}
= link_to page_filter_path(state: 'closed') do = link_to page_filter_path(state: 'closed') do
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
.col-sm-10 .col-sm-10
.file-holder.snippet .file-holder.snippet
.file-title .file-title
= f.text_field :file_name, placeholder: "example.rb", class: 'form-control snippet-file-name', required: true = f.text_field :file_name, placeholder: "Optionally name this file to add code highlighting, e.g. example.rb for Ruby.", class: 'form-control snippet-file-name'
.file-content.code .file-content.code
%pre#editor= @snippet.content %pre#editor= @snippet.content
= f.hidden_field :content, class: 'snippet-file-content' = f.hidden_field :content, class: 'snippet-file-content'
......
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
.row .row
%section.col-md-8 %section.col-md-8
.header-with-avatar .header-with-avatar
= image_tag avatar_icon(@user.email, 90), class: "avatar avatar-tile s90", alt: '' = link_to avatar_icon(@user.email), target: '_blank' do
= image_tag avatar_icon(@user.email, 90), class: "avatar avatar-tile s90", alt: ''
%h3 %h3
= @user.name = @user.name
- if @user == current_user - if @user == current_user
......
# GitLab basics
Step-by-step guides on the basics of working with Git and GitLab.
* [Start using Git on the commandline](start_using_git.md)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment