Commit 2a6942ab authored by Phil Hughes's avatar Phil Hughes

Merge branch 'master' into members-ui

parents a34c0e54 4be63f5b
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
"always-semicolon": true, "always-semicolon": true,
"color-case": "lower", "color-case": "lower",
"block-indent": " ", "block-indent": " ",
"color-shorthand": true, "color-shorthand": false,
"element-case": "lower", "element-case": "lower",
"space-before-colon": "", "space-before-colon": "",
"space-after-colon": " ", "space-after-colon": " ",
......
*.erb *.erb
lib/gitlab/sanitizers/svg/whitelist.rb
lib/gitlab/diff/position_tracer.rb
image: "ruby:2.3.1" image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3-git-2.7-phantomjs-2.1"
cache: cache:
key: "ruby-231" key: "ruby-231"
paths: paths:
- vendor/apt
- vendor/ruby - vendor/ruby
variables: variables:
...@@ -12,7 +11,7 @@ variables: ...@@ -12,7 +11,7 @@ variables:
RSPEC_RETRY_RETRY_COUNT: "3" RSPEC_RETRY_RETRY_COUNT: "3"
RAILS_ENV: "test" RAILS_ENV: "test"
SIMPLECOV: "true" SIMPLECOV: "true"
USE_DB: "true" SETUP_DB: "true"
USE_BUNDLE_INSTALL: "true" USE_BUNDLE_INSTALL: "true"
GIT_DEPTH: "20" GIT_DEPTH: "20"
PHANTOMJS_VERSION: "2.1.1" PHANTOMJS_VERSION: "2.1.1"
...@@ -23,7 +22,7 @@ before_script: ...@@ -23,7 +22,7 @@ before_script:
- bundle --version - bundle --version
- '[ "$USE_BUNDLE_INSTALL" != "true" ] || retry bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}"' - '[ "$USE_BUNDLE_INSTALL" != "true" ] || retry bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}"'
- retry gem install knapsack - retry gem install knapsack
- '[ "$USE_DB" != "true" ] || bundle exec rake db:drop db:create db:schema:load db:migrate' - '[ "$SETUP_DB" != "true" ] || bundle exec rake db:drop db:create db:schema:load db:migrate'
stages: stages:
- prepare - prepare
...@@ -35,7 +34,7 @@ stages: ...@@ -35,7 +34,7 @@ stages:
.knapsack-state: &knapsack-state .knapsack-state: &knapsack-state
services: [] services: []
variables: variables:
USE_DB: "false" SETUP_DB: "false"
USE_BUNDLE_INSTALL: "false" USE_BUNDLE_INSTALL: "false"
cache: cache:
key: "knapsack" key: "knapsack"
...@@ -141,14 +140,13 @@ spinach 9 10: *spinach-knapsack ...@@ -141,14 +140,13 @@ spinach 9 10: *spinach-knapsack
# Execute all testing suites against Ruby 2.1 # Execute all testing suites against Ruby 2.1
.ruby-21: &ruby-21 .ruby-21: &ruby-21
image: "ruby:2.1" image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.1-git-2.7-phantomjs-2.1"
<<: *use-db <<: *use-db
only: only:
- master - master
cache: cache:
key: "ruby21" key: "ruby21"
paths: paths:
- vendor/apt
- vendor/ruby - vendor/ruby
.rspec-knapsack-ruby21: &rspec-knapsack-ruby21 .rspec-knapsack-ruby21: &rspec-knapsack-ruby21
...@@ -196,7 +194,7 @@ spinach 9 10 ruby21: *spinach-knapsack-ruby21 ...@@ -196,7 +194,7 @@ spinach 9 10 ruby21: *spinach-knapsack-ruby21
.ruby-static-analysis: &ruby-static-analysis .ruby-static-analysis: &ruby-static-analysis
variables: variables:
SIMPLECOV: "false" SIMPLECOV: "false"
USE_DB: "false" SETUP_DB: "false"
USE_BUNDLE_INSTALL: "true" USE_BUNDLE_INSTALL: "true"
.exec: &exec .exec: &exec
...@@ -206,10 +204,12 @@ spinach 9 10 ruby21: *spinach-knapsack-ruby21 ...@@ -206,10 +204,12 @@ spinach 9 10 ruby21: *spinach-knapsack-ruby21
- bundle exec $CI_BUILD_NAME - bundle exec $CI_BUILD_NAME
rubocop: *exec rubocop: *exec
rake haml_lint: *exec
rake scss_lint: *exec rake scss_lint: *exec
rake brakeman: *exec rake brakeman: *exec
rake flog: *exec rake flay:
rake flay: *exec <<: *exec
allow_failure: yes
license_finder: *exec license_finder: *exec
rake downtime_check: *exec rake downtime_check: *exec
...@@ -219,6 +219,23 @@ rake db:migrate:reset: ...@@ -219,6 +219,23 @@ rake db:migrate:reset:
script: script:
- rake db:migrate:reset - rake db:migrate:reset
rake db:seed_fu:
stage: test
<<: *use-db
variables:
SIZE: "1"
SETUP_DB: "false"
RAILS_ENV: "development"
script:
- git clone https://gitlab.com/gitlab-org/gitlab-test.git
/home/git/repositories/gitlab-org/gitlab-test.git
- bundle exec rake db:setup db:seed_fu
artifacts:
when: on_failure
expire_in: 1d
paths:
- log/development.log
teaspoon: teaspoon:
stage: test stage: test
<<: *use-db <<: *use-db
...@@ -267,7 +284,7 @@ coverage: ...@@ -267,7 +284,7 @@ coverage:
stage: post-test stage: post-test
services: [] services: []
variables: variables:
USE_DB: "false" SETUP_DB: "false"
USE_BUNDLE_INSTALL: "true" USE_BUNDLE_INSTALL: "true"
script: script:
- bundle exec scripts/merge-simplecov - bundle exec scripts/merge-simplecov
...@@ -283,7 +300,7 @@ coverage: ...@@ -283,7 +300,7 @@ coverage:
notify:slack: notify:slack:
stage: post-test stage: post-test
variables: variables:
USE_DB: "false" SETUP_DB: "false"
USE_BUNDLE_INSTALL: "false" USE_BUNDLE_INSTALL: "false"
script: script:
- ./scripts/notify_slack.sh "#builds" "Build on \`$CI_BUILD_REF_NAME\` failed! Commit \`$(git log -1 --oneline)\` See <https://gitlab.com/gitlab-org/$(basename "$PWD")/commit/"$CI_BUILD_REF"/builds>" - ./scripts/notify_slack.sh "#builds" "Build on \`$CI_BUILD_REF_NAME\` failed! Commit \`$(git log -1 --oneline)\` See <https://gitlab.com/gitlab-org/$(basename "$PWD")/commit/"$CI_BUILD_REF"/builds>"
......
# Whether to ignore frontmatter at the beginning of HAML documents for
# frameworks such as Jekyll/Middleman
skip_frontmatter: false
exclude:
- 'vendor/**/*'
- 'spec/**/*'
linters:
AltText:
enabled: false
ClassAttributeWithStaticValue:
enabled: false
ClassesBeforeIds:
enabled: false
ConsecutiveComments:
enabled: false
ConsecutiveSilentScripts:
enabled: false
max_consecutive: 2
EmptyObjectReference:
enabled: true
EmptyScript:
enabled: true
FinalNewline:
enabled: false
present: true
HtmlAttributes:
enabled: false
ImplicitDiv:
enabled: false
LeadingCommentSpace:
enabled: false
LineLength:
enabled: false
max: 80
MultilinePipe:
enabled: false
MultilineScript:
enabled: true
ObjectReferenceAttributes:
enabled: true
RuboCop:
enabled: false
# These cops are incredibly noisy when it comes to HAML templates, so we
# ignore them.
ignored_cops:
- Lint/BlockAlignment
- Lint/EndAlignment
- Lint/Void
- Metrics/LineLength
- Style/AlignParameters
- Style/BlockNesting
- Style/ElseAlignment
- Style/FileName
- Style/FinalNewline
- Style/FrozenStringLiteralComment
- Style/IfUnlessModifier
- Style/IndentationWidth
- Style/Next
- Style/TrailingBlankLines
- Style/TrailingWhitespace
- Style/WhileUntilModifier
RubyComments:
enabled: false
SpaceBeforeScript:
enabled: false
SpaceInsideHashAttributes:
enabled: false
style: space
Indentation:
enabled: true
character: space # or tab
TagName:
enabled: true
TrailingWhitespace:
enabled: false
UnnecessaryInterpolation:
enabled: false
UnnecessaryStringOutput:
enabled: false
...@@ -3,6 +3,8 @@ group: git ...@@ -3,6 +3,8 @@ group: git
services: services:
- postgres - postgres
before_precompile: ./bin/pkgr_before_precompile.sh before_precompile: ./bin/pkgr_before_precompile.sh
env:
- SKIP_STORAGE_VALIDATION=true
targets: targets:
debian-7: &wheezy debian-7: &wheezy
build_dependencies: build_dependencies:
...@@ -25,6 +27,16 @@ targets: ...@@ -25,6 +27,16 @@ targets:
- libicu52 - libicu52
- libpcre3 - libpcre3
- git - git
ubuntu-16.04:
build_dependencies:
- libkrb5-dev
- libicu-dev
- cmake
- pkg-config
dependencies:
- libicu55
- libpcre3
- git
centos-6: centos-6:
build_dependencies: build_dependencies:
- krb5-devel - krb5-devel
......
...@@ -639,6 +639,10 @@ Lint/RescueException: ...@@ -639,6 +639,10 @@ Lint/RescueException:
Lint/ShadowedException: Lint/ShadowedException:
Enabled: false Enabled: false
# Checks for Object#to_s usage in string interpolation.
Lint/StringConversionInInterpolation:
Enabled: true
# Do not use prefix `_` for a variable that is used. # Do not use prefix `_` for a variable that is used.
Lint/UnderscorePrefixedVariableName: Lint/UnderscorePrefixedVariableName:
Enabled: true Enabled: true
......
This diff is collapsed.
...@@ -79,7 +79,7 @@ linters: ...@@ -79,7 +79,7 @@ linters:
# HEX colors should use three-character values where possible. # HEX colors should use three-character values where possible.
HexLength: HexLength:
enabled: true enabled: false
# HEX color values should use lower-case colors to differentiate between # HEX color values should use lower-case colors to differentiate between
# letters and numbers, e.g. `#E3E3E3` vs. `#e3e3e3`. # letters and numbers, e.g. `#E3E3E3` vs. `#e3e3e3`.
......
This diff is collapsed.
...@@ -91,19 +91,7 @@ This was inspired by [an article by Kent C. Dodds][medium-up-for-grabs]. ...@@ -91,19 +91,7 @@ This was inspired by [an article by Kent C. Dodds][medium-up-for-grabs].
## Implement design & UI elements ## Implement design & UI elements
### Design reference Please see the [UI Guide for building GitLab].
The GitLab design reference can be found in the [gitlab-design] project.
The designs are made using Antetype (`.atype` files). You can use the
[free Antetype viewer (Mac OSX only)] or grab an exported PNG from the design
(the PNG is 1:1).
The current designs can be found in the [`gitlab8.atype` file].
### UI development kit
Implemented UI elements can also be found at https://gitlab.com/help/ui. Please
note that this page isn't comprehensive at this time.
## Issue tracker ## Issue tracker
...@@ -289,6 +277,8 @@ request is as follows: ...@@ -289,6 +277,8 @@ request is as follows:
1. For more complex migrations, write tests. 1. For more complex migrations, write tests.
1. Merge requests **must** adhere to the [merge request performance 1. Merge requests **must** adhere to the [merge request performance
guidelines](doc/development/merge_request_performance_guidelines.md). guidelines](doc/development/merge_request_performance_guidelines.md).
1. For tests that use Capybara or PhantomJS, see this [article on how
to write reliable asynchronous tests](https://robots.thoughtbot.com/write-reliable-asynchronous-integration-tests-with-capybara).
The **official merge window** is in the beginning of the month from the 1st to The **official merge window** is in the beginning of the month from the 1st to
the 7th day of the month. This is the best time to submit an MR and get the 7th day of the month. This is the best time to submit an MR and get
...@@ -489,7 +479,5 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor ...@@ -489,7 +479,5 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[doc-styleguide]: doc/development/doc_styleguide.md "Documentation styleguide" [doc-styleguide]: doc/development/doc_styleguide.md "Documentation styleguide"
[scss-styleguide]: doc/development/scss_styleguide.md "SCSS styleguide" [scss-styleguide]: doc/development/scss_styleguide.md "SCSS styleguide"
[newlines-styleguide]: doc/development/newlines_styleguide.md "Newlines styleguide" [newlines-styleguide]: doc/development/newlines_styleguide.md "Newlines styleguide"
[gitlab-design]: https://gitlab.com/gitlab-org/gitlab-design [UI Guide for building GitLab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/ui_guide.md
[free Antetype viewer (Mac OSX only)]: https://itunes.apple.com/us/app/antetype-viewer/id824152298?mt=12
[`gitlab8.atype` file]: https://gitlab.com/gitlab-org/gitlab-design/tree/master/current/
[license-finder-doc]: doc/development/licensing.md [license-finder-doc]: doc/development/licensing.md
...@@ -6,10 +6,8 @@ gem 'rails-deprecated_sanitizer', '~> 1.0.3' ...@@ -6,10 +6,8 @@ gem 'rails-deprecated_sanitizer', '~> 1.0.3'
# Responders respond_to and respond_with # Responders respond_to and respond_with
gem 'responders', '~> 2.0' gem 'responders', '~> 2.0'
# Specify a sprockets version due to increased performance gem 'sprockets', '~> 3.7.0'
# See https://gitlab.com/gitlab-org/gitlab-ce/issues/6069 gem 'sprockets-es6', '~> 0.9.2'
gem 'sprockets', '~> 3.6.0'
gem 'sprockets-es6'
# Default values for AR models # Default values for AR models
gem 'default_value_for', '~> 3.0.0' gem 'default_value_for', '~> 3.0.0'
...@@ -19,14 +17,14 @@ gem 'mysql2', '~> 0.3.16', group: :mysql ...@@ -19,14 +17,14 @@ gem 'mysql2', '~> 0.3.16', group: :mysql
gem 'pg', '~> 0.18.2', group: :postgres gem 'pg', '~> 0.18.2', group: :postgres
# Authentication libraries # Authentication libraries
gem 'devise', '~> 4.0' gem 'devise', '~> 4.2'
gem 'doorkeeper', '~> 4.2.0' gem 'doorkeeper', '~> 4.2.0'
gem 'omniauth', '~> 1.3.1' gem 'omniauth', '~> 1.3.1'
gem 'omniauth-auth0', '~> 1.4.1' gem 'omniauth-auth0', '~> 1.4.1'
gem 'omniauth-azure-oauth2', '~> 0.0.6' gem 'omniauth-azure-oauth2', '~> 0.0.6'
gem 'omniauth-bitbucket', '~> 0.0.2' gem 'omniauth-bitbucket', '~> 0.0.2'
gem 'omniauth-cas3', '~> 1.1.2' gem 'omniauth-cas3', '~> 1.1.2'
gem 'omniauth-facebook', '~> 3.0.0' gem 'omniauth-facebook', '~> 4.0.0'
gem 'omniauth-github', '~> 1.1.1' gem 'omniauth-github', '~> 1.1.1'
gem 'omniauth-gitlab', '~> 1.0.0' gem 'omniauth-gitlab', '~> 1.0.0'
gem 'omniauth-google-oauth2', '~> 0.4.1' gem 'omniauth-google-oauth2', '~> 0.4.1'
...@@ -53,7 +51,7 @@ gem 'browser', '~> 2.2' ...@@ -53,7 +51,7 @@ gem 'browser', '~> 2.2'
# 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', '~> 10.6.3' gem 'gitlab_git', '~> 10.6.7'
# LDAP Auth # LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes # GitLab fork with several improvements to original library. For full list of changes
...@@ -101,17 +99,17 @@ gem 'unf', '~> 0.1.4' ...@@ -101,17 +99,17 @@ gem 'unf', '~> 0.1.4'
gem 'seed-fu', '~> 2.3.5' gem 'seed-fu', '~> 2.3.5'
# Markdown and HTML processing # Markdown and HTML processing
gem 'html-pipeline', '~> 1.11.0' gem 'html-pipeline', '~> 1.11.0'
gem 'task_list', '~> 1.0.2', require: 'task_list/railtie' gem 'deckar01-task_list', '1.0.5', require: 'task_list/railtie'
gem 'github-markup', '~> 1.4' gem 'github-markup', '~> 1.4'
gem 'redcarpet', '~> 3.3.3' gem 'redcarpet', '~> 3.3.3'
gem 'RedCloth', '~> 4.3.2' gem 'RedCloth', '~> 4.3.2'
gem 'rdoc', '~>3.6' gem 'rdoc', '~>3.6'
gem 'org-ruby', '~> 0.9.12' gem 'org-ruby', '~> 0.9.12'
gem 'creole', '~> 0.5.0' gem 'creole', '~> 0.5.0'
gem 'wikicloth', '0.8.1' gem 'wikicloth', '0.8.1'
gem 'asciidoctor', '~> 1.5.2' gem 'asciidoctor', '~> 1.5.2'
gem 'rouge', '~> 2.0' gem 'rouge', '~> 2.0'
# See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s # See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s
# and https://groups.google.com/forum/#!topic/ruby-security-ann/Dy7YiKb_pMM # and https://groups.google.com/forum/#!topic/ruby-security-ann/Dy7YiKb_pMM
...@@ -122,8 +120,8 @@ gem 'diffy', '~> 3.0.3' ...@@ -122,8 +120,8 @@ gem 'diffy', '~> 3.0.3'
# Application server # Application server
group :unicorn do group :unicorn do
gem 'unicorn', '~> 4.9.0' gem 'unicorn', '~> 5.1.0'
gem 'unicorn-worker-killer', '~> 0.4.2' gem 'unicorn-worker-killer', '~> 0.4.4'
end end
# State machine # State machine
...@@ -135,8 +133,7 @@ gem 'after_commit_queue', '~> 1.3.0' ...@@ -135,8 +133,7 @@ gem 'after_commit_queue', '~> 1.3.0'
gem 'acts-as-taggable-on', '~> 3.4' gem 'acts-as-taggable-on', '~> 3.4'
# Background jobs # Background jobs
gem 'sinatra', '~> 1.4.4', require: false gem 'sidekiq', '~> 4.2'
gem 'sidekiq', '~> 4.0'
gem 'sidekiq-cron', '~> 0.4.0' gem 'sidekiq-cron', '~> 0.4.0'
gem 'redis-namespace', '~> 1.5.2' gem 'redis-namespace', '~> 1.5.2'
...@@ -206,11 +203,14 @@ gem 'mousetrap-rails', '~> 1.4.6' ...@@ -206,11 +203,14 @@ gem 'mousetrap-rails', '~> 1.4.6'
# Detect and convert string character encoding # Detect and convert string character encoding
gem 'charlock_holmes', '~> 0.7.3' gem 'charlock_holmes', '~> 0.7.3'
# Faster JSON
gem 'oj', '~> 2.17.4'
# Parse time & duration # Parse time & duration
gem 'chronic', '~> 0.10.2' gem 'chronic', '~> 0.10.2'
gem 'chronic_duration', '~> 0.10.6' gem 'chronic_duration', '~> 0.10.6'
gem 'sass-rails', '~> 5.0.0' gem 'sass-rails', '~> 5.0.6'
gem 'coffee-rails', '~> 4.1.0' gem 'coffee-rails', '~> 4.1.0'
gem 'uglifier', '~> 2.7.2' gem 'uglifier', '~> 2.7.2'
gem 'turbolinks', '~> 2.5.0' gem 'turbolinks', '~> 2.5.0'
...@@ -295,11 +295,11 @@ group :development, :test do ...@@ -295,11 +295,11 @@ group :development, :test do
gem 'spring-commands-spinach', '~> 1.1.0' gem 'spring-commands-spinach', '~> 1.1.0'
gem 'spring-commands-teaspoon', '~> 0.0.2' gem 'spring-commands-teaspoon', '~> 0.0.2'
gem 'rubocop', '~> 0.41.2', require: false gem 'rubocop', '~> 0.42.0', require: false
gem 'rubocop-rspec', '~> 1.5.0', require: false gem 'rubocop-rspec', '~> 1.5.0', require: false
gem 'scss_lint', '~> 0.47.0', require: false gem 'scss_lint', '~> 0.47.0', require: false
gem 'haml_lint', '~> 0.18.2', require: false
gem 'simplecov', '0.12.0', require: false gem 'simplecov', '0.12.0', require: false
gem 'flog', '~> 4.3.2', require: false
gem 'flay', '~> 2.6.1', require: false gem 'flay', '~> 2.6.1', require: false
gem 'bundler-audit', '~> 0.5.0', require: false gem 'bundler-audit', '~> 0.5.0', require: false
...@@ -316,10 +316,7 @@ group :test do ...@@ -316,10 +316,7 @@ group :test do
gem 'webmock', '~> 1.21.0' gem 'webmock', '~> 1.21.0'
gem 'test_after_commit', '~> 0.4.2' gem 'test_after_commit', '~> 0.4.2'
gem 'sham_rack', '~> 1.3.6' gem 'sham_rack', '~> 1.3.6'
end gem 'timecop', '~> 0.8.0'
group :production do
gem 'gitlab_meta', '7.0'
end end
gem 'newrelic_rpm', '~> 3.16' gem 'newrelic_rpm', '~> 3.16'
...@@ -330,7 +327,7 @@ gem 'mail_room', '~> 0.8' ...@@ -330,7 +327,7 @@ gem 'mail_room', '~> 0.8'
gem 'email_reply_parser', '~> 0.5.8' gem 'email_reply_parser', '~> 0.5.8'
gem 'ruby-prof', '~> 0.15.9' gem 'ruby-prof', '~> 0.16.2'
## CI ## CI
gem 'activerecord-session_store', '~> 1.0.0' gem 'activerecord-session_store', '~> 1.0.0'
......
...@@ -157,11 +157,15 @@ GEM ...@@ -157,11 +157,15 @@ GEM
database_cleaner (1.5.3) database_cleaner (1.5.3)
debug_inspector (0.0.2) debug_inspector (0.0.2)
debugger-ruby_core_source (1.3.8) debugger-ruby_core_source (1.3.8)
deckar01-task_list (1.0.5)
activesupport (~> 4.0)
html-pipeline
rack (~> 1.0)
default_value_for (3.0.2) default_value_for (3.0.2)
activerecord (>= 3.2.0, < 5.1) activerecord (>= 3.2.0, < 5.1)
descendants_tracker (0.0.4) descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1) thread_safe (~> 0.3, >= 0.3.1)
devise (4.1.1) devise (4.2.0)
bcrypt (~> 3.0) bcrypt (~> 3.0)
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
railties (>= 4.1.0, < 5.1) railties (>= 4.1.0, < 5.1)
...@@ -189,7 +193,7 @@ GEM ...@@ -189,7 +193,7 @@ GEM
erubis (2.7.0) erubis (2.7.0)
escape_utils (1.1.1) escape_utils (1.1.1)
eventmachine (1.0.8) eventmachine (1.0.8)
excon (0.49.0) excon (0.52.0)
execjs (2.6.0) execjs (2.6.0)
expression_parser (0.9.0) expression_parser (0.9.0)
factory_girl (4.5.0) factory_girl (4.5.0)
...@@ -209,14 +213,11 @@ GEM ...@@ -209,14 +213,11 @@ GEM
flay (2.6.1) flay (2.6.1)
ruby_parser (~> 3.0) ruby_parser (~> 3.0)
sexp_processor (~> 4.0) sexp_processor (~> 4.0)
flog (4.3.2)
ruby_parser (~> 3.1, > 3.1.0)
sexp_processor (~> 4.4)
flowdock (0.7.1) flowdock (0.7.1)
httparty (~> 0.7) httparty (~> 0.7)
multi_json multi_json
fog-aws (0.9.2) fog-aws (0.11.0)
fog-core (~> 1.27) fog-core (~> 1.38)
fog-json (~> 1.0) fog-json (~> 1.0)
fog-xml (~> 0.1) fog-xml (~> 0.1)
ipaddress (~> 0.8) ipaddress (~> 0.8)
...@@ -225,7 +226,7 @@ GEM ...@@ -225,7 +226,7 @@ GEM
fog-core (~> 1.27) fog-core (~> 1.27)
fog-json (~> 1.0) fog-json (~> 1.0)
fog-xml (~> 0.1) fog-xml (~> 0.1)
fog-core (1.40.0) fog-core (1.42.0)
builder builder
excon (~> 0.49) excon (~> 0.49)
formatador (~> 0.2) formatador (~> 0.2)
...@@ -279,12 +280,11 @@ GEM ...@@ -279,12 +280,11 @@ GEM
diff-lcs (~> 1.1) diff-lcs (~> 1.1)
mime-types (>= 1.16, < 3) mime-types (>= 1.16, < 3)
posix-spawn (~> 0.3) posix-spawn (~> 0.3)
gitlab_git (10.6.3) gitlab_git (10.6.7)
activesupport (~> 4.0) activesupport (~> 4.0)
charlock_holmes (~> 0.7.3) charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0) github-linguist (~> 4.7.0)
rugged (~> 0.24.0) rugged (~> 0.24.0)
gitlab_meta (7.0)
gitlab_omniauth-ldap (1.2.1) gitlab_omniauth-ldap (1.2.1)
net-ldap (~> 0.9) net-ldap (~> 0.9)
omniauth (~> 1.0) omniauth (~> 1.0)
...@@ -322,11 +322,18 @@ GEM ...@@ -322,11 +322,18 @@ GEM
grape-entity (0.4.8) grape-entity (0.4.8)
activesupport activesupport
multi_json (>= 1.3.2) multi_json (>= 1.3.2)
haml (4.0.7)
tilt
haml_lint (0.18.2)
haml (~> 4.0)
rake (>= 10, < 12)
rubocop (>= 0.36.0)
sysexits (~> 1.1)
hamlit (2.6.1) hamlit (2.6.1)
temple (~> 0.7.6) temple (~> 0.7.6)
thor thor
tilt tilt
hashie (3.4.3) hashie (3.4.4)
health_check (2.1.0) health_check (2.1.0)
rails (>= 4.0) rails (>= 4.0)
hipchat (1.5.2) hipchat (1.5.2)
...@@ -394,7 +401,7 @@ GEM ...@@ -394,7 +401,7 @@ GEM
mime-types (>= 1.16, < 4) mime-types (>= 1.16, < 4)
mail_room (0.8.0) mail_room (0.8.0)
method_source (0.8.2) method_source (0.8.2)
mime-types (2.99.2) mime-types (2.99.3)
mimemagic (0.3.0) mimemagic (0.3.0)
mini_portile2 (2.1.0) mini_portile2 (2.1.0)
minitest (5.7.0) minitest (5.7.0)
...@@ -420,6 +427,7 @@ GEM ...@@ -420,6 +427,7 @@ GEM
rack (>= 1.2, < 3) rack (>= 1.2, < 3)
octokit (4.3.0) octokit (4.3.0)
sawyer (~> 0.7.0, >= 0.5.3) sawyer (~> 0.7.0, >= 0.5.3)
oj (2.17.4)
omniauth (1.3.1) omniauth (1.3.1)
hashie (>= 1.2, < 4) hashie (>= 1.2, < 4)
rack (>= 1.0, < 3) rack (>= 1.0, < 3)
...@@ -437,7 +445,7 @@ GEM ...@@ -437,7 +445,7 @@ GEM
addressable (~> 2.3) addressable (~> 2.3)
nokogiri (~> 1.6.6) nokogiri (~> 1.6.6)
omniauth (~> 1.2) omniauth (~> 1.2)
omniauth-facebook (3.0.0) omniauth-facebook (4.0.0)
omniauth-oauth2 (~> 1.2) omniauth-oauth2 (~> 1.2)
omniauth-github (1.1.2) omniauth-github (1.1.2)
omniauth (~> 1.0) omniauth (~> 1.0)
...@@ -546,7 +554,7 @@ GEM ...@@ -546,7 +554,7 @@ GEM
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
rainbow (2.1.0) rainbow (2.1.0)
raindrops (0.15.0) raindrops (0.17.0)
rake (10.5.0) rake (10.5.0)
rb-fsevent (0.9.6) rb-fsevent (0.9.6)
rb-inotify (0.9.5) rb-inotify (0.9.5)
...@@ -580,7 +588,7 @@ GEM ...@@ -580,7 +588,7 @@ GEM
request_store (1.3.1) request_store (1.3.1)
rerun (0.11.0) rerun (0.11.0)
listen (~> 3.0) listen (~> 3.0)
responders (2.1.1) responders (2.3.0)
railties (>= 4.2.0, < 5.1) railties (>= 4.2.0, < 5.1)
rinku (2.0.0) rinku (2.0.0)
rotp (2.1.2) rotp (2.1.2)
...@@ -612,7 +620,7 @@ GEM ...@@ -612,7 +620,7 @@ GEM
rspec-retry (0.4.5) rspec-retry (0.4.5)
rspec-core rspec-core
rspec-support (3.5.0) rspec-support (3.5.0)
rubocop (0.41.2) rubocop (0.42.0)
parser (>= 2.3.1.1, < 3.0) parser (>= 2.3.1.1, < 3.0)
powerpack (~> 0.1) powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0) rainbow (>= 1.99.1, < 3.0)
...@@ -622,7 +630,7 @@ GEM ...@@ -622,7 +630,7 @@ GEM
rubocop (>= 0.40.0) rubocop (>= 0.40.0)
ruby-fogbugz (0.2.1) ruby-fogbugz (0.2.1)
crack (~> 0.4) crack (~> 0.4)
ruby-prof (0.15.9) ruby-prof (0.16.2)
ruby-progressbar (1.8.1) ruby-progressbar (1.8.1)
ruby-saml (1.3.0) ruby-saml (1.3.0)
nokogiri (>= 1.5.10) nokogiri (>= 1.5.10)
...@@ -637,7 +645,7 @@ GEM ...@@ -637,7 +645,7 @@ GEM
sanitize (2.1.0) sanitize (2.1.0)
nokogiri (>= 1.4.4) nokogiri (>= 1.4.4)
sass (3.4.22) sass (3.4.22)
sass-rails (5.0.5) sass-rails (5.0.6)
railties (>= 4.0.0, < 6) railties (>= 4.0.0, < 6)
sass (~> 3.1) sass (~> 3.1)
sprockets (>= 2.8, < 4.0) sprockets (>= 2.8, < 4.0)
...@@ -665,11 +673,11 @@ GEM ...@@ -665,11 +673,11 @@ GEM
rack rack
shoulda-matchers (2.8.0) shoulda-matchers (2.8.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
sidekiq (4.1.4) sidekiq (4.2.1)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0) connection_pool (~> 2.2, >= 2.2.0)
rack-protection (~> 1.5)
redis (~> 3.2, >= 3.2.1) redis (~> 3.2, >= 3.2.1)
sinatra (>= 1.4.7)
sidekiq-cron (0.4.0) sidekiq-cron (0.4.0)
redis-namespace (>= 1.5.2) redis-namespace (>= 1.5.2)
rufus-scheduler (>= 2.0.24) rufus-scheduler (>= 2.0.24)
...@@ -679,10 +687,6 @@ GEM ...@@ -679,10 +687,6 @@ GEM
json (>= 1.8, < 3) json (>= 1.8, < 3)
simplecov-html (~> 0.10.0) simplecov-html (~> 0.10.0)
simplecov-html (0.10.0) simplecov-html (0.10.0)
sinatra (1.4.7)
rack (~> 1.5)
rack-protection (~> 1.4)
tilt (>= 1.3, < 3)
slack-notifier (1.2.1) slack-notifier (1.2.1)
slop (3.6.0) slop (3.6.0)
spinach (0.8.10) spinach (0.8.10)
...@@ -702,10 +706,10 @@ GEM ...@@ -702,10 +706,10 @@ GEM
spring (>= 0.9.1) spring (>= 0.9.1)
spring-commands-teaspoon (0.0.2) spring-commands-teaspoon (0.0.2)
spring (>= 0.9.1) spring (>= 0.9.1)
sprockets (3.6.3) sprockets (3.7.0)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
rack (> 1, < 3) rack (> 1, < 3)
sprockets-es6 (0.9.0) sprockets-es6 (0.9.2)
babel-source (>= 5.8.11) babel-source (>= 5.8.11)
babel-transpiler babel-transpiler
sprockets (>= 3.0.0) sprockets (>= 3.0.0)
...@@ -723,9 +727,8 @@ GEM ...@@ -723,9 +727,8 @@ GEM
stringex (2.5.2) stringex (2.5.2)
sys-filesystem (1.1.6) sys-filesystem (1.1.6)
ffi ffi
sysexits (1.2.0)
systemu (2.6.5) systemu (2.6.5)
task_list (1.0.2)
html-pipeline
teaspoon (1.1.5) teaspoon (1.1.5)
railties (>= 3.2.5, < 6) railties (>= 3.2.5, < 6)
teaspoon-jasmine (2.2.0) teaspoon-jasmine (2.2.0)
...@@ -754,10 +757,9 @@ GEM ...@@ -754,10 +757,9 @@ GEM
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.7.2) unf_ext (0.0.7.2)
unicode-display_width (1.1.0) unicode-display_width (1.1.1)
unicorn (4.9.0) unicorn (5.1.0)
kgio (~> 2.6) kgio (~> 2.6)
rack
raindrops (~> 0.7) raindrops (~> 0.7)
unicorn-worker-killer (0.4.4) unicorn-worker-killer (0.4.4)
get_process_mem (~> 0) get_process_mem (~> 0)
...@@ -831,8 +833,9 @@ DEPENDENCIES ...@@ -831,8 +833,9 @@ DEPENDENCIES
creole (~> 0.5.0) creole (~> 0.5.0)
d3_rails (~> 3.5.0) d3_rails (~> 3.5.0)
database_cleaner (~> 1.5.0) database_cleaner (~> 1.5.0)
deckar01-task_list (= 1.0.5)
default_value_for (~> 3.0.0) default_value_for (~> 3.0.0)
devise (~> 4.0) devise (~> 4.2)
devise-two-factor (~> 3.0.0) devise-two-factor (~> 3.0.0)
diffy (~> 3.0.3) diffy (~> 3.0.3)
doorkeeper (~> 4.2.0) doorkeeper (~> 4.2.0)
...@@ -842,7 +845,6 @@ DEPENDENCIES ...@@ -842,7 +845,6 @@ DEPENDENCIES
factory_girl_rails (~> 4.6.0) factory_girl_rails (~> 4.6.0)
ffaker (~> 2.0.0) ffaker (~> 2.0.0)
flay (~> 2.6.1) flay (~> 2.6.1)
flog (~> 4.3.2)
fog-aws (~> 0.9) fog-aws (~> 0.9)
fog-azure (~> 0.0) fog-azure (~> 0.0)
fog-core (~> 1.40) fog-core (~> 1.40)
...@@ -858,14 +860,14 @@ DEPENDENCIES ...@@ -858,14 +860,14 @@ DEPENDENCIES
github-linguist (~> 4.7.0) github-linguist (~> 4.7.0)
github-markup (~> 1.4) github-markup (~> 1.4)
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab_git (~> 10.6.3) gitlab_git (~> 10.6.7)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1) gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.2) gollum-lib (~> 4.2)
gollum-rugged_adapter (~> 0.4.2) gollum-rugged_adapter (~> 0.4.2)
gon (~> 6.1.0) gon (~> 6.1.0)
grape (~> 0.15.0) grape (~> 0.15.0)
grape-entity (~> 0.4.2) grape-entity (~> 0.4.2)
haml_lint (~> 0.18.2)
hamlit (~> 2.6.1) hamlit (~> 2.6.1)
health_check (~> 2.1.0) health_check (~> 2.1.0)
hipchat (~> 1.5.0) hipchat (~> 1.5.0)
...@@ -895,12 +897,13 @@ DEPENDENCIES ...@@ -895,12 +897,13 @@ DEPENDENCIES
nokogiri (~> 1.6.7, >= 1.6.7.2) nokogiri (~> 1.6.7, >= 1.6.7.2)
oauth2 (~> 1.2.0) oauth2 (~> 1.2.0)
octokit (~> 4.3.0) octokit (~> 4.3.0)
oj (~> 2.17.4)
omniauth (~> 1.3.1) omniauth (~> 1.3.1)
omniauth-auth0 (~> 1.4.1) omniauth-auth0 (~> 1.4.1)
omniauth-azure-oauth2 (~> 0.0.6) omniauth-azure-oauth2 (~> 0.0.6)
omniauth-bitbucket (~> 0.0.2) omniauth-bitbucket (~> 0.0.2)
omniauth-cas3 (~> 1.1.2) omniauth-cas3 (~> 1.1.2)
omniauth-facebook (~> 3.0.0) omniauth-facebook (~> 4.0.0)
omniauth-github (~> 1.1.1) omniauth-github (~> 1.1.1)
omniauth-gitlab (~> 1.0.0) omniauth-gitlab (~> 1.0.0)
omniauth-google-oauth2 (~> 0.4.1) omniauth-google-oauth2 (~> 0.4.1)
...@@ -935,12 +938,12 @@ DEPENDENCIES ...@@ -935,12 +938,12 @@ DEPENDENCIES
rqrcode-rails3 (~> 0.1.7) rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.5.0) rspec-rails (~> 3.5.0)
rspec-retry (~> 0.4.5) rspec-retry (~> 0.4.5)
rubocop (~> 0.41.2) rubocop (~> 0.42.0)
rubocop-rspec (~> 1.5.0) rubocop-rspec (~> 1.5.0)
ruby-fogbugz (~> 0.2.1) ruby-fogbugz (~> 0.2.1)
ruby-prof (~> 0.15.9) ruby-prof (~> 0.16.2)
sanitize (~> 2.0) sanitize (~> 2.0)
sass-rails (~> 5.0.0) sass-rails (~> 5.0.6)
scss_lint (~> 0.47.0) scss_lint (~> 0.47.0)
sdoc (~> 0.3.20) sdoc (~> 0.3.20)
seed-fu (~> 2.3.5) seed-fu (~> 2.3.5)
...@@ -949,10 +952,9 @@ DEPENDENCIES ...@@ -949,10 +952,9 @@ DEPENDENCIES
settingslogic (~> 2.0.9) settingslogic (~> 2.0.9)
sham_rack (~> 1.3.6) sham_rack (~> 1.3.6)
shoulda-matchers (~> 2.8.0) shoulda-matchers (~> 2.8.0)
sidekiq (~> 4.0) sidekiq (~> 4.2)
sidekiq-cron (~> 0.4.0) sidekiq-cron (~> 0.4.0)
simplecov (= 0.12.0) simplecov (= 0.12.0)
sinatra (~> 1.4.4)
slack-notifier (~> 1.2.0) slack-notifier (~> 1.2.0)
spinach-rails (~> 0.2.1) spinach-rails (~> 0.2.1)
spinach-rerun-reporter (~> 0.0.2) spinach-rerun-reporter (~> 0.0.2)
...@@ -960,22 +962,22 @@ DEPENDENCIES ...@@ -960,22 +962,22 @@ DEPENDENCIES
spring-commands-rspec (~> 1.0.4) spring-commands-rspec (~> 1.0.4)
spring-commands-spinach (~> 1.1.0) spring-commands-spinach (~> 1.1.0)
spring-commands-teaspoon (~> 0.0.2) spring-commands-teaspoon (~> 0.0.2)
sprockets (~> 3.6.0) sprockets (~> 3.7.0)
sprockets-es6 sprockets-es6 (~> 0.9.2)
state_machines-activerecord (~> 0.4.0) state_machines-activerecord (~> 0.4.0)
sys-filesystem (~> 1.1.6) sys-filesystem (~> 1.1.6)
task_list (~> 1.0.2)
teaspoon (~> 1.1.0) teaspoon (~> 1.1.0)
teaspoon-jasmine (~> 2.2.0) teaspoon-jasmine (~> 2.2.0)
test_after_commit (~> 0.4.2) test_after_commit (~> 0.4.2)
thin (~> 1.7.0) thin (~> 1.7.0)
timecop (~> 0.8.0)
turbolinks (~> 2.5.0) turbolinks (~> 2.5.0)
u2f (~> 0.2.1) u2f (~> 0.2.1)
uglifier (~> 2.7.2) uglifier (~> 2.7.2)
underscore-rails (~> 1.8.0) underscore-rails (~> 1.8.0)
unf (~> 0.1.4) unf (~> 0.1.4)
unicorn (~> 4.9.0) unicorn (~> 5.1.0)
unicorn-worker-killer (~> 0.4.2) unicorn-worker-killer (~> 0.4.4)
version_sorter (~> 2.1.0) version_sorter (~> 2.1.0)
virtus (~> 1.0.1) virtus (~> 1.0.1)
vmstat (~> 2.2) vmstat (~> 2.2)
...@@ -984,4 +986,4 @@ DEPENDENCIES ...@@ -984,4 +986,4 @@ DEPENDENCIES
wikicloth (= 0.8.1) wikicloth (= 0.8.1)
BUNDLED WITH BUNDLED WITH
1.12.5 1.13.1
...@@ -3,10 +3,11 @@ ...@@ -3,10 +3,11 @@
[![build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master) [![build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
[![coverage report](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master) [![coverage report](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
[![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq) [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
[![Core Infrastructure Initiative Best Practices](https://bestpractices.coreinfrastructure.org/projects/42/badge)](https://bestpractices.coreinfrastructure.org/projects/42)
## Canonical source ## Canonical source
The source of GitLab Community Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/) and there are mirrors to make [contributing](CONTRIBUTING.md) as easy as possible. The canonical source of GitLab Community Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/).
## Open source software to collaborate on code ## Open source software to collaborate on code
......
8.12.0-pre 8.13.0-pre
...@@ -16,9 +16,6 @@ ...@@ -16,9 +16,6 @@
.replace(':id', group_id); .replace(':id', group_id);
return $.ajax({ return $.ajax({
url: url, url: url,
data: {
private_token: gon.api_token
},
dataType: "json" dataType: "json"
}).done(function(group) { }).done(function(group) {
return callback(group); return callback(group);
...@@ -31,7 +28,6 @@ ...@@ -31,7 +28,6 @@
return $.ajax({ return $.ajax({
url: url, url: url,
data: { data: {
private_token: gon.api_token,
search: query, search: query,
per_page: 20 per_page: 20
}, },
...@@ -46,7 +42,6 @@ ...@@ -46,7 +42,6 @@
return $.ajax({ return $.ajax({
url: url, url: url,
data: { data: {
private_token: gon.api_token,
search: query, search: query,
per_page: 20 per_page: 20
}, },
...@@ -61,7 +56,6 @@ ...@@ -61,7 +56,6 @@
return $.ajax({ return $.ajax({
url: url, url: url,
data: { data: {
private_token: gon.api_token,
search: query, search: query,
order_by: order, order_by: order,
per_page: 20 per_page: 20
...@@ -74,7 +68,6 @@ ...@@ -74,7 +68,6 @@
newLabel: function(project_id, data, callback) { newLabel: function(project_id, data, callback) {
var url = Api.buildUrl(Api.labelsPath) var url = Api.buildUrl(Api.labelsPath)
.replace(':id', project_id); .replace(':id', project_id);
data.private_token = gon.api_token;
return $.ajax({ return $.ajax({
url: url, url: url,
type: "POST", type: "POST",
...@@ -93,7 +86,6 @@ ...@@ -93,7 +86,6 @@
return $.ajax({ return $.ajax({
url: url, url: url,
data: { data: {
private_token: gon.api_token,
search: query, search: query,
per_page: 20 per_page: 20
}, },
......
...@@ -247,10 +247,11 @@ ...@@ -247,10 +247,11 @@
$this.toggleClass('active'); $this.toggleClass('active');
var notesHolders = $this.closest('.diff-file').find('.notes_holder'); var notesHolders = $this.closest('.diff-file').find('.notes_holder');
if ($this.hasClass('active')) { if ($this.hasClass('active')) {
notesHolders.show(); notesHolders.show().find('.hide').show();
} else { } else {
notesHolders.hide(); notesHolders.hide();
} }
$this.trigger('blur');
return e.preventDefault(); return e.preventDefault();
}); });
$document.off("click", '.js-confirm-danger'); $document.off("click", '.js-confirm-danger');
......
...@@ -357,7 +357,7 @@ ...@@ -357,7 +357,7 @@
$('ul.emoji-menu-search, h5.emoji-search').remove(); $('ul.emoji-menu-search, h5.emoji-search').remove();
if (term) { if (term) {
// Generate a search result block // Generate a search result block
h5 = $('<h5>').text('Search results'); h5 = $('<h5 class="emoji-search" />').text('Search results');
found_emojis = _this.searchEmojis(term).show(); found_emojis = _this.searchEmojis(term).show();
ul = $('<ul>').addClass('emoji-menu-list emoji-menu-search').append(found_emojis); ul = $('<ul>').addClass('emoji-menu-list emoji-menu-search').append(found_emojis);
$('.emoji-menu-content ul, .emoji-menu-content h5').hide(); $('.emoji-menu-content ul, .emoji-menu-content h5').hide();
......
...@@ -13,6 +13,9 @@ ...@@ -13,6 +13,9 @@
this.buildDropdown(); this.buildDropdown();
this.bindEvents(); this.bindEvents();
this.onFilenameUpdate(); this.onFilenameUpdate();
this.autosizeUpdateEvent = document.createEvent('Event');
this.autosizeUpdateEvent.initEvent('autosize:update', true, false);
} }
TemplateSelector.prototype.buildDropdown = function() { TemplateSelector.prototype.buildDropdown = function() {
...@@ -72,6 +75,10 @@ ...@@ -72,6 +75,10 @@
TemplateSelector.prototype.requestFileSuccess = function(file, skipFocus) { TemplateSelector.prototype.requestFileSuccess = function(file, skipFocus) {
this.editor.setValue(file.content, 1); this.editor.setValue(file.content, 1);
if (!skipFocus) this.editor.focus(); if (!skipFocus) this.editor.focus();
if (this.editor instanceof jQuery) {
this.editor.get(0).dispatchEvent(this.autosizeUpdateEvent);
}
}; };
TemplateSelector.prototype.startLoadingSpinner = function() { TemplateSelector.prototype.startLoadingSpinner = function() {
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
// submitted textarea // submitted textarea
})(this)); })(this));
this.initModePanesAndLinks(); this.initModePanesAndLinks();
this.initSoftWrap();
new BlobLicenseSelectors({ new BlobLicenseSelectors({
editor: this.editor editor: this.editor
}); });
...@@ -50,6 +51,7 @@ ...@@ -50,6 +51,7 @@
this.$editModePanes.hide(); this.$editModePanes.hide();
currentPane.fadeIn(200); currentPane.fadeIn(200);
if (paneId === "#preview") { if (paneId === "#preview") {
this.$toggleButton.hide();
return $.post(currentLink.data("preview-url"), { return $.post(currentLink.data("preview-url"), {
content: this.editor.getValue() content: this.editor.getValue()
}, function(response) { }, function(response) {
...@@ -57,10 +59,23 @@ ...@@ -57,10 +59,23 @@
return currentPane.syntaxHighlight(); return currentPane.syntaxHighlight();
}); });
} else { } else {
this.$toggleButton.show();
return this.editor.focus(); return this.editor.focus();
} }
}; };
EditBlob.prototype.initSoftWrap = function() {
this.isSoftWrapped = false;
this.$toggleButton = $('.soft-wrap-toggle');
this.$toggleButton.on('click', this.toggleSoftWrap.bind(this));
};
EditBlob.prototype.toggleSoftWrap = function(e) {
this.isSoftWrapped = !this.isSoftWrapped;
this.$toggleButton.toggleClass('soft-wrap-active', this.isSoftWrapped);
this.editor.getSession().setUseWrapMode(this.isSoftWrapped);
};
return EditBlob; return EditBlob;
})(); })();
......
...@@ -34,6 +34,11 @@ ...@@ -34,6 +34,11 @@
}, },
issues () { issues () {
this.$nextTick(() => { this.$nextTick(() => {
if (this.scrollHeight() <= this.listHeight() && this.list.issuesSize > this.list.issues.length) {
this.list.page++;
this.list.getIssues(false);
}
if (this.scrollHeight() > this.listHeight()) { if (this.scrollHeight() > this.listHeight()) {
this.showCount = true; this.showCount = true;
} else { } else {
......
...@@ -27,10 +27,11 @@ ...@@ -27,10 +27,11 @@
$(document).off('click', '.js-sidebar-build-toggle').on('click', '.js-sidebar-build-toggle', this.toggleSidebar); $(document).off('click', '.js-sidebar-build-toggle').on('click', '.js-sidebar-build-toggle', this.toggleSidebar);
$(window).off('resize.build').on('resize.build', this.hideSidebar); $(window).off('resize.build').on('resize.build', this.hideSidebar);
$(document).off('click', '.stage-item').on('click', '.stage-item', this.updateDropdown); $(document).off('click', '.stage-item').on('click', '.stage-item', this.updateDropdown);
$('#js-build-scroll > a').off('click').on('click', this.stepTrace);
this.updateArtifactRemoveDate(); this.updateArtifactRemoveDate();
if ($('#build-trace').length) { if ($('#build-trace').length) {
this.getInitialBuildTrace(); this.getInitialBuildTrace();
this.initScrollButtonAffix(); this.initScrollButtons();
} }
if (this.build_status === "running" || this.build_status === "pending") { if (this.build_status === "running" || this.build_status === "pending") {
$('#autoscroll-button').on('click', function() { $('#autoscroll-button').on('click', function() {
...@@ -106,7 +107,7 @@ ...@@ -106,7 +107,7 @@
} }
}; };
Build.prototype.initScrollButtonAffix = function() { Build.prototype.initScrollButtons = function() {
var $body, $buildScroll, $buildTrace; var $body, $buildScroll, $buildTrace;
$buildScroll = $('#js-build-scroll'); $buildScroll = $('#js-build-scroll');
$body = $('body'); $body = $('body');
...@@ -165,6 +166,14 @@ ...@@ -165,6 +166,14 @@
this.populateJobs(stage); this.populateJobs(stage);
}; };
Build.prototype.stepTrace = function(e) {
e.preventDefault();
$currentTarget = $(e.currentTarget);
$.scrollTo($currentTarget.attr('href'), {
offset: -($('.navbar-gitlab').outerHeight() + $('.layout-nav').outerHeight())
});
};
return Build; return Build;
})(); })();
......
...@@ -23,8 +23,9 @@ ...@@ -23,8 +23,9 @@
selectable: true, selectable: true,
filterable: true, filterable: true,
filterByText: true, filterByText: true,
fieldName: $dropdown.attr('name'), toggleLabel: true,
filterInput: 'input[type="text"]', fieldName: $dropdown.data('field-name'),
filterInput: 'input[type="search"]',
renderRow: function(ref) { renderRow: function(ref) {
var link; var link;
if (ref.header != null) { if (ref.header != null) {
......
...@@ -26,15 +26,15 @@ ...@@ -26,15 +26,15 @@
}; };
showTooltip = function(target, title) { showTooltip = function(target, title) {
return $(target).tooltip({ var $target = $(target);
container: 'body', var originalTitle = $target.data('original-title');
html: 'true',
placement: 'auto bottom', $target
title: title, .attr('title', 'Copied!')
trigger: 'manual' .tooltip('fixTitle')
}).tooltip('show').one('mouseleave', function() { .tooltip('show')
return $(this).tooltip('hide'); .attr('title', originalTitle)
}); .tooltip('fixTitle');
}; };
$(function() { $(function() {
......
((global) => {
const COOKIE_NAME = 'cycle_analytics_help_dismissed';
const store = gl.cycleAnalyticsStore = {
isLoading: true,
hasError: false,
isHelpDismissed: $.cookie(COOKIE_NAME),
analytics: {}
};
gl.CycleAnalytics = class CycleAnalytics {
constructor() {
const that = this;
this.vue = new Vue({
el: '#cycle-analytics',
name: 'CycleAnalytics',
created: this.fetchData(),
data: store,
methods: {
dismissLanding() {
that.dismissLanding();
}
}
});
}
fetchData(options) {
store.isLoading = true;
options = options || { startDate: 30 };
$.ajax({
url: $('#cycle-analytics').data('request-path'),
method: 'GET',
dataType: 'json',
contentType: 'application/json',
data: { start_date: options.startDate }
}).done((data) => {
this.decorateData(data);
this.initDropdown();
})
.error((data) => {
this.handleError(data);
})
.always(() => {
store.isLoading = false;
})
}
decorateData(data) {
data.summary = data.summary || [];
data.stats = data.stats || [];
data.summary.forEach((item) => {
item.value = item.value || '-';
});
data.stats.forEach((item) => {
item.value = item.value || '- - -';
});
store.analytics = data;
}
handleError(data) {
store.hasError = true;
new Flash('There was an error while fetching cycle analytics data.', 'alert');
}
dismissLanding() {
store.isHelpDismissed = true;
$.cookie(COOKIE_NAME, true, {
path: gon.relative_url_root || '/'
});
}
initDropdown() {
const $dropdown = $('.js-ca-dropdown');
const $label = $dropdown.find('.dropdown-label');
$dropdown.find('li a').off('click').on('click', (e) => {
e.preventDefault();
const $target = $(e.currentTarget);
const value = $target.data('value');
$label.text($target.text().trim());
this.fetchData({ startDate: value });
})
}
}
})(window.gl || (window.gl = {}));
((w) => { ((w) => {
w.ResolveBtn = Vue.extend({ w.ResolveBtn = Vue.extend({
mixins: [
ButtonMixins
],
props: { props: {
noteId: Number, noteId: Number,
discussionId: String, discussionId: String,
resolved: Boolean, resolved: Boolean,
namespacePath: String,
projectPath: String, projectPath: String,
canResolve: Boolean, canResolve: Boolean,
resolvedBy: String resolvedBy: String
...@@ -69,10 +65,10 @@ ...@@ -69,10 +65,10 @@
if (this.isResolved) { if (this.isResolved) {
promise = ResolveService promise = ResolveService
.unresolve(this.namespace, this.noteId); .unresolve(this.projectPath, this.noteId);
} else { } else {
promise = ResolveService promise = ResolveService
.resolve(this.namespace, this.noteId); .resolve(this.projectPath, this.noteId);
} }
promise.then((response) => { promise.then((response) => {
......
((w) => { ((w) => {
w.ResolveDiscussionBtn = Vue.extend({ w.ResolveDiscussionBtn = Vue.extend({
mixins: [
ButtonMixins
],
props: { props: {
discussionId: String, discussionId: String,
mergeRequestId: Number, mergeRequestId: Number,
namespacePath: String,
projectPath: String, projectPath: String,
canResolve: Boolean, canResolve: Boolean,
}, },
...@@ -50,7 +46,7 @@ ...@@ -50,7 +46,7 @@
}, },
methods: { methods: {
resolve: function () { resolve: function () {
ResolveService.toggleResolveForDiscussion(this.namespace, this.mergeRequestId, this.discussionId); ResolveService.toggleResolveForDiscussion(this.projectPath, this.mergeRequestId, this.discussionId);
} }
}, },
created: function () { created: function () {
......
((w) => {
w.ButtonMixins = {
computed: {
namespace: function () {
return `${this.namespacePath}/${this.projectPath}`;
}
}
};
})(window);
...@@ -9,32 +9,32 @@ ...@@ -9,32 +9,32 @@
Vue.http.headers.common['X-CSRF-Token'] = $.rails.csrfToken(); Vue.http.headers.common['X-CSRF-Token'] = $.rails.csrfToken();
} }
prepareRequest(namespace) { prepareRequest(root) {
this.setCSRF(); this.setCSRF();
Vue.http.options.root = `/${namespace}`; Vue.http.options.root = root;
} }
resolve(namespace, noteId) { resolve(projectPath, noteId) {
this.prepareRequest(namespace); this.prepareRequest(projectPath);
return this.noteResource.save({ noteId }, {}); return this.noteResource.save({ noteId }, {});
} }
unresolve(namespace, noteId) { unresolve(projectPath, noteId) {
this.prepareRequest(namespace); this.prepareRequest(projectPath);
return this.noteResource.delete({ noteId }, {}); return this.noteResource.delete({ noteId }, {});
} }
toggleResolveForDiscussion(namespace, mergeRequestId, discussionId) { toggleResolveForDiscussion(projectPath, mergeRequestId, discussionId) {
const discussion = CommentsStore.state[discussionId], const discussion = CommentsStore.state[discussionId],
isResolved = discussion.isResolved(); isResolved = discussion.isResolved();
let promise; let promise;
if (isResolved) { if (isResolved) {
promise = this.unResolveAll(namespace, mergeRequestId, discussionId); promise = this.unResolveAll(projectPath, mergeRequestId, discussionId);
} else { } else {
promise = this.resolveAll(namespace, mergeRequestId, discussionId); promise = this.resolveAll(projectPath, mergeRequestId, discussionId);
} }
promise.then((response) => { promise.then((response) => {
...@@ -57,10 +57,10 @@ ...@@ -57,10 +57,10 @@
}) })
} }
resolveAll(namespace, mergeRequestId, discussionId) { resolveAll(projectPath, mergeRequestId, discussionId) {
const discussion = CommentsStore.state[discussionId]; const discussion = CommentsStore.state[discussionId];
this.prepareRequest(namespace); this.prepareRequest(projectPath);
discussion.loading = true; discussion.loading = true;
...@@ -70,10 +70,10 @@ ...@@ -70,10 +70,10 @@
}, {}); }, {});
} }
unResolveAll(namespace, mergeRequestId, discussionId) { unResolveAll(projectPath, mergeRequestId, discussionId) {
const discussion = CommentsStore.state[discussionId]; const discussion = CommentsStore.state[discussionId];
this.prepareRequest(namespace); this.prepareRequest(projectPath);
discussion.loading = true; discussion.loading = true;
......
...@@ -94,6 +94,11 @@ ...@@ -94,6 +94,11 @@
break; break;
case "projects:merge_requests:conflicts": case "projects:merge_requests:conflicts":
window.mcui = new MergeConflictResolver() window.mcui = new MergeConflictResolver()
break;
case 'projects:merge_requests:index':
shortcut_handler = new ShortcutsNavigation();
Issuable.init();
break;
case 'dashboard:activity': case 'dashboard:activity':
new Activities(); new Activities();
break; break;
...@@ -185,6 +190,9 @@ ...@@ -185,6 +190,9 @@
new gl.ProtectedBranchCreate(); new gl.ProtectedBranchCreate();
new gl.ProtectedBranchEditList(); new gl.ProtectedBranchEditList();
break; break;
case 'projects:cycle_analytics:show':
new gl.CycleAnalytics();
break;
} }
switch (path.first()) { switch (path.first()) {
case 'admin': case 'admin':
......
...@@ -352,7 +352,13 @@ ...@@ -352,7 +352,13 @@
if (self.options.clicked) { if (self.options.clicked) {
self.options.clicked(selected, $el, e); self.options.clicked(selected, $el, e);
} }
return $el.trigger('blur');
// Update label right after all modifications in dropdown has been done
if (self.options.toggleLabel) {
self.updateLabel(selected, $el, self);
}
$el.trigger('blur');
}); });
} }
} }
...@@ -529,7 +535,7 @@ ...@@ -529,7 +535,7 @@
} else { } else {
if (!selected) { if (!selected) {
value = this.options.id ? this.options.id(data) : data.id; value = this.options.id ? this.options.id(data) : data.id;
fieldName = typeof this.options.fieldName === 'function' ? this.options.fieldName() : this.options.fieldName; fieldName = this.options.fieldName;
field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value + "']"); field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value + "']");
if (field.length) { if (field.length) {
...@@ -589,6 +595,7 @@ ...@@ -589,6 +595,7 @@
GitLabDropdown.prototype.rowClicked = function(el) { GitLabDropdown.prototype.rowClicked = function(el) {
var field, fieldName, groupName, isInput, selectedIndex, selectedObject, value; var field, fieldName, groupName, isInput, selectedIndex, selectedObject, value;
fieldName = this.options.fieldName;
isInput = $(this.el).is('input'); isInput = $(this.el).is('input');
if (this.renderedData) { if (this.renderedData) {
groupName = el.data('group'); groupName = el.data('group');
...@@ -600,27 +607,29 @@ ...@@ -600,27 +607,29 @@
selectedObject = this.renderedData[selectedIndex]; selectedObject = this.renderedData[selectedIndex];
} }
} }
fieldName = typeof this.options.fieldName === 'function' ? this.options.fieldName(selectedObject) : this.options.fieldName; field = [];
value = this.options.id ? this.options.id(selectedObject, el) : selectedObject.id; value = this.options.id ? this.options.id(selectedObject, el) : selectedObject.id;
if (isInput) { if (isInput) {
field = $(this.el); field = $(this.el);
} else { } else if(value) {
field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + escape(value) + "']"); field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value.toString().replace(/'/g, '\\\'') + "']");
} }
if (el.hasClass(ACTIVE_CLASS)) { if (el.hasClass(ACTIVE_CLASS)) {
el.removeClass(ACTIVE_CLASS); el.removeClass(ACTIVE_CLASS);
if (isInput) { if (field && field.length) {
field.val(''); if (isInput) {
} else { field.val('');
field.remove(); } else {
field.remove();
}
} }
} else if (el.hasClass(INDETERMINATE_CLASS)) { } else if (el.hasClass(INDETERMINATE_CLASS)) {
el.addClass(ACTIVE_CLASS); el.addClass(ACTIVE_CLASS);
el.removeClass(INDETERMINATE_CLASS); el.removeClass(INDETERMINATE_CLASS);
if (value == null) { if (field && field.length && value == null) {
field.remove(); field.remove();
} }
if (!field.length && fieldName) { if ((!field || !field.length) && fieldName) {
this.addInput(fieldName, value, selectedObject); this.addInput(fieldName, value, selectedObject);
} }
} else { } else {
...@@ -630,25 +639,20 @@ ...@@ -630,25 +639,20 @@
this.dropdown.parent().find("input[name='" + fieldName + "']").remove(); this.dropdown.parent().find("input[name='" + fieldName + "']").remove();
} }
} }
if (value == null) { if (field && field.length && value == null) {
field.remove(); field.remove();
} }
// Toggle active class for the tick mark // Toggle active class for the tick mark
el.addClass(ACTIVE_CLASS); el.addClass(ACTIVE_CLASS);
if (value != null) { if (value != null) {
if (!field.length && fieldName) { if ((!field || !field.length) && fieldName) {
this.addInput(fieldName, value, selectedObject); this.addInput(fieldName, value, selectedObject);
} else { } else if (field && field.length) {
field.val(value).trigger('change'); field.val(value).trigger('change');
} }
} }
} }
// Update label right after input has been added
if (this.options.toggleLabel) {
this.updateLabel(selectedObject, el, this);
}
return selectedObject; return selectedObject;
}; };
...@@ -659,9 +663,6 @@ ...@@ -659,9 +663,6 @@
if (this.options.inputId != null) { if (this.options.inputId != null) {
$input.attr('id', this.options.inputId); $input.attr('id', this.options.inputId);
} }
if (selectedObject && selectedObject.type) {
$input.attr('data-type', selectedObject.type);
}
return this.dropdown.before($input); return this.dropdown.before($input);
}; };
......
...@@ -10,24 +10,24 @@ ...@@ -10,24 +10,24 @@
ImporterStatus.prototype.initStatusPage = function() { ImporterStatus.prototype.initStatusPage = function() {
$('.js-add-to-import').off('click').on('click', (function(_this) { $('.js-add-to-import').off('click').on('click', (function(_this) {
return function(e) { return function(e) {
var $btn, $namespace_input, $target_field, $tr, id, target_namespace; var $btn, $namespace_input, $target_field, $tr, id, target_namespace, newName;
$btn = $(e.currentTarget); $btn = $(e.currentTarget);
$tr = $btn.closest('tr'); $tr = $btn.closest('tr');
$target_field = $tr.find('.import-target'); $target_field = $tr.find('.import-target');
$namespace_input = $target_field.find('input'); $namespace_input = $target_field.find('.js-select-namespace option:selected');
id = $tr.attr('id').replace('repo_', ''); id = $tr.attr('id').replace('repo_', '');
target_namespace = null; target_namespace = null;
newName = null;
if ($namespace_input.length > 0) { if ($namespace_input.length > 0) {
target_namespace = $namespace_input.prop('value'); target_namespace = $namespace_input[0].innerHTML;
$target_field.empty().append(target_namespace + "/" + ($target_field.data('project_name'))); newName = $target_field.find('#path').prop('value');
$target_field.empty().append(target_namespace + "/" + newName);
} }
$btn.disable().addClass('is-loading'); $btn.disable().addClass('is-loading');
return $.post(_this.import_url, { return $.post(_this.import_url, {
repo_id: id, repo_id: id,
target_namespace: target_namespace target_namespace: target_namespace,
new_name: newName
}, { }, {
dataType: 'script' dataType: 'script'
}); });
......
...@@ -15,25 +15,32 @@ ...@@ -15,25 +15,32 @@
return Issuable.labelRow = _.template('<% _.each(labels, function(label){ %> <span class="label-row btn-group" role="group" aria-label="<%- label.title %>" style="color: <%- label.text_color %>;"> <a href="#" class="btn btn-transparent has-tooltip" style="background-color: <%- label.color %>;" title="<%- label.description %>" data-container="body"> <%- label.title %> </a> <button type="button" class="btn btn-transparent label-remove js-label-filter-remove" style="background-color: <%- label.color %>;" data-label="<%- label.title %>"> <i class="fa fa-times"></i> </button> </span> <% }); %>'); return Issuable.labelRow = _.template('<% _.each(labels, function(label){ %> <span class="label-row btn-group" role="group" aria-label="<%- label.title %>" style="color: <%- label.text_color %>;"> <a href="#" class="btn btn-transparent has-tooltip" style="background-color: <%- label.color %>;" title="<%- label.description %>" data-container="body"> <%- label.title %> </a> <button type="button" class="btn btn-transparent label-remove js-label-filter-remove" style="background-color: <%- label.color %>;" data-label="<%- label.title %>"> <i class="fa fa-times"></i> </button> </span> <% }); %>');
}, },
initSearch: function() { initSearch: function() {
this.timer = null; // `immediate` param set to false debounces on the `trailing` edge, lets user finish typing
return $('#issue_search').off('keyup').on('keyup', function() { const debouncedExecSearch = _.debounce(Issuable.executeSearch, 500, false);
clearTimeout(this.timer);
return this.timer = setTimeout(function() { $('#issuable_search').off('keyup').on('keyup', debouncedExecSearch);
var $form, $input, $search;
$search = $('#issue_search'); // ensures existing filters are preserved when manually submitted
$form = $('.js-filter-form'); $('#issue_search_form').on('submit', (e) => {
$input = $("input[name='" + ($search.attr('name')) + "']", $form); e.preventDefault();
if ($input.length === 0) { debouncedExecSearch(e);
$form.append("<input type='hidden' name='" + ($search.attr('name')) + "' value='" + (_.escape($search.val())) + "'/>");
} else {
$input.val($search.val());
}
if ($search.val() !== '') {
return Issuable.filterResults($form);
}
}, 500);
}); });
}, },
executeSearch: function(e) {
const $search = $('#issuable_search');
const $searchName = $search.attr('name');
const $searchValue = $search.val();
const $filtersForm = $('.js-filter-form');
const $input = $(`input[name='${$searchName}']`, $filtersForm);
if (!$input.length) {
$filtersForm.append(`<input type='hidden' name='${$searchName}' value='${_.escape($searchValue)}'/>`);
} else {
$input.val($searchValue);
}
Issuable.filterResults($filtersForm);
},
initLabelFilterRemove: function() { initLabelFilterRemove: function() {
return $(document).off('click', '.js-label-filter-remove').on('click', '.js-label-filter-remove', function(e) { return $(document).off('click', '.js-label-filter-remove').on('click', '.js-label-filter-remove', function(e) {
var $button; var $button;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
var _this; var _this;
_this = this; _this = this;
$('.js-label-select').each(function(i, dropdown) { $('.js-label-select').each(function(i, dropdown) {
var $block, $colorPreview, $dropdown, $form, $loading, $selectbox, $sidebarCollapsedValue, $value, abilityName, defaultLabel, enableLabelCreateButton, issueURLSplit, issueUpdateURL, labelHTMLTemplate, labelNoneHTMLTemplate, labelUrl, projectId, saveLabelData, selectedLabel, showAny, showNo, $sidebarLabelTooltip; var $block, $colorPreview, $dropdown, $form, $loading, $selectbox, $sidebarCollapsedValue, $value, abilityName, defaultLabel, enableLabelCreateButton, issueURLSplit, issueUpdateURL, labelHTMLTemplate, labelNoneHTMLTemplate, labelUrl, projectId, saveLabelData, selectedLabel, showAny, showNo, $sidebarLabelTooltip, initialSelected;
$dropdown = $(dropdown); $dropdown = $(dropdown);
projectId = $dropdown.data('project-id'); projectId = $dropdown.data('project-id');
labelUrl = $dropdown.data('labels'); labelUrl = $dropdown.data('labels');
...@@ -24,6 +24,11 @@ ...@@ -24,6 +24,11 @@
$sidebarLabelTooltip = $block.find('.js-sidebar-labels-tooltip'); $sidebarLabelTooltip = $block.find('.js-sidebar-labels-tooltip');
$value = $block.find('.value'); $value = $block.find('.value');
$loading = $block.find('.block-loading').fadeOut(); $loading = $block.find('.block-loading').fadeOut();
initialSelected = $selectbox
.find('input[name="' + $dropdown.data('field-name') + '"]')
.map(function () {
return this.value;
}).get();
if (issueUpdateURL != null) { if (issueUpdateURL != null) {
issueURLSplit = issueUpdateURL.split('/'); issueURLSplit = issueUpdateURL.split('/');
} }
...@@ -43,6 +48,10 @@ ...@@ -43,6 +48,10 @@
selected = $dropdown.closest('.selectbox').find("input[name='" + ($dropdown.data('field-name')) + "']").map(function() { selected = $dropdown.closest('.selectbox').find("input[name='" + ($dropdown.data('field-name')) + "']").map(function() {
return this.value; return this.value;
}).get(); }).get();
if (_.isEqual(initialSelected, selected)) return;
initialSelected = selected;
data = {}; data = {};
data[abilityName] = {}; data[abilityName] = {};
data[abilityName].label_ids = selected; data[abilityName].label_ids = selected;
...@@ -166,7 +175,7 @@ ...@@ -166,7 +175,7 @@
instance.addInput(this.fieldName, label.id); instance.addInput(this.fieldName, label.id);
} }
} }
if ($form.find("input[type='hidden'][name='" + ($dropdown.data('fieldName')) + "'][value='" + escape(this.id(label)) + "']").length) { if (this.id(label) && $form.find("input[type='hidden'][name='" + ($dropdown.data('fieldName')) + "'][value='" + this.id(label).toString().replace(/'/g, '\\\'') + "']").length) {
selectedClass.push('is-active'); selectedClass.push('is-active');
} }
if ($dropdown.hasClass('js-multiselect') && removesAll) { if ($dropdown.hasClass('js-multiselect') && removesAll) {
...@@ -280,12 +289,12 @@ ...@@ -280,12 +289,12 @@
if (page === 'projects:boards:show') { if (page === 'projects:boards:show') {
if (label.isAny) { if (label.isAny) {
gl.issueBoards.BoardsStore.state.filters['label_name'] = []; gl.issueBoards.BoardsStore.state.filters['label_name'] = [];
} else if (label.title) { } else if ($el.hasClass('is-active')) {
gl.issueBoards.BoardsStore.state.filters['label_name'].push(label.title); gl.issueBoards.BoardsStore.state.filters['label_name'].push(label.title);
} else { } else {
var filters = gl.issueBoards.BoardsStore.state.filters['label_name']; var filters = gl.issueBoards.BoardsStore.state.filters['label_name'];
filters = filters.filter(function (label) { filters = filters.filter(function (filteredLabel) {
return label !== $el.text().trim(); return filteredLabel !== label.title;
}); });
gl.issueBoards.BoardsStore.state.filters['label_name'] = filters; gl.issueBoards.BoardsStore.state.filters['label_name'] = filters;
} }
......
...@@ -10,11 +10,13 @@ ...@@ -10,11 +10,13 @@
}; };
$(function() { $(function() {
hideEndFade($('.scrolling-tabs')); var $scrollingTabs = $('.scrolling-tabs');
hideEndFade($scrollingTabs);
$(window).off('resize.nav').on('resize.nav', function() { $(window).off('resize.nav').on('resize.nav', function() {
return hideEndFade($('.scrolling-tabs')); return hideEndFade($scrollingTabs);
}); });
return $('.scrolling-tabs').on('scroll', function(event) { $scrollingTabs.off('scroll').on('scroll', function(event) {
var $this, currentPosition, maxPosition; var $this, currentPosition, maxPosition;
$this = $(this); $this = $(this);
currentPosition = $this.scrollLeft(); currentPosition = $this.scrollLeft();
...@@ -22,6 +24,23 @@ ...@@ -22,6 +24,23 @@
$this.siblings('.fade-left').toggleClass('scrolling', currentPosition > 0); $this.siblings('.fade-left').toggleClass('scrolling', currentPosition > 0);
return $this.siblings('.fade-right').toggleClass('scrolling', currentPosition < maxPosition - 1); return $this.siblings('.fade-right').toggleClass('scrolling', currentPosition < maxPosition - 1);
}); });
$scrollingTabs.each(function () {
var $this = $(this),
scrollingTabWidth = $this.width(),
$active = $this.find('.active'),
activeWidth = $active.width();
if ($active.length) {
var offset = $active.offset().left + activeWidth;
if (offset > scrollingTabWidth - 30) {
var scrollLeft = scrollingTabWidth / 2;
scrollLeft = (offset - scrollLeft) - (activeWidth / 2);
$this.scrollLeft(scrollLeft);
}
}
});
}); });
}).call(this); }).call(this);
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
while (i < sURLVariables.length) { while (i < sURLVariables.length) {
sParameterName = sURLVariables[i].split('='); sParameterName = sURLVariables[i].split('=');
if (sParameterName[0] === sParam) { if (sParameterName[0] === sParam) {
values.push(sParameterName[1]); values.push(sParameterName[1].replace(/\+/g, ' '));
} }
i++; i++;
} }
......
...@@ -232,10 +232,10 @@ ...@@ -232,10 +232,10 @@
$('.hll').removeClass('hll'); $('.hll').removeClass('hll');
locationHash = window.location.hash; locationHash = window.location.hash;
if (locationHash !== '') { if (locationHash !== '') {
hashClassString = "." + (locationHash.replace('#', '')); dataLineString = '[data-line-code="' + locationHash.replace('#', '') + '"]';
$diffLine = $(locationHash + ":not(.match)", $('#diffs')); $diffLine = $(locationHash + ":not(.match)", $('#diffs'));
if (!$diffLine.is('tr')) { if (!$diffLine.is('tr')) {
$diffLine = $('#diffs').find("td" + locationHash + ", td" + hashClassString); $diffLine = $('#diffs').find("td" + locationHash + ", td" + dataLineString);
} else { } else {
$diffLine = $diffLine.find('td'); $diffLine = $diffLine.find('td');
} }
......
...@@ -432,14 +432,12 @@ ...@@ -432,14 +432,12 @@
var $form = $(xhr.target); var $form = $(xhr.target);
if ($form.attr('data-resolve-all') != null) { if ($form.attr('data-resolve-all') != null) {
var namespacePath = $form.attr('data-namespace-path'), var projectPath = $form.data('project-path')
projectPath = $form.attr('data-project-path') discussionId = $form.data('discussion-id'),
discussionId = $form.attr('data-discussion-id'), mergeRequestId = $form.data('noteable-iid');
mergeRequestId = $form.attr('data-noteable-iid'),
namespace = namespacePath + '/' + projectPath;
if (ResolveService != null) { if (ResolveService != null) {
ResolveService.toggleResolveForDiscussion(namespace, mergeRequestId, discussionId); ResolveService.toggleResolveForDiscussion(projectPath, mergeRequestId, discussionId);
} }
} }
...@@ -854,7 +852,6 @@ ...@@ -854,7 +852,6 @@
.closest('form') .closest('form')
.attr('data-discussion-id', discussionId) .attr('data-discussion-id', discussionId)
.attr('data-resolve-all', 'true') .attr('data-resolve-all', 'true')
.attr('data-namespace-path', $this.attr('data-namespace-path'))
.attr('data-project-path', $this.attr('data-project-path')); .attr('data-project-path', $this.attr('data-project-path'));
}; };
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
function ProjectFindFile(element1, options) { function ProjectFindFile(element1, options) {
this.element = element1; this.element = element1;
this.options = options; this.options = options;
this.goToBlob = bind(this.goToBlob, this);
this.goToTree = bind(this.goToTree, this); this.goToTree = bind(this.goToTree, this);
this.selectRowDown = bind(this.selectRowDown, this); this.selectRowDown = bind(this.selectRowDown, this);
this.selectRowUp = bind(this.selectRowUp, this); this.selectRowUp = bind(this.selectRowUp, this);
...@@ -36,16 +35,6 @@ ...@@ -36,16 +35,6 @@
} }
}; };
})(this)); })(this));
return this.element.find(".tree-content-holder .tree-table").on("click", function(event) {
var path;
if (event.target.nodeName !== "A") {
path = this.element.find(".tree-item-file-name a", this).attr("href");
if (path) {
return location.href = path;
}
}
});
// init event
}; };
ProjectFindFile.prototype.findFile = function() { ProjectFindFile.prototype.findFile = function() {
...@@ -121,11 +110,12 @@ ...@@ -121,11 +110,12 @@
// make tbody row html // make tbody row html
ProjectFindFile.prototype.makeHtml = function(filePath, matches, blobItemUrl) { ProjectFindFile.prototype.makeHtml = function(filePath, matches, blobItemUrl) {
var $tr; var $tr;
$tr = $("<tr class='tree-item'><td class='tree-item-file-name'><i class='fa fa-file-text-o fa-fw'></i><span class='str-truncated'><a></a></span></td></tr>"); $tr = $("<tr class='tree-item'><td class='tree-item-file-name link-container'><a><i class='fa fa-file-text-o fa-fw'></i><span class='str-truncated'></span></a></td></tr>");
if (matches) { if (matches) {
$tr.find("a").replaceWith(highlighter($tr.find("a"), filePath, matches).attr("href", blobItemUrl)); $tr.find("a").replaceWith(highlighter($tr.find("a"), filePath, matches).attr("href", blobItemUrl));
} else { } else {
$tr.find("a").attr("href", blobItemUrl).text(filePath); $tr.find("a").attr("href", blobItemUrl);
$tr.find(".str-truncated").text(filePath);
} }
return $tr; return $tr;
}; };
...@@ -164,14 +154,6 @@ ...@@ -164,14 +154,6 @@
return location.href = this.options.treeUrl; return location.href = this.options.treeUrl;
}; };
ProjectFindFile.prototype.goToBlob = function() {
var path;
path = this.element.find(".tree-item.selected .tree-item-file-name a").attr("href");
if (path) {
return location.href = path;
}
};
return ProjectFindFile; return ProjectFindFile;
})(); })();
......
...@@ -40,7 +40,6 @@ ...@@ -40,7 +40,6 @@
dataType: 'json', dataType: 'json',
data: { data: {
_method: 'PATCH', _method: 'PATCH',
id: this.$wrap.data('banchId'),
protected_branch: { protected_branch: {
merge_access_levels_attributes: [{ merge_access_levels_attributes: [{
id: this.$allowedToMergeDropdown.data('access-level-id'), id: this.$allowedToMergeDropdown.data('access-level-id'),
......
...@@ -389,4 +389,41 @@ ...@@ -389,4 +389,41 @@
})(); })();
$(function() {
var $projectOptionsDataEl = $('.js-search-project-options');
var $groupOptionsDataEl = $('.js-search-group-options');
var $dashboardOptionsDataEl = $('.js-search-dashboard-options');
if ($projectOptionsDataEl.length) {
gl.projectOptions = gl.projectOptions || {};
var projectPath = $projectOptionsDataEl.data('project-path');
gl.projectOptions[projectPath] = {
name: $projectOptionsDataEl.data('name'),
issuesPath: $projectOptionsDataEl.data('issues-path'),
mrPath: $projectOptionsDataEl.data('mr-path')
};
}
if ($groupOptionsDataEl.length) {
gl.groupOptions = gl.groupOptions || {};
var groupPath = $groupOptionsDataEl.data('group-path');
gl.groupOptions[groupPath] = {
name: $groupOptionsDataEl.data('name'),
issuesPath: $groupOptionsDataEl.data('issues-path'),
mrPath: $groupOptionsDataEl.data('mr-path')
};
}
if ($dashboardOptionsDataEl.length) {
gl.dashboardOptions = {
issuesPath: $dashboardOptionsDataEl.data('issues-path'),
mrPath: $dashboardOptionsDataEl.data('mr-path')
};
}
});
}).call(this); }).call(this);
...@@ -34,6 +34,9 @@ ...@@ -34,6 +34,9 @@
Mousetrap.bind('g i', function() { Mousetrap.bind('g i', function() {
return ShortcutsNavigation.findAndFollowLink('.shortcuts-issues'); return ShortcutsNavigation.findAndFollowLink('.shortcuts-issues');
}); });
Mousetrap.bind('g l', function() {
ShortcutsNavigation.findAndFollowLink('.shortcuts-issue-boards');
});
Mousetrap.bind('g m', function() { Mousetrap.bind('g m', function() {
return ShortcutsNavigation.findAndFollowLink('.shortcuts-merge_requests'); return ShortcutsNavigation.findAndFollowLink('.shortcuts-merge_requests');
}); });
......
...@@ -10,12 +10,13 @@ ...@@ -10,12 +10,13 @@
ERROR_HTML = '<div class="nothing-here-block"><i class="fa fa-warning"></i> Could not load diff</div>'; ERROR_HTML = '<div class="nothing-here-block"><i class="fa fa-warning"></i> Could not load diff</div>';
COLLAPSED_HTML = '<div class="nothing-here-block diff-collapsed">This diff is collapsed. Click to expand it.</div>'; COLLAPSED_HTML = '<div class="nothing-here-block diff-collapsed">This diff is collapsed. <a class="click-to-expand">Click to expand it.</a></div>';
function SingleFileDiff(file) { function SingleFileDiff(file) {
this.file = file; this.file = file;
this.toggleDiff = bind(this.toggleDiff, this); this.toggleDiff = bind(this.toggleDiff, this);
this.content = $('.diff-content', this.file); this.content = $('.diff-content', this.file);
this.$toggleIcon = $('.diff-toggle-caret', this.file);
this.diffForPath = this.content.find('[data-diff-for-path]').data('diff-for-path'); this.diffForPath = this.content.find('[data-diff-for-path]').data('diff-for-path');
this.isOpen = !this.diffForPath; this.isOpen = !this.diffForPath;
if (this.diffForPath) { if (this.diffForPath) {
...@@ -23,18 +24,22 @@ ...@@ -23,18 +24,22 @@
this.loadingContent = $(WRAPPER).addClass('loading').html(LOADING_HTML).hide(); this.loadingContent = $(WRAPPER).addClass('loading').html(LOADING_HTML).hide();
this.content = null; this.content = null;
this.collapsedContent.after(this.loadingContent); this.collapsedContent.after(this.loadingContent);
this.$toggleIcon.addClass('fa-caret-right');
} else { } else {
this.collapsedContent = $(WRAPPER).html(COLLAPSED_HTML).hide(); this.collapsedContent = $(WRAPPER).html(COLLAPSED_HTML).hide();
this.content.after(this.collapsedContent); this.content.after(this.collapsedContent);
this.$toggleIcon.addClass('fa-caret-down');
} }
this.collapsedContent.on('click', this.toggleDiff); $('.file-title, .click-to-expand', this.file).on('click', this.toggleDiff);
$('.file-title > a', this.file).on('click', this.toggleDiff);
} }
SingleFileDiff.prototype.toggleDiff = function(e) { SingleFileDiff.prototype.toggleDiff = function(e) {
var $target = $(e.target);
if (!$target.hasClass('file-title') && !$target.hasClass('click-to-expand') && !$target.hasClass('diff-toggle-caret')) return;
this.isOpen = !this.isOpen; this.isOpen = !this.isOpen;
if (!this.isOpen && !this.hasError) { if (!this.isOpen && !this.hasError) {
this.content.hide(); this.content.hide();
this.$toggleIcon.addClass('fa-caret-right').removeClass('fa-caret-down');
this.collapsedContent.show(); this.collapsedContent.show();
if (typeof DiffNotesApp !== 'undefined') { if (typeof DiffNotesApp !== 'undefined') {
DiffNotesApp.compileComponents(); DiffNotesApp.compileComponents();
...@@ -42,10 +47,12 @@ ...@@ -42,10 +47,12 @@
} else if (this.content) { } else if (this.content) {
this.collapsedContent.hide(); this.collapsedContent.hide();
this.content.show(); this.content.show();
this.$toggleIcon.addClass('fa-caret-down').removeClass('fa-caret-right');
if (typeof DiffNotesApp !== 'undefined') { if (typeof DiffNotesApp !== 'undefined') {
DiffNotesApp.compileComponents(); DiffNotesApp.compileComponents();
} }
} else { } else {
this.$toggleIcon.addClass('fa-caret-down').removeClass('fa-caret-right');
return this.getContentHTML(); return this.getContentHTML();
} }
}; };
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
date.setDate(date.getDate() + i); date.setDate(date.getDate() + i);
var day = date.getDay(); var day = date.getDay();
var count = timestamps[date.getTime() * 0.001]; var count = timestamps[dateFormat(date, 'yyyy-mm-dd')];
// Create a new group array if this is the first day of the week // Create a new group array if this is the first day of the week
// or if is first object // or if is first object
......
...@@ -19,10 +19,8 @@ ...@@ -19,10 +19,8 @@
&.diff-collapsed { &.diff-collapsed {
padding: 5px; padding: 5px;
cursor: pointer; .click-to-expand {
cursor: pointer;
&:hover {
background-color: $row-hover;
} }
} }
} }
...@@ -129,8 +127,6 @@ ...@@ -129,8 +127,6 @@
position: relative; position: relative;
.avatar-holder { .avatar-holder {
margin-bottom: 16px;
.avatar, .identicon { .avatar, .identicon {
margin: 0 auto; margin: 0 auto;
float: none; float: none;
...@@ -143,13 +139,7 @@ ...@@ -143,13 +139,7 @@
.cover-title { .cover-title {
color: $gl-header-color; color: $gl-header-color;
margin: 0;
font-size: 24px;
font-weight: normal;
margin-bottom: 10px;
color: #4c4e54;
font-size: 23px; font-size: 23px;
line-height: 1.1;
h1 { h1 {
color: $gl-gray-dark; color: $gl-gray-dark;
...@@ -213,6 +203,9 @@ ...@@ -213,6 +203,9 @@
} }
} }
} }
&.user-cover-block {
padding: 24px 0 0;
}
.group-info { .group-info {
......
...@@ -336,3 +336,9 @@ ...@@ -336,3 +336,9 @@
box-shadow: inset 0 0 0 white; box-shadow: inset 0 0 0 white;
} }
} }
@media (max-width: $screen-xs-max) {
.btn-wide-on-xs {
width: 100%;
}
}
...@@ -26,6 +26,15 @@ ...@@ -26,6 +26,15 @@
padding: 10px $gl-padding; padding: 10px $gl-padding;
word-wrap: break-word; word-wrap: break-word;
border-radius: 3px 3px 0 0; border-radius: 3px 3px 0 0;
cursor: pointer;
&:hover {
background-color: $dark-background-color;
}
.diff-toggle-caret {
padding-right: 6px;
}
&.file-title-clear { &.file-title-clear {
padding-left: 0; padding-left: 0;
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
margin: 0; margin: 0;
margin-bottom: $gl-padding; margin-bottom: $gl-padding;
font-size: 14px; font-size: 14px;
z-index: 100; position: relative;
z-index: 1;
.flash-notice { .flash-notice {
@extend .alert; @extend .alert;
...@@ -34,6 +35,12 @@ ...@@ -34,6 +35,12 @@
} }
} }
.content-wrapper {
.flash-notice .container-fluid {
background-color: transparent;
}
}
@media (max-width: $screen-md-min) { @media (max-width: $screen-md-min) {
ul.notes { ul.notes {
.flash-container.timeline-content { .flash-container.timeline-content {
...@@ -41,4 +48,3 @@ ...@@ -41,4 +48,3 @@
} }
} }
} }
...@@ -112,11 +112,15 @@ header { ...@@ -112,11 +112,15 @@ header {
.header-logo { .header-logo {
position: absolute; position: absolute;
left: 50%; left: 50%;
margin-left: -18px;
top: 7px; top: 7px;
transition-duration: .3s; transition-duration: .3s;
z-index: 999; z-index: 999;
#logo {
position: relative;
left: -50%;
}
svg, img { svg, img {
height: 36px; height: 36px;
} }
...@@ -126,8 +130,12 @@ header { ...@@ -126,8 +130,12 @@ header {
} }
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
right: 25px; right: 20px;
left: auto; left: auto;
#logo {
left: auto;
}
} }
} }
......
...@@ -166,6 +166,10 @@ ul.content-list { ...@@ -166,6 +166,10 @@ ul.content-list {
margin-right: 0; margin-right: 0;
} }
} }
.no-comments {
opacity: .5;
}
} }
.member-controls { .member-controls {
......
...@@ -79,10 +79,6 @@ ...@@ -79,10 +79,6 @@
padding-left: 15px !important; padding-left: 15px !important;
} }
.issue-info, .merge-request-info {
display: none;
}
.nav-links, .nav-links { .nav-links, .nav-links {
li a { li a {
font-size: 14px; font-size: 14px;
......
...@@ -99,8 +99,7 @@ ...@@ -99,8 +99,7 @@
.top-area { .top-area {
@include clearfix; @include clearfix;
border-bottom: 1px solid $btn-gray-hover;
border-bottom: 1px solid #eee;
.nav-text { .nav-text {
padding-top: 16px; padding-top: 16px;
......
...@@ -142,6 +142,7 @@ ...@@ -142,6 +142,7 @@
transition-duration: .3s; transition-duration: .3s;
position: absolute; position: absolute;
top: 0; top: 0;
cursor: pointer;
&:hover, &:hover,
&:focus { &:focus {
......
...@@ -164,7 +164,7 @@ ...@@ -164,7 +164,7 @@
text-decoration: none; text-decoration: none;
&:after { &:after {
content: url('icon_anchor.svg'); content: image-url('icon_anchor.svg');
visibility: hidden; visibility: hidden;
} }
} }
...@@ -204,7 +204,7 @@ body { ...@@ -204,7 +204,7 @@ body {
} }
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
color: $gl-header-color; color: $gl-title-color;
font-weight: 600; font-weight: 600;
} }
......
...@@ -102,7 +102,7 @@ $gl-grayish-blue: #7f8fa4; ...@@ -102,7 +102,7 @@ $gl-grayish-blue: #7f8fa4;
$gl-gray: $gl-text-color; $gl-gray: $gl-text-color;
$gl-gray-dark: #313236; $gl-gray-dark: #313236;
$gl-gray-light: $gl-placeholder-color; $gl-gray-light: $gl-placeholder-color;
$gl-header-color: $gl-title-color; $gl-header-color: #4c4e54;
/* /*
* Lists * Lists
...@@ -269,6 +269,12 @@ $calendar-hover-bg: #ecf3fe; ...@@ -269,6 +269,12 @@ $calendar-hover-bg: #ecf3fe;
$calendar-border-color: rgba(#000, .1); $calendar-border-color: rgba(#000, .1);
$calendar-unselectable-bg: $gray-light; $calendar-unselectable-bg: $gray-light;
/*
* Cycle Analytics
*/
$cycle-analytics-box-padding: 30px;
$cycle-analytics-box-text-color: #8c8c8c;
/* /*
* Personal Access Tokens * Personal Access Tokens
*/ */
......
lex
[v-cloak] { [v-cloak] {
display: none; display: none;
} }
...@@ -18,6 +19,10 @@ ...@@ -18,6 +19,10 @@
} }
} }
.is-ghost {
opacity: 0.3;
}
.dropdown-menu-issues-board-new { .dropdown-menu-issues-board-new {
width: 320px; width: 320px;
...@@ -34,47 +39,13 @@ ...@@ -34,47 +39,13 @@
> p { > p {
margin: 0; margin: 0;
font-size: 14px; font-size: 14px;
color: #9c9c9c;
} }
} }
.issue-boards-page { .issue-boards-page {
.content-wrapper {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
}
.sub-nav,
.issues-filters {
-webkit-flex: none;
flex: none;
}
.page-with-sidebar { .page-with-sidebar {
display: -webkit-flex;
display: flex;
min-height: 100vh;
max-height: 100vh;
padding-bottom: 0; padding-bottom: 0;
} }
.issue-boards-content {
display: -webkit-flex;
display: flex;
-webkit-flex: 1;
flex: 1;
width: 100%;
.content {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
width: 100%;
}
}
} }
.boards-app-loading { .boards-app-loading {
...@@ -83,46 +54,38 @@ ...@@ -83,46 +54,38 @@
} }
.boards-list { .boards-list {
display: -webkit-flex; height: calc(100vh - 152px);
display: flex; width: 100%;
-webkit-flex: 1;
flex: 1;
-webkit-flex-basis: 0;
flex-basis: 0;
min-height: calc(100vh - 152px);
max-height: calc(100vh - 152px);
padding-top: 25px; padding-top: 25px;
padding-bottom: 25px;
padding-right: ($gl-padding / 2); padding-right: ($gl-padding / 2);
padding-left: ($gl-padding / 2); padding-left: ($gl-padding / 2);
overflow-x: scroll; overflow-x: scroll;
white-space: nowrap;
@media (min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) {
height: 475px; // Needed for PhantomJS
height: calc(100vh - 220px);
min-height: 475px; min-height: 475px;
max-height: none;
} }
} }
.board { .board {
display: -webkit-flex; display: inline-block;
display: flex; width: calc(85vw - 15px);
min-width: calc(85vw - 15px); height: 100%;
max-width: calc(85vw - 15px);
margin-bottom: 25px;
padding-right: ($gl-padding / 2); padding-right: ($gl-padding / 2);
padding-left: ($gl-padding / 2); padding-left: ($gl-padding / 2);
white-space: normal;
vertical-align: top;
@media (min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) {
min-width: 400px; width: 400px;
max-width: 400px;
} }
} }
.board-inner { .board-inner {
display: -webkit-flex; height: 100%;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
width: 100%;
font-size: $issue-boards-font-size; font-size: $issue-boards-font-size;
background: $background-color; background: $background-color;
border: 1px solid $border-color; border: 1px solid $border-color;
...@@ -193,45 +156,31 @@ ...@@ -193,45 +156,31 @@
} }
.board-list { .board-list {
-webkit-flex: 1; height: calc(100% - 49px);
flex: 1;
height: 400px;
margin-bottom: 0; margin-bottom: 0;
padding: 5px; padding: 5px;
list-style: none;
overflow-y: scroll; overflow-y: scroll;
overflow-x: hidden; overflow-x: hidden;
} }
.board-list-loading { .board-list-loading {
margin-top: 10px; margin-top: 10px;
font-size: 26px; font-size: (26px / $issue-boards-font-size) * 1em;
}
.is-ghost {
opacity: 0.3;
} }
.card { .card {
position: relative; position: relative;
width: 100%;
padding: 10px $gl-padding; padding: 10px $gl-padding;
background: #fff; background: #fff;
border-radius: $border-radius-default; border-radius: $border-radius-default;
box-shadow: 0 1px 2px rgba(186, 186, 186, 0.5); box-shadow: 0 1px 2px rgba(186, 186, 186, 0.5);
list-style: none; list-style: none;
&.user-can-drag {
padding-left: $gl-padding;
}
&:not(:last-child) { &:not(:last-child) {
margin-bottom: 5px; margin-bottom: 5px;
} }
a {
cursor: pointer;
}
.label { .label {
border: 0; border: 0;
outline: 0; outline: 0;
...@@ -248,6 +197,7 @@ ...@@ -248,6 +197,7 @@
a { a {
color: inherit; color: inherit;
word-wrap: break-word;
} }
} }
...@@ -256,14 +206,13 @@ ...@@ -256,14 +206,13 @@
line-height: 25px; line-height: 25px;
.label { .label {
margin-right: 4px; margin-right: 5px;
font-size: (14px / $issue-boards-font-size) * 1em; font-size: (14px / $issue-boards-font-size) * 1em;
} }
} }
.card-number { .card-number {
margin-right: 8px; margin-right: 5px;
font-weight: 500;
} }
.issue-boards-search { .issue-boards-search {
......
...@@ -107,6 +107,14 @@ ...@@ -107,6 +107,14 @@
.block { .block {
width: 100%; width: 100%;
&.coverage {
padding: 0 16px 11px;
}
.btn-group-justified {
margin-top: 5px;
}
} }
.js-build-variable { .js-build-variable {
...@@ -210,6 +218,9 @@ ...@@ -210,6 +218,9 @@
.build-detail-row { .build-detail-row {
margin-bottom: 5px; margin-bottom: 5px;
&:last-of-type {
margin-bottom: 0;
}
} }
.build-light-text { .build-light-text {
......
#cycle-analytics {
margin: 24px auto 0;
max-width: 800px;
position: relative;
.panel {
.content-block {
padding: 24px 0;
border-bottom: none;
position: relative;
@media (max-width: $screen-sm-min) {
padding: 6px 0 24px;
}
}
.column {
text-align: center;
@media (max-width: $screen-sm-min) {
padding: 15px 0;
}
.header {
font-size: 30px;
line-height: 38px;
font-weight: normal;
margin: 0;
}
.text {
color: $layout-link-gray;
margin: 0;
}
&:last-child {
text-align: right;
@media (max-width: $screen-sm-min) {
text-align: center;
}
}
}
.dropdown {
top: 13px;
}
}
.bordered-box {
border: 1px solid $border-color;
@include border-radius($border-radius-default);
}
.content-list {
li {
padding: 18px $gl-padding $gl-padding;
.container-fluid {
padding: 0;
}
}
.title-col {
p {
margin: 0;
&.title {
line-height: 19px;
font-size: 15px;
font-weight: 600;
color: $gl-title-color;
}
&.text {
color: $layout-link-gray;
&.value-col {
color: $gl-title-color;
}
}
}
}
.value-col {
text-align: right;
span {
position: relative;
vertical-align: middle;
top: 3px;
}
}
}
.landing {
margin-bottom: $gl-padding;
overflow: hidden;
.dismiss-icon {
position: absolute;
right: $cycle-analytics-box-padding;
cursor: pointer;
color: #b2b2b2;
}
.svg-container {
text-align: center;
svg {
width: 136px;
height: 136px;
}
}
.inner-content {
@media (max-width: $screen-sm-min) {
padding: 0 28px;
text-align: center;
}
h4 {
color: $gl-text-color;
font-size: 17px;
}
p {
color: $cycle-analytics-box-text-color;
margin-bottom: $gl-padding;
}
}
}
.fa-spinner {
font-size: 28px;
position: relative;
margin-left: -20px;
left: 50%;
margin-top: 36px;
}
}
...@@ -68,6 +68,11 @@ ...@@ -68,6 +68,11 @@
border-collapse: separate; border-collapse: separate;
margin: 0; margin: 0;
padding: 0; padding: 0;
table-layout: fixed;
.diff-line-num {
width: 50px;
}
.line_holder td { .line_holder td {
line-height: $code_line_height; line-height: $code_line_height;
...@@ -98,10 +103,6 @@ ...@@ -98,10 +103,6 @@
} }
tr.line_holder.parallel { tr.line_holder.parallel {
.old_line, .new_line {
min-width: 50px;
}
td.line_content.parallel { td.line_content.parallel {
width: 46%; width: 46%;
} }
......
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
} }
.encoding-selector, .encoding-selector,
.soft-wrap-toggle,
.license-selector, .license-selector,
.gitignore-selector, .gitignore-selector,
.gitlab-ci-yml-selector { .gitlab-ci-yml-selector {
...@@ -67,6 +68,24 @@ ...@@ -67,6 +68,24 @@
font-family: $regular_font; font-family: $regular_font;
} }
.soft-wrap-toggle {
margin: 0 $btn-side-margin;
.soft-wrap {
display: block;
}
.no-wrap {
display: none;
}
&.soft-wrap-active {
.soft-wrap {
display: none;
}
.no-wrap {
display: block;
}
}
}
.gitignore-selector, .license-selector, .gitlab-ci-yml-selector { .gitignore-selector, .license-selector, .gitlab-ci-yml-selector {
.dropdown { .dropdown {
line-height: 21px; line-height: 21px;
......
...@@ -41,3 +41,50 @@ ...@@ -41,3 +41,50 @@
} }
} }
} }
.groups-header {
@media (min-width: $screen-sm-min) {
.nav-links {
width: 35%;
}
.nav-controls {
width: 65%;
}
}
}
.groups-empty-state {
padding: 50px 100px;
overflow: hidden;
@media (max-width: $screen-md-min) {
padding: 50px 0;
}
svg {
float: right;
@media (max-width: $screen-md-min) {
float: none;
display: block;
width: 250px;
position: relative;
left: 50%;
margin-left: -125px;
}
}
.text-content {
float: left;
width: 460px;
margin-top: 120px;
@media (max-width: $screen-md-min) {
float: none;
margin-top: 60px;
width: auto;
text-align: center;
}
}
}
...@@ -206,7 +206,7 @@ ...@@ -206,7 +206,7 @@
padding-top: 0; padding-top: 0;
.block { .block {
width: $sidebar_collapsed_width - 1px; width: $sidebar_collapsed_width - 2px;
margin-left: -19px; margin-left: -19px;
padding: 15px 0 0; padding: 15px 0 0;
border-bottom: none; border-bottom: none;
......
...@@ -10,10 +10,6 @@ ...@@ -10,10 +10,6 @@
.issue-labels { .issue-labels {
display: inline-block; display: inline-block;
} }
.issue-no-comments {
opacity: 0.5;
}
} }
} }
...@@ -37,6 +33,15 @@ form.edit-issue { ...@@ -37,6 +33,15 @@ form.edit-issue {
margin: 0; margin: 0;
} }
ul.related-merge-requests > li {
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
.merge-request-id {
flex-shrink: 0;
}
}
.merge-requests-title, .related-branches-title { .merge-requests-title, .related-branches-title {
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
......
...@@ -70,7 +70,8 @@ ...@@ -70,7 +70,8 @@
&.ci-success { &.ci-success {
color: $gl-success; color: $gl-success;
a.environment { a.environment,
a.pipeline {
color: inherit; color: inherit;
} }
} }
...@@ -231,10 +232,6 @@ ...@@ -231,10 +232,6 @@
.merge-request-labels { .merge-request-labels {
display: inline-block; display: inline-block;
} }
.merge-request-no-comments {
opacity: 0.5;
}
} }
.merge-request-angle { .merge-request-angle {
...@@ -377,11 +374,40 @@ ...@@ -377,11 +374,40 @@
.mr-version-controls { .mr-version-controls {
background: $background-color; background: $background-color;
padding: $gl-btn-padding; border-bottom: 1px solid $border-color;
color: $gl-placeholder-color; color: $gl-text-color;
.mr-version-menus-container {
display: -webkit-flex;
display: flex;
-webkit-align-items: center;
align-items: center;
padding: 16px;
}
.comments-disabled-notif {
padding: 10px 16px;
.btn {
margin-left: 5px;
}
}
.mr-version-dropdown,
.mr-version-compare-dropdown {
margin: 0 7px;
}
.comments-disabled-notif {
border-top: 1px solid $border-color;
}
.dropdown-title {
color: $gl-text-color;
}
a.btn-link { .fa-info-circle {
color: $gl-dark-link-color; color: $orange-normal;
padding-right: 5px;
} }
} }
......
...@@ -2,13 +2,17 @@ ...@@ -2,13 +2,17 @@
max-width: 90%; max-width: 90%;
} }
li.milestone { .milestones {
h4 { .milestone {
font-weight: bold; padding: 10px 16px;
}
h4 {
font-weight: bold;
}
.progress { .progress {
height: 6px; height: 6px;
}
} }
} }
...@@ -29,6 +33,7 @@ li.milestone { ...@@ -29,6 +33,7 @@ li.milestone {
// Issue title // Issue title
span a { span a {
color: $gl-text-color; color: $gl-text-color;
word-wrap: break-word;
} }
} }
} }
...@@ -64,3 +69,14 @@ li.milestone { ...@@ -64,3 +69,14 @@ li.milestone {
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
padding: 20px 0; padding: 20px 0;
} }
@media (max-width: $screen-sm-min) {
.milestone-actions {
@include clearfix();
padding-top: $gl-vert-padding;
.btn:first-child {
margin-left: 0;
}
}
}
...@@ -147,14 +147,41 @@ ...@@ -147,14 +147,41 @@
} }
.stage-cell { .stage-cell {
text-align: center; font-size: 0;
svg { svg {
height: 18px; height: 18px;
width: 18px; width: 18px;
position: relative;
z-index: 2;
vertical-align: middle; vertical-align: middle;
overflow: visible; overflow: visible;
} }
.stage-container {
display: inline-block;
position: relative;
margin-right: 6px;
.tooltip {
white-space: nowrap;
}
&:not(:last-child) {
&::after {
content: '';
width: 8px;
position: absolute;;
right: -7px;
bottom: 8px;
border-bottom: 2px solid $border-color;
}
}
a {
display: block;
}
}
} }
.duration, .duration,
...@@ -318,9 +345,17 @@ ...@@ -318,9 +345,17 @@
.build-content { .build-content {
width: 130px; width: 130px;
white-space: nowrap;
overflow: hidden; .ci-status-text {
text-overflow: ellipsis; width: 110px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
display: inline-block;
position: relative;
top: -1px;
}
a { a {
color: $layout-link-gray; color: $layout-link-gray;
...@@ -331,13 +366,74 @@ ...@@ -331,13 +366,74 @@
text-decoration: underline; text-decoration: underline;
} }
} }
}
.dropdown-menu-toggle {
border: none;
width: auto;
padding: 0;
color: $layout-link-gray;
.ci-status-text {
width: 80px;
}
}
.grouped-pipeline-dropdown {
padding: 8px 0;
width: 200px;
left: auto;
right: -214px;
top: -9px;
a:hover {
.ci-status-text {
text-decoration: none;
}
}
.ci-status-text {
width: 145px;
}
.arrow {
&:before,
&:after {
content: '';
display: inline-block;
position: absolute;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
top: 18px;
}
&:before {
left: -5px;
margin-top: -6px;
border-width: 7px 5px 7px 0;
border-right-color: $border-color;
}
&:after {
left: -4px;
margin-top: -9px;
border-width: 10px 7px 10px 0;
border-right-color: $white-light;
}
}
}
.badge {
background-color: $gray-dark;
color: $layout-link-gray;
font-weight: normal;
} }
} }
svg { svg {
position: relative; vertical-align: middle;
top: 2px;
margin-right: 5px; margin-right: 5px;
} }
...@@ -442,7 +538,7 @@ ...@@ -442,7 +538,7 @@
width: 21px; width: 21px;
height: 25px; height: 25px;
position: absolute; position: absolute;
top: -28.5px; top: -29px;
border-top: 2px solid $border-color; border-top: 2px solid $border-color;
} }
......
...@@ -93,8 +93,9 @@ ...@@ -93,8 +93,9 @@
.profile-user-bio { .profile-user-bio {
// Limits the width of the user bio for readability. // Limits the width of the user bio for readability.
max-width: 750px; max-width: 600px;
margin: auto; margin: 15px auto 0;
padding: 0 16px;
} }
.user-avatar-button { .user-avatar-button {
...@@ -212,6 +213,28 @@ ...@@ -212,6 +213,28 @@
} }
.user-profile { .user-profile {
.cover-controls a {
margin-left: 5px;
}
.profile-header {
margin: 0 auto;
.avatar-holder {
width: 90px;
display: inline-block;
}
.user-info {
display: inline-block;
text-align: left;
vertical-align: middle;
margin-left: 15px;
.handle {
color: $gl-gray-light;
}
.member-date {
margin-bottom: 4px;
}
}
}
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
.cover-block { .cover-block {
padding-top: 20px; padding-top: 20px;
...@@ -219,16 +242,26 @@ ...@@ -219,16 +242,26 @@
.cover-controls { .cover-controls {
position: static; position: static;
padding: 0 16px;
margin-bottom: 20px; margin-bottom: 20px;
display: -webkit-flex;
display: flex;
.btn { .btn {
display: inline-block; -webkit-flex-grow: 1;
width: 46%; flex-grow: 1;
&:first-child {
margin-left: 0;
}
} }
} }
} }
} }
.user-profile-nav {
margin-top: 15px;
}
table.u2f-registrations { table.u2f-registrations {
th:not(:last-child), td:not(:last-child) { th:not(:last-child), td:not(:last-child) {
border-right: solid 1px transparent; border-right: solid 1px transparent;
......
...@@ -334,6 +334,10 @@ a.deploy-project-label { ...@@ -334,6 +334,10 @@ a.deploy-project-label {
a { a {
color: $gl-dark-link-color; color: $gl-dark-link-color;
} }
.dropdown-menu {
width: 240px;
}
} }
.last-push-widget { .last-push-widget {
...@@ -739,6 +743,62 @@ pre.light-well { ...@@ -739,6 +743,62 @@ pre.light-well {
.dropdown-menu { .dropdown-menu {
width: 300px; width: 300px;
} }
&.from .compare-dropdown-toggle {
width: 237px;
}
&.to .compare-dropdown-toggle {
width: 254px;
}
.dropdown-toggle-text {
display: block;
height: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 100%;
}
}
.compare-ellipsis {
display: inline;
}
@media (max-width: $screen-xs-max) {
.compare-form-group {
.input-group {
width: 100%;
& > .compare-dropdown-toggle {
width: 100%;
}
}
.dropdown-menu {
width: 100%;
}
}
.compare-switch-container {
text-align: center;
padding: 0 0 $gl-padding;
.commits-compare-switch {
float: none;
}
}
.compare-ellipsis {
display: block;
text-align: center;
padding: 0 0 $gl-padding;
}
.commits-compare-btn {
width: 100%;
}
} }
.clearable-input { .clearable-input {
...@@ -766,3 +826,13 @@ pre.light-well { ...@@ -766,3 +826,13 @@ pre.light-well {
} }
} }
} }
.project-path {
.form-control {
min-width: 100px;
}
.select2-choice {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}
...@@ -103,7 +103,7 @@ ...@@ -103,7 +103,7 @@
// Custom dropdown positioning // Custom dropdown positioning
.dropdown-menu { .dropdown-menu {
top: 30px; top: 37px;
left: -5px; left: -5px;
padding: 0; padding: 0;
......
...@@ -2,20 +2,6 @@ ...@@ -2,20 +2,6 @@
padding: 2px; padding: 2px;
} }
.snippet-holder {
margin-bottom: -$gl-padding;
.file-holder {
border-top: 0;
}
.file-actions {
.btn-clipboard {
@extend .btn;
}
}
}
.markdown-snippet-copy { .markdown-snippet-copy {
position: fixed; position: fixed;
top: -10px; top: -10px;
...@@ -24,29 +10,25 @@ ...@@ -24,29 +10,25 @@
max-width: 0; max-width: 0;
} }
.file-holder.snippet-file-content { .snippet-file-content {
padding-bottom: $gl-padding; border-radius: 3px;
border-bottom: 1px solid $border-color; margin-bottom: $gl-padding;
.file-title {
padding-top: $gl-padding;
padding-bottom: $gl-padding;
}
.file-actions { .btn-clipboard {
top: 12px; @extend .btn;
} }
}
.file-content { .project-snippets .awards {
border-left: 1px solid $border-color; border-bottom: 1px solid $table-border-color;
border-right: 1px solid $border-color; padding-bottom: $gl-padding;
border-bottom: 1px solid $border-color;
}
} }
.snippet-title { .snippet-title {
font-size: 24px; font-size: 24px;
font-weight: normal; font-weight: 600;
padding: $gl-padding;
padding-left: 0;
} }
.snippet-actions { .snippet-actions {
...@@ -54,3 +36,7 @@ ...@@ -54,3 +36,7 @@
float: right; float: right;
} }
} }
.snippet-scope-menu .btn-new {
margin-top: 15px;
}
...@@ -27,7 +27,12 @@ ...@@ -27,7 +27,12 @@
} }
.last-commit { .last-commit {
@include str-truncated(60%); @include str-truncated(506px);
@media (min-width: $screen-sm-max) and (max-width: $screen-md-max) {
@include str-truncated(450px);
}
} }
.commit-history-link-spacer { .commit-history-link-spacer {
...@@ -55,6 +60,15 @@ ...@@ -55,6 +60,15 @@
} }
.tree-item { .tree-item {
.link-container {
padding: 0;
a {
padding: 10px $gl-padding;
display: block;
}
}
.tree-item-file-name { .tree-item-file-name {
max-width: 320px; max-width: 320px;
vertical-align: middle; vertical-align: middle;
......
...@@ -10,7 +10,7 @@ class Admin::GroupsController < Admin::ApplicationController ...@@ -10,7 +10,7 @@ class Admin::GroupsController < Admin::ApplicationController
def show def show
@members = @group.members.order("access_level DESC").page(params[:members_page]) @members = @group.members.order("access_level DESC").page(params[:members_page])
@requesters = @group.requesters @requesters = AccessRequestsFinder.new(@group).execute(current_user)
@projects = @group.projects.page(params[:projects_page]) @projects = @group.projects.page(params[:projects_page])
end end
...@@ -60,6 +60,14 @@ class Admin::GroupsController < Admin::ApplicationController ...@@ -60,6 +60,14 @@ class Admin::GroupsController < Admin::ApplicationController
end end
def group_params def group_params
params.require(:group).permit(:name, :description, :path, :avatar, :visibility_level, :request_access_enabled) params.require(:group).permit(
:avatar,
:description,
:lfs_enabled,
:name,
:path,
:request_access_enabled,
:visibility_level
)
end end
end end
...@@ -22,7 +22,7 @@ class Admin::ProjectsController < Admin::ApplicationController ...@@ -22,7 +22,7 @@ class Admin::ProjectsController < Admin::ApplicationController
end end
@project_members = @project.members.page(params[:project_members_page]) @project_members = @project.members.page(params[:project_members_page])
@requesters = @project.requesters @requesters = AccessRequestsFinder.new(@project).execute(current_user)
end end
def transfer def transfer
......
...@@ -14,6 +14,7 @@ module Ci ...@@ -14,6 +14,7 @@ module Ci
@config_processor = Ci::GitlabCiYamlProcessor.new(@content) @config_processor = Ci::GitlabCiYamlProcessor.new(@content)
@stages = @config_processor.stages @stages = @config_processor.stages
@builds = @config_processor.builds @builds = @config_processor.builds
@jobs = @config_processor.jobs
end end
rescue rescue
@error = 'Undefined error' @error = 'Undefined error'
......
module MembershipActions module MembershipActions
extend ActiveSupport::Concern extend ActiveSupport::Concern
include MembersHelper
def request_access def request_access
membershipable.request_access(current_user) membershipable.request_access(current_user)
...@@ -10,11 +9,7 @@ module MembershipActions ...@@ -10,11 +9,7 @@ module MembershipActions
end end
def approve_access_request def approve_access_request
@member = membershipable.requesters.find(params[:id]) Members::ApproveAccessRequestService.new(membershipable, current_user, params).execute
return render_403 unless can?(current_user, action_member_permission(:update, @member), @member)
@member.accept_request
redirect_to polymorphic_url([membershipable, :members]) redirect_to polymorphic_url([membershipable, :members])
end end
......
...@@ -7,7 +7,7 @@ module SpammableActions ...@@ -7,7 +7,7 @@ module SpammableActions
def mark_as_spam def mark_as_spam
if SpamService.new(spammable).mark_as_spam! if SpamService.new(spammable).mark_as_spam!
redirect_to spammable, notice: "#{spammable.class.to_s} was submitted to Akismet successfully." redirect_to spammable, notice: "#{spammable.class} was submitted to Akismet successfully."
else else
redirect_to spammable, alert: 'Error with Akismet. Please check the logs for more info.' redirect_to spammable, alert: 'Error with Akismet. Please check the logs for more info.'
end end
......
...@@ -10,7 +10,9 @@ module ToggleAwardEmoji ...@@ -10,7 +10,9 @@ module ToggleAwardEmoji
if awardable.user_can_award?(current_user, name) if awardable.user_can_award?(current_user, name)
awardable.toggle_award_emoji(name, current_user) awardable.toggle_award_emoji(name, current_user)
TodoService.new.new_award_emoji(to_todoable(awardable), current_user)
todoable = to_todoable(awardable)
TodoService.new.new_award_emoji(todoable, current_user) if todoable
render json: { ok: true } render json: { ok: true }
else else
...@@ -24,8 +26,10 @@ module ToggleAwardEmoji ...@@ -24,8 +26,10 @@ module ToggleAwardEmoji
case awardable case awardable
when Note when Note
awardable.noteable awardable.noteable
else when MergeRequest, Issue
awardable awardable
when Snippet
nil
end end
end end
......
...@@ -15,7 +15,7 @@ class Groups::GroupMembersController < Groups::ApplicationController ...@@ -15,7 +15,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
end end
@members = @members.order('access_level DESC').page(params[:page]).per(50) @members = @members.order('access_level DESC').page(params[:page]).per(50)
@requesters = @group.requesters if can?(current_user, :admin_group, @group) @requesters = AccessRequestsFinder.new(@group).execute(current_user)
@group_member = @group.group_members.new @group_member = @group.group_members.new
end end
......
...@@ -121,7 +121,17 @@ class GroupsController < Groups::ApplicationController ...@@ -121,7 +121,17 @@ class GroupsController < Groups::ApplicationController
end end
def group_params def group_params
params.require(:group).permit(:name, :description, :path, :avatar, :public, :visibility_level, :share_with_group_lock, :request_access_enabled) params.require(:group).permit(
:avatar,
:description,
:lfs_enabled,
:name,
:path,
:public,
:request_access_enabled,
:share_with_group_lock,
:visibility_level
)
end end
def load_events def load_events
......
...@@ -40,11 +40,12 @@ class Import::GithubController < Import::BaseController ...@@ -40,11 +40,12 @@ class Import::GithubController < Import::BaseController
def create def create
@repo_id = params[:repo_id].to_i @repo_id = params[:repo_id].to_i
repo = client.repo(@repo_id) repo = client.repo(@repo_id)
@project_name = repo.name @project_name = params[:new_name].presence || repo.name
@target_namespace = find_or_create_namespace(repo.owner.login, client.user.login) namespace_path = params[:target_namespace].presence || current_user.namespace_path
@target_namespace = find_or_create_namespace(namespace_path, current_user.namespace_path)
if current_user.can?(:create_projects, @target_namespace) if current_user.can?(:create_projects, @target_namespace)
@project = Gitlab::GithubImport::ProjectCreator.new(repo, @target_namespace, current_user, access_params).execute @project = Gitlab::GithubImport::ProjectCreator.new(repo, @project_name, @target_namespace, current_user, access_params).execute
else else
render 'unauthorized' render 'unauthorized'
end end
......
class Import::GitlabProjectsController < Import::BaseController class Import::GitlabProjectsController < Import::BaseController
before_action :verify_gitlab_project_import_enabled before_action :verify_gitlab_project_import_enabled
before_action :authenticate_admin!
def new def new
@namespace_id = project_params[:namespace_id] @namespace_id = project_params[:namespace_id]
...@@ -48,8 +47,4 @@ class Import::GitlabProjectsController < Import::BaseController ...@@ -48,8 +47,4 @@ class Import::GitlabProjectsController < Import::BaseController
:path, :namespace_id, :file :path, :namespace_id, :file
) )
end end
def authenticate_admin!
render_404 unless current_user.is_admin?
end
end end
...@@ -11,7 +11,8 @@ class JwtController < ApplicationController ...@@ -11,7 +11,8 @@ class JwtController < ApplicationController
service = SERVICES[params[:service]] service = SERVICES[params[:service]]
return head :not_found unless service return head :not_found unless service
result = service.new(@project, @user, auth_params).execute result = service.new(@authentication_result.project, @authentication_result.actor, auth_params).
execute(authentication_abilities: @authentication_result.authentication_abilities || [])
render json: result, status: result[:http_status] render json: result, status: result[:http_status]
end end
...@@ -19,31 +20,37 @@ class JwtController < ApplicationController ...@@ -19,31 +20,37 @@ class JwtController < ApplicationController
private private
def authenticate_project_or_user def authenticate_project_or_user
authenticate_with_http_basic do |login, password| @authentication_result = Gitlab::Auth::Result.new
# if it's possible we first try to authenticate project with login and password
@project = authenticate_project(login, password)
return if @project
@user = authenticate_user(login, password) authenticate_with_http_basic do |login, password|
return if @user @authentication_result = Gitlab::Auth.find_for_git_client(login, password, project: nil, ip: request.ip)
render_403 render_unauthorized unless @authentication_result.success? &&
(@authentication_result.actor.nil? || @authentication_result.actor.is_a?(User))
end end
rescue Gitlab::Auth::MissingPersonalTokenError
render_missing_personal_token
end end
def auth_params def render_missing_personal_token
params.permit(:service, :scope, :account, :client_id) render json: {
errors: [
{ code: 'UNAUTHORIZED',
message: "HTTP Basic: Access denied\n" \
"You have 2FA enabled, please use a personal access token for Git over HTTP.\n" \
"You can generate one at #{profile_personal_access_tokens_url}" }
] }, status: 401
end end
def authenticate_project(login, password) def render_unauthorized
if login == 'gitlab-ci-token' render json: {
Project.with_builds_enabled.find_by(runners_token: password) errors: [
end { code: 'UNAUTHORIZED',
message: 'HTTP Basic: Access denied' }
] }, status: 401
end end
def authenticate_user(login, password) def auth_params
user = Gitlab::Auth.find_with_user_password(login, password) params.permit(:service, :scope, :account, :client_id)
Gitlab::Auth.rate_limit!(request.ip, success: user.present?, login: login)
user
end end
end end
...@@ -73,7 +73,8 @@ class ProfilesController < Profiles::ApplicationController ...@@ -73,7 +73,8 @@ class ProfilesController < Profiles::ApplicationController
:skype, :skype,
:twitter, :twitter,
:username, :username,
:website_url :website_url,
:organization
) )
end end
end end
...@@ -33,7 +33,7 @@ module Projects ...@@ -33,7 +33,7 @@ module Projects
def issue def issue
@issue ||= @issue ||=
IssuesFinder.new(current_user, project_id: project.id, state: 'all') IssuesFinder.new(current_user, project_id: project.id)
.execute .execute
.where(iid: params[:id]) .where(iid: params[:id])
.first! .first!
......
...@@ -35,7 +35,11 @@ class Projects::BuildsController < Projects::ApplicationController ...@@ -35,7 +35,11 @@ class Projects::BuildsController < Projects::ApplicationController
respond_to do |format| respond_to do |format|
format.html format.html
format.json do format.json do
render json: @build.to_json(methods: :trace_html) render json: {
id: @build.id,
status: @build.status,
trace_html: @build.trace_html
}
end end
end end
end end
...@@ -74,7 +78,7 @@ class Projects::BuildsController < Projects::ApplicationController ...@@ -74,7 +78,7 @@ class Projects::BuildsController < Projects::ApplicationController
def erase def erase
@build.erase(erased_by: current_user) @build.erase(erased_by: current_user)
redirect_to namespace_project_build_path(project.namespace, project, @build), redirect_to namespace_project_build_path(project.namespace, project, @build),
notice: "Build has been sucessfully erased!" notice: "Build has been successfully erased!"
end end
def raw def raw
......
...@@ -10,10 +10,11 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -10,10 +10,11 @@ class Projects::CommitController < Projects::ApplicationController
before_action :require_non_empty_project before_action :require_non_empty_project
before_action :authorize_download_code!, except: [:cancel_builds, :retry_builds] before_action :authorize_download_code!, except: [:cancel_builds, :retry_builds]
before_action :authorize_update_build!, only: [:cancel_builds, :retry_builds] before_action :authorize_update_build!, only: [:cancel_builds, :retry_builds]
before_action :authorize_read_pipeline!, only: [:pipelines]
before_action :authorize_read_commit_status!, only: [:builds] before_action :authorize_read_commit_status!, only: [:builds]
before_action :commit before_action :commit
before_action :define_commit_vars, only: [:show, :diff_for_path, :builds] before_action :define_commit_vars, only: [:show, :diff_for_path, :builds, :pipelines]
before_action :define_status_vars, only: [:show, :builds] before_action :define_status_vars, only: [:show, :builds, :pipelines]
before_action :define_note_vars, only: [:show, :diff_for_path] before_action :define_note_vars, only: [:show, :diff_for_path]
before_action :authorize_edit_tree!, only: [:revert, :cherry_pick] before_action :authorize_edit_tree!, only: [:revert, :cherry_pick]
...@@ -31,6 +32,9 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -31,6 +32,9 @@ class Projects::CommitController < Projects::ApplicationController
render_diff_for_path(@commit.diffs(diff_options)) render_diff_for_path(@commit.diffs(diff_options))
end end
def pipelines
end
def builds def builds
end end
...@@ -96,10 +100,6 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -96,10 +100,6 @@ class Projects::CommitController < Projects::ApplicationController
@noteable = @commit ||= @project.commit(params[:id]) @noteable = @commit ||= @project.commit(params[:id])
end end
def pipelines
@pipelines ||= project.pipelines.where(sha: commit.sha)
end
def ci_builds def ci_builds
@ci_builds ||= Ci::Build.where(pipeline: pipelines) @ci_builds ||= Ci::Build.where(pipeline: pipelines)
end end
...@@ -134,8 +134,9 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -134,8 +134,9 @@ class Projects::CommitController < Projects::ApplicationController
end end
def define_status_vars def define_status_vars
@statuses = CommitStatus.where(pipeline: pipelines).relevant @ci_pipelines = project.pipelines.where(sha: commit.sha)
@builds = Ci::Build.where(pipeline: pipelines).relevant @statuses = CommitStatus.where(pipeline: @ci_pipelines).relevant
@builds = Ci::Build.where(pipeline: @ci_pipelines).relevant
end end
def assign_change_commit_vars(mr_source_branch) def assign_change_commit_vars(mr_source_branch)
......
class Projects::CycleAnalyticsController < Projects::ApplicationController
include ActionView::Helpers::DateHelper
include ActionView::Helpers::TextHelper
before_action :authorize_read_cycle_analytics!
def show
@cycle_analytics = CycleAnalytics.new(@project, from: parse_start_date)
respond_to do |format|
format.html
format.json { render json: cycle_analytics_json }
end
end
private
def parse_start_date
case cycle_analytics_params[:start_date]
when '30' then 30.days.ago
when '90' then 90.days.ago
else 90.days.ago
end
end
def cycle_analytics_params
return {} unless params[:cycle_analytics].present?
{ start_date: params[:cycle_analytics][:start_date] }
end
def cycle_analytics_json
cycle_analytics_view_data = [[:issue, "Issue", "Time before an issue gets scheduled"],
[:plan, "Plan", "Time before an issue starts implementation"],
[:code, "Code", "Time until first merge request"],
[:test, "Test", "Total test time for all commits/merges"],
[:review, "Review", "Time between merge request creation and merge/close"],
[:staging, "Staging", "From merge request merge until deploy to production"],
[:production, "Production", "From issue creation until deploy to production"]]
stats = cycle_analytics_view_data.reduce([]) do |stats, (stage_method, stage_text, stage_description)|
value = @cycle_analytics.send(stage_method).presence
stats << {
title: stage_text,
description: stage_description,
value: value && !value.zero? ? distance_of_time_in_words(value) : nil
}
stats
end
issues = @cycle_analytics.summary.new_issues
commits = @cycle_analytics.summary.commits
deploys = @cycle_analytics.summary.deploys
summary = [
{ title: "New Issue".pluralize(issues), value: issues },
{ title: "Commit".pluralize(commits), value: commits },
{ title: "Deploy".pluralize(deploys), value: deploys }
]
{
summary: summary,
stats: stats
}
end
end
...@@ -4,7 +4,11 @@ class Projects::GitHttpClientController < Projects::ApplicationController ...@@ -4,7 +4,11 @@ class Projects::GitHttpClientController < Projects::ApplicationController
include ActionController::HttpAuthentication::Basic include ActionController::HttpAuthentication::Basic
include KerberosSpnegoHelper include KerberosSpnegoHelper
attr_reader :user attr_reader :authentication_result
delegate :actor, :authentication_abilities, to: :authentication_result, allow_nil: true
alias_method :user, :actor
# Git clients will not know what authenticity token to send along # Git clients will not know what authenticity token to send along
skip_before_action :verify_authenticity_token skip_before_action :verify_authenticity_token
...@@ -15,32 +19,25 @@ class Projects::GitHttpClientController < Projects::ApplicationController ...@@ -15,32 +19,25 @@ class Projects::GitHttpClientController < Projects::ApplicationController
private private
def authenticate_user def authenticate_user
@authentication_result = Gitlab::Auth::Result.new
if project && project.public? && download_request? if project && project.public? && download_request?
return # Allow access return # Allow access
end end
if allow_basic_auth? && basic_auth_provided? if allow_basic_auth? && basic_auth_provided?
login, password = user_name_and_password(request) login, password = user_name_and_password(request)
auth_result = Gitlab::Auth.find_for_git_client(login, password, project: project, ip: request.ip)
if auth_result.type == :ci && download_request?
@ci = true
elsif auth_result.type == :oauth && !download_request?
# Not allowed
elsif auth_result.type == :missing_personal_token
render_missing_personal_token
return # Render above denied access, nothing left to do
else
@user = auth_result.user
end
if ci? || user if handle_basic_authentication(login, password)
return # Allow access return # Allow access
end end
elsif allow_kerberos_spnego_auth? && spnego_provided? elsif allow_kerberos_spnego_auth? && spnego_provided?
@user = find_kerberos_user kerberos_user = find_kerberos_user
if kerberos_user
@authentication_result = Gitlab::Auth::Result.new(
kerberos_user, nil, :kerberos, Gitlab::Auth.full_authentication_abilities)
if user
send_final_spnego_response send_final_spnego_response
return # Allow access return # Allow access
end end
...@@ -48,6 +45,8 @@ class Projects::GitHttpClientController < Projects::ApplicationController ...@@ -48,6 +45,8 @@ class Projects::GitHttpClientController < Projects::ApplicationController
send_challenges send_challenges
render plain: "HTTP Basic: Access denied\n", status: 401 render plain: "HTTP Basic: Access denied\n", status: 401
rescue Gitlab::Auth::MissingPersonalTokenError
render_missing_personal_token
end end
def basic_auth_provided? def basic_auth_provided?
...@@ -114,8 +113,41 @@ class Projects::GitHttpClientController < Projects::ApplicationController ...@@ -114,8 +113,41 @@ class Projects::GitHttpClientController < Projects::ApplicationController
render plain: 'Not Found', status: :not_found render plain: 'Not Found', status: :not_found
end end
def handle_basic_authentication(login, password)
@authentication_result = Gitlab::Auth.find_for_git_client(
login, password, project: project, ip: request.ip)
return false unless @authentication_result.success?
if download_request?
authentication_has_download_access?
else
authentication_has_upload_access?
end
end
def ci? def ci?
@ci.present? authentication_result.ci?(project)
end
def lfs_deploy_token?
authentication_result.lfs_deploy_token?(project)
end
def authentication_has_download_access?
has_authentication_ability?(:download_code) || has_authentication_ability?(:build_download_code)
end
def authentication_has_upload_access?
has_authentication_ability?(:push_code)
end
def has_authentication_ability?(capability)
(authentication_abilities || []).include?(capability)
end
def authentication_project
authentication_result.project
end end
def verify_workhorse_api! def verify_workhorse_api!
......
...@@ -86,7 +86,7 @@ class Projects::GitHttpController < Projects::GitHttpClientController ...@@ -86,7 +86,7 @@ class Projects::GitHttpController < Projects::GitHttpClientController
end end
def access def access
@access ||= Gitlab::GitAccess.new(user, project, 'http') @access ||= Gitlab::GitAccess.new(user, project, 'http', authentication_abilities: authentication_abilities)
end end
def access_check def access_check
......
...@@ -23,18 +23,9 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -23,18 +23,9 @@ class Projects::IssuesController < Projects::ApplicationController
respond_to :html respond_to :html
def index def index
terms = params['issue_search']
@issues = issues_collection @issues = issues_collection
if terms.present?
if terms =~ /\A#(\d+)\z/
@issues = @issues.where(iid: $1)
else
@issues = @issues.full_search(terms)
end
end
@issues = @issues.page(params[:page]) @issues = @issues.page(params[:page])
@labels = @project.labels.where(title: params[:label_name]) @labels = @project.labels.where(title: params[:label_name])
respond_to do |format| respond_to do |format|
...@@ -63,7 +54,7 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -63,7 +54,7 @@ class Projects::IssuesController < Projects::ApplicationController
end end
def show def show
raw_notes = @issue.notes_with_associations.fresh raw_notes = @issue.notes.inc_relations_for_view.fresh
@notes = Banzai::NoteRenderer. @notes = Banzai::NoteRenderer.
render(raw_notes, @project, current_user, @path, @project_wiki, @ref) render(raw_notes, @project, current_user, @path, @project_wiki, @ref)
......
...@@ -18,6 +18,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -18,6 +18,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
before_action :define_commit_vars, only: [:diffs] before_action :define_commit_vars, only: [:diffs]
before_action :define_diff_comment_vars, only: [:diffs] before_action :define_diff_comment_vars, only: [:diffs]
before_action :ensure_ref_fetched, only: [:show, :diffs, :commits, :builds, :conflicts, :pipelines] before_action :ensure_ref_fetched, only: [:show, :diffs, :commits, :builds, :conflicts, :pipelines]
before_action :close_merge_request_without_source_project, only: [:show, :diffs, :commits, :builds, :pipelines]
# Allow read any merge_request # Allow read any merge_request
before_action :authorize_read_merge_request! before_action :authorize_read_merge_request!
...@@ -31,17 +32,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -31,17 +32,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
before_action :authorize_can_resolve_conflicts!, only: [:conflicts, :resolve_conflicts] before_action :authorize_can_resolve_conflicts!, only: [:conflicts, :resolve_conflicts]
def index def index
terms = params['issue_search']
@merge_requests = merge_requests_collection @merge_requests = merge_requests_collection
if terms.present?
if terms =~ /\A[#!](\d+)\z/
@merge_requests = @merge_requests.where(iid: $1)
else
@merge_requests = @merge_requests.full_search(terms)
end
end
@merge_requests = @merge_requests.page(params[:page]) @merge_requests = @merge_requests.page(params[:page])
@merge_requests = @merge_requests.preload(:target_project) @merge_requests = @merge_requests.preload(:target_project)
...@@ -285,7 +276,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -285,7 +276,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def remove_wip def remove_wip
MergeRequests::UpdateService.new(project, current_user, title: @merge_request.wipless_title).execute(@merge_request) MergeRequests::UpdateService.new(project, current_user, wip_event: 'unwip').execute(@merge_request)
redirect_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), redirect_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request),
notice: "The merge request can now be merged." notice: "The merge request can now be merged."
...@@ -318,8 +309,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -318,8 +309,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
return return
end end
TodoService.new.merge_merge_request(merge_request, current_user)
@merge_request.update(merge_error: nil) @merge_request.update(merge_error: nil)
if params[:merge_when_build_succeeds].present? if params[:merge_when_build_succeeds].present?
...@@ -428,17 +417,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -428,17 +417,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def validates_merge_request def validates_merge_request
# If source project was removed (Ex. mr from fork to origin)
return invalid_mr unless @merge_request.source_project
# Show git not found page # Show git not found page
# if there is no saved commits between source & target branch # if there is no saved commits between source & target branch
if @merge_request.commits.blank? if @merge_request.commits.blank?
# and if target branch doesn't exist # and if target branch doesn't exist
return invalid_mr unless @merge_request.target_branch_exists? return invalid_mr unless @merge_request.target_branch_exists?
# or if source branch doesn't exist
return invalid_mr unless @merge_request.source_branch_exists?
end end
end end
...@@ -508,7 +491,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -508,7 +491,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def invalid_mr def invalid_mr
# Render special view for MR with removed source or target branch # Render special view for MR with removed target branch
render 'invalid' render 'invalid'
end end
...@@ -550,4 +533,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -550,4 +533,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@diff_notes_disabled = !@merge_request_diff.latest? @diff_notes_disabled = !@merge_request_diff.latest?
@diffs = @merge_request_diff.diffs(diff_options) @diffs = @merge_request_diff.diffs(diff_options)
end end
def close_merge_request_without_source_project
if !@merge_request.source_project && @merge_request.open?
@merge_request.close
end
end
end end
...@@ -22,7 +22,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController ...@@ -22,7 +22,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
@project_members = @project_members.order('access_level DESC') @project_members = @project_members.order('access_level DESC')
@project_members = @project_members.page(params[:page]) @project_members = @project_members.page(params[:page])
@requesters = @project.requesters if can?(current_user, :admin_project, @project) @requesters = AccessRequestsFinder.new(@project).execute(current_user)
@project_member = @project.project_members.new @project_member = @project.project_members.new
end end
......
class Projects::SnippetsController < Projects::ApplicationController class Projects::SnippetsController < Projects::ApplicationController
include ToggleAwardEmoji
before_action :module_enabled before_action :module_enabled
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw] before_action :snippet, only: [:show, :edit, :destroy, :update, :raw, :toggle_award_emoji]
# Allow read any snippet # Allow read any snippet
before_action :authorize_read_project_snippet!, except: [:new, :create, :index] before_action :authorize_read_project_snippet!, except: [:new, :create, :index]
...@@ -80,6 +82,7 @@ class Projects::SnippetsController < Projects::ApplicationController ...@@ -80,6 +82,7 @@ class Projects::SnippetsController < Projects::ApplicationController
def snippet def snippet
@snippet ||= @project.snippets.find(params[:id]) @snippet ||= @project.snippets.find(params[:id])
end end
alias_method :awardable, :snippet
def authorize_read_project_snippet! def authorize_read_project_snippet!
return render_404 unless can?(current_user, :read_project_snippet, @snippet) return render_404 unless can?(current_user, :read_project_snippet, @snippet)
......
...@@ -137,10 +137,10 @@ class ProjectsController < Projects::ApplicationController ...@@ -137,10 +137,10 @@ class ProjectsController < Projects::ApplicationController
noteable = noteable =
case params[:type] case params[:type]
when 'Issue' when 'Issue'
IssuesFinder.new(current_user, project_id: @project.id, state: 'all'). IssuesFinder.new(current_user, project_id: @project.id).
execute.find_by(iid: params[:type_id]) execute.find_by(iid: params[:type_id])
when 'MergeRequest' when 'MergeRequest'
MergeRequestsFinder.new(current_user, project_id: @project.id, state: 'all'). MergeRequestsFinder.new(current_user, project_id: @project.id).
execute.find_by(iid: params[:type_id]) execute.find_by(iid: params[:type_id])
when 'Commit' when 'Commit'
@project.commit(params[:type_id]) @project.commit(params[:type_id])
...@@ -324,7 +324,12 @@ class ProjectsController < Projects::ApplicationController ...@@ -324,7 +324,12 @@ class ProjectsController < Projects::ApplicationController
end end
def repo_exists? def repo_exists?
project.repository_exists? && !project.empty_repo? project.repository_exists? && !project.empty_repo? && project.repo
rescue Gitlab::Git::Repository::NoRepository
project.repository.expire_exists_cache
false
end end
def project_view_files? def project_view_files?
......
...@@ -6,8 +6,6 @@ class SearchController < ApplicationController ...@@ -6,8 +6,6 @@ class SearchController < ApplicationController
layout 'search' layout 'search'
def show def show
return if params[:search].nil? || params[:search].blank?
if params[:project_id].present? if params[:project_id].present?
@project = Project.find_by(id: params[:project_id]) @project = Project.find_by(id: params[:project_id])
@project = nil unless can?(current_user, :download_code, @project) @project = nil unless can?(current_user, :download_code, @project)
...@@ -18,6 +16,8 @@ class SearchController < ApplicationController ...@@ -18,6 +16,8 @@ class SearchController < ApplicationController
@group = nil unless can?(current_user, :read_group, @group) @group = nil unless can?(current_user, :read_group, @group)
end end
return if params[:search].nil? || params[:search].blank?
@search_term = params[:search] @search_term = params[:search]
@scope = params[:scope] @scope = params[:scope]
......
...@@ -3,12 +3,19 @@ class SentNotificationsController < ApplicationController ...@@ -3,12 +3,19 @@ class SentNotificationsController < ApplicationController
def unsubscribe def unsubscribe
@sent_notification = SentNotification.for(params[:id]) @sent_notification = SentNotification.for(params[:id])
return render_404 unless @sent_notification && @sent_notification.unsubscribable? return render_404 unless @sent_notification && @sent_notification.unsubscribable?
return unsubscribe_and_redirect if current_user || params[:force]
end
private
def unsubscribe_and_redirect
noteable = @sent_notification.noteable noteable = @sent_notification.noteable
noteable.unsubscribe(@sent_notification.recipient) noteable.unsubscribe(@sent_notification.recipient)
flash[:notice] = "You have been unsubscribed from this thread." flash[:notice] = "You have been unsubscribed from this thread."
if current_user if current_user
case noteable case noteable
when Issue when Issue
......
class SnippetsController < ApplicationController class SnippetsController < ApplicationController
include ToggleAwardEmoji
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw] before_action :snippet, only: [:show, :edit, :destroy, :update, :raw]
# Allow read snippet # Allow read snippet
...@@ -85,6 +87,7 @@ class SnippetsController < ApplicationController ...@@ -85,6 +87,7 @@ class SnippetsController < ApplicationController
PersonalSnippet.find(params[:id]) PersonalSnippet.find(params[:id])
end end
end end
alias_method :awardable, :snippet
def authorize_read_snippet! def authorize_read_snippet!
authenticate_user! unless can?(current_user, :read_personal_snippet, @snippet) authenticate_user! unless can?(current_user, :read_personal_snippet, @snippet)
......
...@@ -65,7 +65,7 @@ class UsersController < ApplicationController ...@@ -65,7 +65,7 @@ class UsersController < ApplicationController
format.html { render 'show' } format.html { render 'show' }
format.json do format.json do
render json: { render json: {
html: view_to_html_string("snippets/_snippets", collection: @snippets) html: view_to_html_string("snippets/_snippets", collection: @snippets, remote: true)
} }
end end
end end
...@@ -73,7 +73,7 @@ class UsersController < ApplicationController ...@@ -73,7 +73,7 @@ class UsersController < ApplicationController
def calendar def calendar
calendar = contributions_calendar calendar = contributions_calendar
@timestamps = calendar.timestamps @activity_dates = calendar.activity_dates
render 'calendar', layout: false render 'calendar', layout: false
end end
......
class AccessRequestsFinder
attr_accessor :source
# Arguments:
# source - a Group or Project
def initialize(source)
@source = source
end
def execute(*args)
execute!(*args)
rescue Gitlab::Access::AccessDeniedError
[]
end
def execute!(current_user)
raise Gitlab::Access::AccessDeniedError unless can_see_access_requests?(current_user)
source.requesters
end
private
def can_see_access_requests?(current_user)
source && Ability.allowed?(current_user, :"admin_#{source.class.to_s.underscore}", source)
end
end
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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