Commit 468d575f authored by Valery Sizov's avatar Valery Sizov

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into bitbucket-oauth2

parents 8f0cef0b 78f89f7a
...@@ -8,7 +8,8 @@ ...@@ -8,7 +8,8 @@
"globals": { "globals": {
"_": false, "_": false,
"gl": false, "gl": false,
"gon": false "gon": false,
"localStorage": false
}, },
"plugins": [ "plugins": [
"filenames" "filenames"
......
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3-git-2.7-phantomjs-2.1" image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.3-git-2.7-phantomjs-2.1-node-7.1"
cache: cache:
key: "ruby-231" key: "ruby-233"
paths: paths:
- vendor/ruby - vendor/ruby
...@@ -30,7 +30,12 @@ stages: ...@@ -30,7 +30,12 @@ stages:
- post-test - post-test
- pages - pages
# Prepare and merge knapsack tests # Predefined scopes
.dedicated-runner: &dedicated-runner
tags:
- gitlab-org
- 2gb
.knapsack-state: &knapsack-state .knapsack-state: &knapsack-state
services: [] services: []
variables: variables:
...@@ -45,47 +50,14 @@ stages: ...@@ -45,47 +50,14 @@ stages:
paths: paths:
- knapsack/ - knapsack/
knapsack:
<<: *knapsack-state
stage: prepare
script:
- mkdir -p knapsack/
- '[[ -f knapsack/rspec_report.json ]] || echo "{}" > knapsack/rspec_report.json'
- '[[ -f knapsack/spinach_report.json ]] || echo "{}" > knapsack/spinach_report.json'
update-knapsack:
<<: *knapsack-state
stage: post-test
script:
- scripts/merge-reports knapsack/rspec_report.json knapsack/rspec_node_*.json
- scripts/merge-reports knapsack/spinach_report.json knapsack/spinach_node_*.json
- rm -f knapsack/*_node_*.json
only:
- master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee
- master@gitlab/gitlabhq
- master@gitlab/gitlab-ee
.use-db: &use-db .use-db: &use-db
services: services:
- mysql:latest - mysql:latest
- redis:alpine - redis:alpine
setup-test-env:
<<: *use-db
stage: prepare
script:
- bundle exec rake assets:precompile 2>/dev/null
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
artifacts:
expire_in: 7d
paths:
- public/assets
- tmp/tests
.rspec-knapsack: &rspec-knapsack .rspec-knapsack: &rspec-knapsack
stage: test stage: test
<<: *dedicated-runner
<<: *use-db <<: *use-db
script: script:
- JOB_NAME=( $CI_BUILD_NAME ) - JOB_NAME=( $CI_BUILD_NAME )
...@@ -103,6 +75,7 @@ setup-test-env: ...@@ -103,6 +75,7 @@ setup-test-env:
.spinach-knapsack: &spinach-knapsack .spinach-knapsack: &spinach-knapsack
stage: test stage: test
<<: *dedicated-runner
<<: *use-db <<: *use-db
script: script:
- JOB_NAME=( $CI_BUILD_NAME ) - JOB_NAME=( $CI_BUILD_NAME )
...@@ -118,6 +91,44 @@ setup-test-env: ...@@ -118,6 +91,44 @@ setup-test-env:
- knapsack/ - knapsack/
- coverage/ - coverage/
# Prepare and merge knapsack tests
knapsack:
<<: *knapsack-state
<<: *dedicated-runner
stage: prepare
script:
- mkdir -p knapsack/
- '[[ -f knapsack/rspec_report.json ]] || echo "{}" > knapsack/rspec_report.json'
- '[[ -f knapsack/spinach_report.json ]] || echo "{}" > knapsack/spinach_report.json'
setup-test-env:
<<: *use-db
<<: *dedicated-runner
stage: prepare
script:
- bundle exec rake assets:precompile 2>/dev/null
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
artifacts:
expire_in: 7d
paths:
- public/assets
- tmp/tests
update-knapsack:
<<: *knapsack-state
<<: *dedicated-runner
stage: post-test
script:
- scripts/merge-reports knapsack/rspec_report.json knapsack/rspec_node_*.json
- scripts/merge-reports knapsack/spinach_report.json knapsack/spinach_node_*.json
- rm -f knapsack/*_node_*.json
only:
- master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee
- master@gitlab/gitlabhq
- master@gitlab/gitlab-ee
rspec 0 20: *rspec-knapsack rspec 0 20: *rspec-knapsack
rspec 1 20: *rspec-knapsack rspec 1 20: *rspec-knapsack
rspec 2 20: *rspec-knapsack rspec 2 20: *rspec-knapsack
...@@ -166,10 +177,12 @@ spinach 9 10: *spinach-knapsack ...@@ -166,10 +177,12 @@ spinach 9 10: *spinach-knapsack
.rspec-knapsack-ruby21: &rspec-knapsack-ruby21 .rspec-knapsack-ruby21: &rspec-knapsack-ruby21
<<: *rspec-knapsack <<: *rspec-knapsack
<<: *dedicated-runner
<<: *ruby-21 <<: *ruby-21
.spinach-knapsack-ruby21: &spinach-knapsack-ruby21 .spinach-knapsack-ruby21: &spinach-knapsack-ruby21
<<: *spinach-knapsack <<: *spinach-knapsack
<<: *dedicated-runner
<<: *ruby-21 <<: *ruby-21
rspec 0 20 ruby21: *rspec-knapsack-ruby21 rspec 0 20 ruby21: *rspec-knapsack-ruby21
...@@ -214,6 +227,7 @@ spinach 9 10 ruby21: *spinach-knapsack-ruby21 ...@@ -214,6 +227,7 @@ spinach 9 10 ruby21: *spinach-knapsack-ruby21
.exec: &exec .exec: &exec
<<: *ruby-static-analysis <<: *ruby-static-analysis
<<: *dedicated-runner
stage: test stage: test
script: script:
- bundle exec $CI_BUILD_NAME - bundle exec $CI_BUILD_NAME
...@@ -229,14 +243,13 @@ rake ee_compat_check: ...@@ -229,14 +243,13 @@ rake ee_compat_check:
<<: *exec <<: *exec
only: only:
- branches@gitlab-org/gitlab-ce - branches@gitlab-org/gitlab-ce
- branches@gitlab/gitlabhq
except: except:
- master - master
- tags - tags
- /^[\d-]+-stable(-ee)?$/ - /^[\d-]+-stable(-ee)?$/
allow_failure: yes allow_failure: yes
cache: cache:
key: "ruby231-ee_compat_check_repo" key: "ruby233-ee_compat_check_repo"
paths: paths:
- ee_compat_check/repo/ - ee_compat_check/repo/
- vendor/ruby - vendor/ruby
...@@ -250,12 +263,14 @@ rake ee_compat_check: ...@@ -250,12 +263,14 @@ rake ee_compat_check:
rake db:migrate:reset: rake db:migrate:reset:
stage: test stage: test
<<: *use-db <<: *use-db
<<: *dedicated-runner
script: script:
- rake db:migrate:reset - rake db:migrate:reset
rake db:seed_fu: rake db:seed_fu:
stage: test stage: test
<<: *use-db <<: *use-db
<<: *dedicated-runner
variables: variables:
SIZE: "1" SIZE: "1"
SETUP_DB: "false" SETUP_DB: "false"
...@@ -277,9 +292,8 @@ teaspoon: ...@@ -277,9 +292,8 @@ teaspoon:
- node_modules/ - node_modules/
stage: test stage: test
<<: *use-db <<: *use-db
<<: *dedicated-runner
script: script:
- curl --silent --location https://deb.nodesource.com/setup_6.x | bash -
- apt-get install --assume-yes nodejs
- npm install - npm install
- npm link istanbul - npm link istanbul
- rake teaspoon - rake teaspoon
...@@ -291,20 +305,23 @@ teaspoon: ...@@ -291,20 +305,23 @@ teaspoon:
lint-doc: lint-doc:
stage: test stage: test
<<: *dedicated-runner
image: "phusion/baseimage:latest" image: "phusion/baseimage:latest"
before_script: [] before_script: []
script: script:
- scripts/lint-doc.sh - scripts/lint-doc.sh
bundler:check: bundler:check:
stage: test stage: test
<<: *ruby-static-analysis <<: *dedicated-runner
script: <<: *ruby-static-analysis
script:
- bundle check - bundle check
bundler:audit: bundler:audit:
stage: test stage: test
<<: *ruby-static-analysis <<: *ruby-static-analysis
<<: *dedicated-runner
only: only:
- master@gitlab-org/gitlab-ce - master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee - master@gitlab-org/gitlab-ee
...@@ -316,6 +333,7 @@ bundler:audit: ...@@ -316,6 +333,7 @@ bundler:audit:
migration paths: migration paths:
stage: test stage: test
<<: *use-db <<: *use-db
<<: *dedicated-runner
variables: variables:
SETUP_DB: "false" SETUP_DB: "false"
only: only:
...@@ -337,6 +355,7 @@ migration paths: ...@@ -337,6 +355,7 @@ migration paths:
coverage: coverage:
stage: post-test stage: post-test
services: [] services: []
<<: *dedicated-runner
variables: variables:
SETUP_DB: "false" SETUP_DB: "false"
USE_BUNDLE_INSTALL: "true" USE_BUNDLE_INSTALL: "true"
...@@ -350,6 +369,7 @@ coverage: ...@@ -350,6 +369,7 @@ coverage:
- coverage/assets/ - coverage/assets/
lint:javascript: lint:javascript:
<<: *dedicated-runner
cache: cache:
paths: paths:
- node_modules/ - node_modules/
...@@ -361,6 +381,7 @@ lint:javascript: ...@@ -361,6 +381,7 @@ lint:javascript:
- npm --silent run eslint - npm --silent run eslint
lint:javascript:report: lint:javascript:report:
<<: *dedicated-runner
cache: cache:
paths: paths:
- node_modules/ - node_modules/
...@@ -382,6 +403,7 @@ lint:javascript:report: ...@@ -382,6 +403,7 @@ lint:javascript:report:
trigger_docs: trigger_docs:
stage: post-test stage: post-test
image: "alpine" image: "alpine"
<<: *dedicated-runner
before_script: before_script:
- apk update && apk add curl - apk update && apk add curl
variables: variables:
...@@ -397,6 +419,7 @@ trigger_docs: ...@@ -397,6 +419,7 @@ trigger_docs:
notify:slack: notify:slack:
stage: post-test stage: post-test
<<: *dedicated-runner
variables: variables:
SETUP_DB: "false" SETUP_DB: "false"
USE_BUNDLE_INSTALL: "false" USE_BUNDLE_INSTALL: "false"
...@@ -412,6 +435,7 @@ notify:slack: ...@@ -412,6 +435,7 @@ notify:slack:
pages: pages:
before_script: [] before_script: []
stage: pages stage: pages
<<: *dedicated-runner
dependencies: dependencies:
- coverage - coverage
- teaspoon - teaspoon
...@@ -426,11 +450,12 @@ pages: ...@@ -426,11 +450,12 @@ pages:
paths: paths:
- public - public
only: only:
- master - master@gitlab-org/gitlab-ce
# Insurance in case a gem needed by one of our releases gets yanked from # Insurance in case a gem needed by one of our releases gets yanked from
# rubygems.org in the future. # rubygems.org in the future.
cache gems: cache gems:
<<: *dedicated-runner
only: only:
- tags - tags
variables: variables:
...@@ -440,3 +465,5 @@ cache gems: ...@@ -440,3 +465,5 @@ cache gems:
artifacts: artifacts:
paths: paths:
- vendor/cache - vendor/cache
only:
- master@gitlab-org/gitlab-ce
...@@ -21,6 +21,8 @@ logs, and code as it's very hard to read otherwise.) ...@@ -21,6 +21,8 @@ logs, and code as it's very hard to read otherwise.)
### Output of checks ### Output of checks
(If you are reporting a bug on GitLab.com, write: This bug happens on GitLab.com)
#### Results of GitLab application Check #### Results of GitLab application Check
(For installations with omnibus-gitlab package run and paste the output of: (For installations with omnibus-gitlab package run and paste the output of:
......
...@@ -30,7 +30,7 @@ linters: ...@@ -30,7 +30,7 @@ linters:
# variable declarations. They should be referred to via variables everywhere # variable declarations. They should be referred to via variables everywhere
# else. # else.
ColorVariable: ColorVariable:
enabled: false enabled: true
# Which form of comments to prefer in CSS. # Which form of comments to prefer in CSS.
Comment: Comment:
......
...@@ -2,6 +2,48 @@ ...@@ -2,6 +2,48 @@
documentation](doc/development/changelog.md) for instructions on adding your own documentation](doc/development/changelog.md) for instructions on adding your own
entry. entry.
## 8.14.4 (2016-12-08)
- Fix diff view permalink highlighting. !7090
- Fix pipeline author for Slack and use pipeline id for pipeline link. !7506
- Fix compatibility with Internet Explorer 11 for merge requests. !7525 (Steffen Rauh)
- Reenables /user API request to return private-token if user is admin and request is made with sudo. !7615
- Fix Cicking on tabs on pipeline page should set URL. !7709
- Authorize users into imported GitLab project.
- Destroy a user's session when they delete their own account.
- Don't accidentally mark unsafe diff lines as HTML safe.
- Replace MR access checks with use of MergeRequestsFinder.
- Remove visible content caching.
## 8.14.3 (2016-12-02)
- Pass commit data to ProcessCommitWorker to reduce Git overhead. !7744
- Speed up issuable dashboards.
- Don't change relative URLs to absolute URLs in the Help page.
- Fixes "ActionView::Template::Error: undefined method `text?` for nil:NilClass" on MR pages.
- Fix branch validation for GitHub PR where repo/fork was renamed/deleted.
- Validate state param when filtering issuables.
## 8.14.2 (2016-12-01)
- Remove caching of events data. !6578
- Rephrase some system notes to be compatible with new system note style. !7692
- Pass tag SHA to post-receive hook when tag is created via UI. !7700
- Prevent error when submitting a merge request and pipeline is not defined. !7707
- Fixes system note style in commit discussion. !7721
- Use a Redis lease for updating authorized projects. !7733
- Refactor JiraService by moving code out of JiraService#execute method. !7756
- Update GitLab Workhorse to v1.0.1. !7759
- Fix pipelines info being hidden in merge request widget. !7808
- Fixed commit timeago not rendering after initial page.
- Fix for error thrown in cycle analytics events if build has not started.
- Fixed issue boards issue sorting when dragging issue into list.
- Allow access to the wiki with git when repository feature disabled.
- Fixed timeago not rendering when resolving a discussion.
- Update Sidekiq-cron to fix compatibility issues with Sidekiq 4.2.1.
- Timeout creating and viewing merge request for binary file.
- Gracefully recover from Redis connection failures in Sidekiq initializer.
## 8.14.1 (2016-11-28) ## 8.14.1 (2016-11-28)
- Fix deselecting calendar days on contribution graph. !6453 (ClemMakesApps) - Fix deselecting calendar days on contribution graph. !6453 (ClemMakesApps)
...@@ -222,6 +264,16 @@ entry. ...@@ -222,6 +264,16 @@ entry.
- Fix "Without projects" filter. !6611 (Ben Bodenmiller) - Fix "Without projects" filter. !6611 (Ben Bodenmiller)
- Fix 404 when visit /projects page - Fix 404 when visit /projects page
## 8.13.9 (2016-12-08)
- Reenables /user API request to return private-token if user is admin and request is made with sudo. !7615
- Replace MR access checks with use of MergeRequestsFinder.
## 8.13.8 (2016-12-02)
- Pass tag SHA to post-receive hook when tag is created via UI. !7700
- Validate state param when filtering issuables.
## 8.13.7 (2016-11-28) ## 8.13.7 (2016-11-28)
- fixes 500 error on project show when user is not logged in and project is still empty. !7376 - fixes 500 error on project show when user is not logged in and project is still empty. !7376
...@@ -461,6 +513,21 @@ entry. ...@@ -461,6 +513,21 @@ entry.
- Fix broken Project API docs (Takuya Noguchi) - Fix broken Project API docs (Takuya Noguchi)
- Migrate invalid project members (owner -> master) - Migrate invalid project members (owner -> master)
## 8.12.12 (2016-12-08)
- Replace MR access checks with use of MergeRequestsFinder
- Reenables /user API request to return private-token if user is admin and request is made with sudo
## 8.12.11 (2016-12-02)
- No changes
## 8.12.10 (2016-11-28)
- Fix information disclosure in `Projects::BlobController#update`
- Fix missing access checks on issue lookup using IssuableFinder
- Replace issue access checks with use of IssuableFinder
## 8.12.9 (2016-11-07) ## 8.12.9 (2016-11-07)
- Fix XSS issue in Markdown autolinker - Fix XSS issue in Markdown autolinker
......
...@@ -131,7 +131,7 @@ gem 'after_commit_queue', '~> 1.3.0' ...@@ -131,7 +131,7 @@ gem 'after_commit_queue', '~> 1.3.0'
gem 'acts-as-taggable-on', '~> 4.0' gem 'acts-as-taggable-on', '~> 4.0'
# Background jobs # Background jobs
gem 'sidekiq', '~> 4.2' gem 'sidekiq', '~> 4.2.7'
gem 'sidekiq-cron', '~> 0.4.4' gem 'sidekiq-cron', '~> 0.4.4'
gem 'redis-namespace', '~> 1.5.2' gem 'redis-namespace', '~> 1.5.2'
gem 'sidekiq-limit_fetch', '~> 3.4' gem 'sidekiq-limit_fetch', '~> 3.4'
...@@ -263,14 +263,14 @@ group :development do ...@@ -263,14 +263,14 @@ group :development do
end end
group :development, :test do group :development, :test do
gem 'byebug', '~> 8.2.1', platform: :mri gem 'pry-byebug', '~> 3.4.1', platform: :mri
gem 'pry-rails', '~> 0.3.4' gem 'pry-rails', '~> 0.3.4'
gem 'awesome_print', '~> 1.2.0', require: false gem 'awesome_print', '~> 1.2.0', require: false
gem 'fuubar', '~> 2.0.0' gem 'fuubar', '~> 2.0.0'
gem 'database_cleaner', '~> 1.5.0' gem 'database_cleaner', '~> 1.5.0'
gem 'factory_girl_rails', '~> 4.6.0' gem 'factory_girl_rails', '~> 4.7.0'
gem 'rspec-rails', '~> 3.5.0' gem 'rspec-rails', '~> 3.5.0'
gem 'rspec-retry', '~> 0.4.5' gem 'rspec-retry', '~> 0.4.5'
gem 'spinach-rails', '~> 0.2.1' gem 'spinach-rails', '~> 0.2.1'
...@@ -337,7 +337,7 @@ gem 'ruby-prof', '~> 0.16.2' ...@@ -337,7 +337,7 @@ gem 'ruby-prof', '~> 0.16.2'
gem 'oauth2', '~> 1.2.0' gem 'oauth2', '~> 1.2.0'
# Soft deletion # Soft deletion
gem 'paranoia', '~> 2.0' gem 'paranoia', '~> 2.2'
# Health check # Health check
gem 'health_check', '~> 2.2.0' gem 'health_check', '~> 2.2.0'
......
...@@ -91,7 +91,7 @@ GEM ...@@ -91,7 +91,7 @@ GEM
bundler-audit (0.5.0) bundler-audit (0.5.0)
bundler (~> 1.2) bundler (~> 1.2)
thor (~> 0.18) thor (~> 0.18)
byebug (8.2.1) byebug (9.0.6)
capybara (2.6.2) capybara (2.6.2)
addressable addressable
mime-types (>= 1.16) mime-types (>= 1.16)
...@@ -126,7 +126,7 @@ GEM ...@@ -126,7 +126,7 @@ GEM
coffee-script-source (1.10.0) coffee-script-source (1.10.0)
colorize (0.7.7) colorize (0.7.7)
concurrent-ruby (1.0.2) concurrent-ruby (1.0.2)
connection_pool (2.2.0) connection_pool (2.2.1)
crack (0.4.3) crack (0.4.3)
safe_yaml (~> 1.0.0) safe_yaml (~> 1.0.0)
creole (0.5.0) creole (0.5.0)
...@@ -177,10 +177,10 @@ GEM ...@@ -177,10 +177,10 @@ GEM
excon (0.52.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.7.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
factory_girl_rails (4.6.0) factory_girl_rails (4.7.0)
factory_girl (~> 4.5.0) factory_girl (~> 4.7.0)
railties (>= 3.0.0) railties (>= 3.0.0)
faraday (0.9.2) faraday (0.9.2)
multipart-post (>= 1.2, < 3) multipart-post (>= 1.2, < 3)
...@@ -456,8 +456,8 @@ GEM ...@@ -456,8 +456,8 @@ GEM
org-ruby (0.9.12) org-ruby (0.9.12)
rubypants (~> 0.2) rubypants (~> 0.2)
orm_adapter (0.5.0) orm_adapter (0.5.0)
paranoia (2.1.4) paranoia (2.2.0)
activerecord (~> 4.0) activerecord (>= 4.0, < 5.1)
parser (2.3.1.4) parser (2.3.1.4)
ast (~> 2.2) ast (~> 2.2)
pg (0.18.4) pg (0.18.4)
...@@ -479,6 +479,9 @@ GEM ...@@ -479,6 +479,9 @@ GEM
coderay (~> 1.1.0) coderay (~> 1.1.0)
method_source (~> 0.8.1) method_source (~> 0.8.1)
slop (~> 3.4) slop (~> 3.4)
pry-byebug (3.4.1)
byebug (~> 9.0)
pry (~> 0.10)
pry-rails (0.3.4) pry-rails (0.3.4)
pry (>= 0.9.10) pry (>= 0.9.10)
pyu-ruby-sasl (0.0.3.3) pyu-ruby-sasl (0.0.3.3)
...@@ -610,8 +613,7 @@ GEM ...@@ -610,8 +613,7 @@ GEM
rubyntlm (0.5.2) rubyntlm (0.5.2)
rubypants (0.2.0) rubypants (0.2.0)
rubyzip (1.2.0) rubyzip (1.2.0)
rufus-scheduler (3.3.0) rufus-scheduler (3.1.10)
tzinfo
rugged (0.24.0) rugged (0.24.0)
safe_yaml (1.0.4) safe_yaml (1.0.4)
sanitize (2.1.0) sanitize (2.1.0)
...@@ -642,10 +644,10 @@ GEM ...@@ -642,10 +644,10 @@ GEM
rack rack
shoulda-matchers (2.8.0) shoulda-matchers (2.8.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
sidekiq (4.2.1) sidekiq (4.2.7)
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) rack-protection (>= 1.5.0)
redis (~> 3.2, >= 3.2.1) redis (~> 3.2, >= 3.2.1)
sidekiq-cron (0.4.4) sidekiq-cron (0.4.4)
redis-namespace (>= 1.5.2) redis-namespace (>= 1.5.2)
...@@ -793,7 +795,6 @@ DEPENDENCIES ...@@ -793,7 +795,6 @@ DEPENDENCIES
browser (~> 2.2) browser (~> 2.2)
bullet (~> 5.2.0) bullet (~> 5.2.0)
bundler-audit (~> 0.5.0) bundler-audit (~> 0.5.0)
byebug (~> 8.2.1)
capybara (~> 2.6.2) capybara (~> 2.6.2)
capybara-screenshot (~> 1.0.0) capybara-screenshot (~> 1.0.0)
carrierwave (~> 0.10.0) carrierwave (~> 0.10.0)
...@@ -814,7 +815,7 @@ DEPENDENCIES ...@@ -814,7 +815,7 @@ DEPENDENCIES
dropzonejs-rails (~> 0.7.1) dropzonejs-rails (~> 0.7.1)
email_reply_parser (~> 0.5.8) email_reply_parser (~> 0.5.8)
email_spec (~> 1.6.0) email_spec (~> 1.6.0)
factory_girl_rails (~> 4.6.0) factory_girl_rails (~> 4.7.0)
ffaker (~> 2.0.0) ffaker (~> 2.0.0)
flay (~> 2.6.1) flay (~> 2.6.1)
fog-aws (~> 0.9) fog-aws (~> 0.9)
...@@ -883,10 +884,11 @@ DEPENDENCIES ...@@ -883,10 +884,11 @@ DEPENDENCIES
omniauth-twitter (~> 1.2.0) omniauth-twitter (~> 1.2.0)
omniauth_crowd (~> 2.2.0) omniauth_crowd (~> 2.2.0)
org-ruby (~> 0.9.12) org-ruby (~> 0.9.12)
paranoia (~> 2.0) paranoia (~> 2.2)
pg (~> 0.18.2) pg (~> 0.18.2)
poltergeist (~> 1.9.0) poltergeist (~> 1.9.0)
premailer-rails (~> 1.9.0) premailer-rails (~> 1.9.0)
pry-byebug (~> 3.4.1)
pry-rails (~> 0.3.4) pry-rails (~> 0.3.4)
rack-attack (~> 4.4.1) rack-attack (~> 4.4.1)
rack-cors (~> 0.4.0) rack-cors (~> 0.4.0)
...@@ -921,7 +923,7 @@ DEPENDENCIES ...@@ -921,7 +923,7 @@ 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.2) sidekiq (~> 4.2.7)
sidekiq-cron (~> 0.4.4) sidekiq-cron (~> 0.4.4)
sidekiq-limit_fetch (~> 3.4) sidekiq-limit_fetch (~> 3.4)
simplecov (= 0.12.0) simplecov (= 0.12.0)
......
...@@ -76,7 +76,7 @@ GitLab is a Ruby on Rails application that runs on the following software: ...@@ -76,7 +76,7 @@ GitLab is a Ruby on Rails application that runs on the following software:
- Ubuntu/Debian/CentOS/RHEL - Ubuntu/Debian/CentOS/RHEL
- Ruby (MRI) 2.3 - Ruby (MRI) 2.3
- Git 2.7.4+ - Git 2.8.4+
- Redis 2.8+ - Redis 2.8+
- MySQL or PostgreSQL - MySQL or PostgreSQL
......
Copyright 2010, 2012, 2014 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
...@@ -56,33 +56,18 @@ ...@@ -56,33 +56,18 @@
/*= require es6-promise.auto */ /*= require es6-promise.auto */
(function () { (function () {
document.addEventListener('page:fetch', gl.utils.cleanupBeforeFetch); document.addEventListener('page:fetch', function () {
window.addEventListener('hashchange', gl.utils.shiftWindow); // Unbind scroll events
$(document).off('scroll');
// automatically adjust scroll position for hash urls taking the height of the navbar into account // Close any open tooltips
// https://github.com/twitter/bootstrap/issues/1768 $('.has-tooltip, [data-toggle="tooltip"]').tooltip('destroy');
window.adjustScroll = function() { });
var navbar = document.querySelector('.navbar-gitlab');
var subnav = document.querySelector('.layout-nav');
var fixedTabs = document.querySelector('.js-tabs-affix');
adjustment = 0;
if (navbar) adjustment -= navbar.offsetHeight;
if (subnav) adjustment -= subnav.offsetHeight;
if (fixedTabs) adjustment -= fixedTabs.offsetHeight;
return scrollBy(0, adjustment);
};
window.addEventListener("hashchange", adjustScroll); window.addEventListener('hashchange', gl.utils.handleLocationHash);
window.addEventListener('load', function onLoad() {
window.onload = function () { window.removeEventListener('load', onLoad, false);
// Scroll the window to avoid the topnav bar gl.utils.handleLocationHash();
// https://github.com/twitter/bootstrap/issues/1768 }, false);
if (location.hash) {
return setTimeout(adjustScroll, 100);
}
};
$(function () { $(function () {
var $body = $('body'); var $body = $('body');
...@@ -97,7 +82,15 @@ ...@@ -97,7 +82,15 @@
// Set the default path for all cookies to GitLab's root directory // Set the default path for all cookies to GitLab's root directory
Cookies.defaults.path = gon.relative_url_root || '/'; Cookies.defaults.path = gon.relative_url_root || '/';
gl.utils.preventDisabledButtons(); // prevent default action for disabled buttons
$('.btn').click(function(e) {
if ($(this).hasClass('disabled')) {
e.preventDefault();
e.stopImmediatePropagation();
return false;
}
});
$('.nav-sidebar').niceScroll({ $('.nav-sidebar').niceScroll({
cursoropacitymax: '0.4', cursoropacitymax: '0.4',
cursorcolor: '#FFF', cursorcolor: '#FFF',
......
...@@ -70,6 +70,8 @@ ...@@ -70,6 +70,8 @@
// e.g. // e.g.
// Api.gitignoreText item.name, @requestFileSuccess.bind(@) // Api.gitignoreText item.name, @requestFileSuccess.bind(@)
requestFileSuccess(file, { skipFocus } = {}) { requestFileSuccess(file, { skipFocus } = {}) {
if (!file) return;
const oldValue = this.editor.getValue(); const oldValue = this.editor.getValue();
let newValue = file.content; let newValue = file.content;
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
new gl.DueDateSelectors(); new gl.DueDateSelectors();
new LabelsSelect(); new LabelsSelect();
new Sidebar(); new Sidebar();
new Subscription('.subscription'); gl.Subscription.bindAll('.subscription');
} }
}); });
})(); })();
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
this.CommitFile = (function() { this.CommitFile = (function() {
function CommitFile(file) { function CommitFile(file) {
if ($('.image', file).length) { if ($('.image', file).length) {
new ImageFile(file); new gl.ImageFile(file);
} }
} }
......
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-use-before-define, prefer-arrow-callback, no-else-return, consistent-return, prefer-template, quotes, one-var, one-var-declaration-per-line, no-unused-vars, no-return-assign, comma-dangle, quote-props, no-unused-expressions, no-sequences, object-shorthand, padded-blocks, max-len */ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-use-before-define, prefer-arrow-callback, no-else-return, consistent-return, prefer-template, quotes, one-var, one-var-declaration-per-line, no-unused-vars, no-return-assign, comma-dangle, quote-props, no-unused-expressions, no-sequences, object-shorthand, padded-blocks, max-len */
(function() { (function() {
this.ImageFile = (function() { gl.ImageFile = (function() {
var prepareFrames; var prepareFrames;
// Width where images must fits in, for 2-up this gets divided by 2 // Width where images must fits in, for 2-up this gets divided by 2
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
var genericError, genericSuccess, showTooltip; var genericError, genericSuccess, showTooltip;
genericSuccess = function(e) { genericSuccess = function(e) {
showTooltip(e.trigger, 'Copied!'); showTooltip(e.trigger, 'Copied');
// Clear the selection and blur the trigger so it loses its border // Clear the selection and blur the trigger so it loses its border
e.clearSelection(); e.clearSelection();
return $(e.trigger).blur(); return $(e.trigger).blur();
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
var originalTitle = $target.data('original-title'); var originalTitle = $target.data('original-title');
$target $target
.attr('title', 'Copied!') .attr('title', 'Copied')
.tooltip('fixTitle') .tooltip('fixTitle')
.tooltip('show') .tooltip('show')
.attr('title', originalTitle) .attr('title', originalTitle)
......
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, max-len, one-var, camelcase, one-var-declaration-per-line, no-unused-vars, no-unused-expressions, no-sequences, object-shorthand, comma-dangle, prefer-arrow-callback, semi, radix, padded-blocks, max-len */
(function() {
this.Diff = (function() {
var UNFOLD_COUNT;
UNFOLD_COUNT = 20;
function Diff() {
$('.files .diff-file').singleFileDiff();
this.filesCommentButton = $('.files .diff-file').filesCommentButton();
if (this.diffViewType() === 'parallel') {
$('.content-wrapper .container-fluid').removeClass('container-limited');
}
$(document).off('click', '.js-unfold');
$(document).on('click', '.js-unfold', (function(_this) {
return function(event) {
var line_number, link, file, offset, old_line, params, prev_new_line, prev_old_line, ref, ref1, since, target, to, unfold, unfoldBottom;
target = $(event.target);
unfoldBottom = target.hasClass('js-unfold-bottom');
unfold = true;
ref = _this.lineNumbers(target.parent()), old_line = ref[0], line_number = ref[1];
offset = line_number - old_line;
if (unfoldBottom) {
line_number += 1;
since = line_number;
to = line_number + UNFOLD_COUNT;
} else {
ref1 = _this.lineNumbers(target.parent().prev()), prev_old_line = ref1[0], prev_new_line = ref1[1];
line_number -= 1;
to = line_number;
if (line_number - UNFOLD_COUNT > prev_new_line + 1) {
since = line_number - UNFOLD_COUNT;
} else {
since = prev_new_line + 1;
unfold = false;
}
}
file = target.parents('.diff-file');
link = file.data('blob-diff-path');
params = {
since: since,
to: to,
bottom: unfoldBottom,
offset: offset,
unfold: unfold,
view: file.data('view')
};
return $.get(link, params, function(response) {
return target.parent().replaceWith(response);
});
};
})(this));
}
Diff.prototype.diffViewType = function() {
return $('.inline-parallel-buttons a.active').data('view-type');
}
Diff.prototype.lineNumbers = function(line) {
if (!line.children().length) {
return [0, 0];
}
return line.find('.diff-line-num').map(function() {
return parseInt($(this).data('linenumber'));
});
};
return Diff;
})();
}).call(this);
/* eslint-disable class-methods-use-this */
(() => {
const UNFOLD_COUNT = 20;
class Diff {
constructor() {
const $diffFile = $('.files .diff-file');
$diffFile.singleFileDiff();
$diffFile.filesCommentButton();
$diffFile.each((index, file) => new gl.ImageFile(file));
if (this.diffViewType() === 'parallel') {
$('.content-wrapper .container-fluid').removeClass('container-limited');
}
$(document)
.off('click', '.js-unfold, .diff-line-num a')
.on('click', '.js-unfold', this.handleClickUnfold.bind(this))
.on('click', '.diff-line-num a', this.handleClickLineNum.bind(this));
this.highlighSelectedLine();
}
handleClickUnfold(e) {
const $target = $(e.target);
// current babel config relies on iterators implementation, so we cannot simply do:
// const [oldLineNumber, newLineNumber] = this.lineNumbers($target.parent());
const ref = this.lineNumbers($target.parent());
const oldLineNumber = ref[0];
const newLineNumber = ref[1];
const offset = newLineNumber - oldLineNumber;
const bottom = $target.hasClass('js-unfold-bottom');
let since;
let to;
let unfold = true;
if (bottom) {
const lineNumber = newLineNumber + 1;
since = lineNumber;
to = lineNumber + UNFOLD_COUNT;
} else {
const lineNumber = newLineNumber - 1;
since = lineNumber - UNFOLD_COUNT;
to = lineNumber;
// make sure we aren't loading more than we need
const prevNewLine = this.lineNumbers($target.parent().prev())[1];
if (since <= prevNewLine + 1) {
since = prevNewLine + 1;
unfold = false;
}
}
const file = $target.parents('.diff-file');
const link = file.data('blob-diff-path');
const view = file.data('view');
const params = { since, to, bottom, offset, unfold, view };
$.get(link, params, response => $target.parent().replaceWith(response));
}
openAnchoredDiff(anchoredDiff, cb) {
const diffTitle = $(`#file-path-${anchoredDiff}`);
const diffFile = diffTitle.closest('.diff-file');
const nothingHereBlock = $('.nothing-here-block:visible', diffFile);
if (nothingHereBlock.length) {
diffFile.singleFileDiff(true, cb);
} else {
cb();
}
}
handleClickLineNum(e) {
const hash = $(e.currentTarget).attr('href');
e.preventDefault();
if (window.history.pushState) {
window.history.pushState(null, null, hash);
} else {
window.location.hash = hash;
}
this.highlighSelectedLine();
}
diffViewType() {
return $('.inline-parallel-buttons a.active').data('view-type');
}
lineNumbers(line) {
if (!line.children().length) {
return [0, 0];
}
return line.find('.diff-line-num').map((i, elm) => parseInt($(elm).data('linenumber'), 10));
}
highlighSelectedLine() {
const $diffFiles = $('.diff-file');
$diffFiles.find('.hll').removeClass('hll');
if (window.location.hash !== '') {
const hash = window.location.hash.replace('#', '');
$diffFiles
.find(`tr#${hash}:not(.match) td, td#${hash}, td[data-line-code="${hash}"]`)
.addClass('hll');
}
}
}
window.gl = window.gl || {};
window.gl.Diff = Diff;
})();
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
switch (page) { switch (page) {
case 'sessions:new': case 'sessions:new':
new UsernameValidator(); new UsernameValidator();
new ActiveTabMemoizer();
break; break;
case 'projects:boards:show': case 'projects:boards:show':
case 'projects:boards:index': case 'projects:boards:index':
...@@ -61,7 +62,7 @@ ...@@ -61,7 +62,7 @@
new ZenMode(); new ZenMode();
break; break;
case 'projects:compare:show': case 'projects:compare:show':
new Diff(); new gl.Diff();
break; break;
case 'projects:issues:new': case 'projects:issues:new':
case 'projects:issues:edit': case 'projects:issues:edit':
...@@ -74,7 +75,7 @@ ...@@ -74,7 +75,7 @@
break; break;
case 'projects:merge_requests:new': case 'projects:merge_requests:new':
case 'projects:merge_requests:edit': case 'projects:merge_requests:edit':
new Diff(); new gl.Diff();
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
new GLForm($('.merge-request-form')); new GLForm($('.merge-request-form'));
new IssuableForm($('.merge-request-form')); new IssuableForm($('.merge-request-form'));
...@@ -91,7 +92,7 @@ ...@@ -91,7 +92,7 @@
new GLForm($('.release-form')); new GLForm($('.release-form'));
break; break;
case 'projects:merge_requests:show': case 'projects:merge_requests:show':
new Diff(); new gl.Diff();
shortcut_handler = new ShortcutsIssuable(true); shortcut_handler = new ShortcutsIssuable(true);
new ZenMode(); new ZenMode();
new MergedButtons(); new MergedButtons();
...@@ -101,7 +102,7 @@ ...@@ -101,7 +102,7 @@
new MergedButtons(); new MergedButtons();
break; break;
case "projects:merge_requests:diffs": case "projects:merge_requests:diffs":
new Diff(); new gl.Diff();
new ZenMode(); new ZenMode();
new MergedButtons(); new MergedButtons();
break; break;
...@@ -117,7 +118,7 @@ ...@@ -117,7 +118,7 @@
break; break;
case 'projects:commit:show': case 'projects:commit:show':
new Commit(); new Commit();
new Diff(); new gl.Diff();
new ZenMode(); new ZenMode();
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
break; break;
...@@ -135,8 +136,18 @@ ...@@ -135,8 +136,18 @@
new TreeView(); new TreeView();
} }
break; break;
case 'projects:pipelines:builds':
case 'projects:pipelines:show': case 'projects:pipelines:show':
new gl.Pipelines(); const { controllerAction } = document.querySelector('.js-pipeline-container').dataset;
new gl.Pipelines({
initTabs: true,
tabsOptions: {
action: controllerAction,
defaultAction: 'pipelines',
parentEl: '.pipelines-tabs',
},
});
break; break;
case 'groups:activity': case 'groups:activity':
new gl.Activities(); new gl.Activities();
...@@ -262,7 +273,7 @@ ...@@ -262,7 +273,7 @@
new NotificationsDropdown(); new NotificationsDropdown();
break; break;
case 'wikis': case 'wikis':
new Wikis(); new gl.Wikis();
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
new ZenMode(); new ZenMode();
new GLForm($('.wiki-form')); new GLForm($('.wiki-form'));
......
...@@ -74,6 +74,8 @@ ...@@ -74,6 +74,8 @@
projectStoppedEnvironmentsPath: environmentsData.projectStoppedEnvironmentsPath, projectStoppedEnvironmentsPath: environmentsData.projectStoppedEnvironmentsPath,
newEnvironmentPath: environmentsData.newEnvironmentPath, newEnvironmentPath: environmentsData.newEnvironmentPath,
helpPagePath: environmentsData.helpPagePath, helpPagePath: environmentsData.helpPagePath,
commitIconSvg: environmentsData.commitIconSvg,
playIconSvg: environmentsData.playIconSvg,
}; };
}, },
...@@ -227,7 +229,9 @@ ...@@ -227,7 +229,9 @@
:model="model" :model="model"
:toggleRow="toggleRow.bind(model)" :toggleRow="toggleRow.bind(model)"
:can-create-deployment="canCreateDeploymentParsed" :can-create-deployment="canCreateDeploymentParsed"
:can-read-environment="canReadEnvironmentParsed"></tr> :can-read-environment="canReadEnvironmentParsed"
:play-icon-svg="playIconSvg"
:commit-icon-svg="commitIconSvg"></tr>
<tr v-if="model.isOpen && model.children && model.children.length > 0" <tr v-if="model.isOpen && model.children && model.children.length > 0"
is="environment-item" is="environment-item"
...@@ -235,7 +239,9 @@ ...@@ -235,7 +239,9 @@
:model="children" :model="children"
:toggleRow="toggleRow.bind(children)" :toggleRow="toggleRow.bind(children)"
:can-create-deployment="canCreateDeploymentParsed" :can-create-deployment="canCreateDeploymentParsed"
:can-read-environment="canReadEnvironmentParsed"> :can-read-environment="canReadEnvironmentParsed"
:play-icon-svg="playIconSvg"
:commit-icon-svg="commitIconSvg">
</tr> </tr>
</template> </template>
......
...@@ -12,38 +12,18 @@ ...@@ -12,38 +12,18 @@
required: false, required: false,
default: () => [], default: () => [],
}, },
},
/**
* Appends the svg icon that were render in the index page.
* In order to reuse the svg instead of copy and paste in this template
* we need to render it outside this component using =custom_icon partial.
*
* TODO: Remove this when webpack is merged.
*
*/
mounted() {
const playIcon = document.querySelector('.play-icon-svg.hidden svg');
const dropdownContainer = this.$el.querySelector('.dropdown-play-icon-container');
const actionContainers = this.$el.querySelectorAll('.action-play-icon-container');
// Phantomjs does not have support to iterate a nodelist.
const actionsArray = [].slice.call(actionContainers);
if (playIcon && actionsArray && dropdownContainer) {
dropdownContainer.appendChild(playIcon.cloneNode(true));
actionsArray.forEach((element) => { playIconSvg: {
element.appendChild(playIcon.cloneNode(true)); type: String,
}); required: false,
} },
}, },
template: ` template: `
<div class="inline"> <div class="inline">
<div class="dropdown"> <div class="dropdown">
<a class="dropdown-new btn btn-default" data-toggle="dropdown"> <a class="dropdown-new btn btn-default" data-toggle="dropdown">
<span class="dropdown-play-icon-container"></span> <span class="js-dropdown-play-icon-container" v-html="playIconSvg"></span>
<i class="fa fa-caret-down"></i> <i class="fa fa-caret-down"></i>
</a> </a>
...@@ -53,7 +33,9 @@ ...@@ -53,7 +33,9 @@
data-method="post" data-method="post"
rel="nofollow" rel="nofollow"
class="js-manual-action-link"> class="js-manual-action-link">
<span class="action-play-icon-container"></span>
<span class="js-action-play-icon-container" v-html="playIconSvg"></span>
<span> <span>
{{action.name}} {{action.name}}
</span> </span>
......
...@@ -7,14 +7,14 @@ ...@@ -7,14 +7,14 @@
window.gl.environmentsList.ExternalUrlComponent = Vue.component('external-url-component', { window.gl.environmentsList.ExternalUrlComponent = Vue.component('external-url-component', {
props: { props: {
external_url: { externalUrl: {
type: String, type: String,
default: '', default: '',
}, },
}, },
template: ` template: `
<a class="btn external_url" :href="external_url" target="_blank"> <a class="btn external_url" :href="externalUrl" target="_blank">
<i class="fa fa-external-link"></i> <i class="fa fa-external-link"></i>
</a> </a>
`, `,
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
window.gl = window.gl || {}; window.gl = window.gl || {};
window.gl.environmentsList = window.gl.environmentsList || {}; window.gl.environmentsList = window.gl.environmentsList || {};
window.gl.environmentsList.timeagoInstance = new timeago(); // eslint-disable-line
gl.environmentsList.EnvironmentItem = Vue.component('environment-item', { gl.environmentsList.EnvironmentItem = Vue.component('environment-item', {
...@@ -57,6 +58,16 @@ ...@@ -57,6 +58,16 @@
required: false, required: false,
default: false, default: false,
}, },
commitIconSvg: {
type: String,
required: false,
},
playIconSvg: {
type: String,
required: false,
},
}, },
data() { data() {
...@@ -147,15 +158,26 @@ ...@@ -147,15 +158,26 @@
this.model.last_deployment.deployable; this.model.last_deployment.deployable;
}, },
/**
* Verifies if the date to be shown is present.
*
* @returns {Boolean|Undefined}
*/
canShowDate() {
return this.model.last_deployment &&
this.model.last_deployment.deployable &&
this.model.last_deployment.deployable !== undefined;
},
/** /**
* Human readable date. * Human readable date.
* *
* @returns {String} * @returns {String}
*/ */
createdDate() { createdDate() {
const timeagoInstance = new timeago(); // eslint-disable-line return window.gl.environmentsList.timeagoInstance.format(
this.model.last_deployment.deployable.created_at,
return timeagoInstance.format(this.model.created_at); );
}, },
/** /**
...@@ -439,11 +461,12 @@ ...@@ -439,11 +461,12 @@
<div v-if="!isFolder && hasLastDeploymentKey" class="js-commit-component"> <div v-if="!isFolder && hasLastDeploymentKey" class="js-commit-component">
<commit-component <commit-component
:tag="commitTag" :tag="commitTag"
:ref="commitRef" :commit-ref="commitRef"
:commit_url="commitUrl" :commit-url="commitUrl"
:short_sha="commitShortSha" :short-sha="commitShortSha"
:title="commitTitle" :title="commitTitle"
:author="commitAuthor"> :author="commitAuthor"
:commit-icon-svg="commitIconSvg">
</commit-component> </commit-component>
</div> </div>
<p v-if="!isFolder && !hasLastDeploymentKey" class="commit-title"> <p v-if="!isFolder && !hasLastDeploymentKey" class="commit-title">
...@@ -453,7 +476,7 @@ ...@@ -453,7 +476,7 @@
<td> <td>
<span <span
v-if="!isFolder && model.last_deployment" v-if="!isFolder && canShowDate"
class="environment-created-date-timeago"> class="environment-created-date-timeago">
{{createdDate}} {{createdDate}}
</span> </span>
...@@ -464,6 +487,7 @@ ...@@ -464,6 +487,7 @@
<div v-if="hasManualActions && canCreateDeployment" <div v-if="hasManualActions && canCreateDeployment"
class="inline js-manual-actions-container"> class="inline js-manual-actions-container">
<actions-component <actions-component
:play-icon-svg="playIconSvg"
:actions="manualActions"> :actions="manualActions">
</actions-component> </actions-component>
</div> </div>
...@@ -471,22 +495,22 @@ ...@@ -471,22 +495,22 @@
<div v-if="model.external_url && canReadEnvironment" <div v-if="model.external_url && canReadEnvironment"
class="inline js-external-url-container"> class="inline js-external-url-container">
<external-url-component <external-url-component
:external_url="model.external_url"> :external-url="model.external_url">
</external_url-component> </external-url-component>
</div> </div>
<div v-if="isStoppable && canCreateDeployment" <div v-if="isStoppable && canCreateDeployment"
class="inline js-stop-component-container"> class="inline js-stop-component-container">
<stop-component <stop-component
:stop_url="model.stop_path"> :stop-url="model.stop_path">
</stop-component> </stop-component>
</div> </div>
<div v-if="canRetry && canCreateDeployment" <div v-if="canRetry && canCreateDeployment"
class="inline js-rollback-component-container"> class="inline js-rollback-component-container">
<rollback-component <rollback-component
:is_last_deployment="isLastDeployment" :is-last-deployment="isLastDeployment"
:retry_url="retryUrl"> :retry-url="retryUrl">
</rollback-component> </rollback-component>
</div> </div>
</div> </div>
......
...@@ -7,19 +7,20 @@ ...@@ -7,19 +7,20 @@
window.gl.environmentsList.RollbackComponent = Vue.component('rollback-component', { window.gl.environmentsList.RollbackComponent = Vue.component('rollback-component', {
props: { props: {
retry_url: { retryUrl: {
type: String, type: String,
default: '', default: '',
}, },
is_last_deployment: {
isLastDeployment: {
type: Boolean, type: Boolean,
default: true, default: true,
}, },
}, },
template: ` template: `
<a class="btn" :href="retry_url" data-method="post" rel="nofollow"> <a class="btn" :href="retryUrl" data-method="post" rel="nofollow">
<span v-if="is_last_deployment"> <span v-if="isLastDeployment">
Re-deploy Re-deploy
</span> </span>
<span v-else> <span v-else>
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
window.gl.environmentsList.StopComponent = Vue.component('stop-component', { window.gl.environmentsList.StopComponent = Vue.component('stop-component', {
props: { props: {
stop_url: { stopUrl: {
type: String, type: String,
default: '', default: '',
}, },
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
template: ` template: `
<a class="btn stop-env-link" <a class="btn stop-env-link"
:href="stop_url" :href="stopUrl"
data-confirm="Are you sure you want to stop this environment?" data-confirm="Are you sure you want to stop this environment?"
data-method="post" data-method="post"
rel="nofollow"> rel="nofollow">
......
/* global Element */ /* global Element */
/* eslint-disable consistent-return, max-len */ /* eslint-disable consistent-return, max-len, no-empty, no-plusplus, func-names */
Element.prototype.matches = Element.prototype.matches || Element.prototype.msMatchesSelector;
Element.prototype.closest = Element.prototype.closest || function closest(selector, selectedElement = this) { Element.prototype.closest = Element.prototype.closest || function closest(selector, selectedElement = this) {
if (!selectedElement) return; if (!selectedElement) return;
return selectedElement.matches(selector) ? selectedElement : Element.prototype.closest(selector, selectedElement.parentElement); return selectedElement.matches(selector) ? selectedElement : Element.prototype.closest(selector, selectedElement.parentElement);
}; };
Element.prototype.matches = Element.prototype.matches ||
Element.prototype.matchesSelector ||
Element.prototype.mozMatchesSelector ||
Element.prototype.msMatchesSelector ||
Element.prototype.oMatchesSelector ||
Element.prototype.webkitMatchesSelector ||
function (s) {
const matches = (this.document || this.ownerDocument).querySelectorAll(s);
let i = matches.length;
while (--i >= 0 && matches.item(i) !== this) {}
return i > -1;
};
...@@ -5,6 +5,10 @@ ...@@ -5,6 +5,10 @@
window.GitLab = {}; window.GitLab = {};
} }
function sanitize(str) {
return str.replace(/<(?:.|\n)*?>/gm, '');
}
GitLab.GfmAutoComplete = { GitLab.GfmAutoComplete = {
dataLoading: false, dataLoading: false,
dataLoaded: false, dataLoaded: false,
...@@ -48,6 +52,10 @@ ...@@ -48,6 +52,10 @@
return $.fn.atwho["default"].callbacks.filter(query, data, searchKey); return $.fn.atwho["default"].callbacks.filter(query, data, searchKey);
}, },
beforeInsert: function(value) { beforeInsert: function(value) {
if (value && !this.setting.skipSpecialCharacterTest) {
var withoutAt = value.substring(1);
if (withoutAt && /[^\w\d]/.test(withoutAt)) value = value.charAt() + '"' + withoutAt + '"';
}
if (!GitLab.GfmAutoComplete.dataLoaded) { if (!GitLab.GfmAutoComplete.dataLoaded) {
return this.at; return this.at;
} else { } else {
...@@ -59,12 +67,13 @@ ...@@ -59,12 +67,13 @@
// Tweaked to commands to start without a space only if char before is a non-word character // Tweaked to commands to start without a space only if char before is a non-word character
// https://github.com/ichord/At.js // https://github.com/ichord/At.js
var _a, _y, regexp, match; var _a, _y, regexp, match;
subtext = subtext.split(' ').pop();
flag = flag.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); flag = flag.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
_a = decodeURI("%C3%80"); _a = decodeURI("%C3%80");
_y = decodeURI("%C3%BF"); _y = decodeURI("%C3%BF");
regexp = new RegExp("(?:\\B|\\W|\\s)" + flag + "([A-Za-z" + _a + "-" + _y + "0-9_\'\.\+\-]*)|([^\\x00-\\xff]*)$", 'gi'); regexp = new RegExp("(?:\\B|\\W|\\s)" + flag + "(?!\\W)([A-Za-z" + _a + "-" + _y + "0-9_\'\.\+\-]*)|([^\\x00-\\xff]*)$", 'gi');
match = regexp.exec(subtext); match = regexp.exec(subtext);
...@@ -112,6 +121,7 @@ ...@@ -112,6 +121,7 @@
insertTpl: ':${name}:', insertTpl: ':${name}:',
data: ['loading'], data: ['loading'],
startWithSpace: false, startWithSpace: false,
skipSpecialCharacterTest: true,
callbacks: { callbacks: {
sorter: this.DefaultOptions.sorter, sorter: this.DefaultOptions.sorter,
filter: this.DefaultOptions.filter, filter: this.DefaultOptions.filter,
...@@ -136,6 +146,7 @@ ...@@ -136,6 +146,7 @@
data: ['loading'], data: ['loading'],
startWithSpace: false, startWithSpace: false,
alwaysHighlightFirst: true, alwaysHighlightFirst: true,
skipSpecialCharacterTest: true,
callbacks: { callbacks: {
sorter: this.DefaultOptions.sorter, sorter: this.DefaultOptions.sorter,
filter: this.DefaultOptions.filter, filter: this.DefaultOptions.filter,
...@@ -159,8 +170,8 @@ ...@@ -159,8 +170,8 @@
return { return {
username: m.username, username: m.username,
avatarTag: autoCompleteAvatar.length === 1 ? txtAvatar : imgAvatar, avatarTag: autoCompleteAvatar.length === 1 ? txtAvatar : imgAvatar,
title: gl.utils.sanitize(title), title: sanitize(title),
search: gl.utils.sanitize(m.username + " " + m.name) search: sanitize(m.username + " " + m.name)
}; };
}); });
} }
...@@ -194,7 +205,7 @@ ...@@ -194,7 +205,7 @@
} }
return { return {
id: i.iid, id: i.iid,
title: gl.utils.sanitize(i.title), title: sanitize(i.title),
search: i.iid + " " + i.title search: i.iid + " " + i.title
}; };
}); });
...@@ -214,12 +225,13 @@ ...@@ -214,12 +225,13 @@
} }
}; };
})(this), })(this),
insertTpl: '${atwho-at}"${title}"', insertTpl: '${atwho-at}${title}',
data: ['loading'], data: ['loading'],
startWithSpace: false, startWithSpace: false,
callbacks: { callbacks: {
matcher: this.DefaultOptions.matcher, matcher: this.DefaultOptions.matcher,
sorter: this.DefaultOptions.sorter, sorter: this.DefaultOptions.sorter,
beforeInsert: this.DefaultOptions.beforeInsert,
beforeSave: function(milestones) { beforeSave: function(milestones) {
return $.map(milestones, function(m) { return $.map(milestones, function(m) {
if (m.title == null) { if (m.title == null) {
...@@ -227,7 +239,7 @@ ...@@ -227,7 +239,7 @@
} }
return { return {
id: m.iid, id: m.iid,
title: gl.utils.sanitize(m.title), title: sanitize(m.title),
search: "" + m.title search: "" + m.title
}; };
}); });
...@@ -262,7 +274,7 @@ ...@@ -262,7 +274,7 @@
} }
return { return {
id: m.iid, id: m.iid,
title: gl.utils.sanitize(m.title), title: sanitize(m.title),
search: m.iid + " " + m.title search: m.iid + " " + m.title
}; };
}); });
...@@ -279,18 +291,11 @@ ...@@ -279,18 +291,11 @@
callbacks: { callbacks: {
matcher: this.DefaultOptions.matcher, matcher: this.DefaultOptions.matcher,
sorter: this.DefaultOptions.sorter, sorter: this.DefaultOptions.sorter,
beforeInsert: this.DefaultOptions.beforeInsert,
beforeSave: function(merges) { beforeSave: function(merges) {
var sanitizeLabelTitle;
sanitizeLabelTitle = function(title) {
if (/[\w\?&]+\s+[\w\?&]+/g.test(title)) {
return "\"" + (gl.utils.sanitize(title)) + "\"";
} else {
return gl.utils.sanitize(title);
}
};
return $.map(merges, function(m) { return $.map(merges, function(m) {
return { return {
title: sanitizeLabelTitle(m.title), title: sanitize(m.title),
color: m.color, color: m.color,
search: "" + m.title search: "" + m.title
}; };
...@@ -303,6 +308,7 @@ ...@@ -303,6 +308,7 @@
at: '/', at: '/',
alias: 'commands', alias: 'commands',
searchKey: 'search', searchKey: 'search',
skipSpecialCharacterTest: true,
displayTpl: function(value) { displayTpl: function(value) {
var tpl = '<li>/${name}'; var tpl = '<li>/${name}';
if (value.aliases.length > 0) { if (value.aliases.length > 0) {
......
...@@ -650,6 +650,11 @@ ...@@ -650,6 +650,11 @@
} else if(value) { } else if(value) {
field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value.toString().replace(/'/g, '\\\'') + "']"); field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value.toString().replace(/'/g, '\\\'') + "']");
} }
if (this.options.isSelectable && !this.options.isSelectable(selectedObject, el)) {
return;
}
if (el.hasClass(ACTIVE_CLASS)) { if (el.hasClass(ACTIVE_CLASS)) {
el.removeClass(ACTIVE_CLASS); el.removeClass(ACTIVE_CLASS);
if (field && field.length) { if (field && field.length) {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
(function() { (function() {
window.ContributorsStatGraphUtil = { window.ContributorsStatGraphUtil = {
parse_log: function(log) { parse_log: function(log) {
var by_author, by_email, data, entry, i, len, total; var by_author, by_email, data, entry, i, len, total, normalized_email;
total = {}; total = {};
by_author = {}; by_author = {};
by_email = {}; by_email = {};
...@@ -11,7 +11,8 @@ ...@@ -11,7 +11,8 @@
if (total[entry.date] == null) { if (total[entry.date] == null) {
this.add_date(entry.date, total); this.add_date(entry.date, total);
} }
data = by_author[entry.author_name] || by_email[entry.author_email]; normalized_email = entry.author_email.toLowerCase();
data = by_author[entry.author_name] || by_email[normalized_email];
if (data == null) { if (data == null) {
data = this.add_author(entry, by_author, by_email); data = this.add_author(entry, by_author, by_email);
} }
...@@ -32,12 +33,14 @@ ...@@ -32,12 +33,14 @@
return collection[date].date = date; return collection[date].date = date;
}, },
add_author: function(author, by_author, by_email) { add_author: function(author, by_author, by_email) {
var data; var data, normalized_email;
data = {}; data = {};
data.author_name = author.author_name; data.author_name = author.author_name;
data.author_email = author.author_email; data.author_email = author.author_email;
normalized_email = author.author_email.toLowerCase();
by_author[author.author_name] = data; by_author[author.author_name] = data;
return by_email[author.author_email] = data; by_email[normalized_email] = data;
return data;
}, },
store_data: function(entry, total, by_author) { store_data: function(entry, total, by_author) {
this.store_commits(total, by_author); this.store_commits(total, by_author);
......
/**
* Linked Tabs
*
* Handles persisting and restores the current tab selection and content.
* Reusable component for static content.
*
* ### Example Markup
*
* <ul class="nav-links tab-links">
* <li class="active">
* <a data-action="tab1" data-target="#tab1" data-toggle="tab" href="/path/tab1">
* Tab 1
* </a>
* </li>
* <li class="groups-tab">
* <a data-action="tab2" data-target="#tab2" data-toggle="tab" href="/path/tab2">
* Tab 2
* </a>
* </li>
*
*
* <div class="tab-content">
* <div class="tab-pane" id="tab1">
* Tab 1 Content
* </div>
* <div class="tab-pane" id="tab2">
* Tab 2 Content
* </div>
* </div>
*
*
* ### How to use
*
* new window.gl.LinkedTabs({
* action: "#{controller.action_name}",
* defaultAction: 'tab1',
* parentEl: '.tab-links'
* });
*/
(() => {
window.gl = window.gl || {};
window.gl.LinkedTabs = class LinkedTabs {
/**
* Binds the events and activates de default tab.
*
* @param {Object} options
*/
constructor(options) {
this.options = options || {};
this.defaultAction = this.options.defaultAction;
this.action = this.options.action || this.defaultAction;
if (this.action === 'show') {
this.action = this.defaultAction;
}
this.currentLocation = window.location;
const tabSelector = `${this.options.parentEl} a[data-toggle="tab"]`;
// since this is a custom event we need jQuery :(
$(document)
.off('shown.bs.tab', tabSelector)
.on('shown.bs.tab', tabSelector, e => this.tabShown(e));
this.activateTab(this.action);
}
/**
* Handles the `shown.bs.tab` event to set the currect url action.
*
* @param {type} evt
* @return {Function}
*/
tabShown(evt) {
const source = evt.target.getAttribute('href');
return this.setCurrentAction(source);
}
/**
* Updates the URL with the path that matched the given action.
*
* @param {String} source
* @return {String}
*/
setCurrentAction(source) {
const copySource = source;
copySource.replace(/\/+$/, '');
const newState = `${copySource}${this.currentLocation.search}${this.currentLocation.hash}`;
history.replaceState({
turbolinks: true,
url: newState,
}, document.title, newState);
return newState;
}
/**
* Given the current action activates the correct tab.
* http://getbootstrap.com/javascript/#tab-show
* Note: Will trigger `shown.bs.tab`
*/
activateTab() {
return $(`${this.options.parentEl} a[data-action='${this.action}']`).tab('show');
}
};
})();
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-unused-expressions, no-param-reassign, no-else-return, quotes, object-shorthand, comma-dangle, camelcase, one-var, vars-on-top, one-var-declaration-per-line, no-return-assign, consistent-return, padded-blocks, max-len */ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-unused-expressions, no-param-reassign, no-else-return, quotes, object-shorthand, comma-dangle, camelcase, one-var, vars-on-top, one-var-declaration-per-line, no-return-assign, consistent-return, padded-blocks, max-len, prefer-template */
(function() { (function() {
(function(w) { (function(w) {
var base; var base;
...@@ -33,10 +33,6 @@ ...@@ -33,10 +33,6 @@
}); });
}; };
w.gl.utils.split = function(val) {
return val.split(/,\s*/);
};
w.gl.utils.extractLast = function(term) { w.gl.utils.extractLast = function(term) {
return this.split(term).pop(); return this.split(term).pop();
}; };
...@@ -67,63 +63,51 @@ ...@@ -67,63 +63,51 @@
}); });
}; };
w.gl.utils.disableButtonIfAnyEmptyField = function(form, form_selector, button_selector) { // automatically adjust scroll position for hash urls taking the height of the navbar into account
var closest_submit, updateButtons; // https://github.com/twitter/bootstrap/issues/1768
closest_submit = form.find(button_selector); w.gl.utils.handleLocationHash = function() {
updateButtons = function() { var hash = w.gl.utils.getLocationHash();
var filled; if (!hash) return;
filled = true;
form.find('input').filter(form_selector).each(function() {
return filled = this.rstrip($(this).val()) !== "" || !$(this).attr('required');
});
if (filled) {
return closest_submit.enable();
} else {
return closest_submit.disable();
}
};
updateButtons();
return form.keyup(updateButtons);
};
w.gl.utils.sanitize = function(str) {
return str.replace(/<(?:.|\n)*?>/gm, '');
};
w.gl.utils.unbindEvents = function() {
return $(document).off('scroll');
};
w.gl.utils.shiftWindow = function() { var navbar = document.querySelector('.navbar-gitlab');
return w.scrollBy(0, -100); var subnav = document.querySelector('.layout-nav');
}; var fixedTabs = document.querySelector('.js-tabs-affix');
var adjustment = 0;
if (navbar) adjustment -= navbar.offsetHeight;
if (subnav) adjustment -= subnav.offsetHeight;
gl.utils.updateTooltipTitle = function($tooltipEl, newTitle) { // scroll to user-generated markdown anchor if we cannot find a match
return $tooltipEl.tooltip('destroy').attr('title', newTitle).tooltip('fixTitle'); if (document.getElementById(hash) === null) {
}; var target = document.getElementById('user-content-' + hash);
gl.utils.preventDisabledButtons = function() { if (target && target.scrollIntoView) {
return $('.btn').click(function(e) { target.scrollIntoView(true);
if ($(this).hasClass('disabled')) { window.scrollBy(0, adjustment);
e.preventDefault();
e.stopImmediatePropagation();
return false;
} }
}); } else {
// only adjust for fixedTabs when not targeting user-generated content
if (fixedTabs) {
adjustment -= fixedTabs.offsetHeight;
}
window.scrollBy(0, adjustment);
}
}; };
gl.utils.getPagePath = function() { gl.utils.getPagePath = function() {
return $('body').data('page').split(':')[0]; return $('body').data('page').split(':')[0];
}; };
gl.utils.parseUrl = function (url) { gl.utils.parseUrl = function (url) {
var parser = document.createElement('a'); var parser = document.createElement('a');
parser.href = url; parser.href = url;
return parser; return parser;
}; };
gl.utils.cleanupBeforeFetch = function() {
// Unbind scroll events gl.utils.parseUrlPathname = function (url) {
$(document).off('scroll'); var parsedUrl = gl.utils.parseUrl(url);
// Close any open tooltips // parsedUrl.pathname will return an absolute path for Firefox and a relative path for IE11
$('.has-tooltip, [data-toggle="tooltip"]').tooltip('destroy'); // We have to make sure we always have an absolute path.
return parsedUrl.pathname.charAt(0) === '/' ? parsedUrl.pathname : '/' + parsedUrl.pathname;
}; };
gl.utils.isMetaKey = function(e) { gl.utils.isMetaKey = function(e) {
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
setTimeago = true; setTimeago = true;
} }
$timeagoEls.each(function() { $timeagoEls.filter(':not([data-timeago-rendered])').each(function() {
var $el = $(this); var $el = $(this);
$el.attr('title', gl.utils.formatDate($el.attr('datetime'))); $el.attr('title', gl.utils.formatDate($el.attr('datetime')));
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
template: '<div class="tooltip local-timeago" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>' template: '<div class="tooltip local-timeago" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
}); });
} }
$el.attr('data-timeago-rendered', true);
gl.utils.renderTimeago($el); gl.utils.renderTimeago($el);
}); });
}; };
......
/* eslint-disable */ /* eslint-disable class-methods-use-this */
((w) => { (() => {
w.gl = w.gl || {}; window.gl = window.gl || {};
class Members { class Members {
constructor() { constructor() {
this.addListeners(); this.addListeners();
this.initGLDropdown();
} }
addListeners() { addListeners() {
$('.project_member, .group_member').off('ajax:success').on('ajax:success', this.removeRow); $('.project_member, .group_member').off('ajax:success').on('ajax:success', this.removeRow);
$('.js-member-update-control').off('change').on('change', this.formSubmit); $('.js-member-update-control').off('change').on('change', this.formSubmit.bind(this));
$('.js-edit-member-form').off('ajax:success').on('ajax:success', this.formSuccess); $('.js-edit-member-form').off('ajax:success').on('ajax:success', this.formSuccess.bind(this));
gl.utils.disableButtonIfEmptyField('#user_ids', 'input[name=commit]', 'change'); gl.utils.disableButtonIfEmptyField('#user_ids', 'input[name=commit]', 'change');
} }
initGLDropdown() {
$('.js-member-permissions-dropdown').each((i, btn) => {
const $btn = $(btn);
$btn.glDropdown({
selectable: true,
isSelectable(selected, $el) {
return !$el.hasClass('is-active');
},
fieldName: $btn.data('field-name'),
id(selected, $el) {
return $el.data('id');
},
toggleLabel(selected, $el) {
return $el.text();
},
clicked: (selected, $link) => {
this.formSubmit(null, $link);
},
});
});
}
removeRow(e) { removeRow(e) {
const $target = $(e.target); const $target = $(e.target);
if ($target.hasClass('btn-remove')) { if ($target.hasClass('btn-remove')) {
$target.closest('.member') $target.closest('.member')
.fadeOut(function () { .fadeOut(function fadeOutMemberRow() {
$(this).remove(); $(this).remove();
}); });
} }
} }
formSubmit() { formSubmit(e, $el = null) {
$(this).closest('form').trigger("submit.rails").end().disable(); const $this = e ? $(e.currentTarget) : $el;
const { $toggle, $dateInput } = this.getMemberListItems($this);
$this.closest('form').trigger('submit.rails');
$toggle.disable();
$dateInput.disable();
} }
formSuccess() { formSuccess(e) {
$(this).find('.js-member-update-control').enable(); const { $toggle, $dateInput } = this.getMemberListItems($(e.currentTarget).closest('.member'));
$toggle.enable();
$dateInput.enable();
}
getMemberListItems($el) {
const $memberListItem = $el.is('.member') ? $el : $(`#${$el.data('el-id')}`);
return {
$memberListItem,
$toggle: $memberListItem.find('.dropdown-menu-toggle'),
$dateInput: $memberListItem.find('.js-access-expiration-date'),
};
} }
} }
gl.Members = Members; gl.Members = Members;
})(window); })();
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
if (window.mrTabs) { if (window.mrTabs) {
window.mrTabs.unbindEvents(); window.mrTabs.unbindEvents();
} }
window.mrTabs = new MergeRequestTabs(this.opts); window.mrTabs = new gl.MergeRequestTabs(this.opts);
}; };
MergeRequest.prototype.showAllCommits = function() { MergeRequest.prototype.showAllCommits = function() {
......
...@@ -40,19 +40,26 @@ ...@@ -40,19 +40,26 @@
$('#modal_merge_info').modal({ $('#modal_merge_info').modal({
show: false show: false
}); });
this.firstCICheck = true;
this.readyForCICheck = false;
this.readyForCIEnvironmentCheck = false;
this.cancel = false;
clearInterval(this.fetchBuildStatusInterval);
clearInterval(this.fetchBuildEnvironmentStatusInterval);
this.clearEventListeners(); this.clearEventListeners();
this.addEventListeners(); this.addEventListeners();
this.getCIStatus(false); this.getCIStatus(false);
this.getCIEnvironmentsStatus();
this.retrieveSuccessIcon(); this.retrieveSuccessIcon();
this.pollCIStatus();
this.pollCIEnvironmentsStatus(); this.ciStatusInterval = new global.SmartInterval({
callback: this.getCIStatus.bind(this, true),
startingInterval: 10000,
maxInterval: 30000,
hiddenInterval: 120000,
incrementByFactorOf: 5000,
});
this.ciEnvironmentStatusInterval = new global.SmartInterval({
callback: this.getCIEnvironmentsStatus.bind(this),
startingInterval: 30000,
maxInterval: 120000,
hiddenInterval: 240000,
incrementByFactorOf: 15000,
immediateExecution: true,
});
notifyPermissions(); notifyPermissions();
} }
...@@ -60,10 +67,6 @@ ...@@ -60,10 +67,6 @@
return $(document).off('page:change.merge_request'); return $(document).off('page:change.merge_request');
}; };
MergeRequestWidget.prototype.cancelPolling = function() {
return this.cancel = true;
};
MergeRequestWidget.prototype.addEventListeners = function() { MergeRequestWidget.prototype.addEventListeners = function() {
var allowedPages; var allowedPages;
allowedPages = ['show', 'commits', 'builds', 'pipelines', 'changes']; allowedPages = ['show', 'commits', 'builds', 'pipelines', 'changes'];
...@@ -72,9 +75,6 @@ ...@@ -72,9 +75,6 @@
var page; var page;
page = $('body').data('page').split(':').last(); page = $('body').data('page').split(':').last();
if (allowedPages.indexOf(page) < 0) { if (allowedPages.indexOf(page) < 0) {
clearInterval(_this.fetchBuildStatusInterval);
clearInterval(_this.fetchBuildEnvironmentStatusInterval);
_this.cancelPolling();
return _this.clearEventListeners(); return _this.clearEventListeners();
} }
}; };
...@@ -101,7 +101,7 @@ ...@@ -101,7 +101,7 @@
urlSuffix = deleteSourceBranch ? '?deleted_source_branch=true' : ''; urlSuffix = deleteSourceBranch ? '?deleted_source_branch=true' : '';
return window.location.href = window.location.pathname + urlSuffix; return window.location.href = window.location.pathname + urlSuffix;
} else if (data.merge_error) { } else if (data.merge_error) {
return this.$widgetBody.html("<h4>" + data.merge_error + "</h4>"); return _this.$widgetBody.html("<h4>" + data.merge_error + "</h4>");
} else { } else {
callback = function() { callback = function() {
return merge_request_widget.mergeInProgress(deleteSourceBranch); return merge_request_widget.mergeInProgress(deleteSourceBranch);
...@@ -114,6 +114,11 @@ ...@@ -114,6 +114,11 @@
}); });
}; };
MergeRequestWidget.prototype.cancelPolling = function () {
this.ciStatusInterval.cancel();
this.ciEnvironmentStatusInterval.cancel();
};
MergeRequestWidget.prototype.getMergeStatus = function() { MergeRequestWidget.prototype.getMergeStatus = function() {
return $.get(this.opts.merge_check_url, function(data) { return $.get(this.opts.merge_check_url, function(data) {
return $('.mr-state-widget').replaceWith(data); return $('.mr-state-widget').replaceWith(data);
...@@ -131,18 +136,6 @@ ...@@ -131,18 +136,6 @@
} }
}; };
MergeRequestWidget.prototype.pollCIStatus = function() {
return this.fetchBuildStatusInterval = setInterval(((function(_this) {
return function() {
if (!_this.readyForCICheck) {
return;
}
_this.getCIStatus(true);
return _this.readyForCICheck = false;
};
})(this)), 10000);
};
MergeRequestWidget.prototype.getCIStatus = function(showNotification) { MergeRequestWidget.prototype.getCIStatus = function(showNotification) {
var _this; var _this;
_this = this; _this = this;
...@@ -150,23 +143,17 @@ ...@@ -150,23 +143,17 @@
return $.getJSON(this.opts.ci_status_url, (function(_this) { return $.getJSON(this.opts.ci_status_url, (function(_this) {
return function(data) { return function(data) {
var message, status, title; var message, status, title;
if (_this.cancel) {
return;
}
_this.readyForCICheck = true;
if (data.status === '') { if (data.status === '') {
return; return;
} }
if (data.environments && data.environments.length) _this.renderEnvironments(data.environments); if (data.environments && data.environments.length) _this.renderEnvironments(data.environments);
if (_this.firstCICheck || data.status !== _this.opts.ci_status && (data.status != null)) { if (data.status !== _this.opts.ci_status && (data.status != null)) {
_this.opts.ci_status = data.status; _this.opts.ci_status = data.status;
_this.showCIStatus(data.status); _this.showCIStatus(data.status);
if (data.coverage) { if (data.coverage) {
_this.showCICoverage(data.coverage); _this.showCICoverage(data.coverage);
} }
// The first check should only update the UI, a notification if (showNotification) {
// should only be displayed on status changes
if (showNotification && !_this.firstCICheck) {
status = _this.ciLabelForStatus(data.status); status = _this.ciLabelForStatus(data.status);
if (status === "preparing") { if (status === "preparing") {
title = _this.opts.ci_title.preparing; title = _this.opts.ci_title.preparing;
...@@ -184,24 +171,13 @@ ...@@ -184,24 +171,13 @@
return Turbolinks.visit(_this.opts.builds_path); return Turbolinks.visit(_this.opts.builds_path);
}); });
} }
return _this.firstCICheck = false;
} }
}; };
})(this)); })(this));
}; };
MergeRequestWidget.prototype.pollCIEnvironmentsStatus = function() {
this.fetchBuildEnvironmentStatusInterval = setInterval(() => {
if (!this.readyForCIEnvironmentCheck) return;
this.getCIEnvironmentsStatus();
this.readyForCIEnvironmentCheck = false;
}, 300000);
};
MergeRequestWidget.prototype.getCIEnvironmentsStatus = function() { MergeRequestWidget.prototype.getCIEnvironmentsStatus = function() {
$.getJSON(this.opts.ci_environments_status_url, (environments) => { $.getJSON(this.opts.ci_environments_status_url, (environments) => {
if (this.cancel) return;
this.readyForCIEnvironmentCheck = true;
if (environments && environments.length) this.renderEnvironments(environments); if (environments && environments.length) this.renderEnvironments(environments);
}); });
}; };
...@@ -212,11 +188,11 @@ ...@@ -212,11 +188,11 @@
if ($(`.mr-state-widget #${ environment.id }`).length) return; if ($(`.mr-state-widget #${ environment.id }`).length) return;
const $template = $(DEPLOYMENT_TEMPLATE); const $template = $(DEPLOYMENT_TEMPLATE);
if (!environment.external_url || !environment.external_url_formatted) $('.js-environment-link', $template).remove(); if (!environment.external_url || !environment.external_url_formatted) $('.js-environment-link', $template).remove();
if (!environment.stop_url) { if (!environment.stop_url) {
$('.js-stop-env-link', $template).remove(); $('.js-stop-env-link', $template).remove();
} }
if (environment.deployed_at && environment.deployed_at_formatted) { if (environment.deployed_at && environment.deployed_at_formatted) {
environment.deployed_at = gl.utils.getTimeago().format(environment.deployed_at, 'gl_en') + '.'; environment.deployed_at = gl.utils.getTimeago().format(environment.deployed_at, 'gl_en') + '.';
} else { } else {
......
//= require lib/utils/bootstrap_linked_tabs
/* eslint-disable */ /* eslint-disable */
((global) => { ((global) => {
class Pipelines { class Pipelines {
constructor() { constructor(options = {}) {
if (options.initTabs && options.tabsOptions) {
new global.LinkedTabs(options.tabsOptions);
}
this.addMarginToBuildColumns(); this.addMarginToBuildColumns();
} }
addMarginToBuildColumns() { addMarginToBuildColumns() {
this.pipelineGraph = document.querySelector('.pipeline-graph'); this.pipelineGraph = document.querySelector('.js-pipeline-graph');
const secondChildBuildNodes = document.querySelector('.pipeline-graph').querySelectorAll('.build:nth-child(2)');
for (buildNodeIndex in secondChildBuildNodes) { const secondChildBuildNodes = this.pipelineGraph.querySelectorAll('.build:nth-child(2)');
for (const buildNodeIndex in secondChildBuildNodes) {
const buildNode = secondChildBuildNodes[buildNodeIndex]; const buildNode = secondChildBuildNodes[buildNodeIndex];
const firstChildBuildNode = buildNode.previousElementSibling; const firstChildBuildNode = buildNode.previousElementSibling;
if (!firstChildBuildNode || !firstChildBuildNode.matches('.build')) continue; if (!firstChildBuildNode || !firstChildBuildNode.matches('.build')) continue;
...@@ -21,6 +30,7 @@ ...@@ -21,6 +30,7 @@
const columnBuilds = previousColumn.querySelectorAll('.build'); const columnBuilds = previousColumn.querySelectorAll('.build');
if (columnBuilds.length === 1) previousColumn.classList.add('no-margin'); if (columnBuilds.length === 1) previousColumn.classList.add('no-margin');
} }
this.pipelineGraph.classList.remove('hidden'); this.pipelineGraph.classList.remove('hidden');
} }
} }
......
/* eslint no-param-reassign: ["error", { "props": false }]*/
/* eslint no-new: "off" */
((global) => {
/**
* Memorize the last selected tab after reloading a page.
* Does that setting the current selected tab in the localStorage
*/
class ActiveTabMemoizer {
constructor({ currentTabKey = 'current_signin_tab', tabSelector = 'ul.nav-tabs' } = {}) {
this.currentTabKey = currentTabKey;
this.tabSelector = tabSelector;
this.bootstrap();
}
bootstrap() {
const tabs = document.querySelectorAll(this.tabSelector);
if (tabs.length > 0) {
tabs[0].addEventListener('click', (e) => {
if (e.target && e.target.nodeName === 'A') {
const anchorName = e.target.getAttribute('href');
this.saveData(anchorName);
}
});
}
this.showTab();
}
showTab() {
const anchorName = this.readData();
if (anchorName) {
const tab = document.querySelector(`${this.tabSelector} a[href="${anchorName}"]`);
if (tab) {
tab.click();
}
}
}
saveData(val) {
localStorage.setItem(this.currentTabKey, val);
}
readData() {
return localStorage.getItem(this.currentTabKey);
}
}
global.ActiveTabMemoizer = ActiveTabMemoizer;
})(window);
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
COLLAPSED_HTML = '<div class="nothing-here-block diff-collapsed">This diff is collapsed. <a class="click-to-expand">Click to expand it.</a></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, forceLoad, cb) { function SingleFileDiff(file, forceLoad, cb) {
var clickTarget;
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);
...@@ -31,9 +32,9 @@ ...@@ -31,9 +32,9 @@
this.content.after(this.collapsedContent); this.content.after(this.collapsedContent);
this.$toggleIcon.addClass('fa-caret-down'); this.$toggleIcon.addClass('fa-caret-down');
} }
$('.file-title, .click-to-expand', this.file).on('click', this.toggleDiff); clickTarget = $('.file-title, .click-to-expand', this.file).on('click', this.toggleDiff);
if (forceLoad) { if (forceLoad) {
this.toggleDiff(null, cb); this.toggleDiff({ target: clickTarget }, cb);
} }
} }
......
...@@ -7,24 +7,31 @@ ...@@ -7,24 +7,31 @@
(() => { (() => {
class SmartInterval { class SmartInterval {
/** /**
* @param { function } callback Function to be called on each iteration (required) * @param { function } opts.callback Function to be called on each iteration (required)
* @param { milliseconds } startingInterval `currentInterval` is set to this initially * @param { milliseconds } opts.startingInterval `currentInterval` is set to this initially
* @param { milliseconds } maxInterval `currentInterval` will be incremented to this * @param { milliseconds } opts.maxInterval `currentInterval` will be incremented to this
* @param { integer } incrementByFactorOf `currentInterval` is incremented by this factor * @param { milliseconds } opts.hiddenInterval `currentInterval` is set to this
* @param { boolean } lazyStart Configure if timer is initialized on instantiation or lazily * when the page is hidden
* @param { integer } opts.incrementByFactorOf `currentInterval` is incremented by this factor
* @param { boolean } opts.lazyStart Configure if timer is initialized on
* instantiation or lazily
* @param { boolean } opts.immediateExecution Configure if callback should
* be executed before the first interval.
*/ */
constructor({ callback, startingInterval, maxInterval, incrementByFactorOf, lazyStart }) { constructor(opts = {}) {
this.cfg = { this.cfg = {
callback, callback: opts.callback,
startingInterval, startingInterval: opts.startingInterval,
maxInterval, maxInterval: opts.maxInterval,
incrementByFactorOf, hiddenInterval: opts.hiddenInterval,
lazyStart, incrementByFactorOf: opts.incrementByFactorOf,
lazyStart: opts.lazyStart,
immediateExecution: opts.immediateExecution,
}; };
this.state = { this.state = {
intervalId: null, intervalId: null,
currentInterval: startingInterval, currentInterval: this.cfg.startingInterval,
pageVisibility: 'visible', pageVisibility: 'visible',
}; };
...@@ -36,6 +43,11 @@ ...@@ -36,6 +43,11 @@
const cfg = this.cfg; const cfg = this.cfg;
const state = this.state; const state = this.state;
if (cfg.immediateExecution) {
cfg.immediateExecution = false;
cfg.callback();
}
state.intervalId = window.setInterval(() => { state.intervalId = window.setInterval(() => {
cfg.callback(); cfg.callback();
...@@ -54,14 +66,29 @@ ...@@ -54,14 +66,29 @@
this.stopTimer(); this.stopTimer();
} }
onVisibilityHidden() {
if (this.cfg.hiddenInterval) {
this.setCurrentInterval(this.cfg.hiddenInterval);
this.resume();
} else {
this.cancel();
}
}
// start a timer, using the existing interval // start a timer, using the existing interval
resume() { resume() {
this.stopTimer(); // stop exsiting timer, in case timer was not previously stopped this.stopTimer(); // stop exsiting timer, in case timer was not previously stopped
this.start(); this.start();
} }
onVisibilityVisible() {
this.cancel();
this.start();
}
destroy() { destroy() {
this.cancel(); this.cancel();
document.removeEventListener('visibilitychange', this.handleVisibilityChange);
$(document).off('visibilitychange').off('page:before-unload'); $(document).off('visibilitychange').off('page:before-unload');
} }
...@@ -80,11 +107,7 @@ ...@@ -80,11 +107,7 @@
initVisibilityChangeHandling() { initVisibilityChangeHandling() {
// cancel interval when tab no longer shown (prevents cached pages from polling) // cancel interval when tab no longer shown (prevents cached pages from polling)
$(document) document.addEventListener('visibilitychange', this.handleVisibilityChange.bind(this));
.off('visibilitychange').on('visibilitychange', (e) => {
this.state.pageVisibility = e.target.visibilityState;
this.handleVisibilityChange();
});
} }
initPageUnloadHandling() { initPageUnloadHandling() {
...@@ -92,10 +115,11 @@ ...@@ -92,10 +115,11 @@
$(document).on('page:before-unload', () => this.cancel()); $(document).on('page:before-unload', () => this.cancel());
} }
handleVisibilityChange() { handleVisibilityChange(e) {
const state = this.state; this.state.pageVisibility = e.target.visibilityState;
const intervalAction = this.isPageVisible() ?
const intervalAction = state.pageVisibility === 'hidden' ? this.cancel : this.resume; this.onVisibilityVisible :
this.onVisibilityHidden;
intervalAction.apply(this); intervalAction.apply(this);
} }
...@@ -111,6 +135,7 @@ ...@@ -111,6 +135,7 @@
incrementInterval() { incrementInterval() {
const cfg = this.cfg; const cfg = this.cfg;
const currentInterval = this.getCurrentInterval(); const currentInterval = this.getCurrentInterval();
if (cfg.hiddenInterval && !this.isPageVisible()) return;
let nextInterval = currentInterval * cfg.incrementByFactorOf; let nextInterval = currentInterval * cfg.incrementByFactorOf;
if (nextInterval > cfg.maxInterval) { if (nextInterval > cfg.maxInterval) {
...@@ -120,6 +145,8 @@ ...@@ -120,6 +145,8 @@
this.setCurrentInterval(nextInterval); this.setCurrentInterval(nextInterval);
} }
isPageVisible() { return this.state.pageVisibility === 'visible'; }
stopTimer() { stopTimer() {
const state = this.state; const state = this.state;
......
/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, vars-on-top, no-unused-vars, one-var, one-var-declaration-per-line, camelcase, consistent-return, no-undef, padded-blocks, max-len */
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
this.Subscription = (function() {
function Subscription(container) {
this.toggleSubscription = bind(this.toggleSubscription, this);
var $container;
this.$container = $(container);
this.url = this.$container.attr('data-url');
this.subscribe_button = this.$container.find('.js-subscribe-button');
this.subscription_status = this.$container.find('.subscription-status');
this.subscribe_button.unbind('click').click(this.toggleSubscription);
}
Subscription.prototype.toggleSubscription = function(event) {
var action, btn, current_status;
btn = $(event.currentTarget);
action = btn.find('span').text();
current_status = this.subscription_status.attr('data-status');
btn.addClass('disabled');
if ($('html').hasClass('issue-boards-page')) {
this.url = this.$container.attr('data-url');
}
return $.post(this.url, (function(_this) {
return function() {
var status;
btn.removeClass('disabled');
if ($('html').hasClass('issue-boards-page')) {
Vue.set(gl.issueBoards.BoardsStore.detail.issue, 'subscribed', !gl.issueBoards.BoardsStore.detail.issue.subscribed);
} else {
status = current_status === 'subscribed' ? 'unsubscribed' : 'subscribed';
_this.subscription_status.attr('data-status', status);
action = status === 'subscribed' ? 'Unsubscribe' : 'Subscribe';
btn.find('span').text(action);
_this.subscription_status.find('>div').toggleClass('hidden');
if (btn.attr('data-original-title')) {
return btn.tooltip('hide').attr('data-original-title', action).tooltip('fixTitle');
}
}
};
})(this));
};
return Subscription;
})();
}).call(this);
/* global Vue */
(() => {
class Subscription {
constructor(containerElm) {
this.containerElm = containerElm;
const subscribeButton = containerElm.querySelector('.js-subscribe-button');
if (subscribeButton) {
// remove class so we don't bind twice
subscribeButton.classList.remove('js-subscribe-button');
subscribeButton.addEventListener('click', this.toggleSubscription.bind(this));
}
}
toggleSubscription(event) {
const button = event.currentTarget;
const buttonSpan = button.querySelector('span');
if (!buttonSpan || button.classList.contains('disabled')) {
return;
}
button.classList.add('disabled');
const isSubscribed = buttonSpan.innerHTML.trim().toLowerCase() !== 'subscribe';
const toggleActionUrl = this.containerElm.dataset.url;
$.post(toggleActionUrl, () => {
button.classList.remove('disabled');
// hack to allow this to work with the issue boards Vue object
if (document.querySelector('html').classList.contains('issue-boards-page')) {
Vue.set(
gl.issueBoards.BoardsStore.detail.issue,
'subscribed',
!gl.issueBoards.BoardsStore.detail.issue.subscribed,
);
} else {
buttonSpan.innerHTML = isSubscribed ? 'Subscribe' : 'Unsubscribe';
}
});
}
static bindAll(selector) {
[].forEach.call(document.querySelectorAll(selector), elm => new Subscription(elm));
}
}
window.gl = window.gl || {};
window.gl.Subscription = Subscription;
})();
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
* name * name
* ref_url * ref_url
*/ */
ref: { commitRef: {
type: Object, type: Object,
required: false, required: false,
default: () => ({}), default: () => ({}),
...@@ -32,16 +32,16 @@ ...@@ -32,16 +32,16 @@
/** /**
* Used to link to the commit sha. * Used to link to the commit sha.
*/ */
commit_url: { commitUrl: {
type: String, type: String,
required: false, required: false,
default: '', default: '',
}, },
/** /**
* Used to show the commit short_sha that links to the commit url. * Used to show the commit short sha that links to the commit url.
*/ */
short_sha: { shortSha: {
type: String, type: String,
required: false, required: false,
default: '', default: '',
...@@ -68,6 +68,11 @@ ...@@ -68,6 +68,11 @@
required: false, required: false,
default: () => ({}), default: () => ({}),
}, },
commitIconSvg: {
type: String,
required: false,
},
}, },
computed: { computed: {
...@@ -79,8 +84,8 @@ ...@@ -79,8 +84,8 @@
* *
* @returns {Boolean} * @returns {Boolean}
*/ */
hasRef() { hasCommitRef() {
return this.ref && this.ref.name && this.ref.ref_url; return this.commitRef && this.commitRef.name && this.commitRef.ref_url;
}, },
/** /**
...@@ -110,43 +115,25 @@ ...@@ -110,43 +115,25 @@
}, },
}, },
/**
* In order to reuse the svg instead of copy and paste in this template
* we need to render it outside this component using =custom_icon partial.
* Make sure it has this structure:
* .commit-icon-svg.hidden
* svg
*
* TODO: Find a better way to include SVG
*/
mounted() {
const commitIconContainer = this.$el.querySelector('.commit-icon-container');
const commitIcon = document.querySelector('.commit-icon-svg.hidden svg');
if (commitIconContainer && commitIcon) {
commitIconContainer.appendChild(commitIcon.cloneNode(true));
}
},
template: ` template: `
<div class="branch-commit"> <div class="branch-commit">
<div v-if="hasRef" class="icon-container"> <div v-if="hasCommitRef" class="icon-container">
<i v-if="tag" class="fa fa-tag"></i> <i v-if="tag" class="fa fa-tag"></i>
<i v-if="!tag" class="fa fa-code-fork"></i> <i v-if="!tag" class="fa fa-code-fork"></i>
</div> </div>
<a v-if="hasRef" <a v-if="hasCommitRef"
class="monospace branch-name" class="monospace branch-name"
:href="ref.ref_url"> :href="commitRef.ref_url">
{{ref.name}} {{commitRef.name}}
</a> </a>
<div class="icon-container commit-icon commit-icon-container"></div> <div v-html="commitIconSvg" class="commit-icon js-commit-icon"></div>
<a class="commit-id monospace" <a class="commit-id monospace"
:href="commit_url"> :href="commitUrl">
{{short_sha}} {{shortSha}}
</a> </a>
<p class="commit-title"> <p class="commit-title">
...@@ -162,7 +149,7 @@ ...@@ -162,7 +149,7 @@
</a> </a>
<a class="commit-row-message" <a class="commit-row-message"
:href="commit_url"> :href="commitUrl">
{{title}} {{title}}
</a> </a>
</span> </span>
......
/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, consistent-return, one-var, one-var-declaration-per-line, no-undef, prefer-template, padded-blocks, max-len */
/*= require latinise */
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
this.Wikis = (function() {
function Wikis() {
this.slugify = bind(this.slugify, this);
$('.new-wiki-page').on('submit', (function(_this) {
return function(e) {
var field, path, slug;
$('[data-error~=slug]').addClass('hidden');
field = $('#new_wiki_path');
slug = _this.slugify(field.val());
if (slug.length > 0) {
path = field.attr('data-wikis-path');
location.href = path + '/' + slug;
return e.preventDefault();
}
};
})(this));
}
Wikis.prototype.dasherize = function(value) {
return value.replace(/[_\s]+/g, '-');
};
Wikis.prototype.slugify = function(value) {
return this.dasherize(value.trim().toLowerCase().latinise());
};
return Wikis;
})();
}).call(this);
/* eslint-disable no-param-reassign */
/* global Breakpoints */
/*= require latinise */
/*= require breakpoints */
/*= require jquery.nicescroll */
((global) => {
const dasherize = str => str.replace(/[_\s]+/g, '-');
const slugify = str => dasherize(str.trim().toLowerCase().latinise());
class Wikis {
constructor() {
this.bp = Breakpoints.get();
this.sidebarEl = document.querySelector('.js-wiki-sidebar');
this.sidebarExpanded = false;
$(this.sidebarEl).niceScroll();
const sidebarToggles = document.querySelectorAll('.js-sidebar-wiki-toggle');
for (let i = 0; i < sidebarToggles.length; i += 1) {
sidebarToggles[i].addEventListener('click', e => this.handleToggleSidebar(e));
}
this.newWikiForm = document.querySelector('form.new-wiki-page');
if (this.newWikiForm) {
this.newWikiForm.addEventListener('submit', e => this.handleNewWikiSubmit(e));
}
window.addEventListener('resize', () => this.renderSidebar());
this.renderSidebar();
}
handleNewWikiSubmit(e) {
if (!this.newWikiForm) return;
const slugInput = this.newWikiForm.querySelector('#new_wiki_path');
const slug = slugify(slugInput.value);
if (slug.length > 0) {
const wikisPath = slugInput.getAttribute('data-wikis-path');
window.location.href = `${wikisPath}/${slug}`;
e.preventDefault();
}
}
handleToggleSidebar(e) {
e.preventDefault();
this.sidebarExpanded = !this.sidebarExpanded;
this.renderSidebar();
}
sidebarCanCollapse() {
const bootstrapBreakpoint = this.bp.getBreakpointSize();
return bootstrapBreakpoint === 'xs' || bootstrapBreakpoint === 'sm';
}
renderSidebar() {
if (!this.sidebarEl) return;
const { classList } = this.sidebarEl;
if (this.sidebarExpanded || !this.sidebarCanCollapse()) {
if (!classList.contains('right-sidebar-expanded')) {
classList.remove('right-sidebar-collapsed');
classList.add('right-sidebar-expanded');
}
} else if (classList.contains('right-sidebar-expanded')) {
classList.add('right-sidebar-collapsed');
classList.remove('right-sidebar-expanded');
}
}
}
global.Wikis = Wikis;
})(window.gl || (window.gl = {}));
@import "framework/fonts";
@import "framework/variables"; @import "framework/variables";
@import "framework/mixins"; @import "framework/mixins";
@import 'framework/tw_bootstrap_variables'; @import 'framework/tw_bootstrap_variables';
...@@ -7,6 +6,7 @@ ...@@ -7,6 +6,7 @@
@import "framework/animations.scss"; @import "framework/animations.scss";
@import "framework/avatar.scss"; @import "framework/avatar.scss";
@import "framework/asciidoctor.scss";
@import "framework/blocks.scss"; @import "framework/blocks.scss";
@import "framework/buttons.scss"; @import "framework/buttons.scss";
@import "framework/calendar.scss"; @import "framework/calendar.scss";
...@@ -41,3 +41,6 @@ ...@@ -41,3 +41,6 @@
@import "framework/blank"; @import "framework/blank";
@import "framework/wells.scss"; @import "framework/wells.scss";
@import "framework/page-header.scss"; @import "framework/page-header.scss";
@import "framework/awards.scss";
@import "framework/images.scss";
@import "framework/broadcast-messages";
.admonitionblock td.icon {
width: 1%;
[class^="fa icon-"] {
@extend .fa-2x;
}
.icon-note {
@extend .fa-thumb-tack;
}
.icon-tip {
@extend .fa-lightbulb-o;
}
.icon-warning {
@extend .fa-exclamation-triangle;
}
.icon-caution {
@extend .fa-fire;
}
.icon-important {
@extend .fa-exclamation-circle;
}
}
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
float: left; float: left;
margin-right: 15px; margin-right: 15px;
border-radius: $avatar_radius; border-radius: $avatar_radius;
border: 1px solid rgba(0, 0, 0, .1); border: 1px solid $avatar-border;
&.s16 { @include avatar-size(16px, 6px); } &.s16 { @include avatar-size(16px, 6px); }
&.s20 { @include avatar-size(20px, 7px); } &.s20 { @include avatar-size(20px, 7px); }
&.s24 { @include avatar-size(24px, 8px); } &.s24 { @include avatar-size(24px, 8px); }
......
.awards { .awards {
.emoji-icon { .emoji-icon {
width: 19px; width: 20px;
height: 19px; height: 20px;
} }
} }
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
background-color: $award-emoji-menu-bg; background-color: $award-emoji-menu-bg;
border: 1px solid $award-emoji-menu-border; border: 1px solid $award-emoji-menu-border;
border-radius: $border-radius-base; border-radius: $border-radius-base;
box-shadow: 0 6px 12px rgba(0,0,0,.175); box-shadow: 0 6px 12px $award-emoji-menu-shadow;
pointer-events: none; pointer-events: none;
opacity: 0; opacity: 0;
transform: scale(.2); transform: scale(.2);
...@@ -127,7 +127,7 @@ ...@@ -127,7 +127,7 @@
.award-control-icon { .award-control-icon {
float: left; float: left;
margin-right: 5px; margin-right: 5px;
font-size: 19px; font-size: 18px;
} }
.award-control-icon-loading { .award-control-icon-loading {
...@@ -136,5 +136,6 @@ ...@@ -136,5 +136,6 @@
.award-control-icon { .award-control-icon {
color: $award-emoji-new-btn-icon-color; color: $award-emoji-new-btn-icon-color;
margin-top: 1px;
} }
} }
...@@ -32,14 +32,14 @@ ...@@ -32,14 +32,14 @@
.blank-state-title { .blank-state-title {
margin-top: 0; margin-top: 0;
margin-bottom: 5px; margin-bottom: 5px;
font-size: 19px; font-size: 18px;
font-weight: normal; font-weight: normal;
} }
.blank-state-text { .blank-state-text {
margin-top: 0; margin-top: 0;
margin-bottom: $gl-padding; margin-bottom: $gl-padding;
font-size: 15px; font-size: 14px;
> strong { > strong {
font-weight: 600; font-weight: 600;
......
.light-well {
background-color: $background-color;
padding: 15px;
}
.centered-light-block { .centered-light-block {
text-align: center; text-align: center;
color: $gl-gray; color: $gl-gray;
...@@ -41,7 +36,7 @@ ...@@ -41,7 +36,7 @@
} }
&.white { &.white {
background-color: white; background-color: $white-light;
} }
&.top-block { &.top-block {
...@@ -158,7 +153,7 @@ ...@@ -158,7 +153,7 @@
p { p {
padding: 0 $gl-padding; padding: 0 $gl-padding;
color: #5c5d5e; color: $gl-text-color-dark;
} }
} }
...@@ -274,6 +269,10 @@ ...@@ -274,6 +269,10 @@
} }
} }
.emoji-icon {
display: inline-block;
}
@media(max-width: $screen-xs-max) { @media(max-width: $screen-xs-max) {
margin-top: 50px; margin-top: 50px;
text-align: center; text-align: center;
......
.broadcast-message {
@extend .alert-warning;
padding: 10px;
text-align: center;
div,
p {
display: inline;
margin: 0;
a {
color: inherit;
text-decoration: underline;
}
}
}
.broadcast-message-preview {
@extend .broadcast-message;
margin-bottom: 20px;
}
@mixin btn-default { @mixin btn-default {
border-radius: 3px; border-radius: 3px;
font-size: $gl-font-size; font-size: $gl-font-size;
font-weight: 500; font-weight: 400;
padding: $gl-vert-padding $gl-btn-padding; padding: $gl-vert-padding $gl-btn-padding;
&:focus, &:focus,
...@@ -68,23 +68,23 @@ ...@@ -68,23 +68,23 @@
} }
@mixin btn-green { @mixin btn-green {
@include btn-color($green-light, $border-green-light, $green-normal, $border-green-normal, $green-dark, $border-green-dark, #fff); @include btn-color($green-light, $border-green-light, $green-normal, $border-green-normal, $green-dark, $border-green-dark, $white-light);
} }
@mixin btn-blue { @mixin btn-blue {
@include btn-color($blue-light, $border-blue-light, $blue-normal, $border-blue-normal, $blue-dark, $border-blue-dark, #fff); @include btn-color($blue-light, $border-blue-light, $blue-normal, $border-blue-normal, $blue-dark, $border-blue-dark, $white-light);
} }
@mixin btn-blue-medium { @mixin btn-blue-medium {
@include btn-color($blue-medium-light, $border-blue-light, $blue-medium, $border-blue-normal, $blue-medium-dark, $border-blue-dark, #fff); @include btn-color($blue-medium-light, $border-blue-light, $blue-medium, $border-blue-normal, $blue-medium-dark, $border-blue-dark, $white-light);
} }
@mixin btn-orange { @mixin btn-orange {
@include btn-color($orange-light, $border-orange-light, $orange-normal, $border-orange-normal, $orange-dark, $border-orange-dark, #fff); @include btn-color($orange-light, $border-orange-light, $orange-normal, $border-orange-normal, $orange-dark, $border-orange-dark, $white-light);
} }
@mixin btn-red { @mixin btn-red {
@include btn-color($red-light, $border-red-light, $red-normal, $border-red-normal, $red-dark, $border-red-dark, #fff); @include btn-color($red-light, $border-red-light, $red-normal, $border-red-normal, $red-dark, $border-red-dark, $white-light);
} }
@mixin btn-gray { @mixin btn-gray {
...@@ -289,8 +289,8 @@ ...@@ -289,8 +289,8 @@
.active { .active {
box-shadow: $gl-btn-active-background; box-shadow: $gl-btn-active-background;
border: 1px solid #c6cacf !important; border: 1px solid $border-white-dark !important;
background-color: #e4e7ed !important; background-color: $btn-active-gray-light !important;
} }
} }
...@@ -345,13 +345,13 @@ ...@@ -345,13 +345,13 @@
.btn-static { .btn-static {
background-color: $background-color !important; background-color: $background-color !important;
border: 1px solid lightgrey; border: 1px solid $border-gray-light;
cursor: default; cursor: default;
&:active { &:active {
-moz-box-shadow: inset 0 0 0 white; -moz-box-shadow: inset 0 0 0 $white-light;
-webkit-box-shadow: inset 0 0 0 white; -webkit-box-shadow: inset 0 0 0 $white-light;
box-shadow: inset 0 0 0 white; box-shadow: inset 0 0 0 $white-light;
} }
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
padding-left: 0; padding-left: 0;
padding-right: 0; padding-right: 0;
@media (min-width: $screen-sm-min) and (max-width: $screen-lg-min) { @media (min-width: $screen-sm-min) and (max-width: $screen-md-max) {
overflow-x: scroll; overflow-x: scroll;
} }
} }
...@@ -28,13 +28,13 @@ ...@@ -28,13 +28,13 @@
.user-contrib-cell { .user-contrib-cell {
&:hover { &:hover {
cursor: pointer; cursor: pointer;
stroke: #000; stroke: $black;
} }
} }
.user-contrib-text { .user-contrib-text {
font-size: 12px; font-size: 12px;
fill: #959494; fill: $calendar-user-contrib-text;
} }
.calendar-hint { .calendar-hint {
......
...@@ -25,25 +25,25 @@ ...@@ -25,25 +25,25 @@
/* Variations */ /* Variations */
.bs-callout-danger { .bs-callout-danger {
background-color: #fdf7f7; background-color: $callout-danger-bg;
border-color: #eed3d7; border-color: $callout-danger-border;
color: #b94a48; color: $callout-danger-color;
} }
.bs-callout-warning { .bs-callout-warning {
background-color: #faf8f0; background-color: $callout-warning-bg;
border-color: #faebcc; border-color: $callout-warning-border;
color: #8a6d3b; color: $callout-warning-color;
} }
.bs-callout-info { .bs-callout-info {
background-color: #f4f8fa; background-color: $callout-info-bg;
border-color: #bce8f1; border-color: $callout-info-border;
color: #34789a; color: $callout-info-color;
} }
.bs-callout-success { .bs-callout-success {
background-color: #dff0d8; background-color: $callout-success-bg;
border-color: #5ca64d; border-color: $callout-success-border;
color: #3c763d; color: $callout-success-color;
} }
/** COLORS **/ /** COLORS **/
.cgray { color: $gl-gray; } .cgray { color: $common-gray; }
.clgray { color: #bbb; } .clgray { color: $common-gray-light; }
.cred { color: $gl-text-red; } .cred { color: $common-red; }
.cgreen { color: $gl-text-green; } .cgreen { color: $common-green; }
.cdark { color: #444; } .cdark { color: $common-gray-dark; }
/** COMMON CLASSES **/ /** COMMON CLASSES **/
.prepend-top-0 { margin-top: 0; } .prepend-top-0 { margin-top: 0; }
...@@ -28,12 +28,12 @@ ...@@ -28,12 +28,12 @@
.center { text-align: center; } .center { text-align: center; }
.underlined-link { text-decoration: underline; } .underlined-link { text-decoration: underline; }
.hint { font-style: italic; color: #999; } .hint { font-style: italic; color: $hint-color; }
.light { color: $gl-gray; } .light { color: $common-gray; }
.slead { .slead {
color: $gl-gray; color: $common-gray;
font-size: 15px; font-size: 14px;
margin-bottom: 12px; margin-bottom: 12px;
font-weight: normal; font-weight: normal;
line-height: 24px; line-height: 24px;
...@@ -52,10 +52,10 @@ pre { ...@@ -52,10 +52,10 @@ pre {
} }
&.well-pre { &.well-pre {
border: 1px solid #eee; border: 1px solid $well-pre-bg;
background: $gray-light; background: $gray-light;
border-radius: 0; border-radius: 0;
color: #555; color: $well-pre-color;
} }
} }
...@@ -87,14 +87,14 @@ table a code { ...@@ -87,14 +87,14 @@ table a code {
.loading { .loading {
margin: 20px auto; margin: 20px auto;
height: 40px; height: 40px;
color: #555; color: $loading-color;
font-size: 32px; font-size: 32px;
text-align: center; text-align: center;
} }
span.update-author { span.update-author {
display: block; display: block;
color: #999; color: $update-author-color;
font-weight: normal; font-weight: normal;
font-style: italic; font-style: italic;
...@@ -105,7 +105,7 @@ span.update-author { ...@@ -105,7 +105,7 @@ span.update-author {
} }
.user-mention { .user-mention {
color: #2fa0bb; color: $user-mention-color;
font-weight: bold; font-weight: bold;
} }
...@@ -114,7 +114,7 @@ span.update-author { ...@@ -114,7 +114,7 @@ span.update-author {
} }
p.time { p.time {
color: #999; color: $time-color;
font-size: 90%; font-size: 90%;
margin: 30px 3px 3px 2px; margin: 30px 3px 3px 2px;
} }
...@@ -150,7 +150,7 @@ li.note { ...@@ -150,7 +150,7 @@ li.note {
.project_member_show { .project_member_show {
td:first-child { td:first-child {
color: #aaa; color: $project-member-show-color;
} }
} }
...@@ -176,7 +176,7 @@ li.note { ...@@ -176,7 +176,7 @@ li.note {
margin-top: 40px; margin-top: 40px;
pre { pre {
background: white; background: $white-light;
border: none; border: none;
font-size: 12px; font-size: 12px;
} }
...@@ -184,12 +184,12 @@ li.note { ...@@ -184,12 +184,12 @@ li.note {
.error-message { .error-message {
padding: 10px; padding: 10px;
background: #c67; background: $error-bg;
margin: 0; margin: 0;
color: #fff; color: $white-light;
a { a {
color: #fff; color: $white-light;
text-decoration: underline; text-decoration: underline;
} }
} }
...@@ -197,22 +197,22 @@ li.note { ...@@ -197,22 +197,22 @@ li.note {
.browser-alert { .browser-alert {
padding: 10px; padding: 10px;
text-align: center; text-align: center;
background: #c67; background: $error-bg;
color: #fff; color: $white-light;
font-weight: bold; font-weight: bold;
a { a {
color: #fff; color: $white-light;
text-decoration: underline; text-decoration: underline;
} }
} }
.warning_message { .warning_message {
border-left: 4px solid #ed9; border-left: 4px solid $warning-message-border;
color: #b90; color: $warning-message-color;
padding: 10px; padding: 10px;
margin-bottom: 10px; margin-bottom: 10px;
background: #ffffe6; background: $warning-message-bg;
padding-left: 20px; padding-left: 20px;
&.centered { &.centered {
...@@ -222,7 +222,7 @@ li.note { ...@@ -222,7 +222,7 @@ li.note {
.gitlab-promo { .gitlab-promo {
a { a {
color: #aaa; color: $gl-promo-color;
margin-right: 30px; margin-right: 30px;
} }
} }
...@@ -245,7 +245,7 @@ li.note { ...@@ -245,7 +245,7 @@ li.note {
position: relative; position: relative;
top: 2px; top: 2px;
left: 5px; left: 5px;
color: #666; color: $control-group-descr-color;
} }
} }
} }
...@@ -255,6 +255,7 @@ img.emoji { ...@@ -255,6 +255,7 @@ img.emoji {
height: 20px; height: 20px;
vertical-align: top; vertical-align: top;
width: 20px; width: 20px;
margin-top: 1px;
} }
.chart { .chart {
...@@ -270,7 +271,7 @@ img.emoji { ...@@ -270,7 +271,7 @@ img.emoji {
table { table {
td.permission-x { td.permission-x {
background: #d9edf7 !important; background: $table-permission-x-bg !important;
text-align: center; text-align: center;
} }
} }
...@@ -323,13 +324,13 @@ table { ...@@ -323,13 +324,13 @@ table {
.username { .username {
font-size: 18px; font-size: 18px;
color: #666; color: $username-color;
margin-top: 8px; margin-top: 8px;
} }
.description { .description {
font-size: $gl-font-size; font-size: $gl-font-size;
color: #666; color: $description-color;
margin-top: 8px; margin-top: 8px;
} }
} }
...@@ -339,7 +340,7 @@ table { ...@@ -339,7 +340,7 @@ table {
.profiler-button, .profiler-button,
.profiler-controls { .profiler-controls {
border-color: #eee !important; border-color: $profiler-border !important;
} }
} }
...@@ -379,7 +380,9 @@ table { ...@@ -379,7 +380,9 @@ table {
border-top: 1px solid $border-color; border-top: 1px solid $border-color;
} }
.hide-bottom-border { border-bottom: none !important; } .hide-bottom-border {
border-bottom: none !important;
}
.gl-accessibility { .gl-accessibility {
&:focus { &:focus {
...@@ -396,3 +399,13 @@ table { ...@@ -396,3 +399,13 @@ table {
z-index: 1; z-index: 1;
} }
} }
.str-truncated {
&-60 {
@include str-truncated(60%);
}
&-100 {
@include str-truncated(100%);
}
}
...@@ -36,12 +36,17 @@ ...@@ -36,12 +36,17 @@
padding: 6px 8px 6px 10px; padding: 6px 8px 6px 10px;
background-color: $dropdown-toggle-bg; background-color: $dropdown-toggle-bg;
color: $dropdown-toggle-color; color: $dropdown-toggle-color;
font-size: 15px; font-size: 14px;
text-align: left; text-align: left;
border: 1px solid $border-color; border: 1px solid $border-color;
border-radius: $border-radius-base; border-radius: $border-radius-base;
white-space: nowrap; white-space: nowrap;
&[disabled] {
background-color: $input-bg-disabled;
cursor: not-allowed;
}
&.no-outline { &.no-outline {
outline: 0; outline: 0;
} }
...@@ -123,7 +128,7 @@ ...@@ -123,7 +128,7 @@
width: 240px; width: 240px;
margin-top: 2px; margin-top: 2px;
margin-bottom: 0; margin-bottom: 0;
font-size: 15px; font-size: 14px;
font-weight: normal; font-weight: normal;
padding: 8px 0; padding: 8px 0;
background-color: $dropdown-bg; background-color: $dropdown-bg;
...@@ -376,7 +381,7 @@ ...@@ -376,7 +381,7 @@
position: absolute; position: absolute;
top: 10px; top: 10px;
right: 20px; right: 20px;
color: #c7c7c7; color: $dropdown-input-fa-color;
font-size: 12px; font-size: 12px;
pointer-events: none; pointer-events: none;
} }
...@@ -529,7 +534,7 @@ ...@@ -529,7 +534,7 @@
.ui-datepicker-calendar { .ui-datepicker-calendar {
.ui-state-hover, .ui-state-hover,
.ui-state-active { .ui-state-active {
color: #fff; color: $white-light;
border: 0; border: 0;
} }
} }
...@@ -589,7 +594,7 @@ ...@@ -589,7 +594,7 @@
.ui-datepicker-title { .ui-datepicker-title {
color: $gl-gray; color: $gl-gray;
font-size: 15px; font-size: 14px;
line-height: 1; line-height: 1;
font-weight: normal; font-weight: normal;
} }
......
...@@ -59,10 +59,10 @@ ...@@ -59,10 +59,10 @@
} }
.file-content { .file-content {
background: #fff; background: $white-light;
&.image_file { &.image_file {
background: #eee; background: $file-image-bg;
text-align: center; text-align: center;
img { img {
...@@ -84,8 +84,8 @@ ...@@ -84,8 +84,8 @@
} }
&.blob-no-preview { &.blob-no-preview {
background: #eee; background: $blob-bg;
text-shadow: 0 1px 2px #fff; text-shadow: 0 1px 2px $white-light;
padding: 100px 0; padding: 100px 0;
} }
...@@ -99,7 +99,7 @@ ...@@ -99,7 +99,7 @@
} }
tr { tr {
border-bottom: 1px solid #eee; border-bottom: 1px solid $blame-border;
} }
td { td {
...@@ -120,7 +120,7 @@ ...@@ -120,7 +120,7 @@
td.line-numbers { td.line-numbers {
float: none; float: none;
border-left: 1px solid #ddd; border-left: 1px solid $blame-line-numbers-border;
i { i {
float: none; float: none;
...@@ -134,7 +134,7 @@ ...@@ -134,7 +134,7 @@
} }
&.logs { &.logs {
background: #eee; background: $logs-bg;
max-height: 700px; max-height: 700px;
overflow-y: auto; overflow-y: auto;
...@@ -143,14 +143,14 @@ ...@@ -143,14 +143,14 @@
padding: 10px 0; padding: 10px 0;
border-left: 1px solid $border-color; border-left: 1px solid $border-color;
margin-bottom: 0; margin-bottom: 0;
background: white; background: $white-light;
li { li {
color: #888; color: $logs-li-color;
p { p {
margin: 0; margin: 0;
color: #333; color: $logs-p-color;
line-height: 24px; line-height: 24px;
padding-left: 10px; padding-left: 10px;
} }
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
} }
} }
@media (max-width: $screen-md-min) { @media (max-width: $screen-sm-max) {
ul.notes { ul.notes {
.flash-container.timeline-content { .flash-container.timeline-content {
margin-left: 0; margin-left: 0;
......
// Disabling "SpaceAfterPropertyColon" linter because the linter doesn't like
// the way the `src` property is formatted in this file.
// scss-lint:disable SpaceAfterPropertyColon
/* latin-ext */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 300;
src:
local('Source Sans Pro Light'),
local('SourceSansPro-Light'),
font-url('SourceSansPro-Light.ttf.woff2') format('woff2'),
font-url('SourceSansPro-Light.ttf.woff') format('woff');
}
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src:
local('Source Sans Pro'),
local('SourceSansPro-Regular'),
font-url('SourceSansPro-Regular.ttf.woff2') format('woff2'),
font-url('SourceSansPro-Regular.ttf.woff') format('woff');
}
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 600;
src:
local('Source Sans Pro Semibold'),
local('SourceSansPro-Semibold'),
font-url('SourceSansPro-Semibold.ttf.woff2') format('woff2'),
font-url('SourceSansPro-Semibold.ttf.woff') format('woff');
}
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
src:
local('Source Sans Pro Bold'),
local('SourceSansPro-Bold'),
font-url('SourceSansPro-Bold.ttf.woff2') format('woff2'),
font-url('SourceSansPro-Bold.ttf.woff') format('woff');
}
...@@ -7,9 +7,9 @@ input { ...@@ -7,9 +7,9 @@ input {
} }
input[type='text'].danger { input[type='text'].danger {
background: #f2dede!important; background: $input-danger-bg !important;
border-color: #d66; border-color: $input-danger-border;
text-shadow: 0 1px 1px #fff; text-shadow: 0 1px 1px $white-light;
} }
.datetime-controls { .datetime-controls {
...@@ -98,7 +98,7 @@ label { ...@@ -98,7 +98,7 @@ label {
} }
} }
@media(max-width: $screen-sm-min) { @media(max-width: $screen-xs-max) {
padding: 0 $gl-padding; padding: 0 $gl-padding;
.control-label, .control-label,
...@@ -159,7 +159,7 @@ label { ...@@ -159,7 +159,7 @@ label {
} }
.input-group-addon { .input-group-addon {
background-color: #f7f8fa; background-color: $input-group-addon-bg;
} }
.input-group-addon:not(:first-child):not(:last-child) { .input-group-addon:not(:first-child):not(:last-child) {
...@@ -181,7 +181,7 @@ label { ...@@ -181,7 +181,7 @@ label {
border: 1px solid $green-normal; border: 1px solid $green-normal;
&:focus { &:focus {
box-shadow: 0 0 0 1px $green-normal inset, 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 4px 0 $green-normal; box-shadow: 0 0 0 1px $green-normal inset, 0 1px 1px $gl-field-focus-shadow inset, 0 0 4px 0 $green-normal;
border: 0 none; border: 0 none;
} }
} }
...@@ -190,7 +190,7 @@ label { ...@@ -190,7 +190,7 @@ label {
border: 1px solid $red-normal; border: 1px solid $red-normal;
&:focus { &:focus {
box-shadow: 0 0 0 1px $red-normal inset, 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 4px 0 rgba(210, 40, 82, 0.6); box-shadow: 0 0 0 1px $red-normal inset, 0 1px 1px $gl-field-focus-shadow inset, 0 0 4px 0 $gl-field-focus-shadow-error;
border: 0 none; border: 0 none;
} }
} }
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
background: $color-darker; background: $color-darker;
} }
.sidebar-header,
.sidebar-action-buttons { .sidebar-action-buttons {
color: $color-light; color: $color-light;
background-color: lighten($color-darker, 5%); background-color: lighten($color-darker, 5%);
...@@ -86,37 +85,57 @@ ...@@ -86,37 +85,57 @@
} }
$theme-charcoal: #3d454d; $theme-charcoal: #3d454d;
$theme-charcoal-light: #485157;
$theme-charcoal-dark: #383f45; $theme-charcoal-dark: #383f45;
$theme-charcoal-text: #b9bbbe; $theme-charcoal-text: #b9bbbe;
$theme-blue-light: #becde9;
$theme-blue: #2980b9; $theme-blue: #2980b9;
$theme-blue-dark: #1970a9;
$theme-blue-darker: #096099;
$theme-graphite-lighter: #ccc;
$theme-graphite-light: #777;
$theme-graphite: #666; $theme-graphite: #666;
$theme-graphite-dark: #555;
$theme-gray-light: #979797;
$theme-gray: #373737; $theme-gray: #373737;
$theme-gray-dark: #272727;
$theme-gray-darker: #222;
$theme-green-light: #adc;
$theme-green: #019875; $theme-green: #019875;
$theme-green-dark: #018865;
$theme-green-darker: #017855;
$theme-violet-light: #98c;
$theme-violet: #548; $theme-violet: #548;
$theme-violet-dark: #436;
$theme-violet-darker: #325;
body { body {
&.ui_blue { &.ui_blue {
@include gitlab-theme(#becde9, $theme-blue, #1970a9, #096099); @include gitlab-theme($theme-blue-light, $theme-blue, $theme-blue-dark, $theme-blue-darker);
} }
&.ui_charcoal { &.ui_charcoal {
@include gitlab-theme($theme-charcoal-text, #485157, $theme-charcoal, $theme-charcoal-dark); @include gitlab-theme($theme-charcoal-text, $theme-charcoal-light, $theme-charcoal, $theme-charcoal-dark);
} }
&.ui_graphite { &.ui_graphite {
@include gitlab-theme(#ccc, #777, $theme-graphite, #555); @include gitlab-theme($theme-graphite-lighter, $theme-graphite-light, $theme-graphite, $theme-graphite-dark);
} }
&.ui_gray { &.ui_gray {
@include gitlab-theme(#979797, $theme-gray, #272727, #222); @include gitlab-theme($theme-gray-light, $theme-gray, $theme-gray-dark, $theme-gray-darker);
} }
&.ui_green { &.ui_green {
@include gitlab-theme(#adc, $theme-green, #018865, #017855); @include gitlab-theme($theme-green-light, $theme-green, $theme-green-dark, $theme-green-darker);
} }
&.ui_violet { &.ui_violet {
@include gitlab-theme(#98c, $theme-violet, #436, #325); @include gitlab-theme($theme-violet-light, $theme-violet, $theme-violet-dark, $theme-violet-darker);
} }
} }
...@@ -8,7 +8,7 @@ header { ...@@ -8,7 +8,7 @@ header {
&.navbar-empty { &.navbar-empty {
height: $header-height; height: $header-height;
background: #fff; background: $white-light;
border-bottom: 1px solid $btn-gray-hover; border-bottom: 1px solid $btn-gray-hover;
.center-logo { .center-logo {
...@@ -71,12 +71,12 @@ header { ...@@ -71,12 +71,12 @@ header {
} }
.fa-caret-down { .fa-caret-down {
font-size: 15px; font-size: 14px;
} }
} }
.navbar-toggle { .navbar-toggle {
color: #666; color: $nav-toggle-gray;
margin: 6px 0; margin: 6px 0;
border-radius: 0; border-radius: 0;
position: absolute; position: absolute;
...@@ -156,7 +156,7 @@ header { ...@@ -156,7 +156,7 @@ header {
position: relative; position: relative;
padding-right: 20px; padding-right: 20px;
margin: 0; margin: 0;
font-size: 19px; font-size: 18px;
max-width: 385px; max-width: 385px;
display: inline-block; display: inline-block;
line-height: $header-height; line-height: $header-height;
...@@ -228,7 +228,7 @@ header { ...@@ -228,7 +228,7 @@ header {
} }
.page-sidebar-pinned.right-sidebar-expanded { .page-sidebar-pinned.right-sidebar-expanded {
@media (max-width: $screen-lg-min) { @media (max-width: $screen-md-max) {
.header-content .title { .header-content .title {
width: 300px; width: 300px;
} }
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
display: block; display: block;
float: left; float: left;
margin-right: 10px; margin-right: 10px;
color: #fff; color: $white-light;
font-size: $gl-font-size; font-size: $gl-font-size;
line-height: 25px; line-height: 25px;
...@@ -37,10 +37,10 @@ ...@@ -37,10 +37,10 @@
} }
&.status-box-expired { &.status-box-expired {
background: #cea61b; background-color: $issue-status-expired;
} }
&.status-box-upcoming { &.status-box-upcoming {
background: #8f8f8f; background: $issue-box-upcoming-bg;
} }
} }
...@@ -4,13 +4,13 @@ ...@@ -4,13 +4,13 @@
&.ui-datepicker, &.ui-datepicker,
&.ui-datepicker-inline { &.ui-datepicker-inline {
border: 1px solid #ddd; border: 1px solid $jq-ui-border;
padding: 10px; padding: 10px;
width: 270px; width: 270px;
.ui-datepicker-header { .ui-datepicker-header {
background: #fff; background: $white-light;
border-color: #ddd; border-color: $jq-ui-border;
.ui-datepicker-prev, .ui-datepicker-prev,
.ui-datepicker-next { .ui-datepicker-next {
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
} }
&.ui-autocomplete { &.ui-autocomplete {
border-color: #ddd; border-color: $jq-ui-border;
padding: 0; padding: 0;
margin-top: 2px; margin-top: 2px;
z-index: 1001; z-index: 1001;
...@@ -50,9 +50,9 @@ ...@@ -50,9 +50,9 @@
} }
.ui-state-default { .ui-state-default {
border: 1px solid #fff; border: 1px solid $white-light;
background: #fff; background: $white-light;
color: #777; color: $jq-ui-default-color;
} }
.ui-state-highlight { .ui-state-highlight {
...@@ -66,7 +66,7 @@ ...@@ -66,7 +66,7 @@
.ui-state-focus { .ui-state-focus {
border: 1px solid $gl-primary; border: 1px solid $gl-primary;
background: $gl-primary; background: $gl-primary;
color: #fff; color: $white-light;
} }
} }
} }
......
...@@ -6,7 +6,7 @@ html { ...@@ -6,7 +6,7 @@ html {
body { body {
&.navless { &.navless {
background-color: white !important; background-color: $white-light !important;
} }
} }
......
...@@ -11,8 +11,8 @@ ...@@ -11,8 +11,8 @@
> li { > li {
padding: 10px 15px; padding: 10px 15px;
min-height: 20px; min-height: 20px;
border-bottom: 1px solid #eee; border-bottom: 1px solid $list-border-light;
border-bottom: 1px solid rgba(0, 0, 0, 0.05); border-bottom: 1px solid $list-border;
&::after { &::after {
content: " "; content: " ";
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
} }
&.disabled { &.disabled {
color: #888; color: $list-text-disabled-color;
} }
&.unstyled { &.unstyled {
...@@ -31,9 +31,9 @@ ...@@ -31,9 +31,9 @@
} }
&.warning-row { &.warning-row {
background-color: #fcf8e3; background-color: $list-warning-row-bg;
border-color: #faebcc; border-color: $list-warning-row-border;
color: #8a6d3b; color: $list-warning-row-color;
} }
&.smoke { background-color: $background-color; } &.smoke { background-color: $background-color; }
...@@ -106,13 +106,13 @@ ul.task-list { ...@@ -106,13 +106,13 @@ ul.task-list {
} }
} }
// Generic content list
ul.content-list { ul.content-list {
@include basic-list; @include basic-list;
margin: 0; margin: 0;
padding: 0; padding: 0;
> li { li {
border-color: $table-border-color; border-color: $table-border-color;
font-size: $list-font-size; font-size: $list-font-size;
color: $list-text-color; color: $list-text-color;
...@@ -193,6 +193,41 @@ ul.content-list { ...@@ -193,6 +193,41 @@ ul.content-list {
} }
} }
// Content list using flexbox
.flex-list {
.flex-row {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
white-space: nowrap;
}
.row-main-content {
flex: 1 1 auto;
overflow: hidden;
padding-right: 8px;
}
.row-title {
font-weight: 600;
}
.row-second-line {
display: block;
}
.dropdown {
.btn-block {
margin-bottom: 0;
line-height: inherit;
}
}
.label-default {
color: $btn-transparent-color;
}
}
.panel > .content-list > li { .panel > .content-list > li {
padding: $gl-padding-top $gl-padding; padding: $gl-padding-top $gl-padding;
......
...@@ -56,16 +56,9 @@ ...@@ -56,16 +56,9 @@
.md-header { .md-header {
.nav-links { .nav-links {
.active {
a {
border-bottom-color: #000;
}
}
a { a {
padding-top: 0; padding-top: 0;
line-height: 19px; line-height: 19px;
border-bottom: 1px solid $border-color;
&.btn.btn-xs { &.btn.btn-xs {
padding: 2px 5px; padding: 2px 5px;
...@@ -80,7 +73,7 @@ ...@@ -80,7 +73,7 @@
} }
.referenced-users { .referenced-users {
color: #4c4e54; color: $gl-header-color;
padding-top: 10px; padding-top: 10px;
} }
...@@ -92,8 +85,8 @@ ...@@ -92,8 +85,8 @@
.markdown-area { .markdown-area {
border-radius: 0; border-radius: 0;
background: #fff; background: $white-light;
border: 1px solid #ddd; border: 1px solid $md-area-border;
min-height: 140px; min-height: 140px;
max-height: 500px; max-height: 500px;
padding: 5px; padding: 5px;
...@@ -115,7 +108,7 @@ ...@@ -115,7 +108,7 @@
hr { hr {
// Darken 'whitesmoke' a bit to make it more visible in note bodies // Darken 'whitesmoke' a bit to make it more visible in note bodies
border-color: darken(#f5f5f5, 8%); border-color: darken($gray-normal, 8%);
margin: 10px 0; margin: 10px 0;
} }
...@@ -142,7 +135,7 @@ ...@@ -142,7 +135,7 @@
.toolbar-btn { .toolbar-btn {
float: left; float: left;
padding: 0 5px; padding: 0 5px;
color: #959494; color: $note-toolbar-color;
background: transparent; background: transparent;
border: 0; border: 0;
outline: 0; outline: 0;
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
@include clearfix; @include clearfix;
padding: 10px 0; padding: 10px 0;
border-bottom: 1px solid #eee; border-bottom: 1px solid $list-border-light;
display: block; display: block;
margin: 0; margin: 0;
...@@ -67,8 +67,8 @@ ...@@ -67,8 +67,8 @@
} }
@mixin dark-diff-match-line { @mixin dark-diff-match-line {
color: rgba(255, 255, 255, 0.3); color: $dark-diff-match-bg;
background: rgba(255, 255, 255, 0.1); background: $dark-diff-match-color;
} }
@mixin webkit-prefix($property, $value) { @mixin webkit-prefix($property, $value) {
......
...@@ -133,9 +133,9 @@ ...@@ -133,9 +133,9 @@
right: 0; right: 0;
top: 30%; top: 30%;
padding: 5px 15px; padding: 5px 15px;
background: #eee; background: $show-aside-bg;
font-size: 20px; font-size: 20px;
color: #777; color: $show-aside-color;
z-index: 100; z-index: 100;
box-shadow: 0 1px 2px #ddd; box-shadow: 0 1px 2px $show-aside-shadow;
} }
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
padding: $gl-btn-padding; padding: $gl-btn-padding;
padding-bottom: 11px; padding-bottom: 11px;
margin-bottom: -1px; margin-bottom: -1px;
font-size: 15px; font-size: 14px;
line-height: 28px; line-height: 28px;
color: $note-toolbar-color; color: $note-toolbar-color;
border-bottom: 2px solid transparent; border-bottom: 2px solid transparent;
...@@ -71,11 +71,15 @@ ...@@ -71,11 +71,15 @@
border-bottom: 2px solid $link-underline-blue; border-bottom: 2px solid $link-underline-blue;
color: $black; color: $black;
font-weight: 600; font-weight: 600;
.badge {
color: $black;
}
} }
.badge { .badge {
font-weight: normal; font-weight: normal;
background-color: #eee; background-color: $nav-badge-bg;
color: $btn-transparent-color; color: $btn-transparent-color;
vertical-align: baseline; vertical-align: baseline;
} }
...@@ -123,7 +127,7 @@ ...@@ -123,7 +127,7 @@
line-height: 28px; line-height: 28px;
/* Small devices (phones, tablets, 768px and lower) */ /* Small devices (phones, tablets, 768px and lower) */
@media (max-width: $screen-sm-min) { @media (max-width: $screen-xs-max) {
width: 100%; width: 100%;
} }
} }
...@@ -268,6 +272,16 @@ ...@@ -268,6 +272,16 @@
width: auto; width: auto;
} }
} }
&.multi-line {
.nav-text {
line-height: 20px;
}
.nav-controls {
padding: 17px 0;
}
}
} }
.layout-nav { .layout-nav {
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
/** /**
* Small screen pagination * Small screen pagination
*/ */
@media (max-width: $screen-xs) { @media (max-width: $screen-xs-min) {
.gl-pagination { .gl-pagination {
.pagination li a { .pagination li a {
padding: 6px 10px; padding: 6px 10px;
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
/** /**
* Medium screen pagination * Medium screen pagination
*/ */
@media (min-width: $screen-xs) and (max-width: $screen-md-max) { @media (min-width: $screen-xs-min) and (max-width: $screen-md-max) {
.gl-pagination { .gl-pagination {
.page { .page {
display: none; display: none;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
.select2-container, .select2-container,
.select2-container.select2-drop-above { .select2-container.select2-drop-above {
.select2-choice { .select2-choice {
background: #fff; background: $white-light;
border-color: $input-border; border-color: $input-border;
height: 35px; height: 35px;
padding: $gl-vert-padding $gl-input-padding; padding: $gl-vert-padding $gl-input-padding;
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
} }
.select2-drop { .select2-drop {
box-shadow: rgba(76, 86, 103, 0.247059) 0 0 1px 0, rgba(31, 37, 50, 0.317647) 0 2px 18px 0; box-shadow: $select2-drop-shadow1 0 0 1px 0, $select2-drop-shadow2 0 2px 18px 0;
border-radius: $border-radius-default; border-radius: $border-radius-default;
border: none; border: none;
min-width: 175px; min-width: 175px;
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
} }
.select2-drop { .select2-drop {
color: #7f8fa4; color: $gl-grayish-blue;
} }
.select2-highlighted { .select2-highlighted {
...@@ -156,7 +156,7 @@ ...@@ -156,7 +156,7 @@
.select2-search input { .select2-search input {
padding: 2px 25px 2px 5px; padding: 2px 25px 2px 5px;
background: #fff image-url('select2.png'); background: $white-light image-url('select2.png');
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: right 0 bottom 6px; background-position: right 0 bottom 6px;
border: 1px solid $input-border; border: 1px solid $input-border;
...@@ -169,7 +169,7 @@ ...@@ -169,7 +169,7 @@
} }
.select2-search input.select2-active { .select2-search input.select2-active {
background-color: #fff; background-color: $white-light;
background-image: image-url('select2-spinner.gif') !important; background-image: image-url('select2-spinner.gif') !important;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: right 5px center !important; background-position: right 5px center !important;
...@@ -206,7 +206,7 @@ ...@@ -206,7 +206,7 @@
.select2-highlighted { .select2-highlighted {
.group-result { .group-result {
.group-path { .group-path {
color: #fff; color: $white-light;
} }
} }
} }
...@@ -221,7 +221,7 @@ ...@@ -221,7 +221,7 @@
} }
.group-path { .group-path {
color: #999; color: $group-path-color;
} }
} }
...@@ -241,7 +241,7 @@ ...@@ -241,7 +241,7 @@
.namespace-result { .namespace-result {
.namespace-kind { .namespace-kind {
color: #aaa; color: $namespace-kind-color;
font-weight: normal; font-weight: normal;
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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