Commit f1350a5c authored by Phil Hughes's avatar Phil Hughes

Merge branch 'master' into issue-board-sidebar

parents e4176f4e f64e36c4
CHANGELOG merge=union CHANGELOG.md merge=union
*.js.es6 gitlab-language=javascript *.js.es6 gitlab-language=javascript
...@@ -22,7 +22,7 @@ before_script: ...@@ -22,7 +22,7 @@ before_script:
- bundle --version - bundle --version
- '[ "$USE_BUNDLE_INSTALL" != "true" ] || retry bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}"' - '[ "$USE_BUNDLE_INSTALL" != "true" ] || retry bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}"'
- retry gem install knapsack - retry gem install knapsack
- '[ "$SETUP_DB" != "true" ] || bundle exec rake db:drop db:create db:schema:load db:migrate' - '[ "$SETUP_DB" != "true" ] || bundle exec rake db:drop db:create db:schema:load db:migrate add_limits_mysql'
stages: stages:
- prepare - prepare
...@@ -99,7 +99,7 @@ update-knapsack: ...@@ -99,7 +99,7 @@ update-knapsack:
- export KNAPSACK_REPORT_PATH=knapsack/spinach_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json - export KNAPSACK_REPORT_PATH=knapsack/spinach_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
- export KNAPSACK_GENERATE_REPORT=true - export KNAPSACK_GENERATE_REPORT=true
- cp knapsack/spinach_report.json ${KNAPSACK_REPORT_PATH} - cp knapsack/spinach_report.json ${KNAPSACK_REPORT_PATH}
- knapsack spinach "-r rerun" || retry '[ ! -e tmp/spinach-rerun.txt ] || bundle exec spinach -r rerun $(cat tmp/spinach-rerun.txt)' - knapsack spinach "-r rerun" || retry '[[ -e tmp/spinach-rerun.txt ]] && bundle exec spinach -r rerun $(cat tmp/spinach-rerun.txt)'
artifacts: artifacts:
expire_in: 31d expire_in: 31d
paths: paths:
...@@ -210,6 +210,13 @@ rake brakeman: *exec ...@@ -210,6 +210,13 @@ rake brakeman: *exec
rake flay: *exec rake flay: *exec
license_finder: *exec license_finder: *exec
rake downtime_check: *exec rake downtime_check: *exec
rake ce_to_ee_merge_check:
<<: *exec
only:
- branches
except:
- tags
allow_failure: yes
rake db:migrate:reset: rake db:migrate:reset:
stage: test stage: test
...@@ -255,6 +262,12 @@ lint-doc: ...@@ -255,6 +262,12 @@ lint-doc:
script: script:
- scripts/lint-doc.sh - scripts/lint-doc.sh
bundler:check:
stage: test
<<: *ruby-static-analysis
script:
- bundle check
bundler:audit: bundler:audit:
stage: test stage: test
<<: *ruby-static-analysis <<: *ruby-static-analysis
...@@ -293,6 +306,17 @@ coverage: ...@@ -293,6 +306,17 @@ coverage:
- coverage/index.html - coverage/index.html
- coverage/assets/ - coverage/assets/
# Trigger docs build
trigger_docs:
stage: post-test
before_script: []
cache: {}
artifacts: {}
script:
- "curl -X POST -F token=${DOCS_TRIGGER_TOKEN} -F ref=master https://gitlab.com/api/v3/projects/38069/trigger/builds"
only:
- master
# Notify slack in the end # Notify slack in the end
notify:slack: notify:slack:
...@@ -325,3 +349,16 @@ pages: ...@@ -325,3 +349,16 @@ pages:
- public - public
only: only:
- master - master
# Insurance in case a gem needed by one of our releases gets yanked from
# rubygems.org in the future.
cache gems:
only:
- tags
variables:
SETUP_DB: "false"
script:
- bundle package --all --all-platforms
artifacts:
paths:
- vendor/cache
See the general Documentation guidelines http://docs.gitlab.com/ce/development/doc_styleguide.html. See the general Documentation guidelines http://docs.gitlab.com/ce/development/doc_styleguide.html
## What does this MR do? ## What does this MR do?
......
...@@ -61,7 +61,7 @@ linters: ...@@ -61,7 +61,7 @@ linters:
# Separate rule, function, and mixin declarations with empty lines. # Separate rule, function, and mixin declarations with empty lines.
EmptyLineBetweenBlocks: EmptyLineBetweenBlocks:
enabled: false enabled: true
# Reports when you have an empty rule set. # Reports when you have an empty rule set.
EmptyRule: EmptyRule:
...@@ -219,7 +219,7 @@ linters: ...@@ -219,7 +219,7 @@ linters:
# Property values, @extend, @include, and @import directives, and variable # Property values, @extend, @include, and @import directives, and variable
# declarations should always end with a semicolon. # declarations should always end with a semicolon.
TrailingSemicolon: TrailingSemicolon:
enabled: false enabled: true
# Reports lines containing trailing whitespace. # Reports lines containing trailing whitespace.
TrailingWhitespace: TrailingWhitespace:
......
This diff is collapsed.
...@@ -226,8 +226,7 @@ a feedback issue (if there isn't one already) and leave a comment asking for it ...@@ -226,8 +226,7 @@ a feedback issue (if there isn't one already) and leave a comment asking for it
to be marked as `Accepting merge requests`. Please include screenshots or to be marked as `Accepting merge requests`. Please include screenshots or
wireframes if the feature will also change the UI. wireframes if the feature will also change the UI.
Merge requests can be filed either at [GitLab.com][gitlab-mr-tracker] or at Merge requests should be opened at [GitLab.com][gitlab-mr-tracker].
[github.com][github-mr-tracker].
If you are new to GitLab development (or web development in general), see the If you are new to GitLab development (or web development in general), see the
[I want to contribute!](#i-want-to-contribute) section to get you started with [I want to contribute!](#i-want-to-contribute) section to get you started with
...@@ -246,10 +245,17 @@ tests are least likely to receive timely feedback. The workflow to make a merge ...@@ -246,10 +245,17 @@ tests are least likely to receive timely feedback. The workflow to make a merge
request is as follows: request is as follows:
1. Fork the project into your personal space on GitLab.com 1. Fork the project into your personal space on GitLab.com
1. Create a feature branch, branch away from `master`. 1. Create a feature branch, branch away from `master`
1. Write [tests](https://gitlab.com/gitlab-org/gitlab-development-kit#running-the-tests) and code 1. Write [tests](https://gitlab.com/gitlab-org/gitlab-development-kit#running-the-tests) and code
1. Add your changes to the [CHANGELOG](CHANGELOG) 1. Add your changes to the [CHANGELOG.md](CHANGELOG.md):
1. If you are writing documentation, make sure to read the [documentation styleguide][doc-styleguide] 1. If you are fixing a ~regression issue, you can add your entry to the next
patch release (e.g. `8.12.5` if current version is `8.12.4`)
1. Otherwise, add your entry to the next minor release (e.g. `8.13.0` if
current version is `8.12.4`
1. Please add your entry at a random place among the entries of the targeted
release
1. If you are writing documentation, make sure to follow the
[documentation styleguide][doc-styleguide]
1. If you have multiple commits please combine them into one commit by 1. If you have multiple commits please combine them into one commit by
[squashing them][git-squash] [squashing them][git-squash]
1. Push the commit(s) to your fork 1. Push the commit(s) to your fork
...@@ -258,7 +264,7 @@ request is as follows: ...@@ -258,7 +264,7 @@ request is as follows:
1. The MR description should give a motive for your change and the method you 1. The MR description should give a motive for your change and the method you
used to achieve it, see the [merge request description format] used to achieve it, see the [merge request description format]
(#merge-request-description-format) (#merge-request-description-format)
1. If the MR changes the UI it should include before and after screenshots 1. If the MR changes the UI it should include *Before* and *After* screenshots
1. If the MR changes CSS classes please include the list of affected pages, 1. If the MR changes CSS classes please include the list of affected pages,
`grep css-class ./app -R` `grep css-class ./app -R`
1. Link any relevant [issues][ce-tracker] in the merge request description and 1. Link any relevant [issues][ce-tracker] in the merge request description and
...@@ -270,7 +276,9 @@ request is as follows: ...@@ -270,7 +276,9 @@ request is as follows:
[shell command guidelines](doc/development/shell_commands.md) [shell command guidelines](doc/development/shell_commands.md)
1. If your code creates new files on disk please read the 1. If your code creates new files on disk please read the
[shared files guidelines](doc/development/shared_files.md). [shared files guidelines](doc/development/shared_files.md).
1. When writing commit messages please follow [these](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) [guidelines](http://chris.beams.io/posts/git-commit/). 1. When writing commit messages please follow
[these](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
[guidelines](http://chris.beams.io/posts/git-commit/).
1. If your merge request adds one or more migrations, make sure to execute all 1. If your merge request adds one or more migrations, make sure to execute all
migrations on a fresh database before the MR is reviewed. If the review leads migrations on a fresh database before the MR is reviewed. If the review leads
to large changes in the MR, do this again once the review is complete. to large changes in the MR, do this again once the review is complete.
...@@ -305,23 +313,6 @@ Please ensure that your merge request meets the contribution acceptance criteria ...@@ -305,23 +313,6 @@ Please ensure that your merge request meets the contribution acceptance criteria
When having your code reviewed and when reviewing merge requests please take the When having your code reviewed and when reviewing merge requests please take the
[code review guidelines](doc/development/code_review.md) into account. [code review guidelines](doc/development/code_review.md) into account.
### Merge request description format
Please submit merge requests using the following template in the merge request
description area. Copy-paste it to retain the markdown format.
```
## What does this MR do?
## Are there points in the code the reviewer needs to double check?
## Why was this MR needed?
## What are the relevant issue numbers?
## Screenshots (if relevant)
```
### Contribution acceptance criteria ### Contribution acceptance criteria
1. The change is as small as possible 1. The change is as small as possible
...@@ -333,8 +324,8 @@ description area. Copy-paste it to retain the markdown format. ...@@ -333,8 +324,8 @@ description area. Copy-paste it to retain the markdown format.
aforementioned failing test aforementioned failing test
1. Your MR initially contains a single commit (please use `git rebase -i` to 1. Your MR initially contains a single commit (please use `git rebase -i` to
squash commits) squash commits)
1. Your changes can merge without problems (if not please merge `master`, never 1. Your changes can merge without problems (if not please rebase if you're the
rebase commits pushed to the remote server) only one working on your feature branch, otherwise, merge `master`)
1. Does not break any existing functionality 1. Does not break any existing functionality
1. Fixes one specific issue or implements one specific feature (do not combine 1. Fixes one specific issue or implements one specific feature (do not combine
things, send separate merge requests if needed) things, send separate merge requests if needed)
...@@ -352,7 +343,10 @@ description area. Copy-paste it to retain the markdown format. ...@@ -352,7 +343,10 @@ description area. Copy-paste it to retain the markdown format.
entire line to follow it. This prevents linting tools from generating warnings. entire line to follow it. This prevents linting tools from generating warnings.
- Don't touch neighbouring lines. As an exception, automatic mass - Don't touch neighbouring lines. As an exception, automatic mass
refactoring modifications may leave style non-compliant. refactoring modifications may leave style non-compliant.
1. If the merge request adds any new libraries (gems, JavaScript libraries, etc.), they should conform to our [Licensing guidelines][license-finder-doc]. See the instructions in that document for help if your MR fails the "license-finder" test with a "Dependencies that need approval" error. 1. If the merge request adds any new libraries (gems, JavaScript libraries,
etc.), they should conform to our [Licensing guidelines][license-finder-doc].
See the instructions in that document for help if your MR fails the
"license-finder" test with a "Dependencies that need approval" error.
## Changes for Stable Releases ## Changes for Stable Releases
...@@ -468,7 +462,6 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor ...@@ -468,7 +462,6 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[accepting-mrs-ce]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=Accepting+Merge+Requests [accepting-mrs-ce]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=Accepting+Merge+Requests
[accepting-mrs-ee]: https://gitlab.com/gitlab-org/gitlab-ee/issues?label_name=Accepting+Merge+Requests [accepting-mrs-ee]: https://gitlab.com/gitlab-org/gitlab-ee/issues?label_name=Accepting+Merge+Requests
[gitlab-mr-tracker]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests [gitlab-mr-tracker]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests
[github-mr-tracker]: https://github.com/gitlabhq/gitlabhq/pulls
[gdk]: https://gitlab.com/gitlab-org/gitlab-development-kit [gdk]: https://gitlab.com/gitlab-org/gitlab-development-kit
[git-squash]: https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits [git-squash]: https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits
[closed-merge-requests]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests?assignee_id=&label_name=&milestone_id=&scope=&sort=&state=closed [closed-merge-requests]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests?assignee_id=&label_name=&milestone_id=&scope=&sort=&state=closed
......
...@@ -51,7 +51,7 @@ gem 'browser', '~> 2.2' ...@@ -51,7 +51,7 @@ gem 'browser', '~> 2.2'
# Extracting information from a git repository # Extracting information from a git repository
# Provide access to Gitlab::Git library # Provide access to Gitlab::Git library
gem 'gitlab_git', '~> 10.6.7' gem 'gitlab_git', '~> 10.6.8'
# LDAP Auth # LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes # GitLab fork with several improvements to original library. For full list of changes
...@@ -101,7 +101,7 @@ gem 'seed-fu', '~> 2.3.5' ...@@ -101,7 +101,7 @@ gem 'seed-fu', '~> 2.3.5'
# Markdown and HTML processing # Markdown and HTML processing
gem 'html-pipeline', '~> 1.11.0' gem 'html-pipeline', '~> 1.11.0'
gem 'deckar01-task_list', '1.0.5', require: 'task_list/railtie' gem 'deckar01-task_list', '1.0.5', require: 'task_list/railtie'
gem 'github-markup', '~> 1.4' gem 'gitlab-markup', '~> 1.5.0'
gem 'redcarpet', '~> 3.3.3' gem 'redcarpet', '~> 3.3.3'
gem 'RedCloth', '~> 4.3.2' gem 'RedCloth', '~> 4.3.2'
gem 'rdoc', '~>3.6' gem 'rdoc', '~>3.6'
...@@ -110,6 +110,7 @@ gem 'creole', '~> 0.5.0' ...@@ -110,6 +110,7 @@ gem 'creole', '~> 0.5.0'
gem 'wikicloth', '0.8.1' gem 'wikicloth', '0.8.1'
gem 'asciidoctor', '~> 1.5.2' gem 'asciidoctor', '~> 1.5.2'
gem 'rouge', '~> 2.0' gem 'rouge', '~> 2.0'
gem 'truncato', '~> 0.7.8'
# See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s # See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s
# and https://groups.google.com/forum/#!topic/ruby-security-ann/Dy7YiKb_pMM # and https://groups.google.com/forum/#!topic/ruby-security-ann/Dy7YiKb_pMM
...@@ -224,7 +225,7 @@ gem 'gon', '~> 6.1.0' ...@@ -224,7 +225,7 @@ gem 'gon', '~> 6.1.0'
gem 'jquery-atwho-rails', '~> 1.3.2' gem 'jquery-atwho-rails', '~> 1.3.2'
gem 'jquery-rails', '~> 4.1.0' gem 'jquery-rails', '~> 4.1.0'
gem 'jquery-ui-rails', '~> 5.0.0' gem 'jquery-ui-rails', '~> 5.0.0'
gem 'request_store', '~> 1.3.0' gem 'request_store', '~> 1.3'
gem 'select2-rails', '~> 3.5.9' gem 'select2-rails', '~> 3.5.9'
gem 'virtus', '~> 1.0.1' gem 'virtus', '~> 1.0.1'
gem 'net-ssh', '~> 3.0.1' gem 'net-ssh', '~> 3.0.1'
...@@ -307,6 +308,8 @@ group :development, :test do ...@@ -307,6 +308,8 @@ group :development, :test do
gem 'license_finder', '~> 2.1.0', require: false gem 'license_finder', '~> 2.1.0', require: false
gem 'knapsack', '~> 1.11.0' gem 'knapsack', '~> 1.11.0'
gem 'activerecord_sane_schema_dumper', '0.2'
end end
group :test do group :test do
...@@ -323,7 +326,7 @@ gem 'newrelic_rpm', '~> 3.16' ...@@ -323,7 +326,7 @@ gem 'newrelic_rpm', '~> 3.16'
gem 'octokit', '~> 4.3.0' gem 'octokit', '~> 4.3.0'
gem 'mail_room', '~> 0.8' gem 'mail_room', '~> 0.8.1'
gem 'email_reply_parser', '~> 0.5.8' gem 'email_reply_parser', '~> 0.5.8'
...@@ -340,7 +343,7 @@ gem 'oauth2', '~> 1.2.0' ...@@ -340,7 +343,7 @@ gem 'oauth2', '~> 1.2.0'
gem 'paranoia', '~> 2.0' gem 'paranoia', '~> 2.0'
# Health check # Health check
gem 'health_check', '~> 2.1.0' gem 'health_check', '~> 2.2.0'
# System information # System information
gem 'vmstat', '~> 2.2' gem 'vmstat', '~> 2.2'
......
...@@ -38,6 +38,8 @@ GEM ...@@ -38,6 +38,8 @@ GEM
multi_json (~> 1.11, >= 1.11.2) multi_json (~> 1.11, >= 1.11.2)
rack (>= 1.5.2, < 3) rack (>= 1.5.2, < 3)
railties (>= 4.0, < 5.1) railties (>= 4.0, < 5.1)
activerecord_sane_schema_dumper (0.2)
rails (>= 4, < 5)
activesupport (4.2.7.1) activesupport (4.2.7.1)
i18n (~> 0.7) i18n (~> 0.7)
json (~> 1.7, >= 1.7.7) json (~> 1.7, >= 1.7.7)
...@@ -280,7 +282,8 @@ GEM ...@@ -280,7 +282,8 @@ GEM
diff-lcs (~> 1.1) diff-lcs (~> 1.1)
mime-types (>= 1.16, < 3) mime-types (>= 1.16, < 3)
posix-spawn (~> 0.3) posix-spawn (~> 0.3)
gitlab_git (10.6.7) gitlab-markup (1.5.0)
gitlab_git (10.6.8)
activesupport (~> 4.0) activesupport (~> 4.0)
charlock_holmes (~> 0.7.3) charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0) github-linguist (~> 4.7.0)
...@@ -334,7 +337,7 @@ GEM ...@@ -334,7 +337,7 @@ GEM
thor thor
tilt tilt
hashie (3.4.4) hashie (3.4.4)
health_check (2.1.0) health_check (2.2.1)
rails (>= 4.0) rails (>= 4.0)
hipchat (1.5.2) hipchat (1.5.2)
httparty httparty
...@@ -399,7 +402,7 @@ GEM ...@@ -399,7 +402,7 @@ GEM
systemu (~> 2.6.2) systemu (~> 2.6.2)
mail (2.6.4) mail (2.6.4)
mime-types (>= 1.16, < 4) mime-types (>= 1.16, < 4)
mail_room (0.8.0) mail_room (0.8.1)
method_source (0.8.2) method_source (0.8.2)
mime-types (2.99.3) mime-types (2.99.3)
mimemagic (0.3.0) mimemagic (0.3.0)
...@@ -745,6 +748,9 @@ GEM ...@@ -745,6 +748,9 @@ GEM
tilt (2.0.5) tilt (2.0.5)
timecop (0.8.1) timecop (0.8.1)
timfel-krb5-auth (0.8.3) timfel-krb5-auth (0.8.3)
truncato (0.7.8)
htmlentities (~> 4.3.1)
nokogiri (~> 1.6.1)
turbolinks (2.5.3) turbolinks (2.5.3)
coffee-rails coffee-rails
tzinfo (1.2.2) tzinfo (1.2.2)
...@@ -802,6 +808,7 @@ DEPENDENCIES ...@@ -802,6 +808,7 @@ DEPENDENCIES
RedCloth (~> 4.3.2) RedCloth (~> 4.3.2)
ace-rails-ap (~> 4.1.0) ace-rails-ap (~> 4.1.0)
activerecord-session_store (~> 1.0.0) activerecord-session_store (~> 1.0.0)
activerecord_sane_schema_dumper (= 0.2)
acts-as-taggable-on (~> 4.0) acts-as-taggable-on (~> 4.0)
addressable (~> 2.3.8) addressable (~> 2.3.8)
after_commit_queue (~> 1.3.0) after_commit_queue (~> 1.3.0)
...@@ -858,9 +865,9 @@ DEPENDENCIES ...@@ -858,9 +865,9 @@ DEPENDENCIES
gemnasium-gitlab-service (~> 0.2) gemnasium-gitlab-service (~> 0.2)
gemojione (~> 3.0) gemojione (~> 3.0)
github-linguist (~> 4.7.0) github-linguist (~> 4.7.0)
github-markup (~> 1.4)
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab_git (~> 10.6.7) gitlab-markup (~> 1.5.0)
gitlab_git (~> 10.6.8)
gitlab_omniauth-ldap (~> 1.2.1) gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.2) gollum-lib (~> 4.2)
gollum-rugged_adapter (~> 0.4.2) gollum-rugged_adapter (~> 0.4.2)
...@@ -869,7 +876,7 @@ DEPENDENCIES ...@@ -869,7 +876,7 @@ DEPENDENCIES
grape-entity (~> 0.4.2) grape-entity (~> 0.4.2)
haml_lint (~> 0.18.2) haml_lint (~> 0.18.2)
hamlit (~> 2.6.1) hamlit (~> 2.6.1)
health_check (~> 2.1.0) health_check (~> 2.2.0)
hipchat (~> 1.5.0) hipchat (~> 1.5.0)
html-pipeline (~> 1.11.0) html-pipeline (~> 1.11.0)
httparty (~> 0.13.3) httparty (~> 0.13.3)
...@@ -886,7 +893,7 @@ DEPENDENCIES ...@@ -886,7 +893,7 @@ DEPENDENCIES
license_finder (~> 2.1.0) license_finder (~> 2.1.0)
licensee (~> 8.0.0) licensee (~> 8.0.0)
loofah (~> 2.0.3) loofah (~> 2.0.3)
mail_room (~> 0.8) mail_room (~> 0.8.1)
method_source (~> 0.8) method_source (~> 0.8)
minitest (~> 5.7.0) minitest (~> 5.7.0)
mousetrap-rails (~> 1.4.6) mousetrap-rails (~> 1.4.6)
...@@ -931,7 +938,7 @@ DEPENDENCIES ...@@ -931,7 +938,7 @@ DEPENDENCIES
redis (~> 3.2) redis (~> 3.2)
redis-namespace (~> 1.5.2) redis-namespace (~> 1.5.2)
redis-rails (~> 4.0.0) redis-rails (~> 4.0.0)
request_store (~> 1.3.0) request_store (~> 1.3)
rerun (~> 0.11.0) rerun (~> 0.11.0)
responders (~> 2.0) responders (~> 2.0)
rouge (~> 2.0) rouge (~> 2.0)
...@@ -971,6 +978,7 @@ DEPENDENCIES ...@@ -971,6 +978,7 @@ DEPENDENCIES
test_after_commit (~> 0.4.2) test_after_commit (~> 0.4.2)
thin (~> 1.7.0) thin (~> 1.7.0)
timecop (~> 0.8.0) timecop (~> 0.8.0)
truncato (~> 0.7.8)
turbolinks (~> 2.5.0) turbolinks (~> 2.5.0)
u2f (~> 0.2.1) u2f (~> 0.2.1)
uglifier (~> 2.7.2) uglifier (~> 2.7.2)
......
# GitLab # GitLab
[![build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master) [![Build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
[![coverage report](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master) [![CE coverage report](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](http://gitlab-org.gitlab.io/gitlab-ce/coverage-ruby)
[![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq) [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
[![Core Infrastructure Initiative Best Practices](https://bestpractices.coreinfrastructure.org/projects/42/badge)](https://bestpractices.coreinfrastructure.org/projects/42) [![Core Infrastructure Initiative Best Practices](https://bestpractices.coreinfrastructure.org/projects/42/badge)](https://bestpractices.coreinfrastructure.org/projects/42)
......
...@@ -6,11 +6,10 @@ ...@@ -6,11 +6,10 @@
groupProjectsPath: "/api/:version/groups/:id/projects.json", groupProjectsPath: "/api/:version/groups/:id/projects.json",
projectsPath: "/api/:version/projects.json?simple=true", projectsPath: "/api/:version/projects.json?simple=true",
labelsPath: "/:namespace_path/:project_path/labels", labelsPath: "/:namespace_path/:project_path/labels",
licensePath: "/api/:version/licenses/:key", licensePath: "/api/:version/templates/licenses/:key",
gitignorePath: "/api/:version/gitignores/:key", gitignorePath: "/api/:version/templates/gitignores/:key",
gitlabCiYmlPath: "/api/:version/gitlab_ci_ymls/:key", gitlabCiYmlPath: "/api/:version/templates/gitlab_ci_ymls/:key",
issuableTemplatePath: "/:namespace_path/:project_path/templates/:type/:key", issuableTemplatePath: "/:namespace_path/:project_path/templates/:type/:key",
group: function(group_id, callback) { group: function(group_id, callback) {
var url = Api.buildUrl(Api.groupPath) var url = Api.buildUrl(Api.groupPath)
.replace(':id', group_id); .replace(':id', group_id);
......
...@@ -31,12 +31,13 @@ $(() => { ...@@ -31,12 +31,13 @@ $(() => {
state: Store.state, state: Store.state,
loading: true, loading: true,
endpoint: $boardApp.dataset.endpoint, endpoint: $boardApp.dataset.endpoint,
boardId: $boardApp.dataset.boardId,
disabled: $boardApp.dataset.disabled === 'true', disabled: $boardApp.dataset.disabled === 'true',
issueLinkBase: $boardApp.dataset.issueLinkBase issueLinkBase: $boardApp.dataset.issueLinkBase
}, },
init: Store.create.bind(Store), init: Store.create.bind(Store),
created () { created () {
gl.boardService = new BoardService(this.endpoint); gl.boardService = new BoardService(this.endpoint, this.boardId);
}, },
ready () { ready () {
Store.disabled = this.disabled; Store.disabled = this.disabled;
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
this.$nextTick(() => { this.$nextTick(() => {
new IssuableContext(this.currentUser); new IssuableContext(this.currentUser);
new MilestoneSelect(); new MilestoneSelect();
new DueDateSelect(); new gl.DueDateSelectors();
new LabelsSelect(); new LabelsSelect();
new Sidebar(); new Sidebar();
new Subscription('.subscription'); new Subscription('.subscription');
......
class BoardService { class BoardService {
constructor (root) { constructor (root, boardId) {
this.lists = Vue.resource(`${root}/lists{/id}`, {}, { this.lists = Vue.resource(`${root}/${boardId}/lists{/id}`, {}, {
generate: { generate: {
method: 'POST', method: 'POST',
url: `${root}/lists/generate.json` url: `${root}/${boardId}/lists/generate.json`
} }
}); });
this.issue = Vue.resource(`${root}/issues{/id}`, {}); this.issue = Vue.resource(`${root}/${boardId}/issues{/id}`, {});
this.issues = Vue.resource(`${root}/lists{/id}/issues`, {}); this.issues = Vue.resource(`${root}/${boardId}/lists{/id}/issues`, {});
Vue.http.interceptors.push((request, next) => { Vue.http.interceptors.push((request, next) => {
request.headers['X-CSRF-Token'] = $.rails.csrfToken(); request.headers['X-CSRF-Token'] = $.rails.csrfToken();
......
...@@ -15,18 +15,17 @@ ...@@ -15,18 +15,17 @@
this.hideSidebar = bind(this.hideSidebar, this); this.hideSidebar = bind(this.hideSidebar, this);
this.toggleSidebar = bind(this.toggleSidebar, this); this.toggleSidebar = bind(this.toggleSidebar, this);
this.updateDropdown = bind(this.updateDropdown, this); this.updateDropdown = bind(this.updateDropdown, this);
this.$document = $(document);
clearInterval(Build.interval); clearInterval(Build.interval);
// Init breakpoint checker // Init breakpoint checker
this.bp = Breakpoints.get(); this.bp = Breakpoints.get();
$('.js-build-sidebar').niceScroll(); this.initSidebar();
this.populateJobs(this.build_stage); this.populateJobs(this.build_stage);
this.updateStageDropdownText(this.build_stage); this.updateStageDropdownText(this.build_stage);
this.hideSidebar();
$(document).off('click', '.js-sidebar-build-toggle').on('click', '.js-sidebar-build-toggle', this.toggleSidebar);
$(window).off('resize.build').on('resize.build', this.hideSidebar); $(window).off('resize.build').on('resize.build', this.hideSidebar);
$(document).off('click', '.stage-item').on('click', '.stage-item', this.updateDropdown); this.$document.off('click', '.stage-item').on('click', '.stage-item', this.updateDropdown);
$('#js-build-scroll > a').off('click').on('click', this.stepTrace); $('#js-build-scroll > a').off('click').on('click', this.stepTrace);
this.updateArtifactRemoveDate(); this.updateArtifactRemoveDate();
if ($('#build-trace').length) { if ($('#build-trace').length) {
...@@ -62,6 +61,21 @@ ...@@ -62,6 +61,21 @@
} }
} }
Build.prototype.initSidebar = function() {
this.$sidebar = $('.js-build-sidebar');
this.sidebarTranslationLimits = {
min: $('.navbar-gitlab').outerHeight() + $('.layout-nav').outerHeight()
}
this.sidebarTranslationLimits.max = this.sidebarTranslationLimits.min + $('.scrolling-tabs-container').outerHeight();
this.$sidebar.css({
top: this.sidebarTranslationLimits.max
});
this.$sidebar.niceScroll();
this.hideSidebar();
this.$document.off('click', '.js-sidebar-build-toggle').on('click', '.js-sidebar-build-toggle', this.toggleSidebar);
this.$document.off('scroll.translateSidebar').on('scroll.translateSidebar', this.translateSidebar.bind(this));
};
Build.prototype.getInitialBuildTrace = function() { Build.prototype.getInitialBuildTrace = function() {
var removeRefreshStatuses = ['success', 'failed', 'canceled', 'skipped'] var removeRefreshStatuses = ['success', 'failed', 'canceled', 'skipped']
...@@ -129,15 +143,23 @@ ...@@ -129,15 +143,23 @@
Build.prototype.toggleSidebar = function() { Build.prototype.toggleSidebar = function() {
if (this.shouldHideSidebar()) { if (this.shouldHideSidebar()) {
return $('.js-build-sidebar').toggleClass('right-sidebar-expanded right-sidebar-collapsed'); return this.$sidebar.toggleClass('right-sidebar-expanded right-sidebar-collapsed');
} }
}; };
Build.prototype.translateSidebar = function(e) {
var newPosition = this.sidebarTranslationLimits.max - document.body.scrollTop;
if (newPosition < this.sidebarTranslationLimits.min) newPosition = this.sidebarTranslationLimits.min;
this.$sidebar.css({
top: newPosition
});
};
Build.prototype.hideSidebar = function() { Build.prototype.hideSidebar = function() {
if (this.shouldHideSidebar()) { if (this.shouldHideSidebar()) {
return $('.js-build-sidebar').removeClass('right-sidebar-expanded').addClass('right-sidebar-collapsed'); return this.$sidebar.removeClass('right-sidebar-expanded').addClass('right-sidebar-collapsed');
} else { } else {
return $('.js-build-sidebar').removeClass('right-sidebar-collapsed').addClass('right-sidebar-expanded'); return this.$sidebar.removeClass('right-sidebar-collapsed').addClass('right-sidebar-expanded');
} }
}; };
......
...@@ -9,7 +9,10 @@ ...@@ -9,7 +9,10 @@
var $dropdown, selected; var $dropdown, selected;
$dropdown = $(this); $dropdown = $(this);
selected = $dropdown.data('selected'); selected = $dropdown.data('selected');
return $dropdown.glDropdown({ const $dropdownContainer = $dropdown.closest('.dropdown');
const $fieldInput = $(`input[name="${$dropdown.data('field-name')}"]`, $dropdownContainer);
const $filterInput = $('input[type="search"]', $dropdownContainer);
$dropdown.glDropdown({
data: function(term, callback) { data: function(term, callback) {
return $.ajax({ return $.ajax({
url: $dropdown.data('refs-url'), url: $dropdown.data('refs-url'),
...@@ -42,6 +45,14 @@ ...@@ -42,6 +45,14 @@
return $el.text().trim(); return $el.text().trim();
} }
}); });
$filterInput.on('keyup', (e) => {
const keyCode = e.keyCode || e.which;
if (keyCode !== 13) return;
const text = $filterInput.val();
$fieldInput.val(text);
$('.dropdown-toggle-text', $dropdown).text(text);
$dropdownContainer.removeClass('open');
});
}); });
}; };
......
//= require vue
((global) => { ((global) => {
const COOKIE_NAME = 'cycle_analytics_help_dismissed'; const COOKIE_NAME = 'cycle_analytics_help_dismissed';
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
Dispatcher = (function() { Dispatcher = (function() {
function Dispatcher() { function Dispatcher() {
this.initSearch(); this.initSearch();
this.initFieldErrors();
this.initPageScripts(); this.initPageScripts();
} }
...@@ -20,7 +21,11 @@ ...@@ -20,7 +21,11 @@
path = page.split(':'); path = page.split(':');
shortcut_handler = null; shortcut_handler = null;
switch (page) { switch (page) {
case 'sessions:new':
new UsernameValidator();
break;
case 'projects:boards:show': case 'projects:boards:show':
case 'projects:boards:index':
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
break; break;
case 'projects:merge_requests:index': case 'projects:merge_requests:index':
...@@ -45,7 +50,7 @@ ...@@ -45,7 +50,7 @@
case 'projects:milestones:new': case 'projects:milestones:new':
case 'projects:milestones:edit': case 'projects:milestones:edit':
new ZenMode(); new ZenMode();
new DueDateSelect(); new gl.DueDateSelectors();
new GLForm($('.milestone-form')); new GLForm($('.milestone-form'));
break; break;
case 'groups:milestones:new': case 'groups:milestones:new':
...@@ -96,9 +101,6 @@ ...@@ -96,9 +101,6 @@
new ZenMode(); new ZenMode();
new MergedButtons(); new MergedButtons();
break; break;
case "projects:merge_requests:conflicts":
window.mcui = new MergeConflictResolver()
break;
case 'projects:merge_requests:index': case 'projects:merge_requests:index':
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
Issuable.init(); Issuable.init();
...@@ -126,6 +128,9 @@ ...@@ -126,6 +128,9 @@
new TreeView(); new TreeView();
} }
break; break;
case 'projects:pipelines:show':
new gl.Pipelines();
break;
case 'groups:activity': case 'groups:activity':
new Activities(); new Activities();
break; break;
...@@ -136,12 +141,12 @@ ...@@ -136,12 +141,12 @@
break; break;
case 'groups:group_members:index': case 'groups:group_members:index':
new gl.MemberExpirationDate(); new gl.MemberExpirationDate();
new GroupMembers(); new gl.Members();
new UsersSelect(); new UsersSelect();
break; break;
case 'projects:project_members:index': case 'projects:project_members:index':
new gl.MemberExpirationDate(); new gl.MemberExpirationDate();
new ProjectMembers(); new gl.Members();
new UsersSelect(); new UsersSelect();
break; break;
case 'groups:new': case 'groups:new':
...@@ -287,6 +292,12 @@ ...@@ -287,6 +292,12 @@
} }
}; };
Dispatcher.prototype.initFieldErrors = function() {
$('.show-gl-field-errors').each((i, form) => {
new gl.GlFieldErrors(form);
});
};
return Dispatcher; return Dispatcher;
})(); })();
......
(function() {
this.DueDateSelect = (function() {
function DueDateSelect() {
var $datePicker, $dueDate, $loading;
// Milestone edit/new form
$datePicker = $('.datepicker');
if ($datePicker.length) {
$dueDate = $('#milestone_due_date');
$datePicker.datepicker({
dateFormat: 'yy-mm-dd',
onSelect: function(dateText, inst) {
return $dueDate.val(dateText);
}
}).datepicker('setDate', $.datepicker.parseDate('yy-mm-dd', $dueDate.val()));
}
$('.js-clear-due-date').on('click', function(e) {
e.preventDefault();
return $.datepicker._clearDate($datePicker);
});
// Issuable sidebar
$loading = $('.js-issuable-update .due_date').find('.block-loading').hide();
$('.js-due-date-select').each(function(i, dropdown) {
var $block, $dropdown, $dropdownParent, $selectbox, $sidebarValue, $value, $valueContent, abilityName, addDueDate, fieldName, issueUpdateURL;
$dropdown = $(dropdown);
$dropdownParent = $dropdown.closest('.dropdown');
$datePicker = $dropdownParent.find('.js-due-date-calendar');
$block = $dropdown.closest('.block');
$selectbox = $dropdown.closest('.selectbox');
$value = $block.find('.value');
$valueContent = $block.find('.value-content');
$sidebarValue = $('.js-due-date-sidebar-value', $block);
fieldName = $dropdown.data('field-name');
abilityName = $dropdown.data('ability-name');
issueUpdateURL = $dropdown.data('issue-update');
$dropdown.glDropdown({
hidden: function() {
$selectbox.hide();
return $value.css('display', '');
}
});
var updateIssueBoardIssue = function () {
$dropdown.trigger('loading.gl.dropdown');
$selectbox.hide();
$value.css('display', '');
$loading.fadeIn();
gl.issueBoards.BoardsStore.detail.issue.update(issueUpdateURL)
.then(function () {
$loading.fadeOut();
});
}
addDueDate = function(isDropdown) {
var data, date, mediumDate, value;
// Create the post date
value = $("input[name='" + fieldName + "']").val();
if (value !== '') {
date = new Date(value.replace(new RegExp('-', 'g'), ','));
mediumDate = $.datepicker.formatDate('M d, yy', date);
} else {
mediumDate = 'No due date';
}
data = {};
data[abilityName] = {};
data[abilityName].due_date = value;
return $.ajax({
type: 'PUT',
url: issueUpdateURL,
data: data,
dataType: 'json',
beforeSend: function() {
var cssClass;
$loading.fadeIn();
if (isDropdown) {
$dropdown.trigger('loading.gl.dropdown');
$selectbox.hide();
}
$value.css('display', '');
cssClass = Date.parse(mediumDate) ? 'bold' : 'no-value';
$valueContent.html("<span class='" + cssClass + "'>" + mediumDate + "</span>");
$sidebarValue.html(mediumDate);
if (value !== '') {
return $('.js-remove-due-date-holder').removeClass('hidden');
} else {
return $('.js-remove-due-date-holder').addClass('hidden');
}
}
}).done(function(data) {
if (isDropdown) {
$dropdown.trigger('loaded.gl.dropdown');
$dropdown.dropdown('toggle');
}
return $loading.fadeOut();
});
};
$block.on('click', '.js-remove-due-date', function(e) {
e.preventDefault();
if ($dropdown.hasClass('js-issue-boards-due-date')) {
gl.issueBoards.BoardsStore.detail.issue.dueDate = '';
updateIssueBoardIssue();
} else {
$("input[name='" + fieldName + "']").val('');
return addDueDate(false);
}
});
return $datePicker.datepicker({
dateFormat: 'yy-mm-dd',
defaultDate: $("input[name='" + fieldName + "']").val(),
altField: "input[name='" + fieldName + "']",
onSelect: function() {
if ($dropdown.hasClass('js-issue-boards-due-date')) {
gl.issueBoards.BoardsStore.detail.issue.dueDate = $("input[name='" + fieldName + "']").val();
updateIssueBoardIssue();
} else {
return addDueDate(true);
}
}
});
});
$(document).off('click', '.ui-datepicker-header a').on('click', '.ui-datepicker-header a', function(e) {
return e.stopImmediatePropagation();
});
}
return DueDateSelect;
})();
}).call(this);
(function(global) {
class DueDateSelect {
constructor({ $dropdown, $loading } = {}) {
const $dropdownParent = $dropdown.closest('.dropdown');
const $block = $dropdown.closest('.block');
this.$loading = $loading;
this.$dropdown = $dropdown;
this.$dropdownParent = $dropdownParent;
this.$datePicker = $dropdownParent.find('.js-due-date-calendar');
this.$block = $block;
this.$selectbox = $dropdown.closest('.selectbox');
this.$value = $block.find('.value');
this.$valueContent = $block.find('.value-content');
this.$sidebarValue = $('.js-due-date-sidebar-value', $block);
this.fieldName = $dropdown.data('field-name'),
this.abilityName = $dropdown.data('ability-name'),
this.issueUpdateURL = $dropdown.data('issue-update')
this.rawSelectedDate = null;
this.displayedDate = null;
this.datePayload = null;
this.initGlDropdown();
this.initRemoveDueDate();
this.initDatePicker();
this.initStopPropagation();
}
initGlDropdown() {
this.$dropdown.glDropdown({
hidden: () => {
this.$selectbox.hide();
this.$value.css('display', '');
}
});
}
initDatePicker() {
this.$datePicker.datepicker({
dateFormat: 'yy-mm-dd',
defaultDate: $("input[name='" + this.fieldName + "']").val(),
altField: "input[name='" + this.fieldName + "']",
onSelect: () => {
return this.saveDueDate(true);
}
});
}
initRemoveDueDate() {
this.$block.on('click', '.js-remove-due-date', (e) => {
e.preventDefault();
$("input[name='" + this.fieldName + "']").val('');
return this.saveDueDate(false);
});
}
initStopPropagation() {
$(document).off('click', '.ui-datepicker-header a').on('click', '.ui-datepicker-header a', (e) => {
return e.stopImmediatePropagation();
});
}
saveDueDate(isDropdown) {
this.parseSelectedDate();
this.prepSelectedDate();
this.submitSelectedDate(isDropdown);
}
parseSelectedDate() {
this.rawSelectedDate = $("input[name='" + this.fieldName + "']").val();
if (this.rawSelectedDate.length) {
let dateObj = new Date(this.rawSelectedDate);
this.displayedDate = $.datepicker.formatDate('M d, yy', dateObj);
} else {
this.displayedDate = 'No due date';
}
}
prepSelectedDate() {
const datePayload = {};
datePayload[this.abilityName] = {};
datePayload[this.abilityName].due_date = this.rawSelectedDate;
this.datePayload = datePayload;
}
submitSelectedDate(isDropdown) {
return $.ajax({
type: 'PUT',
url: this.issueUpdateURL,
data: this.datePayload,
dataType: 'json',
beforeSend: () => {
const selectedDateValue = this.datePayload[this.abilityName].due_date;
const displayedDateStyle = this.displayedDate !== 'No due date' ? 'bold' : 'no-value';
this.$loading.fadeIn();
if (isDropdown) {
this.$dropdown.trigger('loading.gl.dropdown');
this.$selectbox.hide();
}
this.$value.css('display', '');
this.$valueContent.html(`<span class='${displayedDateStyle}'>${this.displayedDate}</span>`);
this.$sidebarValue.html(this.displayedDate);
return selectedDateValue.length ?
$('.js-remove-due-date-holder').removeClass('hidden') :
$('.js-remove-due-date-holder').addClass('hidden');
}
}).done((data) => {
if (isDropdown) {
this.$dropdown.trigger('loaded.gl.dropdown');
this.$dropdown.dropdown('toggle');
}
return this.$loading.fadeOut();
});
}
}
class DueDateSelectors {
constructor() {
this.initMilestoneDueDate();
this.initIssuableSelect();
}
initMilestoneDueDate() {
const $datePicker = $('.datepicker');
if ($datePicker.length) {
const $dueDate = $('#milestone_due_date');
$datePicker.datepicker({
dateFormat: 'yy-mm-dd',
onSelect: (dateText, inst) => {
$dueDate.val(dateText);
}
}).datepicker('setDate', $.datepicker.parseDate('yy-mm-dd', $dueDate.val()));
}
$('.js-clear-due-date').on('click', (e) => {
e.preventDefault();
$.datepicker._clearDate($datePicker);
});
}
initIssuableSelect() {
const $loading = $('.js-issuable-update .due_date').find('.block-loading').hide();
$('.js-due-date-select').each((i, dropdown) => {
const $dropdown = $(dropdown);
new DueDateSelect({
$dropdown,
$loading
});
});
}
}
global.DueDateSelectors = DueDateSelectors;
})(window.gl || (window.gl = {}));
...@@ -52,37 +52,27 @@ ...@@ -52,37 +52,27 @@
} }
} }
}, },
setup: function(input) { setup: _.debounce(function(input) {
// Add GFM auto-completion to all input fields, that accept GFM input. // Add GFM auto-completion to all input fields, that accept GFM input.
this.input = input || $('.js-gfm-input'); this.input = input || $('.js-gfm-input');
// destroy previous instances // destroy previous instances
this.destroyAtWho(); this.destroyAtWho();
// set up instances // set up instances
this.setupAtWho(); this.setupAtWho();
if (this.dataSource) {
if (!this.dataLoading && !this.cachedData) { if (this.dataSource && !this.dataLoading && !this.cachedData) {
this.dataLoading = true; this.dataLoading = true;
setTimeout((function(_this) { return this.fetchData(this.dataSource)
return function() { .done((data) => {
var fetch; this.dataLoading = false;
fetch = _this.fetchData(_this.dataSource); this.loadData(data);
return fetch.done(function(data) { });
_this.dataLoading = false; };
return _this.loadData(data);
}); if (this.cachedData != null) {
}; return this.loadData(this.cachedData);
// We should wait until initializations are done
// and only trigger the last .setup since
// The previous .dataSource belongs to the previous issuable
// and the last one will have the **proper** .dataSource property
// TODO: Make this a singleton and turn off events when moving to another page
})(this), 1000);
}
if (this.cachedData != null) {
return this.loadData(this.cachedData);
}
} }
}, }, 1000),
setupAtWho: function() { setupAtWho: function() {
// Emoji // Emoji
this.input.atwho({ this.input.atwho({
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
return function(e) { return function(e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
return _this.input.val('').trigger('keyup').focus(); return _this.input.val('').trigger('input').focus();
}; };
})(this)); })(this));
// Key events // Key events
...@@ -37,28 +37,16 @@ ...@@ -37,28 +37,16 @@
e.preventDefault() e.preventDefault()
} }
}) })
.on('keyup', function(e) { .on('input', function() {
var keyCode;
keyCode = e.which;
if (ARROW_KEY_CODES.indexOf(keyCode) >= 0) {
return;
}
if (this.input.val() !== "" && !$inputContainer.hasClass(HAS_VALUE_CLASS)) { if (this.input.val() !== "" && !$inputContainer.hasClass(HAS_VALUE_CLASS)) {
$inputContainer.addClass(HAS_VALUE_CLASS); $inputContainer.addClass(HAS_VALUE_CLASS);
} else if (this.input.val() === "" && $inputContainer.hasClass(HAS_VALUE_CLASS)) { } else if (this.input.val() === "" && $inputContainer.hasClass(HAS_VALUE_CLASS)) {
$inputContainer.removeClass(HAS_VALUE_CLASS); $inputContainer.removeClass(HAS_VALUE_CLASS);
} }
if (keyCode === 13 && !options.elIsInput) {
return false;
}
// Only filter asynchronously only if option remote is set // Only filter asynchronously only if option remote is set
if (this.options.remote) { if (this.options.remote) {
clearTimeout(timeout); clearTimeout(timeout);
return timeout = setTimeout(function() { return timeout = setTimeout(function() {
var blurField = this.shouldBlur(keyCode);
if (blurField && this.filterInputBlur) {
this.input.blur();
}
return this.options.query(this.input.val(), function(data) { return this.options.query(this.input.val(), function(data) {
return this.options.callback(data); return this.options.callback(data);
}.bind(this)); }.bind(this));
...@@ -255,7 +243,7 @@ ...@@ -255,7 +243,7 @@
_this.fullData = data; _this.fullData = data;
_this.parseData(_this.fullData); _this.parseData(_this.fullData);
if (_this.options.filterable && _this.filter && _this.filter.input) { if (_this.options.filterable && _this.filter && _this.filter.input) {
return _this.filter.input.trigger('keyup'); return _this.filter.input.trigger('input');
} }
}; };
// Remote data // Remote data
...@@ -487,7 +475,7 @@ ...@@ -487,7 +475,7 @@
// Triggering 'keyup' will re-render the dropdown which is not always required // Triggering 'keyup' will re-render the dropdown which is not always required
// specially if we want to keep the state of the dropdown needed for bulk-assignment // specially if we want to keep the state of the dropdown needed for bulk-assignment
if (!this.options.persistWhenHide) { if (!this.options.persistWhenHide) {
$input.trigger("keyup"); $input.trigger("input");
} }
if (this.dropdown.find(".dropdown-toggle-page").length) { if (this.dropdown.find(".dropdown-toggle-page").length) {
$('.dropdown-menu', this.dropdown).removeClass(PAGE_TWO_CLASS); $('.dropdown-menu', this.dropdown).removeClass(PAGE_TWO_CLASS);
...@@ -500,14 +488,27 @@ ...@@ -500,14 +488,27 @@
// Render the full menu // Render the full menu
GitLabDropdown.prototype.renderMenu = function(html) { GitLabDropdown.prototype.renderMenu = function(html) {
var menu_html;
menu_html = "";
if (this.options.renderMenu) { if (this.options.renderMenu) {
menu_html = this.options.renderMenu(html); return this.options.renderMenu(html);
} else { } else {
menu_html = $('<ul />').append(html); var ul = document.createElement('ul');
for (var i = 0; i < html.length; i++) {
var el = html[i];
if (el instanceof jQuery) {
el = el.get(0);
}
if (typeof el === 'string') {
ul.innerHTML += el;
} else {
ul.appendChild(el);
}
}
return ul;
} }
return menu_html;
}; };
// Append the menu into the dropdown // Append the menu into the dropdown
...@@ -521,7 +522,7 @@ ...@@ -521,7 +522,7 @@
}; };
GitLabDropdown.prototype.renderItem = function(data, group, index) { GitLabDropdown.prototype.renderItem = function(data, group, index) {
var cssClass, field, fieldName, groupAttrs, html, selected, text, url, value; var field, fieldName, html, selected, text, url, value;
if (group == null) { if (group == null) {
group = false; group = false;
} }
...@@ -529,18 +530,16 @@ ...@@ -529,18 +530,16 @@
// Render the row // Render the row
index = false; index = false;
} }
html = ""; html = document.createElement('li');
// Divider if (data === 'divider' || data === 'separator') {
if (data === "divider") { html.className = data;
return "<li class='divider'></li>"; return html;
}
// Separator is a full-width divider
if (data === "separator") {
return "<li class='separator'></li>";
} }
// Header // Header
if (data.header != null) { if (data.header != null) {
return _.template('<li class="dropdown-header"><%- header %></li>')({ header: data.header }); html.className = 'dropdown-header';
html.innerHTML = data.header;
return html;
} }
if (this.options.renderRow) { if (this.options.renderRow) {
// Call the render function // Call the render function
...@@ -567,24 +566,25 @@ ...@@ -567,24 +566,25 @@
} else { } else {
text = data.text != null ? data.text : ''; text = data.text != null ? data.text : '';
} }
cssClass = "";
if (selected) {
cssClass = "is-active";
}
if (this.highlight) { if (this.highlight) {
text = this.highlightTextMatches(text, this.filterInput.val()); text = this.highlightTextMatches(text, this.filterInput.val());
} }
// Create the list item & the link
var link = document.createElement('a');
link.href = url;
link.innerHTML = text;
if (selected) {
link.className = 'is-active';
}
if (group) { if (group) {
groupAttrs = 'data-group=' + group + ' data-index=' + index; link.dataset.group = group;
} else { link.dataset.index = index;
groupAttrs = '';
} }
html = _.template('<li><a href="<%- url %>" <%- groupAttrs %> class="<%- cssClass %>"><%= text %></a></li>')({
url: url, html.appendChild(link);
groupAttrs: groupAttrs,
cssClass: cssClass,
text: text
});
} }
return html; return html;
}; };
...@@ -749,6 +749,7 @@ ...@@ -749,6 +749,7 @@
return false; return false;
} }
if (currentKeyCode === 13 && currentIndex !== -1) { if (currentKeyCode === 13 && currentIndex !== -1) {
e.preventDefault();
_this.selectRowAtIndex(); _this.selectRowAtIndex();
} }
}; };
......
((global) => {
/*
* This class overrides the browser's validation error bubbles, displaying custom
* error messages for invalid fields instead. To begin validating any form, add the
* class `show-gl-field-errors` to the form element, and ensure error messages are
* declared in each inputs' title attribute.
*
* Example:
*
* <form class='show-gl-field-errors'>
* <input type='text' name='username' title='Username is required.'/>
*</form>
*
* */
const errorMessageClass = 'gl-field-error';
const inputErrorClass = 'gl-field-error-outline';
class GlFieldError {
constructor({ input, formErrors }) {
this.inputElement = $(input);
this.inputDomElement = this.inputElement.get(0);
this.form = formErrors;
this.errorMessage = this.inputElement.attr('title') || 'This field is required.';
this.fieldErrorElement = $(`<p class='${errorMessageClass} hide'>${ this.errorMessage }</p>`);
this.state = {
valid: false,
empty: true
};
this.initFieldValidation();
}
initFieldValidation() {
// hidden when injected into DOM
this.inputElement.after(this.fieldErrorElement);
this.inputElement.off('invalid').on('invalid', this.handleInvalidSubmit.bind(this));
this.scopedSiblings = this.safelySelectSiblings();
}
safelySelectSiblings() {
// Apply `ignoreSelector` in markup to siblings whose visibility should not be toggled with input validity
const ignoreSelector = '.validation-ignore';
const unignoredSiblings = this.inputElement.siblings(`p:not(${ignoreSelector})`);
const parentContainer = this.inputElement.parent('.form-group');
// Only select siblings when they're scoped within a form-group with one input
const safelyScoped = parentContainer.length && parentContainer.find('input').length === 1;
return safelyScoped ? unignoredSiblings : this.fieldErrorElement;
}
renderValidity() {
this.renderClear();
if (this.state.valid) {
return this.renderValid();
}
if (this.state.empty) {
return this.renderEmpty();
}
if (!this.state.valid) {
return this.renderInvalid();
}
}
handleInvalidSubmit(event) {
event.preventDefault();
const currentValue = this.accessCurrentValue();
this.state.valid = false;
this.state.empty = currentValue === '';
this.renderValidity();
this.form.focusOnFirstInvalid.apply(this.form);
// For UX, wait til after first invalid submission to check each keyup
this.inputElement.off('keyup.field_validator')
.on('keyup.field_validator', this.updateValidity.bind(this));
}
/* Get or set current input value */
accessCurrentValue(newVal) {
return newVal ? this.inputElement.val(newVal) : this.inputElement.val();
}
getInputValidity() {
return this.inputDomElement.validity.valid;
}
updateValidity() {
const inputVal = this.accessCurrentValue();
this.state.empty = !inputVal.length;
this.state.valid = this.getInputValidity();
this.renderValidity();
}
renderValid() {
return this.renderClear();
}
renderEmpty() {
return this.renderInvalid();
}
renderInvalid() {
this.inputElement.addClass(inputErrorClass);
this.scopedSiblings.hide();
return this.fieldErrorElement.show();
}
renderClear() {
const inputVal = this.accessCurrentValue();
if (!inputVal.split(' ').length) {
const trimmedInput = inputVal.trim();
this.accessCurrentValue(trimmedInput);
}
this.inputElement.removeClass(inputErrorClass);
this.scopedSiblings.hide();
this.fieldErrorElement.hide();
}
}
const customValidationFlag = 'no-gl-field-errors';
class GlFieldErrors {
constructor(form) {
this.form = $(form);
this.state = {
inputs: [],
valid: false
};
this.initValidators();
}
initValidators () {
// select all non-hidden inputs in form
this.state.inputs = this.form.find(':input:not([type=hidden])').toArray()
.filter((input) => !input.classList.contains(customValidationFlag))
.map((input) => new GlFieldError({ input, formErrors: this }));
this.form.on('submit', this.catchInvalidFormSubmit);
}
/* Neccessary to prevent intercept and override invalid form submit
* because Safari & iOS quietly allow form submission when form is invalid
* and prevents disabling of invalid submit button by application.js */
catchInvalidFormSubmit (event) {
if (!event.currentTarget.checkValidity()) {
event.preventDefault();
event.stopPropagation();
}
}
focusOnFirstInvalid () {
const firstInvalid = this.state.inputs.filter((input) => !input.inputDomElement.validity.valid)[0];
firstInvalid.inputElement.focus();
}
}
global.GlFieldErrors = GlFieldErrors;
})(window.gl || (window.gl = {}));
(function() {
this.GroupMembers = (function() {
function GroupMembers() {
$('li.group_member').bind('ajax:success', function() {
return $(this).fadeOut();
});
}
return GroupMembers;
})();
}).call(this);
...@@ -292,7 +292,7 @@ ...@@ -292,7 +292,7 @@
return; return;
} }
if (page === 'projects:boards:show') { if ($('html').hasClass('issue-boards-page')) {
return; return;
} }
if ($dropdown.hasClass('js-multiselect')) { if ($dropdown.hasClass('js-multiselect')) {
...@@ -335,7 +335,7 @@ ...@@ -335,7 +335,7 @@
page = $('body').data('page'); page = $('body').data('page');
isIssueIndex = page === 'projects:issues:index'; isIssueIndex = page === 'projects:issues:index';
isMRIndex = page === 'projects:merge_requests:index'; isMRIndex = page === 'projects:merge_requests:index';
if (page === 'projects:boards:show' && !$dropdown.hasClass('js-issue-board-sidebar')) { if ($('html').hasClass('issue-boards-page') && !$dropdown.hasClass('js-issue-board-sidebar')) {
if (label.isAny) { if (label.isAny) {
gl.issueBoards.BoardsStore.state.filters['label_name'] = []; gl.issueBoards.BoardsStore.state.filters['label_name'] = [];
} }
......
...@@ -14,14 +14,18 @@ ...@@ -14,14 +14,18 @@
inputs.datepicker({ inputs.datepicker({
dateFormat: 'yy-mm-dd', dateFormat: 'yy-mm-dd',
minDate: 1, minDate: 1,
onSelect: toggleClearInput onSelect: function () {
$(this).trigger('change');
toggleClearInput.call(this);
}
}); });
inputs.next('.js-clear-input').on('click', function(event) { inputs.next('.js-clear-input').on('click', function(event) {
event.preventDefault(); event.preventDefault();
var input = $(this).closest('.clearable-input').find('.js-access-expiration-date'); var input = $(this).closest('.clearable-input').find('.js-access-expiration-date');
input.datepicker('setDate', null); input.datepicker('setDate', null)
.trigger('change');
toggleClearInput.call(input); toggleClearInput.call(input);
}); });
......
((w) => {
w.gl = w.gl || {};
class Members {
constructor() {
this.addListeners();
}
addListeners() {
$('.project_member, .group_member').off('ajax:success').on('ajax:success', this.removeRow);
$('.js-member-update-control').off('change').on('change', this.formSubmit);
$('.js-edit-member-form').off('ajax:success').on('ajax:success', this.formSuccess);
}
removeRow(e) {
const $target = $(e.target);
if ($target.hasClass('btn-remove')) {
$target.closest('.member')
.fadeOut(function () {
$(this).remove();
});
}
}
formSubmit() {
$(this).closest('form').trigger("submit.rails").end().disable();
}
formSuccess() {
$(this).find('.js-member-update-control').enable();
}
}
gl.Members = Members;
})(window);
const HEAD_HEADER_TEXT = 'HEAD//our changes';
const ORIGIN_HEADER_TEXT = 'origin//their changes';
const HEAD_BUTTON_TITLE = 'Use ours';
const ORIGIN_BUTTON_TITLE = 'Use theirs';
class MergeConflictDataProvider {
getInitialData() {
// TODO: remove reliance on jQuery and DOM state introspection
const diffViewType = $.cookie('diff_view');
const fixedLayout = $('.content-wrapper .container-fluid').hasClass('container-limited');
return {
isLoading : true,
hasError : false,
isParallel : diffViewType === 'parallel',
diffViewType : diffViewType,
fixedLayout : fixedLayout,
isSubmitting : false,
conflictsData : {},
resolutionData : {}
}
}
decorateData(vueInstance, data) {
this.vueInstance = vueInstance;
if (data.type === 'error') {
vueInstance.hasError = true;
data.errorMessage = data.message;
}
else {
data.shortCommitSha = data.commit_sha.slice(0, 7);
data.commitMessage = data.commit_message;
this.setParallelLines(data);
this.setInlineLines(data);
this.updateResolutionsData(data);
}
vueInstance.conflictsData = data;
vueInstance.isSubmitting = false;
const conflictsText = this.getConflictsCount() > 1 ? 'conflicts' : 'conflict';
vueInstance.conflictsData.conflictsText = conflictsText;
}
updateResolutionsData(data) {
const vi = this.vueInstance;
data.files.forEach( (file) => {
file.sections.forEach( (section) => {
if (section.conflict) {
vi.$set(`resolutionData['${section.id}']`, false);
}
});
});
}
setParallelLines(data) {
data.files.forEach( (file) => {
file.filePath = this.getFilePath(file);
file.iconClass = `fa-${file.blob_icon}`;
file.blobPath = file.blob_path;
file.parallelLines = [];
const linesObj = { left: [], right: [] };
file.sections.forEach( (section) => {
const { conflict, lines, id } = section;
if (conflict) {
linesObj.left.push(this.getOriginHeaderLine(id));
linesObj.right.push(this.getHeadHeaderLine(id));
}
lines.forEach( (line) => {
const { type } = line;
if (conflict) {
if (type === 'old') {
linesObj.left.push(this.getLineForParallelView(line, id, 'conflict'));
}
else if (type === 'new') {
linesObj.right.push(this.getLineForParallelView(line, id, 'conflict', true));
}
}
else {
const lineType = type || 'context';
linesObj.left.push (this.getLineForParallelView(line, id, lineType));
linesObj.right.push(this.getLineForParallelView(line, id, lineType, true));
}
});
this.checkLineLengths(linesObj);
});
for (let i = 0, len = linesObj.left.length; i < len; i++) {
file.parallelLines.push([
linesObj.right[i],
linesObj.left[i]
]);
}
});
}
checkLineLengths(linesObj) {
let { left, right } = linesObj;
if (left.length !== right.length) {
if (left.length > right.length) {
const diff = left.length - right.length;
for (let i = 0; i < diff; i++) {
right.push({ lineType: 'emptyLine', richText: '' });
}
}
else {
const diff = right.length - left.length;
for (let i = 0; i < diff; i++) {
left.push({ lineType: 'emptyLine', richText: '' });
}
}
}
}
setInlineLines(data) {
data.files.forEach( (file) => {
file.iconClass = `fa-${file.blob_icon}`;
file.blobPath = file.blob_path;
file.filePath = this.getFilePath(file);
file.inlineLines = []
file.sections.forEach( (section) => {
let currentLineType = 'new';
const { conflict, lines, id } = section;
if (conflict) {
file.inlineLines.push(this.getHeadHeaderLine(id));
}
lines.forEach( (line) => {
const { type } = line;
if ((type === 'new' || type === 'old') && currentLineType !== type) {
currentLineType = type;
file.inlineLines.push({ lineType: 'emptyLine', richText: '' });
}
this.decorateLineForInlineView(line, id, conflict);
file.inlineLines.push(line);
})
if (conflict) {
file.inlineLines.push(this.getOriginHeaderLine(id));
}
});
});
}
handleSelected(sectionId, selection) {
const vi = this.vueInstance;
vi.resolutionData[sectionId] = selection;
vi.conflictsData.files.forEach( (file) => {
file.inlineLines.forEach( (line) => {
if (line.id === sectionId && (line.hasConflict || line.isHeader)) {
this.markLine(line, selection);
}
});
file.parallelLines.forEach( (lines) => {
const left = lines[0];
const right = lines[1];
const hasSameId = right.id === sectionId || left.id === sectionId;
const isLeftMatch = left.hasConflict || left.isHeader;
const isRightMatch = right.hasConflict || right.isHeader;
if (hasSameId && (isLeftMatch || isRightMatch)) {
this.markLine(left, selection);
this.markLine(right, selection);
}
})
});
}
updateViewType(newType) {
const vi = this.vueInstance;
if (newType === vi.diffViewType || !(newType === 'parallel' || newType === 'inline')) {
return;
}
vi.diffViewType = newType;
vi.isParallel = newType === 'parallel';
$.cookie('diff_view', newType, {
path: (gon && gon.relative_url_root) || '/'
});
$('.content-wrapper .container-fluid')
.toggleClass('container-limited', !vi.isParallel && vi.fixedLayout);
}
markLine(line, selection) {
if (selection === 'head' && line.isHead) {
line.isSelected = true;
line.isUnselected = false;
}
else if (selection === 'origin' && line.isOrigin) {
line.isSelected = true;
line.isUnselected = false;
}
else {
line.isSelected = false;
line.isUnselected = true;
}
}
getConflictsCount() {
return Object.keys(this.vueInstance.resolutionData).length;
}
getResolvedCount() {
let count = 0;
const data = this.vueInstance.resolutionData;
for (const id in data) {
const resolution = data[id];
if (resolution) {
count++;
}
}
return count;
}
isReadyToCommit() {
const { conflictsData, isSubmitting } = this.vueInstance
const allResolved = this.getConflictsCount() === this.getResolvedCount();
const hasCommitMessage = $.trim(conflictsData.commitMessage).length;
return !isSubmitting && hasCommitMessage && allResolved;
}
getCommitButtonText() {
const initial = 'Commit conflict resolution';
const inProgress = 'Committing...';
const vue = this.vueInstance;
return vue ? vue.isSubmitting ? inProgress : initial : initial;
}
decorateLineForInlineView(line, id, conflict) {
const { type } = line;
line.id = id;
line.hasConflict = conflict;
line.isHead = type === 'new';
line.isOrigin = type === 'old';
line.hasMatch = type === 'match';
line.richText = line.rich_text;
line.isSelected = false;
line.isUnselected = false;
}
getLineForParallelView(line, id, lineType, isHead) {
const { old_line, new_line, rich_text } = line;
const hasConflict = lineType === 'conflict';
return {
id,
lineType,
hasConflict,
isHead : hasConflict && isHead,
isOrigin : hasConflict && !isHead,
hasMatch : lineType === 'match',
lineNumber : isHead ? new_line : old_line,
section : isHead ? 'head' : 'origin',
richText : rich_text,
isSelected : false,
isUnselected : false
}
}
getHeadHeaderLine(id) {
return {
id : id,
richText : HEAD_HEADER_TEXT,
buttonTitle : HEAD_BUTTON_TITLE,
type : 'new',
section : 'head',
isHeader : true,
isHead : true,
isSelected : false,
isUnselected: false
}
}
getOriginHeaderLine(id) {
return {
id : id,
richText : ORIGIN_HEADER_TEXT,
buttonTitle : ORIGIN_BUTTON_TITLE,
type : 'old',
section : 'origin',
isHeader : true,
isOrigin : true,
isSelected : false,
isUnselected: false
}
}
handleFailedRequest(vueInstance, data) {
vueInstance.hasError = true;
vueInstance.conflictsData.errorMessage = 'Something went wrong!';
}
getCommitData() {
return {
commit_message: this.vueInstance.conflictsData.commitMessage,
sections: this.vueInstance.resolutionData
}
}
getFilePath(file) {
const { old_path, new_path } = file;
return old_path === new_path ? new_path : `${old_path} → ${new_path}`;
}
}
//= require vue
class MergeConflictResolver {
constructor() {
this.dataProvider = new MergeConflictDataProvider()
this.initVue()
}
initVue() {
const that = this;
this.vue = new Vue({
el : '#conflicts',
name : 'MergeConflictResolver',
data : this.dataProvider.getInitialData(),
created : this.fetchData(),
computed : this.setComputedProperties(),
methods : {
handleSelected(sectionId, selection) {
that.dataProvider.handleSelected(sectionId, selection);
},
handleViewTypeChange(newType) {
that.dataProvider.updateViewType(newType);
},
commit() {
that.commit();
}
}
})
}
setComputedProperties() {
const dp = this.dataProvider;
return {
conflictsCount() { return dp.getConflictsCount() },
resolvedCount() { return dp.getResolvedCount() },
readyToCommit() { return dp.isReadyToCommit() },
commitButtonText() { return dp.getCommitButtonText() }
}
}
fetchData() {
const dp = this.dataProvider;
$.get($('#conflicts').data('conflictsPath'))
.done((data) => {
dp.decorateData(this.vue, data);
})
.error((data) => {
dp.handleFailedRequest(this.vue, data);
})
.always(() => {
this.vue.isLoading = false;
this.vue.$nextTick(() => {
$('#conflicts .js-syntax-highlight').syntaxHighlight();
});
$('.content-wrapper .container-fluid')
.toggleClass('container-limited', !this.vue.isParallel && this.vue.fixedLayout);
})
}
commit() {
this.vue.isSubmitting = true;
$.post($('#conflicts').data('resolveConflictsPath'), this.dataProvider.getCommitData())
.done((data) => {
window.location.href = data.redirect_to;
})
.error(() => {
this.vue.isSubmitting = false;
new Flash('Something went wrong!');
});
}
}
((global) => {
global.mergeConflicts = global.mergeConflicts || {};
global.mergeConflicts.diffFileEditor = Vue.extend({
props: {
file: Object,
onCancelDiscardConfirmation: Function,
onAcceptDiscardConfirmation: Function
},
data() {
return {
saved: false,
loading: false,
fileLoaded: false,
originalContent: '',
}
},
computed: {
classObject() {
return {
'saved': this.saved,
'is-loading': this.loading
};
}
},
watch: {
['file.showEditor'](val) {
this.resetEditorContent();
if (!val || this.fileLoaded || this.loading) {
return;
}
this.loadEditor();
}
},
ready() {
if (this.file.loadEditor) {
this.loadEditor();
}
},
methods: {
loadEditor() {
this.loading = true;
$.get(this.file.content_path)
.done((file) => {
let content = this.$el.querySelector('pre');
let fileContent = document.createTextNode(file.content);
content.textContent = fileContent.textContent;
this.originalContent = file.content;
this.fileLoaded = true;
this.editor = ace.edit(content);
this.editor.$blockScrolling = Infinity; // Turn off annoying warning
this.editor.getSession().setMode(`ace/mode/${file.blob_ace_mode}`);
this.editor.on('change', () => {
this.saveDiffResolution();
});
this.saveDiffResolution();
})
.fail(() => {
new Flash('Failed to load the file, please try again.');
})
.always(() => {
this.loading = false;
});
},
saveDiffResolution() {
this.saved = true;
// This probably be better placed in the data provider
this.file.content = this.editor.getValue();
this.file.resolveEditChanged = this.file.content !== this.originalContent;
this.file.promptDiscardConfirmation = false;
},
resetEditorContent() {
if (this.fileLoaded) {
this.editor.setValue(this.originalContent, -1);
}
},
cancelDiscardConfirmation(file) {
this.onCancelDiscardConfirmation(file);
},
acceptDiscardConfirmation(file) {
this.onAcceptDiscardConfirmation(file);
}
}
});
})(window.gl || (window.gl = {}));
((global) => {
global.mergeConflicts = global.mergeConflicts || {};
global.mergeConflicts.inlineConflictLines = Vue.extend({
props: {
file: Object
},
mixins: [global.mergeConflicts.utils, global.mergeConflicts.actions],
});
})(window.gl || (window.gl = {}));
((global) => {
global.mergeConflicts = global.mergeConflicts || {};
global.mergeConflicts.parallelConflictLine = Vue.extend({
props: {
file: Object,
line: Object
},
mixins: [global.mergeConflicts.utils, global.mergeConflicts.actions],
template: '#parallel-conflict-line'
});
})(window.gl || (window.gl = {}));
((global) => {
global.mergeConflicts = global.mergeConflicts || {};
global.mergeConflicts.parallelConflictLines = Vue.extend({
props: {
file: Object
},
mixins: [global.mergeConflicts.utils],
components: {
'parallel-conflict-line': gl.mergeConflicts.parallelConflictLine
}
});
})(window.gl || (window.gl = {}));
((global) => {
global.mergeConflicts = global.mergeConflicts || {};
class mergeConflictsService {
constructor(options) {
this.conflictsPath = options.conflictsPath;
this.resolveConflictsPath = options.resolveConflictsPath;
}
fetchConflictsData() {
return $.ajax({
dataType: 'json',
url: this.conflictsPath
});
}
submitResolveConflicts(data) {
return $.ajax({
url: this.resolveConflictsPath,
data: JSON.stringify(data),
contentType: 'application/json',
dataType: 'json',
method: 'POST'
});
}
};
global.mergeConflicts.mergeConflictsService = mergeConflictsService;
})(window.gl || (window.gl = {}));
//= require vue
//= require ./merge_conflict_store
//= require ./merge_conflict_service
//= require ./mixins/line_conflict_utils
//= require ./mixins/line_conflict_actions
//= require ./components/diff_file_editor
//= require ./components/inline_conflict_lines
//= require ./components/parallel_conflict_line
//= require ./components/parallel_conflict_lines
$(() => {
const INTERACTIVE_RESOLVE_MODE = 'interactive';
const conflictsEl = document.querySelector('#conflicts');
const mergeConflictsStore = gl.mergeConflicts.mergeConflictsStore;
const mergeConflictsService = new gl.mergeConflicts.mergeConflictsService({
conflictsPath: conflictsEl.dataset.conflictsPath,
resolveConflictsPath: conflictsEl.dataset.resolveConflictsPath
});
gl.MergeConflictsResolverApp = new Vue({
el: '#conflicts',
data: mergeConflictsStore.state,
components: {
'diff-file-editor': gl.mergeConflicts.diffFileEditor,
'inline-conflict-lines': gl.mergeConflicts.inlineConflictLines,
'parallel-conflict-lines': gl.mergeConflicts.parallelConflictLines
},
computed: {
conflictsCountText() { return mergeConflictsStore.getConflictsCountText() },
readyToCommit() { return mergeConflictsStore.isReadyToCommit() },
commitButtonText() { return mergeConflictsStore.getCommitButtonText() },
showDiffViewTypeSwitcher() { return mergeConflictsStore.fileTextTypePresent() }
},
created() {
mergeConflictsService
.fetchConflictsData()
.done((data) => {
if (data.type === 'error') {
mergeConflictsStore.setFailedRequest(data.message);
} else {
mergeConflictsStore.setConflictsData(data);
}
})
.error(() => {
mergeConflictsStore.setFailedRequest();
})
.always(() => {
mergeConflictsStore.setLoadingState(false);
this.$nextTick(() => {
$(conflictsEl.querySelectorAll('.js-syntax-highlight')).syntaxHighlight();
});
});
},
methods: {
handleViewTypeChange(viewType) {
mergeConflictsStore.setViewType(viewType);
},
onClickResolveModeButton(file, mode) {
if (mode === INTERACTIVE_RESOLVE_MODE && file.resolveEditChanged) {
mergeConflictsStore.setPromptConfirmationState(file, true);
return;
}
mergeConflictsStore.setFileResolveMode(file, mode);
},
acceptDiscardConfirmation(file) {
mergeConflictsStore.setPromptConfirmationState(file, false);
mergeConflictsStore.setFileResolveMode(file, INTERACTIVE_RESOLVE_MODE);
},
cancelDiscardConfirmation(file) {
mergeConflictsStore.setPromptConfirmationState(file, false);
},
commit() {
mergeConflictsStore.setSubmitState(true);
mergeConflictsService
.submitResolveConflicts(mergeConflictsStore.getCommitData())
.done((data) => {
window.location.href = data.redirect_to;
})
.error(() => {
mergeConflictsStore.setSubmitState(false);
new Flash('Failed to save merge conflicts resolutions. Please try again!');
});
}
}
})
});
((global) => {
global.mergeConflicts = global.mergeConflicts || {};
global.mergeConflicts.actions = {
methods: {
handleSelected(file, sectionId, selection) {
gl.mergeConflicts.mergeConflictsStore.handleSelected(file, sectionId, selection);
}
}
};
})(window.gl || (window.gl = {}));
((global) => {
global.mergeConflicts = global.mergeConflicts || {};
global.mergeConflicts.utils = {
methods: {
lineCssClass(line) {
return {
'head': line.isHead,
'origin': line.isOrigin,
'match': line.hasMatch,
'selected': line.isSelected,
'unselected': line.isUnselected
};
}
}
};
})(window.gl || (window.gl = {}));
...@@ -71,6 +71,7 @@ ...@@ -71,6 +71,7 @@
this._location = location; this._location = location;
this.bindEvents(); this.bindEvents();
this.activateTab(this.opts.action); this.activateTab(this.opts.action);
this.initAffix();
} }
MergeRequestTabs.prototype.bindEvents = function() { MergeRequestTabs.prototype.bindEvents = function() {
...@@ -380,6 +381,46 @@ ...@@ -380,6 +381,46 @@
// Only when sidebar is collapsed // Only when sidebar is collapsed
}; };
MergeRequestTabs.prototype.initAffix = function () {
var $tabs = $('.js-tabs-affix');
// Screen space on small screens is usually very sparse
// So we dont affix the tabs on these
if (Breakpoints.get().getBreakpointSize() === 'xs' || !$tabs.length) return;
var tabsWidth = $tabs.outerWidth(),
$diffTabs = $('#diff-notes-app'),
offsetTop = $tabs.offset().top - ($('.navbar-fixed-top').height() + $('.layout-nav').height());
$tabs.off('affix.bs.affix affix-top.bs.affix')
.affix({
offset: {
top: offsetTop
}
}).on('affix.bs.affix', function () {
$tabs.css({
left: $tabs.offset().left,
width: tabsWidth
});
$diffTabs.css({
marginTop: $tabs.height()
});
}).on('affix-top.bs.affix', function () {
$tabs.css({
left: '',
width: ''
});
$diffTabs.css({
marginTop: ''
});
});
// Fix bug when reloading the page already scrolling
if ($tabs.hasClass('affix')) {
$tabs.trigger('affix.bs.affix');
}
};
return MergeRequestTabs; return MergeRequestTabs;
})(); })();
......
(function() { ((global) => {
var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
this.MergeRequestWidget = (function() { const DEPLOYMENT_TEMPLATE = `<div class="mr-widget-heading" id="<%- id %>">
<div class="ci_widget ci-success">
<%= ci_success_icon %>
<span>
Deployed to
<a href="<%- url %>" target="_blank" class="environment">
<%- name %>
</a>
<span class="js-environment-timeago" data-toggle="tooltip" data-placement="top" data-title="<%- deployed_at_formatted %>">
<%- deployed_at %>
</span>
<a class="js-environment-link" href="<%- external_url %>" target="_blank">
<i class="fa fa-external-link"></i>
View on <%- external_url_formatted %>
</a>
</span>
</div>
</div>`;
global.MergeRequestWidget = (function() {
function MergeRequestWidget(opts) { function MergeRequestWidget(opts) {
// Initialize MergeRequestWidget behavior // Initialize MergeRequestWidget behavior
// //
...@@ -10,17 +29,23 @@ ...@@ -10,17 +29,23 @@
// ci_status_url - String, URL to use to check CI status // ci_status_url - String, URL to use to check CI status
// //
this.opts = opts; this.opts = opts;
this.$widgetBody = $('.mr-widget-body');
$('#modal_merge_info').modal({ $('#modal_merge_info').modal({
show: false show: false
}); });
this.firstCICheck = true; this.firstCICheck = true;
this.readyForCICheck = false; this.readyForCICheck = false;
this.readyForCIEnvironmentCheck = false;
this.cancel = false; this.cancel = false;
clearInterval(this.fetchBuildStatusInterval); 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.pollCIStatus(); this.pollCIStatus();
this.pollCIEnvironmentsStatus();
notifyPermissions(); notifyPermissions();
} }
...@@ -41,6 +66,7 @@ ...@@ -41,6 +66,7 @@
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.fetchBuildStatusInterval);
clearInterval(_this.fetchBuildEnvironmentStatusInterval);
_this.cancelPolling(); _this.cancelPolling();
return _this.clearEventListeners(); return _this.clearEventListeners();
} }
...@@ -48,6 +74,12 @@ ...@@ -48,6 +74,12 @@
})(this)); })(this));
}; };
MergeRequestWidget.prototype.retrieveSuccessIcon = function() {
const $ciSuccessIcon = $('.js-success-icon');
this.$ciSuccessIcon = $ciSuccessIcon.html();
$ciSuccessIcon.remove();
}
MergeRequestWidget.prototype.mergeInProgress = function(deleteSourceBranch) { MergeRequestWidget.prototype.mergeInProgress = function(deleteSourceBranch) {
if (deleteSourceBranch == null) { if (deleteSourceBranch == null) {
deleteSourceBranch = false; deleteSourceBranch = false;
...@@ -62,7 +94,7 @@ ...@@ -62,7 +94,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 $('.mr-widget-body').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);
...@@ -118,6 +150,7 @@ ...@@ -118,6 +150,7 @@
if (data.status === '') { if (data.status === '') {
return; return;
} }
if (data.environments && data.environments.length) _this.renderEnvironments(data.environments);
if (_this.firstCICheck || data.status !== _this.opts.ci_status && (data.status != null)) { if (_this.firstCICheck || 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);
...@@ -150,6 +183,41 @@ ...@@ -150,6 +183,41 @@
})(this)); })(this));
}; };
MergeRequestWidget.prototype.pollCIEnvironmentsStatus = function() {
this.fetchBuildEnvironmentStatusInterval = setInterval(() => {
if (!this.readyForCIEnvironmentCheck) return;
this.getCIEnvironmentsStatus();
this.readyForCIEnvironmentCheck = false;
}, 300000);
};
MergeRequestWidget.prototype.getCIEnvironmentsStatus = function() {
$.getJSON(this.opts.ci_environments_status_url, (environments) => {
if (this.cancel) return;
this.readyForCIEnvironmentCheck = true;
if (environments && environments.length) this.renderEnvironments(environments);
});
};
MergeRequestWidget.prototype.renderEnvironments = function(environments) {
for (let i = 0; i < environments.length; i++) {
const environment = environments[i];
if ($(`.mr-state-widget #${ environment.id }`).length) return;
const $template = $(DEPLOYMENT_TEMPLATE);
if (!environment.external_url || !environment.external_url_formatted) $('.js-environment-link', $template).remove();
if (environment.deployed_at && environment.deployed_at_formatted) {
environment.deployed_at = $.timeago(environment.deployed_at) + '.';
} else {
$('.js-environment-timeago', $template).remove();
environment.name += '.';
}
environment.ci_success_icon = this.$ciSuccessIcon;
const templateString = _.unescape($template[0].outerHTML);
const template = _.template(templateString)(environment)
this.$widgetBody.before(template);
}
};
MergeRequestWidget.prototype.showCIStatus = function(state) { MergeRequestWidget.prototype.showCIStatus = function(state) {
var allowed_states; var allowed_states;
if (state == null) { if (state == null) {
...@@ -190,4 +258,4 @@ ...@@ -190,4 +258,4 @@
})(); })();
}).call(this); })(window.gl || (window.gl = {}));
...@@ -111,7 +111,7 @@ ...@@ -111,7 +111,7 @@
e.preventDefault(); e.preventDefault();
return; return;
} }
if (page === 'projects:boards:show' && !$dropdown.hasClass('js-issue-board-sidebar')) { if ($('html').hasClass('issue-boards-page') && !$dropdown.hasClass('js-issue-board-sidebar')) {
gl.issueBoards.BoardsStore.state.filters[$dropdown.data('field-name')] = selected.name; gl.issueBoards.BoardsStore.state.filters[$dropdown.data('field-name')] = selected.name;
gl.issueBoards.BoardsStore.updateFiltersUrl(); gl.issueBoards.BoardsStore.updateFiltersUrl();
e.preventDefault(); e.preventDefault();
......
(function() {
function toggleGraph() {
const $pipelineBtn = $(this).closest('.toggle-pipeline-btn');
const $pipelineGraph = $(this).closest('.row-content-block').next('.pipeline-graph');
const $btnText = $(this).find('.toggle-btn-text');
const $icon = $(this).find('.fa');
$($pipelineBtn).add($pipelineGraph).toggleClass('graph-collapsed');
const graphCollapsed = $pipelineGraph.hasClass('graph-collapsed');
const expandIcon = 'fa-caret-down';
const hideIcon = 'fa-caret-up';
if(graphCollapsed) {
$btnText.text('Expand');
$icon.removeClass(hideIcon).addClass(expandIcon);
} else {
$btnText.text('Hide');
$icon.removeClass(expandIcon).addClass(hideIcon);
}
}
$(document).on('click', '.toggle-pipeline-btn', toggleGraph);
})();
((global) => {
class Pipelines {
constructor() {
$(document).off('click', '.toggle-pipeline-btn').on('click', '.toggle-pipeline-btn', this.toggleGraph);
this.addMarginToBuildColumns();
}
toggleGraph() {
const $pipelineBtn = $(this).closest('.toggle-pipeline-btn');
const $pipelineGraph = $(this).closest('.row-content-block').next('.pipeline-graph');
const $btnText = $(this).find('.toggle-btn-text');
const graphCollapsed = $pipelineGraph.hasClass('graph-collapsed');
$($pipelineBtn).add($pipelineGraph).toggleClass('graph-collapsed');
graphCollapsed ? $btnText.text('Hide') : $btnText.text('Expand')
}
addMarginToBuildColumns() {
const $secondChildBuildNode = $('.build:nth-child(2)');
if ($secondChildBuildNode.length) {
const $firstChildBuildNode = $secondChildBuildNode.prev('.build');
const $multiBuildColumn = $secondChildBuildNode.closest('.stage-column');
const $previousColumn = $multiBuildColumn.prev('.stage-column');
$multiBuildColumn.addClass('left-margin');
$firstChildBuildNode.addClass('left-connector');
$previousColumn.each(function() {
$this = $(this);
if ($('.build', $this).length === 1) $this.addClass('no-margin');
});
}
$('.pipeline-graph').removeClass('hidden');
}
}
global.Pipelines = Pipelines;
})(window.gl || (window.gl = {}));
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
function ProjectFindFile(element1, options) { function ProjectFindFile(element1, options) {
this.element = element1; this.element = element1;
this.options = options; this.options = options;
this.goToBlob = bind(this.goToBlob, this);
this.goToTree = bind(this.goToTree, this); this.goToTree = bind(this.goToTree, this);
this.selectRowDown = bind(this.selectRowDown, this); this.selectRowDown = bind(this.selectRowDown, this);
this.selectRowUp = bind(this.selectRowUp, this); this.selectRowUp = bind(this.selectRowUp, this);
...@@ -154,6 +155,14 @@ ...@@ -154,6 +155,14 @@
return location.href = this.options.treeUrl; return location.href = this.options.treeUrl;
}; };
ProjectFindFile.prototype.goToBlob = function() {
var $link = this.element.find(".tree-item.selected .tree-item-file-name a");
if ($link.length) {
$link.get(0).click();
}
};
return ProjectFindFile; return ProjectFindFile;
})(); })();
......
(function() {
this.ProjectMembers = (function() {
function ProjectMembers() {
$('li.project_member').bind('ajax:success', function() {
return $(this).fadeOut();
});
}
return ProjectMembers;
})();
}).call(this);
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
function ProjectNew() { function ProjectNew() {
this.toggleSettings = bind(this.toggleSettings, this); this.toggleSettings = bind(this.toggleSettings, this);
this.$selects = $('.features select'); this.$selects = $('.features select');
this.$repoSelects = this.$selects.filter('.js-repo-select');
$('.project-edit-container').on('ajax:before', (function(_this) { $('.project-edit-container').on('ajax:before', (function(_this) {
return function() { return function() {
...@@ -14,6 +15,7 @@ ...@@ -14,6 +15,7 @@
})(this)); })(this));
this.toggleSettings(); this.toggleSettings();
this.toggleSettingsOnclick(); this.toggleSettingsOnclick();
this.toggleRepoVisibility();
} }
ProjectNew.prototype.toggleSettings = function() { ProjectNew.prototype.toggleSettings = function() {
...@@ -41,6 +43,38 @@ ...@@ -41,6 +43,38 @@
} }
}; };
ProjectNew.prototype.toggleRepoVisibility = function () {
var $repoAccessLevel = $('.js-repo-access-level select');
this.$repoSelects.find("option[value='" + $repoAccessLevel.val() + "']")
.nextAll()
.hide();
$repoAccessLevel.off('change')
.on('change', function () {
var selectedVal = parseInt($repoAccessLevel.val());
this.$repoSelects.each(function () {
var $this = $(this),
repoSelectVal = parseInt($this.val());
$this.find('option').show();
if (selectedVal < repoSelectVal) {
$this.val(selectedVal);
}
$this.find("option[value='" + selectedVal + "']").nextAll().hide();
});
if (selectedVal) {
this.$repoSelects.removeClass('disabled');
} else {
this.$repoSelects.addClass('disabled');
}
}.bind(this));
};
return ProjectNew; return ProjectNew;
})(); })();
......
...@@ -16,7 +16,13 @@ ...@@ -16,7 +16,13 @@
if (initialQuery.name) this.requestFile(initialQuery); if (initialQuery.name) this.requestFile(initialQuery);
$('.reset-template', this.dropdown.parent()).on('click', () => { $('.reset-template', this.dropdown.parent()).on('click', () => {
if (this.currentTemplate) this.setInputValueToTemplateContent(false); this.setInputValueToTemplateContent();
});
$('.no-template', this.dropdown.parent()).on('click', () => {
this.currentTemplate = '';
this.setInputValueToTemplateContent();
$('.dropdown-toggle-text', this.dropdown).text('Choose a template');
}); });
} }
......
((global) => {
const debounceTimeoutDuration = 1000;
const invalidInputClass = 'gl-field-error-outline';
const successInputClass = 'gl-field-success-outline';
const unavailableMessageSelector = '.username .validation-error';
const successMessageSelector = '.username .validation-success';
const pendingMessageSelector = '.username .validation-pending';
const invalidMessageSelector = '.username .gl-field-error';
class UsernameValidator {
constructor() {
this.inputElement = $('#new_user_username');
this.inputDomElement = this.inputElement.get(0);
this.state = {
available: false,
valid: false,
pending: false,
empty: true
};
const debounceTimeout = _.debounce((username) => {
this.validateUsername(username);
}, debounceTimeoutDuration);
this.inputElement.on('keyup.username_check', () => {
const username = this.inputElement.val();
this.state.valid = this.inputDomElement.validity.valid;
this.state.empty = !username.length;
if (this.state.valid) {
return debounceTimeout(username);
}
this.renderState();
});
// Override generic field validation
this.inputElement.on('invalid', this.interceptInvalid.bind(this));
}
renderState() {
// Clear all state
this.clearFieldValidationState();
if (this.state.valid && this.state.available) {
return this.setSuccessState();
}
if (this.state.empty) {
return this.clearFieldValidationState();
}
if (this.state.pending) {
return this.setPendingState();
}
if (!this.state.available) {
return this.setUnavailableState();
}
if (!this.state.valid) {
return this.setInvalidState();
}
}
interceptInvalid(event) {
event.preventDefault();
event.stopPropagation();
}
validateUsername(username) {
if (this.state.valid) {
this.state.pending = true;
this.state.available = false;
this.renderState();
return $.ajax({
type: 'GET',
url: `/users/${username}/exists`,
dataType: 'json',
success: (res) => this.setAvailabilityState(res.exists)
});
}
}
setAvailabilityState(usernameTaken) {
if (usernameTaken) {
this.state.valid = false;
this.state.available = false;
} else {
this.state.available = true;
}
this.state.pending = false;
this.renderState();
}
clearFieldValidationState() {
this.inputElement.siblings('p').hide();
this.inputElement.removeClass(invalidInputClass)
.removeClass(successInputClass);
}
setUnavailableState() {
const $usernameUnavailableMessage = this.inputElement.siblings(unavailableMessageSelector);
this.inputElement.addClass(invalidInputClass).removeClass(successInputClass);
$usernameUnavailableMessage.show();
}
setSuccessState() {
const $usernameSuccessMessage = this.inputElement.siblings(successMessageSelector);
this.inputElement.addClass(successInputClass).removeClass(invalidInputClass);
$usernameSuccessMessage.show();
}
setPendingState() {
const $usernamePendingMessage = $(pendingMessageSelector);
if (this.state.pending) {
$usernamePendingMessage.show();
} else {
$usernamePendingMessage.hide();
}
}
setInvalidState() {
const $inputErrorMessage = $(invalidMessageSelector);
this.inputElement.addClass(invalidInputClass).removeClass(successInputClass);
$inputErrorMessage.show();
}
}
global.UsernameValidator = UsernameValidator;
})(window);
...@@ -186,7 +186,7 @@ ...@@ -186,7 +186,7 @@
selectedId = user.id; selectedId = user.id;
return; return;
} }
if (page === 'projects:boards:show' && !$dropdown.hasClass('js-issue-board-sidebar')) { if ($('html').hasClass('issue-boards-page') && !$dropdown.hasClass('js-issue-board-sidebar')) {
selectedId = user.id; selectedId = user.id;
gl.issueBoards.BoardsStore.state.filters[$dropdown.data('field-name')] = user.id; gl.issueBoards.BoardsStore.state.filters[$dropdown.data('field-name')] = user.id;
gl.issueBoards.BoardsStore.updateFiltersUrl(); gl.issueBoards.BoardsStore.updateFiltersUrl();
...@@ -300,10 +300,11 @@ ...@@ -300,10 +300,11 @@
} }
} }
if (showEmailUser && data.results.length === 0 && query.term.match(/^[^@]+@[^@]+$/)) { if (showEmailUser && data.results.length === 0 && query.term.match(/^[^@]+@[^@]+$/)) {
var trimmed = query.term.trim();
emailUser = { emailUser = {
name: "Invite \"" + query.term + "\"", name: "Invite \"" + query.term + "\"",
username: query.term, username: trimmed,
id: query.term id: trimmed
}; };
data.results.unshift(emailUser); data.results.unshift(emailUser);
} }
...@@ -363,6 +364,10 @@ ...@@ -363,6 +364,10 @@
}; };
UsersSelect.prototype.user = function(user_id, callback) { UsersSelect.prototype.user = function(user_id, callback) {
if(!/^\d+$/.test(user_id)) {
return false;
}
var url; var url;
url = this.buildUrl(this.userPath); url = this.buildUrl(this.userPath);
url = url.replace(':id', user_id); url = url.replace(':id', user_id);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
display: none; display: none;
&.hide { display: block; } &.hide { display: block; }
} }
&.open .content { &.open .content {
display: block; display: block;
&.hide { display: none; } &.hide { display: none; }
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
width: 40px; width: 40px;
height: 40px; height: 40px;
padding: 0; padding: 0;
@include border-radius($avatar_radius); border-radius: $avatar_radius;
border: 1px solid rgba(0, 0, 0, .1); border: 1px solid rgba(0, 0, 0, .1);
&.avatar-inline { &.avatar-inline {
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
} }
&.avatar-tile { &.avatar-tile {
@include border-radius(0); border-radius: 0;
border: none; border: none;
} }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
&.diff-collapsed { &.diff-collapsed {
padding: 5px; padding: 5px;
.click-to-expand { .click-to-expand {
cursor: pointer; cursor: pointer;
} }
...@@ -133,7 +134,7 @@ ...@@ -133,7 +134,7 @@
} }
.identicon { .identicon {
@include border-radius(50%); border-radius: 50%;
} }
} }
...@@ -203,6 +204,7 @@ ...@@ -203,6 +204,7 @@
} }
} }
} }
&.user-cover-block { &.user-cover-block {
padding: 24px 0 0; padding: 24px 0 0;
} }
......
@mixin btn-default { @mixin btn-default {
@include border-radius(3px); border-radius: 3px;
font-size: $gl-font-size; font-size: $gl-font-size;
font-weight: 500; font-weight: 500;
padding: $gl-vert-padding $gl-btn-padding; padding: $gl-vert-padding $gl-btn-padding;
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
&:active { &:active {
outline: none; outline: none;
background-color: $btn-active-gray; background-color: $btn-active-gray;
@include box-shadow($gl-btn-active-background); box-shadow: $gl-btn-active-background;
} }
} }
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
&:focus { &:focus {
background-color: $hover-background; background-color: $hover-background;
color: $hover-text; color: $hover-text;
border-color: $hover-border;; border-color: $hover-border;
} }
} }
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
&:active, &:active,
&.active { &.active {
@include box-shadow ($gl-btn-active-background); box-shadow: $gl-btn-active-background;
background-color: $dark; background-color: $dark;
border-color: $border-dark; border-color: $border-dark;
...@@ -152,7 +152,8 @@ ...@@ -152,7 +152,8 @@
@include btn-blue-medium; @include btn-blue-medium;
} }
&.btn-info { &.btn-info,
&.btn-register {
@include btn-blue; @include btn-blue;
} }
...@@ -240,6 +241,7 @@ ...@@ -240,6 +241,7 @@
width: 100%; width: 100%;
margin: 0; margin: 0;
margin-bottom: 15px; margin-bottom: 15px;
&.btn { &.btn {
padding: 6px 0; padding: 6px 0;
} }
...@@ -279,7 +281,7 @@ ...@@ -279,7 +281,7 @@
} }
.active { .active {
@include box-shadow($gl-btn-active-background); box-shadow: $gl-btn-active-background;
border: 1px solid #c6cacf !important; border: 1px solid #c6cacf !important;
background-color: #e4e7ed !important; background-color: #e4e7ed !important;
...@@ -321,6 +323,7 @@ ...@@ -321,6 +323,7 @@
.btn-build { .btn-build {
margin-left: 10px; margin-left: 10px;
i { i {
color: $gl-icon-color; color: $gl-icon-color;
} }
...@@ -328,6 +331,7 @@ ...@@ -328,6 +331,7 @@
.clone-dropdown-btn a { .clone-dropdown-btn a {
color: $dropdown-link-color; color: $dropdown-link-color;
&:hover { &:hover {
text-decoration: none; text-decoration: none;
} }
...@@ -337,6 +341,7 @@ ...@@ -337,6 +341,7 @@
background-color: $background-color !important; background-color: $background-color !important;
border: 1px solid lightgrey; border: 1px solid lightgrey;
cursor: default; cursor: default;
&:active { &:active {
-moz-box-shadow: inset 0 0 0 white; -moz-box-shadow: inset 0 0 0 white;
-webkit-box-shadow: inset 0 0 0 white; -webkit-box-shadow: inset 0 0 0 white;
......
...@@ -13,10 +13,12 @@ ...@@ -13,10 +13,12 @@
color: $text-color; color: $text-color;
background: $background-color; background: $background-color;
} }
.bs-callout h4 { .bs-callout h4 {
margin-top: 0; margin-top: 0;
margin-bottom: 5px; margin-bottom: 5px;
} }
.bs-callout p:last-child { .bs-callout p:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
...@@ -27,16 +29,19 @@ ...@@ -27,16 +29,19 @@
border-color: #eed3d7; border-color: #eed3d7;
color: #b94a48; color: #b94a48;
} }
.bs-callout-warning { .bs-callout-warning {
background-color: #faf8f0; background-color: #faf8f0;
border-color: #faebcc; border-color: #faebcc;
color: #8a6d3b; color: #8a6d3b;
} }
.bs-callout-info { .bs-callout-info {
background-color: #f4f8fa; background-color: #f4f8fa;
border-color: #bce8f1; border-color: #bce8f1;
color: #34789a; color: #34789a;
} }
.bs-callout-success { .bs-callout-success {
background-color: #dff0d8; background-color: #dff0d8;
border-color: #5ca64d; border-color: #5ca64d;
......
/** COLORS **/ /** COLORS **/
.cgray { color: $gl-gray; } .cgray { color: $gl-gray; }
.clgray { color: #bbb } .clgray { color: #bbb; }
.cred { color: $gl-text-red; } .cred { color: $gl-text-red; }
.cgreen { color: $gl-text-green; } .cgreen { color: $gl-text-green; }
.cdark { color: #444 } .cdark { color: #444; }
/** COMMON CLASSES **/ /** COMMON CLASSES **/
.prepend-top-0 { margin-top: 0; } .prepend-top-0 { margin-top: 0; }
.prepend-top-5 { margin-top: 5px; } .prepend-top-5 { margin-top: 5px; }
.prepend-top-10 { margin-top: 10px } .prepend-top-10 { margin-top: 10px; }
.prepend-top-default { margin-top: $gl-padding !important; } .prepend-top-default { margin-top: $gl-padding !important; }
.prepend-top-20 { margin-top: 20px } .prepend-top-20 { margin-top: 20px; }
.prepend-left-5 { margin-left: 5px } .prepend-left-5 { margin-left: 5px; }
.prepend-left-10 { margin-left: 10px } .prepend-left-10 { margin-left: 10px; }
.prepend-left-default { margin-left: $gl-padding; } .prepend-left-default { margin-left: $gl-padding; }
.prepend-left-20 { margin-left: 20px } .prepend-left-20 { margin-left: 20px; }
.append-right-5 { margin-right: 5px } .append-right-5 { margin-right: 5px; }
.append-right-10 { margin-right: 10px } .append-right-10 { margin-right: 10px; }
.append-right-default { margin-right: $gl-padding; } .append-right-default { margin-right: $gl-padding; }
.append-right-20 { margin-right: 20px } .append-right-20 { margin-right: 20px; }
.append-bottom-0 { margin-bottom: 0 } .append-bottom-0 { margin-bottom: 0; }
.append-bottom-10 { margin-bottom: 10px } .append-bottom-10 { margin-bottom: 10px; }
.append-bottom-15 { margin-bottom: 15px } .append-bottom-15 { margin-bottom: 15px; }
.append-bottom-20 { margin-bottom: 20px } .append-bottom-20 { margin-bottom: 20px; }
.append-bottom-default { margin-bottom: $gl-padding; } .append-bottom-default { margin-bottom: $gl-padding; }
.inline { display: inline-block } .inline { display: inline-block; }
.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: #999; }
...@@ -97,6 +97,7 @@ span.update-author { ...@@ -97,6 +97,7 @@ span.update-author {
color: #999; color: #999;
font-weight: normal; font-weight: normal;
font-style: italic; font-style: italic;
strong { strong {
font-weight: bold; font-weight: bold;
font-style: normal; font-style: normal;
...@@ -128,7 +129,7 @@ p.time { ...@@ -128,7 +129,7 @@ p.time {
// Fix issue with notes & lists creating a bunch of bottom borders. // Fix issue with notes & lists creating a bunch of bottom borders.
li.note { li.note {
img { max-width: 100% } img { max-width: 100%; }
.note-title { .note-title {
li { li {
border-bottom: none !important; border-bottom: none !important;
...@@ -172,6 +173,7 @@ li.note { ...@@ -172,6 +173,7 @@ li.note {
@extend .col-md-6; @extend .col-md-6;
text-align: left; text-align: left;
margin-top: 40px; margin-top: 40px;
pre { pre {
background: white; background: white;
border: none; border: none;
...@@ -197,6 +199,7 @@ li.note { ...@@ -197,6 +199,7 @@ li.note {
background: #c67; background: #c67;
color: #fff; color: #fff;
font-weight: bold; font-weight: bold;
a { a {
color: #fff; color: #fff;
text-decoration: underline; text-decoration: underline;
...@@ -227,6 +230,7 @@ li.note { ...@@ -227,6 +230,7 @@ li.note {
&.milestone-closed { &.milestone-closed {
background: $gray-light; background: $gray-light;
} }
.progress { .progress {
margin-bottom: 0; margin-bottom: 0;
margin-top: 4px; margin-top: 4px;
...@@ -286,6 +290,7 @@ table { ...@@ -286,6 +290,7 @@ table {
.footer-links { .footer-links {
margin-bottom: 20px; margin-bottom: 20px;
a { a {
margin-right: 15px; margin-right: 15px;
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
.dropdown-menu, .dropdown-menu,
.dropdown-menu-nav { .dropdown-menu-nav {
display: block; display: block;
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
width: 100%; width: 100%;
} }
...@@ -48,6 +49,7 @@ ...@@ -48,6 +49,7 @@
margin-top: -6px; margin-top: -6px;
color: $dropdown-toggle-icon-color; color: $dropdown-toggle-icon-color;
font-size: 10px; font-size: 10px;
&.fa-spinner { &.fa-spinner {
font-size: 16px; font-size: 16px;
margin-top: -8px; margin-top: -8px;
......
...@@ -26,15 +26,6 @@ ...@@ -26,15 +26,6 @@
padding: 10px $gl-padding; padding: 10px $gl-padding;
word-wrap: break-word; word-wrap: break-word;
border-radius: 3px 3px 0 0; border-radius: 3px 3px 0 0;
cursor: pointer;
&:hover {
background-color: $dark-background-color;
}
.diff-toggle-caret {
padding-right: 6px;
}
&.file-title-clear { &.file-title-clear {
padding-left: 0; padding-left: 0;
...@@ -66,6 +57,7 @@ ...@@ -66,6 +57,7 @@
margin-top: -3px; margin-top: -3px;
} }
} }
.file-content { .file-content {
background: #fff; background: #fff;
...@@ -105,22 +97,27 @@ ...@@ -105,22 +97,27 @@
border: none; border: none;
margin: 0; margin: 0;
} }
tr { tr {
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;
} }
td { td {
&:first-child { &:first-child {
border-left: none; border-left: none;
} }
&:last-child { &:last-child {
border-right: none; border-right: none;
} }
} }
td.blame-commit { td.blame-commit {
padding: 0 10px; padding: 0 10px;
min-width: 400px; min-width: 400px;
background: $gray-light; background: $gray-light;
} }
td.line-numbers { td.line-numbers {
float: none; float: none;
border-left: 1px solid #ddd; border-left: 1px solid #ddd;
...@@ -130,6 +127,7 @@ ...@@ -130,6 +127,7 @@
margin-right: 0; margin-right: 0;
} }
} }
td.lines { td.lines {
padding: 0; padding: 0;
} }
...@@ -146,8 +144,10 @@ ...@@ -146,8 +144,10 @@
border-left: 1px solid $border-color; border-left: 1px solid $border-color;
margin-bottom: 0; margin-bottom: 0;
background: white; background: white;
li { li {
color: #888; color: #888;
p { p {
margin: 0; margin: 0;
color: #333; color: #333;
......
...@@ -9,7 +9,7 @@ input { ...@@ -9,7 +9,7 @@ input {
input[type='text'].danger { input[type='text'].danger {
background: #f2dede!important; background: #f2dede!important;
border-color: #d66; border-color: #d66;
text-shadow: 0 1px 1px #fff text-shadow: 0 1px 1px #fff;
} }
.datetime-controls { .datetime-controls {
...@@ -74,7 +74,7 @@ label { ...@@ -74,7 +74,7 @@ label {
.form-control { .form-control {
@include box-shadow(none); @include box-shadow(none);
border-radius: 3px; border-radius: 2px;
padding: $gl-vert-padding $gl-input-padding; padding: $gl-vert-padding $gl-input-padding;
} }
...@@ -117,9 +117,11 @@ label { ...@@ -117,9 +117,11 @@ label {
display: table-cell; display: table-cell;
width: 200px !important; width: 200px !important;
} }
.input-group-addon { .input-group-addon {
background-color: #f7f8fa; background-color: #f7f8fa;
} }
.input-group-addon:not(:first-child):not(:last-child) { .input-group-addon:not(:first-child):not(:last-child) {
border-left: 0; border-left: 0;
border-right: 0; border-right: 0;
...@@ -129,3 +131,8 @@ label { ...@@ -129,3 +131,8 @@ label {
.help-block { .help-block {
margin-bottom: 0; margin-bottom: 0;
} }
.gl-field-error {
color: $red-normal;
}
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
} }
i { i {
color: $white-light color: $white-light;
} }
path, path,
......
...@@ -168,6 +168,7 @@ header { ...@@ -168,6 +168,7 @@ header {
a { a {
color: $gl-text-color; color: $gl-text-color;
&:hover { &:hover {
text-decoration: underline; text-decoration: underline;
} }
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
margin-top: 5px; margin-top: 5px;
} }
@include border-radius(3px); border-radius: 3px;
display: block; display: block;
float: left; float: left;
margin-right: 10px; margin-right: 10px;
......
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
padding-top: 1px; padding-top: 1px;
margin: 0; margin: 0;
color: $gray-dark; color: $gray-dark;
img { img {
position: relative; position: relative;
top: 3px; top: 3px;
...@@ -128,6 +129,10 @@ ul.content-list { ...@@ -128,6 +129,10 @@ ul.content-list {
color: $gl-dark-link-color; color: $gl-dark-link-color;
} }
.member-group-link {
color: $blue-normal;
}
.description { .description {
p { p {
@include str-truncated; @include str-truncated;
...@@ -168,6 +173,14 @@ ul.content-list { ...@@ -168,6 +173,14 @@ ul.content-list {
} }
} }
.member-controls {
float: none;
@media (min-width: $screen-sm-min) {
float: right;
}
}
// When dragging a list item // When dragging a list item
&.ui-sortable-helper { &.ui-sortable-helper {
border-bottom: none; border-bottom: none;
......
@mixin unique-keyframes {
$animation-name: unique-id();
@include webkit-prefix(animation-name, $animation-name);
@-webkit-keyframes #{$animation-name} {
@content;
}
@keyframes #{$animation-name} {
@content;
}
}
@mixin tanuki-logo-colors($path-color) { @mixin tanuki-logo-colors($path-color) {
fill: $path-color; fill: $path-color;
transition: all 0.8s; transition: all 0.8s;
...@@ -20,28 +8,6 @@ ...@@ -20,28 +8,6 @@
} }
} }
@mixin tanuki-second-highlight-animations($tanuki-color) {
@include unique-keyframes {
10%, 80% {
fill: #{$tanuki-color}
}
20%, 90% {
fill: lighten($tanuki-color, 25%);
}
}
}
@mixin tanuki-forth-highlight-animations($tanuki-color) {
@include unique-keyframes {
30%, 60% {
fill: #{$tanuki-color};
}
40%, 70% {
fill: lighten($tanuki-color, 25%);
}
}
}
.tanuki-logo { .tanuki-logo {
.tanuki-left-ear, .tanuki-left-ear,
...@@ -67,10 +33,11 @@ ...@@ -67,10 +33,11 @@
} }
.tanuki-left-cheek { .tanuki-left-cheek {
@include unique-keyframes { @include include-keyframes(animate-tanuki-left-cheek) {
0%, 10%, 100% { 0%, 10%, 100% {
fill: lighten($tanuki-yellow, 25%); fill: lighten($tanuki-yellow, 25%);
} }
90% { 90% {
fill: $tanuki-yellow; fill: $tanuki-yellow;
} }
...@@ -78,18 +45,35 @@ ...@@ -78,18 +45,35 @@
} }
.tanuki-left-eye { .tanuki-left-eye {
@include tanuki-second-highlight-animations($tanuki-orange); @include include-keyframes(animate-tanuki-left-eye) {
10%, 80% {
fill: $tanuki-orange;
}
20%, 90% {
fill: lighten($tanuki-orange, 25%);
}
}
} }
.tanuki-left-ear { .tanuki-left-ear {
@include tanuki-second-highlight-animations($tanuki-red); @include include-keyframes(animate-tanuki-left-ear) {
10%, 80% {
fill: $tanuki-red;
}
20%, 90% {
fill: lighten($tanuki-red, 25%);
}
}
} }
.tanuki-nose { .tanuki-nose {
@include unique-keyframes { @include include-keyframes(animate-tanuki-nose) {
20%, 70% { 20%, 70% {
fill: $tanuki-red; fill: $tanuki-red;
} }
30%, 80% { 30%, 80% {
fill: lighten($tanuki-red, 25%); fill: lighten($tanuki-red, 25%);
} }
...@@ -97,22 +81,39 @@ ...@@ -97,22 +81,39 @@
} }
.tanuki-right-eye { .tanuki-right-eye {
@include tanuki-forth-highlight-animations($tanuki-orange); @include include-keyframes(animate-tanuki-right-eye) {
30%, 60% {
fill: $tanuki-orange;
}
40%, 70% {
fill: lighten($tanuki-orange, 25%);
}
}
} }
.tanuki-right-ear { .tanuki-right-ear {
@include tanuki-forth-highlight-animations($tanuki-red); @include include-keyframes(animate-tanuki-right-ear) {
30%, 60% {
fill: $tanuki-red;
}
40%, 70% {
fill: lighten($tanuki-red, 25%);
}
}
} }
.tanuki-right-cheek { .tanuki-right-cheek {
@include unique-keyframes { @include include-keyframes(animate-tanuki-right-cheek) {
40% { 40% {
fill: $tanuki-yellow; fill: $tanuki-yellow;
} }
60% { 60% {
fill: lighten($tanuki-yellow, 25%); fill: lighten($tanuki-yellow, 25%);
} }
} }
} }
} }
} }
\ No newline at end of file
...@@ -86,7 +86,7 @@ ...@@ -86,7 +86,7 @@
} }
.markdown-area { .markdown-area {
@include border-radius(0); border-radius: 0;
background: #fff; background: #fff;
border: 1px solid #ddd; border: 1px solid #ddd;
min-height: 140px; min-height: 140px;
......
/**
* Generic mixins
*/
@mixin box-shadow($shadow) {
box-shadow: $shadow;
}
@mixin border-radius($radius) {
border-radius: $radius;
}
/** /**
* Prefilled mixins * Prefilled mixins
* Mixins with fixed values * Mixins with fixed values
...@@ -45,6 +34,7 @@ ...@@ -45,6 +34,7 @@
&.active { &.active {
background: $gray-light; background: $gray-light;
a { a {
font-weight: 600; font-weight: 600;
} }
...@@ -95,3 +85,10 @@ ...@@ -95,3 +85,10 @@
@content; @content;
} }
} }
@mixin include-keyframes($animation-name) {
@include webkit-prefix(animation-name, $animation-name);
@include keyframes($animation-name) {
@content;
}
}
...@@ -133,5 +133,5 @@ ...@@ -133,5 +133,5 @@
font-size: 20px; font-size: 20px;
color: #777; color: #777;
z-index: 100; z-index: 100;
@include box-shadow(0 1px 2px #ddd); box-shadow: 0 1px 2px #ddd;
} }
...@@ -210,6 +210,7 @@ ...@@ -210,6 +210,7 @@
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
padding-bottom: 0; padding-bottom: 0;
width: 100%; width: 100%;
.btn, form, .dropdown, .dropdown-menu-toggle, .form-control { .btn, form, .dropdown, .dropdown-menu-toggle, .form-control {
margin: 0 0 10px; margin: 0 0 10px;
display: block; display: block;
......
...@@ -13,6 +13,11 @@ ...@@ -13,6 +13,11 @@
.dropdown-menu-toggle { .dropdown-menu-toggle {
line-height: 20px; line-height: 20px;
} }
.badge {
margin-top: -2px;
margin-left: 5px;
}
} }
.panel-body { .panel-body {
......
...@@ -46,8 +46,8 @@ ...@@ -46,8 +46,8 @@
} }
.select2-drop { .select2-drop {
@include box-shadow(rgba(76, 86, 103, 0.247059) 0 0 1px 0, rgba(31, 37, 50, 0.317647) 0 2px 18px 0); box-shadow: rgba(76, 86, 103, 0.247059) 0 0 1px 0, rgba(31, 37, 50, 0.317647) 0 2px 18px 0;
@include border-radius ($border-radius-default); border-radius: $border-radius-default;
border: none; border: none;
min-width: 175px; min-width: 175px;
} }
...@@ -72,7 +72,7 @@ ...@@ -72,7 +72,7 @@
.select2-container-active { .select2-container-active {
.select2-choice, .select2-choices { .select2-choice, .select2-choices {
@include box-shadow(none); box-shadow: none;
} }
} }
...@@ -82,18 +82,18 @@ ...@@ -82,18 +82,18 @@
outline: 0; outline: 0;
background-image: none; background-image: none;
background-color: $white-dark; background-color: $white-dark;
@include box-shadow($gl-btn-active-gradient); box-shadow: $gl-btn-active-gradient;
} }
} }
.select2-container-multi { .select2-container-multi {
.select2-choices { .select2-choices {
@include border-radius($border-radius-default); border-radius: $border-radius-default;
border-color: $input-border; border-color: $input-border;
background: none; background: none;
.select2-search-field input { .select2-search-field input {
padding: $gl-padding / 2; padding: 5px $gl-padding / 2;
font-size: 13px; font-size: 13px;
height: auto; height: auto;
font-family: inherit; font-family: inherit;
...@@ -101,7 +101,7 @@ ...@@ -101,7 +101,7 @@
} }
.select2-search-choice { .select2-search-choice {
margin: 8px 0 0 8px; margin: 5px 0 0 8px;
box-shadow: none; box-shadow: none;
border-color: $input-border; border-color: $input-border;
color: $gl-text-color; color: $gl-text-color;
...@@ -123,7 +123,7 @@ ...@@ -123,7 +123,7 @@
&.select2-container-active .select2-choices, &.select2-container-active .select2-choices,
&.select2-dropdown-open .select2-choices { &.select2-dropdown-open .select2-choices {
border-color: $border-white-normal; border-color: $border-white-normal;
@include box-shadow($gl-btn-active-gradient); box-shadow: $gl-btn-active-gradient;
} }
} }
...@@ -137,6 +137,7 @@ ...@@ -137,6 +137,7 @@
.select2-results { .select2-results {
max-height: 350px; max-height: 350px;
.select2-highlighted { .select2-highlighted {
background: $gl-primary; background: $gl-primary;
} }
...@@ -157,7 +158,7 @@ ...@@ -157,7 +158,7 @@
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;
@include border-radius($border-radius-default); border-radius: $border-radius-default;
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
&:focus { &:focus {
...@@ -212,9 +213,11 @@ ...@@ -212,9 +213,11 @@
.group-image { .group-image {
float: left; float: left;
} }
.group-name { .group-name {
font-weight: bold; font-weight: bold;
} }
.group-path { .group-path {
color: #999; color: #999;
} }
...@@ -239,6 +242,7 @@ ...@@ -239,6 +242,7 @@
color: #aaa; color: #aaa;
font-weight: normal; font-weight: normal;
} }
.namespace-path { .namespace-path {
margin-left: 10px; margin-left: 10px;
font-weight: bolder; font-weight: bolder;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
&.page-sidebar-pinned { &.page-sidebar-pinned {
.sidebar-wrapper { .sidebar-wrapper {
@include box-shadow(none); box-shadow: none;
} }
} }
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
width: 0; width: 0;
overflow: hidden; overflow: hidden;
transition: width $sidebar-transition-duration; transition: width $sidebar-transition-duration;
@include box-shadow(2px 0 16px 0 $black-transparent); box-shadow: 2px 0 16px 0 $black-transparent;
} }
} }
...@@ -100,7 +100,7 @@ ...@@ -100,7 +100,7 @@
.count { .count {
float: right; float: right;
padding: 0 8px; padding: 0 8px;
@include border-radius(6px); border-radius: 6px;
} }
} }
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
&:before { &:before {
background: none; background: none;
} }
.timeline-entry .timeline-entry-inner { .timeline-entry .timeline-entry-inner {
.timeline-icon { .timeline-icon {
display: none; display: none;
......
...@@ -48,31 +48,40 @@ ...@@ -48,31 +48,40 @@
.clearfix { .clearfix {
@include clearfix(); @include clearfix();
} }
.center-block { .center-block {
@include center-block(); @include center-block();
} }
.pull-right { .pull-right {
float: right !important; float: right !important;
} }
.pull-left { .pull-left {
float: left !important; float: left !important;
} }
.hide { .hide {
display: none; display: none;
} }
.show { .show {
display: block !important; display: block !important;
} }
.invisible { .invisible {
visibility: hidden; visibility: hidden;
} }
.text-hide { .text-hide {
@include text-hide(); @include text-hide();
} }
.hidden { .hidden {
display: none !important; display: none !important;
visibility: hidden !important; visibility: hidden !important;
} }
.affix { .affix {
position: fixed; position: fixed;
} }
...@@ -146,6 +155,7 @@ ...@@ -146,6 +155,7 @@
padding: 6px 15px; padding: 6px 15px;
font-size: 13px; font-size: 13px;
font-weight: normal; font-weight: normal;
a { a {
color: #777; color: #777;
} }
......
...@@ -45,40 +45,38 @@ ...@@ -45,40 +45,38 @@
} }
h1 { h1 {
font-size: 2em; font-size: 1.75em;
font-weight: 600; font-weight: 600;
margin: 1em 0 10px; margin: 16px 0 10px;
padding: 0 0 0.3em; padding: 0 0 0.3em;
border-bottom: 1px solid $btn-default-border; border-bottom: 1px solid $white-dark;
color: $gl-gray-dark; color: $gl-gray-dark;
} }
h2 { h2 {
font-size: 1.6em; font-size: 1.5em;
font-weight: 600; font-weight: 600;
margin: 1em 0 10px; margin: 16px 0 10px;
padding-bottom: 0.3em;
border-bottom: 1px solid $btn-default-border;
color: $gl-gray-dark; color: $gl-gray-dark;
} }
h3 { h3 {
margin: 1em 0 10px; margin: 16px 0 10px;
font-size: 1.4em; font-size: 1.3em;
} }
h4 { h4 {
margin: 1em 0 10px; margin: 16px 0 10px;
font-size: 1.25em; font-size: 1.2em;
} }
h5 { h5 {
margin: 1em 0 10px; margin: 16px 0 10px;
font-size: 1em; font-size: 1em;
} }
h6 { h6 {
margin: 1em 0 10px; margin: 16px 0 10px;
font-size: 0.95em; font-size: 0.95em;
} }
...@@ -87,7 +85,12 @@ ...@@ -87,7 +85,12 @@
font-size: inherit; font-size: inherit;
padding: 8px 21px; padding: 8px 21px;
margin: 12px 0; margin: 12px 0;
border-left: 3px solid #e7e9ed; border-left: 3px solid $white-dark;
}
blockquote:dir(rtl) {
border-left: 0;
border-right: 3px solid $white-dark;
} }
blockquote p { blockquote p {
...@@ -106,17 +109,22 @@ ...@@ -106,17 +109,22 @@
@extend .table-bordered; @extend .table-bordered;
margin: 12px 0; margin: 12px 0;
color: #5c5d5e; color: #5c5d5e;
th { th {
background: #f8fafc; background: #f8fafc;
} }
} }
table:dir(rtl) th {
text-align: right;
}
pre { pre {
margin: 12px 0; margin: 12px 0;
font-size: 13px; font-size: 13px;
line-height: 1.6em; line-height: 1.6em;
overflow-x: auto; overflow-x: auto;
@include border-radius(2px); border-radius: 2px;
} }
p > code { p > code {
...@@ -128,6 +136,10 @@ ...@@ -128,6 +136,10 @@
margin: 3px 0 3px 28px !important; margin: 3px 0 3px 28px !important;
} }
ul:dir(rtl), ol:dir(rtl) {
margin: 3px 28px 3px 0 !important;
}
li { li {
line-height: 1.6em; line-height: 1.6em;
} }
......
This diff is collapsed.
...@@ -86,7 +86,7 @@ ...@@ -86,7 +86,7 @@
background-color: #fafe3d !important; background-color: #fafe3d !important;
} }
.hll { background-color: #f8f8f8 } .hll { background-color: #f8f8f8; }
.c { color: #998; font-style: italic; } .c { color: #998; font-style: italic; }
.err { color: #a61717; background-color: #e3d2d2; } .err { color: #a61717; background-color: #e3d2d2; }
.k { font-weight: bold; } .k { font-weight: bold; }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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