Commit cafa408b authored by Rémy Coutable's avatar Rémy Coutable

Merge remote-tracking branch 'origin/master' into remove-wip

parents 0b942541 18fc7c66
{
"always-semicolon": true,
"color-case": "lower",
"block-indent": " ",
"color-shorthand": true,
"element-case": "lower",
"space-before-colon": "",
"space-after-colon": " ",
"space-before-combinator": " ",
"space-after-combinator": " ",
"space-between-declarations": "\n",
"space-before-opening-brace": " ",
"space-after-opening-brace": "\n",
"space-before-closing-brace": "\n",
"unitless-zero": true
}
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
.sass-cache/ .sass-cache/
.secret .secret
.vagrant .vagrant
.byebug_history
Vagrantfile Vagrantfile
backups/* backups/*
config/aws.yml config/aws.yml
...@@ -23,6 +24,7 @@ config/gitlab.yml ...@@ -23,6 +24,7 @@ config/gitlab.yml
config/gitlab_ci.yml config/gitlab_ci.yml
config/initializers/rack_attack.rb config/initializers/rack_attack.rb
config/initializers/smtp_settings.rb config/initializers/smtp_settings.rb
config/initializers/relative_url.rb
config/resque.yml config/resque.yml
config/unicorn.rb config/unicorn.rb
config/secrets.yml config/secrets.yml
......
...@@ -12,16 +12,18 @@ cache: ...@@ -12,16 +12,18 @@ cache:
variables: variables:
MYSQL_ALLOW_EMPTY_PASSWORD: "1" MYSQL_ALLOW_EMPTY_PASSWORD: "1"
# retry tests only in CI environment
RSPEC_RETRY_RETRY_COUNT: "3"
before_script: before_script:
- source ./scripts/prepare_build.sh - source ./scripts/prepare_build.sh
- ruby -v - ruby -v
- which ruby - which ruby
- gem install bundler --no-ri --no-rdoc - retry gem install bundler --no-ri --no-rdoc
- cp config/gitlab.yml.example config/gitlab.yml - cp config/gitlab.yml.example config/gitlab.yml
- touch log/application.log - touch log/application.log
- touch log/test.log - touch log/test.log
- bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}" - retry bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}"
- RAILS_ENV=test bundle exec rake db:drop db:create db:schema:load db:migrate - RAILS_ENV=test bundle exec rake db:drop db:create db:schema:load db:migrate
stages: stages:
...@@ -69,15 +71,6 @@ spec:services: ...@@ -69,15 +71,6 @@ spec:services:
- ruby - ruby
- mysql - mysql
spec:benchmark:
stage: test
script:
- RAILS_ENV=test bundle exec rake spec:benchmark
tags:
- ruby
- mysql
allow_failure: true
spec:other: spec:other:
stage: test stage: test
script: script:
...@@ -89,6 +82,7 @@ spec:other: ...@@ -89,6 +82,7 @@ spec:other:
spinach:project:half: spinach:project:half:
stage: test stage: test
script: script:
- RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:half - RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:half
tags: tags:
- ruby - ruby
...@@ -97,6 +91,7 @@ spinach:project:half: ...@@ -97,6 +91,7 @@ spinach:project:half:
spinach:project:rest: spinach:project:rest:
stage: test stage: test
script: script:
- RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:rest - RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:rest
tags: tags:
- ruby - ruby
...@@ -105,6 +100,7 @@ spinach:project:rest: ...@@ -105,6 +100,7 @@ spinach:project:rest:
spinach:other: spinach:other:
stage: test stage: test
script: script:
- RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:other - RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:other
tags: tags:
- ruby - ruby
...@@ -126,6 +122,14 @@ rubocop: ...@@ -126,6 +122,14 @@ rubocop:
- ruby - ruby
- mysql - mysql
scss-lint:
stage: test
script:
- bundle exec rake scss_lint
tags:
- ruby
allow_failure: true
brakeman: brakeman:
stage: test stage: test
script: script:
...@@ -152,13 +156,14 @@ flay: ...@@ -152,13 +156,14 @@ flay:
bundler:audit: bundler:audit:
stage: test stage: test
only:
- master
script: script:
- "bundle exec bundle-audit update" - "bundle exec bundle-audit update"
- "bundle exec bundle-audit check" - "bundle exec bundle-audit check --ignore OSVDB-115941"
tags: tags:
- ruby - ruby
- mysql - mysql
allow_failure: true
# Ruby 2.2 jobs # Ruby 2.2 jobs
...@@ -166,7 +171,7 @@ spec:feature:ruby22: ...@@ -166,7 +171,7 @@ spec:feature:ruby22:
stage: test stage: test
image: ruby:2.2 image: ruby:2.2
only: only:
- master - master
script: script:
- RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null - RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:feature - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:feature
...@@ -238,22 +243,6 @@ spec:services:ruby22: ...@@ -238,22 +243,6 @@ spec:services:ruby22:
- ruby - ruby
- mysql - mysql
spec:benchmark:ruby22:
stage: test
image: ruby:2.2
only:
- master
script:
- RAILS_ENV=test bundle exec rake spec:benchmark
cache:
key: "ruby22"
paths:
- vendor
tags:
- ruby
- mysql
allow_failure: true
spec:other:ruby22: spec:other:ruby22:
stage: test stage: test
image: ruby:2.2 image: ruby:2.2
...@@ -275,6 +264,7 @@ spinach:project:half:ruby22: ...@@ -275,6 +264,7 @@ spinach:project:half:ruby22:
only: only:
- master - master
script: script:
- RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:half - RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:half
cache: cache:
key: "ruby22" key: "ruby22"
...@@ -290,6 +280,7 @@ spinach:project:rest:ruby22: ...@@ -290,6 +280,7 @@ spinach:project:rest:ruby22:
only: only:
- master - master
script: script:
- RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:rest - RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:rest
cache: cache:
key: "ruby22" key: "ruby22"
...@@ -305,6 +296,7 @@ spinach:other:ruby22: ...@@ -305,6 +296,7 @@ spinach:other:ruby22:
only: only:
- master - master
script: script:
- RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:other - RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:other
cache: cache:
key: "ruby22" key: "ruby22"
...@@ -318,10 +310,10 @@ spinach:other:ruby22: ...@@ -318,10 +310,10 @@ spinach:other:ruby22:
notify:slack: notify:slack:
stage: notifications stage: notifications
script: script:
- ./scripts/notify_slack.sh "#builds" "Build on \`$CI_BUILD_REF_NAME\` failed! Check <https://gitlab.com/gitlab-org/$(basename "$PWD")/commit/"$CI_BUILD_REF"/builds>" - ./scripts/notify_slack.sh "#builds" "Build on \`$CI_BUILD_REF_NAME\` failed! Commit \`$(git log -1 --oneline)\` See <https://gitlab.com/gitlab-org/$(basename "$PWD")/commit/"$CI_BUILD_REF"/builds>"
when: on_failure when: on_failure
only: only:
- master@gitlab-org/gitlab-ce - master@gitlab-org/gitlab-ce
- tags@gitlab-org/gitlab-ce - tags@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee - master@gitlab-org/gitlab-ee
- tags@gitlab-org/gitlab-ee - tags@gitlab-org/gitlab-ee
\ No newline at end of file
# Linter Documentation:
# https://github.com/brigade/scss-lint/blob/master/lib/scss_lint/linter/README.md
scss_files: 'app/assets/stylesheets/**/*.scss'
exclude:
- 'app/assets/stylesheets/pages/emojis.scss'
linters:
BangFormat:
enabled: false
BorderZero:
enabled: false
ColorKeyword:
enabled: false
ColorVariable:
enabled: false
Comment:
enabled: false
DeclarationOrder:
enabled: false
# `scss-lint:disable` control comments should be preceded by a comment
# explaining why these linters are being disabled for this file.
# See https://github.com/brigade/scss-lint#disabling-linters-via-source for
# more information.
DisableLinterReason:
enabled: true
DuplicateProperty:
enabled: false
EmptyLineBetweenBlocks:
enabled: false
EmptyRule:
enabled: false
FinalNewline:
enabled: false
# HEX colors should use three-character values where possible.
HexLength:
enabled: true
# HEX color values should use lower-case colors to differentiate between
# letters and numbers, e.g. `#E3E3E3` vs. `#e3e3e3`.
HexNotation:
enabled: true
IdSelector:
enabled: false
ImportPath:
enabled: false
ImportantRule:
enabled: false
# Indentation should always be done in increments of 2 spaces.
Indentation:
enabled: true
width: 2
LeadingZero:
enabled: false
MergeableSelector:
enabled: false
NameFormat:
enabled: false
NestingDepth:
enabled: false
PlaceholderInExtend:
enabled: false
PropertySortOrder:
enabled: false
PropertySpelling:
enabled: false
PseudoElement:
enabled: false
QualifyingElement:
enabled: false
SelectorDepth:
enabled: false
# Selectors should always use hyphenated-lowercase, rather than camelCase or
# snake_case.
SelectorFormat:
enabled: true
convention: hyphenated_lowercase
# Prefer the shortest shorthand form possible for properties that support it.
Shorthand:
enabled: true
# Each property should have its own line, except in the special case of
# single line rulesets.
SingleLinePerProperty:
enabled: true
allow_single_line_rule_sets: true
SingleLinePerSelector:
enabled: false
SpaceAfterComma:
enabled: false
# Properties should be formatted with a single space separating the colon
# from the property's value.
SpaceAfterPropertyColon:
enabled: true
# Properties should be formatted with no space between the name and the
# colon.
SpaceAfterPropertyName:
enabled: true
SpaceAroundOperator:
enabled: false
SpaceBeforeBrace:
enabled: false
StringQuotes:
enabled: false
TrailingSemicolon:
enabled: false
TrailingWhitespace:
enabled: false
UnnecessaryMantissa:
enabled: false
UnnecessaryParentReference:
enabled: false
VendorPrefix:
enabled: false
# Omit length units on zero values, e.g. `0px` vs. `0`.
ZeroUnit:
enabled: true
This diff is collapsed.
...@@ -3,24 +3,27 @@ ...@@ -3,24 +3,27 @@
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Contribute to GitLab](#contribute-to-gitlab) - [Contribute to GitLab](#contribute-to-gitlab)
- [Contributor license agreement](#contributor-license-agreement) - [Contributor license agreement](#contributor-license-agreement)
- [Security vulnerability disclosure](#security-vulnerability-disclosure) - [Security vulnerability disclosure](#security-vulnerability-disclosure)
- [Closing policy for issues and merge requests](#closing-policy-for-issues-and-merge-requests) - [Closing policy for issues and merge requests](#closing-policy-for-issues-and-merge-requests)
- [Helping others](#helping-others) - [Helping others](#helping-others)
- [I want to contribute!](#i-want-to-contribute) - [I want to contribute!](#i-want-to-contribute)
- [Issue tracker](#issue-tracker) - [Implement design & UI elements](#implement-design-ui-elements)
- [Feature proposals](#feature-proposals) - [Design reference](#design-reference)
- [Issue tracker guidelines](#issue-tracker-guidelines) - [UI development kit](#ui-development-kit)
- [Issue weight](#issue-weight) - [Issue tracker](#issue-tracker)
- [Regression issues](#regression-issues) - [Feature proposals](#feature-proposals)
- [Merge requests](#merge-requests) - [Issue tracker guidelines](#issue-tracker-guidelines)
- [Merge request guidelines](#merge-request-guidelines) - [Issue weight](#issue-weight)
- [Merge request description format](#merge-request-description-format) - [Regression issues](#regression-issues)
- [Contribution acceptance criteria](#contribution-acceptance-criteria) - [Merge requests](#merge-requests)
- [Changes for Stable Releases](#changes-for-stable-releases) - [Merge request guidelines](#merge-request-guidelines)
- [Definition of done](#definition-of-done) - [Merge request description format](#merge-request-description-format)
- [Style guides](#style-guides) - [Contribution acceptance criteria](#contribution-acceptance-criteria)
- [Code of conduct](#code-of-conduct) - [Changes for Stable Releases](#changes-for-stable-releases)
- [Definition of done](#definition-of-done)
- [Style guides](#style-guides)
- [Code of conduct](#code-of-conduct)
<!-- END doctoc generated TOC please keep comment here to allow auto update --> <!-- END doctoc generated TOC please keep comment here to allow auto update -->
...@@ -83,6 +86,22 @@ GitLab. ...@@ -83,6 +86,22 @@ GitLab.
This was inspired by [an article by Kent C. Dodds][medium-up-for-grabs]. This was inspired by [an article by Kent C. Dodds][medium-up-for-grabs].
## Implement design & UI elements
### Design reference
The GitLab design reference can be found in the [gitlab-design] project.
The designs are made using Antetype (`.atype` files). You can use the
[free Antetype viewer (Mac OSX only)] or grab an exported PNG from the design
(the PNG is 1:1).
The current designs can be found in the [`gitlab1.atype` file].
### UI development kit
Implemented UI elements can also be found at https://gitlab.com/help/ui. Please
note that this page isn't comprehensive at this time.
## Issue tracker ## Issue tracker
To get support for your particular problem please use the To get support for your particular problem please use the
...@@ -299,13 +318,14 @@ to us than having a minimal commit log. The smaller an MR is the more likely it ...@@ -299,13 +318,14 @@ to us than having a minimal commit log. The smaller an MR is the more likely it
is it will be merged (quickly). After that you can send more MRs to enhance it. is it will be merged (quickly). After that you can send more MRs to enhance it.
For examples of feedback on merge requests please look at already For examples of feedback on merge requests please look at already
[closed merge requests][closed-merge-requests]. If you would like quick feedback on your merge [closed merge requests][closed-merge-requests]. If you would like quick feedback
request feel free to mention one of the Merge Marshalls of the [core team][core-team]. on your merge request feel free to mention one of the Merge Marshalls in the
[core team][core-team] or one of the
[Merge request coaches](https://about.gitlab.com/team/).
Please ensure that your merge request meets the contribution acceptance criteria. 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
[thoughtbot code review guidelines](https://github.com/thoughtbot/guides/tree/master/code-review) [Thoughtbot code review guide] into account.
into account.
### Merge request description format ### Merge request description format
...@@ -343,7 +363,8 @@ description area. Copy-paste it to retain the markdown format. ...@@ -343,7 +363,8 @@ description area. Copy-paste it to retain the markdown format.
to a new table or remove an old table) to aid retrying on failure to a new table or remove an old table) to aid retrying on failure
1. Keeps the GitLab code base clean and well structured 1. Keeps the GitLab code base clean and well structured
1. Contains functionality we think other users will benefit from too 1. Contains functionality we think other users will benefit from too
1. Doesn't add configuration options since they complicate future changes 1. Doesn't add configuration options or settings options since they complicate
making and testing future changes
1. Changes after submitting the merge request should be in separate commits 1. Changes after submitting the merge request should be in separate commits
(no squashing). If necessary, you will be asked to squash when the review is (no squashing). If necessary, you will be asked to squash when the review is
over, before merging. over, before merging.
...@@ -406,6 +427,7 @@ merge request: ...@@ -406,6 +427,7 @@ merge request:
1. [Rails](https://github.com/bbatsov/rails-style-guide) 1. [Rails](https://github.com/bbatsov/rails-style-guide)
1. [Testing](https://github.com/thoughtbot/guides/tree/master/style/testing) 1. [Testing](https://github.com/thoughtbot/guides/tree/master/style/testing)
1. [CoffeeScript](https://github.com/thoughtbot/guides/tree/master/style/coffeescript) 1. [CoffeeScript](https://github.com/thoughtbot/guides/tree/master/style/coffeescript)
1. [SCSS styleguide][scss-styleguide]
1. [Shell commands](doc/development/shell_commands.md) created by GitLab 1. [Shell commands](doc/development/shell_commands.md) created by GitLab
contributors to enhance security contributors to enhance security
1. [Database Migrations](doc/development/migration_style_guide.md) 1. [Database Migrations](doc/development/migration_style_guide.md)
...@@ -473,3 +495,8 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor ...@@ -473,3 +495,8 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[rss-source]: https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#source-code-layout [rss-source]: https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#source-code-layout
[rss-naming]: https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#naming [rss-naming]: https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#naming
[doc-styleguide]: doc/development/doc_styleguide.md "Documentation styleguide" [doc-styleguide]: doc/development/doc_styleguide.md "Documentation styleguide"
[scss-styleguide]: doc/development/scss_styleguide.md "SCSS styleguide"
[gitlab-design]: https://gitlab.com/gitlab-org/gitlab-design
[free Antetype viewer (Mac OSX only)]: https://itunes.apple.com/us/app/antetype-viewer/id824152298?mt=12
[`gitlab1.atype` file]: https://gitlab.com/gitlab-org/gitlab-design/tree/master/gitlab1.atype/
[Thoughtbot code review guide]: https://github.com/thoughtbot/guides/tree/master/code-review
source "https://rubygems.org" source "https://rubygems.org"
gem 'rails', '4.2.5.1' gem 'rails', '4.2.5.2'
gem 'rails-deprecated_sanitizer', '~> 1.0.3' gem 'rails-deprecated_sanitizer', '~> 1.0.3'
# Responders respond_to and respond_with # Responders respond_to and respond_with
gem 'responders', '~> 2.0' gem 'responders', '~> 2.0'
# Specify a sprockets version due to security issue # Specify a sprockets version due to increased performance
# See https://groups.google.com/forum/#!topic/rubyonrails-security/doAVp0YaTqY # See https://gitlab.com/gitlab-org/gitlab-ce/issues/6069
gem 'sprockets', '~> 2.12.3' gem 'sprockets', '~> 3.3.5'
# Default values for AR models # Default values for AR models
gem "default_value_for", "~> 3.0.0" gem "default_value_for", "~> 3.0.0"
...@@ -22,6 +22,7 @@ gem 'devise', '~> 3.5.4' ...@@ -22,6 +22,7 @@ gem 'devise', '~> 3.5.4'
gem 'devise-async', '~> 0.9.0' gem 'devise-async', '~> 0.9.0'
gem 'doorkeeper', '~> 2.2.0' gem 'doorkeeper', '~> 2.2.0'
gem 'omniauth', '~> 1.3.1' gem 'omniauth', '~> 1.3.1'
gem 'omniauth-auth0', '~> 1.4.1'
gem 'omniauth-azure-oauth2', '~> 0.0.6' gem 'omniauth-azure-oauth2', '~> 0.0.6'
gem 'omniauth-bitbucket', '~> 0.0.2' gem 'omniauth-bitbucket', '~> 0.0.2'
gem 'omniauth-cas3', '~> 1.1.2' gem 'omniauth-cas3', '~> 1.1.2'
...@@ -30,7 +31,7 @@ gem 'omniauth-github', '~> 1.1.1' ...@@ -30,7 +31,7 @@ gem 'omniauth-github', '~> 1.1.1'
gem 'omniauth-gitlab', '~> 1.0.0' gem 'omniauth-gitlab', '~> 1.0.0'
gem 'omniauth-google-oauth2', '~> 0.2.0' gem 'omniauth-google-oauth2', '~> 0.2.0'
gem 'omniauth-kerberos', '~> 0.3.0', group: :kerberos gem 'omniauth-kerberos', '~> 0.3.0', group: :kerberos
gem 'omniauth-saml', '~> 1.4.2' gem 'omniauth-saml', '~> 1.5.0'
gem 'omniauth-shibboleth', '~> 1.2.0' gem 'omniauth-shibboleth', '~> 1.2.0'
gem 'omniauth-twitter', '~> 1.2.0' gem 'omniauth-twitter', '~> 1.2.0'
gem 'omniauth_crowd', '~> 2.2.0' gem 'omniauth_crowd', '~> 2.2.0'
...@@ -50,7 +51,7 @@ gem "browser", '~> 1.0.0' ...@@ -50,7 +51,7 @@ gem "browser", '~> 1.0.0'
# Extracting information from a git repository # Extracting information from a git repository
# Provide access to Gitlab::Git library # Provide access to Gitlab::Git library
gem "gitlab_git", '~> 8.2' gem "gitlab_git", '~> 10.0'
# 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
...@@ -58,7 +59,9 @@ gem "gitlab_git", '~> 8.2' ...@@ -58,7 +59,9 @@ gem "gitlab_git", '~> 8.2'
gem 'gitlab_omniauth-ldap', '~> 1.2.1', require: "omniauth-ldap" gem 'gitlab_omniauth-ldap', '~> 1.2.1', require: "omniauth-ldap"
# Git Wiki # Git Wiki
gem 'gollum-lib', '~> 4.1.0' # Required manually in config/initializers/gollum.rb to control load order
gem 'gollum-lib', '~> 4.1.0', require: false
gem 'gollum-rugged_adapter', '~> 0.4.2', require: false
# Language detection # Language detection
gem "github-linguist", "~> 4.7.0", require: "linguist" gem "github-linguist", "~> 4.7.0", require: "linguist"
...@@ -75,10 +78,7 @@ gem "kaminari", "~> 0.16.3" ...@@ -75,10 +78,7 @@ gem "kaminari", "~> 0.16.3"
gem "haml-rails", '~> 0.9.0' gem "haml-rails", '~> 0.9.0'
# Files attachments # Files attachments
gem "carrierwave", '~> 0.9.0' gem "carrierwave", '~> 0.10.0'
# Image editing
gem "mini_magick", '~> 4.4.0'
# Drag and Drop UI # Drag and Drop UI
gem 'dropzonejs-rails', '~> 0.7.1' gem 'dropzonejs-rails', '~> 0.7.1'
...@@ -213,7 +213,6 @@ gem 'jquery-atwho-rails', '~> 1.3.2' ...@@ -213,7 +213,6 @@ gem 'jquery-atwho-rails', '~> 1.3.2'
gem 'jquery-rails', '~> 4.0.0' gem 'jquery-rails', '~> 4.0.0'
gem 'jquery-scrollto-rails', '~> 1.4.3' gem 'jquery-scrollto-rails', '~> 1.4.3'
gem 'jquery-ui-rails', '~> 5.0.0' gem 'jquery-ui-rails', '~> 5.0.0'
gem 'nprogress-rails', '~> 0.1.6.7'
gem 'raphael-rails', '~> 2.1.2' gem 'raphael-rails', '~> 2.1.2'
gem 'request_store', '~> 1.2.0' gem 'request_store', '~> 1.2.0'
gem 'select2-rails', '~> 3.5.9' gem 'select2-rails', '~> 3.5.9'
...@@ -261,10 +260,12 @@ group :development, :test do ...@@ -261,10 +260,12 @@ group :development, :test do
gem 'awesome_print', '~> 1.2.0', require: false gem 'awesome_print', '~> 1.2.0', require: false
gem 'fuubar', '~> 2.0.0' gem 'fuubar', '~> 2.0.0'
gem 'database_cleaner', '~> 1.4.0' gem 'database_cleaner', '~> 1.4.0'
gem 'factory_girl_rails', '~> 4.3.0' gem 'factory_girl_rails', '~> 4.6.0'
gem 'rspec-rails', '~> 3.3.0' gem 'rspec-rails', '~> 3.3.0'
gem 'spinach-rails', '~> 0.2.1' gem 'rspec-retry'
gem 'spinach-rails', '~> 0.2.1'
gem 'spinach-rerun-reporter', '~> 0.0.2'
# Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826) # Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826)
gem 'minitest', '~> 5.7.0' gem 'minitest', '~> 5.7.0'
...@@ -272,19 +273,20 @@ group :development, :test do ...@@ -272,19 +273,20 @@ group :development, :test do
# Generate Fake data # Generate Fake data
gem 'ffaker', '~> 2.0.0' gem 'ffaker', '~> 2.0.0'
gem 'capybara', '~> 2.4.0' gem 'capybara', '~> 2.6.2'
gem 'capybara-screenshot', '~> 1.0.0' gem 'capybara-screenshot', '~> 1.0.0'
gem 'poltergeist', '~> 1.8.1' gem 'poltergeist', '~> 1.9.0'
gem 'teaspoon', '~> 1.0.0' gem 'teaspoon', '~> 1.0.0'
gem 'teaspoon-jasmine', '~> 2.2.0' gem 'teaspoon-jasmine', '~> 2.2.0'
gem 'spring', '~> 1.3.6' gem 'spring', '~> 1.6.4'
gem 'spring-commands-rspec', '~> 1.0.4' gem 'spring-commands-rspec', '~> 1.0.4'
gem 'spring-commands-spinach', '~> 1.0.0' gem 'spring-commands-spinach', '~> 1.0.0'
gem 'spring-commands-teaspoon', '~> 0.0.2' gem 'spring-commands-teaspoon', '~> 0.0.2'
gem 'rubocop', '~> 0.35.0', require: false gem 'rubocop', '~> 0.35.0', require: false
gem 'scss_lint', '~> 0.47.0', require: false
gem 'coveralls', '~> 0.8.2', require: false gem 'coveralls', '~> 0.8.2', require: false
gem 'simplecov', '~> 0.10.0', require: false gem 'simplecov', '~> 0.10.0', require: false
gem 'flog', require: false gem 'flog', require: false
......
This diff is collapsed.
This diff is collapsed.
...@@ -68,7 +68,7 @@ GitLab is a Ruby on Rails application that runs on the following software: ...@@ -68,7 +68,7 @@ GitLab is a Ruby on Rails application that runs on the following software:
- Ubuntu/Debian/CentOS/RHEL - Ubuntu/Debian/CentOS/RHEL
- Ruby (MRI) 2.1 - Ruby (MRI) 2.1
- Git 1.7.10+ - Git 2.7.4+
- Redis 2.8+ - Redis 2.8+
- MySQL or PostgreSQL - MySQL or PostgreSQL
......
...@@ -4,4 +4,7 @@ ...@@ -4,4 +4,7 @@
require File.expand_path('../config/application', __FILE__) require File.expand_path('../config/application', __FILE__)
relative_url_conf = File.expand_path('../config/initializers/relative_url', __FILE__)
require relative_url_conf if File.exist?("#{relative_url_conf}.rb")
Gitlab::Application.load_tasks Gitlab::Application.load_tasks
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
namespaces_path: "/api/:version/namespaces.json" namespaces_path: "/api/:version/namespaces.json"
group_projects_path: "/api/:version/groups/:id/projects.json" group_projects_path: "/api/:version/groups/:id/projects.json"
projects_path: "/api/:version/projects.json" projects_path: "/api/:version/projects.json"
labels_path: "/api/:version/projects/:id/labels"
group: (group_id, callback) -> group: (group_id, callback) ->
url = Api.buildUrl(Api.group_path) url = Api.buildUrl(Api.group_path)
...@@ -61,6 +62,19 @@ ...@@ -61,6 +62,19 @@
).done (projects) -> ).done (projects) ->
callback(projects) callback(projects)
newLabel: (project_id, data, callback) ->
url = Api.buildUrl(Api.labels_path)
url = url.replace(':id', project_id)
data.private_token = gon.api_token
$.ajax(
url: url
type: "POST"
data: data
dataType: "json"
).done (label) ->
callback(label)
# Return group projects list. Filtered by query # Return group projects list. Filtered by query
groupProjects: (group_id, query, callback) -> groupProjects: (group_id, query, callback) ->
url = Api.buildUrl(Api.group_projects_path) url = Api.buildUrl(Api.group_projects_path)
......
...@@ -31,8 +31,6 @@ ...@@ -31,8 +31,6 @@
#= require ace/ace #= require ace/ace
#= require ace/ext-searchbox #= require ace/ext-searchbox
#= require underscore #= require underscore
#= require nprogress
#= require nprogress-turbolinks
#= require dropzone #= require dropzone
#= require mousetrap #= require mousetrap
#= require mousetrap/pause #= require mousetrap/pause
...@@ -44,7 +42,6 @@ ...@@ -44,7 +42,6 @@
#= require jquery.nicescroll #= require jquery.nicescroll
#= require_tree . #= require_tree .
#= require fuzzaldrin-plus #= require fuzzaldrin-plus
#= require cropper.js
window.slugify = (text) -> window.slugify = (text) ->
text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase() text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase()
...@@ -110,6 +107,8 @@ window.onload = -> ...@@ -110,6 +107,8 @@ window.onload = ->
setTimeout shiftWindow, 100 setTimeout shiftWindow, 100
$ -> $ ->
bootstrapBreakpoint = bp.getBreakpointSize()
$(".nicescroll").niceScroll(cursoropacitymax: '0.4', cursorcolor: '#FFF', cursorborder: "1px solid #FFF") $(".nicescroll").niceScroll(cursoropacitymax: '0.4', cursorcolor: '#FFF', cursorborder: "1px solid #FFF")
# Click a .js-select-on-focus field, select the contents # Click a .js-select-on-focus field, select the contents
...@@ -222,71 +221,50 @@ $ -> ...@@ -222,71 +221,50 @@ $ ->
.off 'breakpoint:change' .off 'breakpoint:change'
.on 'breakpoint:change', (e, breakpoint) -> .on 'breakpoint:change', (e, breakpoint) ->
if breakpoint is 'sm' or breakpoint is 'xs' if breakpoint is 'sm' or breakpoint is 'xs'
$gutterIcon = $('.gutter-toggle').find('i') $gutterIcon = $('.js-sidebar-toggle').find('i')
if $gutterIcon.hasClass('fa-angle-double-right') if $gutterIcon.hasClass('fa-angle-double-right')
$gutterIcon.closest('a').trigger('click') $gutterIcon.closest('a').trigger('click')
$(document) $(document)
.off 'click', 'aside .gutter-toggle' .off 'click', '.js-sidebar-toggle'
.on 'click', 'aside .gutter-toggle', (e) -> .on 'click', '.js-sidebar-toggle', (e, triggered) ->
e.preventDefault() e.preventDefault()
$this = $(this) $this = $(this)
$thisIcon = $this.find 'i' $thisIcon = $this.find 'i'
$allGutterToggleIcons = $('.js-sidebar-toggle i')
if $thisIcon.hasClass('fa-angle-double-right') if $thisIcon.hasClass('fa-angle-double-right')
$thisIcon $allGutterToggleIcons
.removeClass('fa-angle-double-right') .removeClass('fa-angle-double-right')
.addClass('fa-angle-double-left') .addClass('fa-angle-double-left')
$this $('aside.right-sidebar')
.closest('aside')
.removeClass('right-sidebar-expanded') .removeClass('right-sidebar-expanded')
.addClass('right-sidebar-collapsed') .addClass('right-sidebar-collapsed')
$('.page-with-sidebar') $('.page-with-sidebar')
.removeClass('right-sidebar-expanded') .removeClass('right-sidebar-expanded')
.addClass('right-sidebar-collapsed') .addClass('right-sidebar-collapsed')
else else
$thisIcon $allGutterToggleIcons
.removeClass('fa-angle-double-left') .removeClass('fa-angle-double-left')
.addClass('fa-angle-double-right') .addClass('fa-angle-double-right')
$this $('aside.right-sidebar')
.closest('aside')
.removeClass('right-sidebar-collapsed') .removeClass('right-sidebar-collapsed')
.addClass('right-sidebar-expanded') .addClass('right-sidebar-expanded')
$('.page-with-sidebar') $('.page-with-sidebar')
.removeClass('right-sidebar-collapsed') .removeClass('right-sidebar-collapsed')
.addClass('right-sidebar-expanded') .addClass('right-sidebar-expanded')
$.cookie("collapsed_gutter", if not triggered
$('.right-sidebar') $.cookie("collapsed_gutter",
.hasClass('right-sidebar-collapsed'), { path: '/' }) $('.right-sidebar')
.hasClass('right-sidebar-collapsed'), { path: '/' })
bootstrapBreakpoint = undefined;
checkBootstrapBreakpoints = ->
if $('.device-xs').is(':visible')
bootstrapBreakpoint = "xs"
else if $('.device-sm').is(':visible')
bootstrapBreakpoint = "sm"
else if $('.device-md').is(':visible')
bootstrapBreakpoint = "md"
else if $('.device-lg').is(':visible')
bootstrapBreakpoint = "lg"
setBootstrapBreakpoints = ->
if $('.device-xs').length
return
$("body")
.append('<div class="device-xs visible-xs"></div>'+
'<div class="device-sm visible-sm"></div>'+
'<div class="device-md visible-md"></div>'+
'<div class="device-lg visible-lg"></div>')
checkBootstrapBreakpoints()
fitSidebarForSize = -> fitSidebarForSize = ->
oldBootstrapBreakpoint = bootstrapBreakpoint oldBootstrapBreakpoint = bootstrapBreakpoint
checkBootstrapBreakpoints() bootstrapBreakpoint = bp.getBreakpointSize()
if bootstrapBreakpoint != oldBootstrapBreakpoint if bootstrapBreakpoint != oldBootstrapBreakpoint
$(document).trigger('breakpoint:change', [bootstrapBreakpoint]) $(document).trigger('breakpoint:change', [bootstrapBreakpoint])
checkInitialSidebarSize = -> checkInitialSidebarSize = ->
bootstrapBreakpoint = bp.getBreakpointSize()
if bootstrapBreakpoint is "xs" or "sm" if bootstrapBreakpoint is "xs" or "sm"
$(document).trigger('breakpoint:change', [bootstrapBreakpoint]) $(document).trigger('breakpoint:change', [bootstrapBreakpoint])
...@@ -295,6 +273,5 @@ $ -> ...@@ -295,6 +273,5 @@ $ ->
.on "resize", (e) -> .on "resize", (e) ->
fitSidebarForSize() fitSidebarForSize()
setBootstrapBreakpoints()
checkInitialSidebarSize() checkInitialSidebarSize()
new Aside() new Aside()
class @AwardsHandler class @AwardsHandler
constructor: (@post_emoji_url, @noteable_type, @noteable_id, @aliases) -> constructor: (@post_emoji_url, @noteable_type, @noteable_id, @aliases) ->
$(".add-award").click (event) => $(".js-add-award").on "click", (event) =>
event.stopPropagation() event.stopPropagation()
event.preventDefault() event.preventDefault()
...@@ -9,27 +9,46 @@ class @AwardsHandler ...@@ -9,27 +9,46 @@ class @AwardsHandler
$("html").on 'click', (event) -> $("html").on 'click', (event) ->
if !$(event.target).closest(".emoji-menu").length if !$(event.target).closest(".emoji-menu").length
if $(".emoji-menu").is(":visible") if $(".emoji-menu").is(":visible")
$(".emoji-menu").hide() $(".emoji-menu").removeClass "is-visible"
$(".awards")
.off "click"
.on "click", ".js-emoji-btn", @handleClick
@renderFrequentlyUsedBlock() @renderFrequentlyUsedBlock()
@setupSearch()
handleClick: (e) ->
e.preventDefault()
emoji = $(this)
.find(".icon")
.data "emoji"
awards_handler.addAward emoji
showEmojiMenu: -> showEmojiMenu: ->
if $(".emoji-menu").length if $(".emoji-menu").length
$(".emoji-menu").show() if $(".emoji-menu").is ".is-visible"
$("#emoji_search").focus() $(".emoji-menu").removeClass "is-visible"
else $("#emoji_search").blur()
$.get "/emojis", (response) -> else
$(".add-award").after response $(".emoji-menu").addClass "is-visible"
$(".emoji-menu").show()
$("#emoji_search").focus() $("#emoji_search").focus()
else
$('.js-add-award').addClass "is-loading"
$.get "/emojis", (response) =>
$('.js-add-award').removeClass "is-loading"
$(".js-award-holder").append response
setTimeout =>
$(".emoji-menu").addClass "is-visible"
$("#emoji_search").focus()
@setupSearch()
, 200
addAward: (emoji) -> addAward: (emoji) ->
emoji = @normilizeEmojiName(emoji) emoji = @normilizeEmojiName(emoji)
@postEmoji emoji, => @postEmoji emoji, =>
@addAwardToEmojiBar(emoji) @addAwardToEmojiBar(emoji)
$(".emoji-menu").hide() $(".emoji-menu").removeClass "is-visible"
addAwardToEmojiBar: (emoji) -> addAwardToEmojiBar: (emoji) ->
@addEmojiToFrequentlyUsedList(emoji) @addEmojiToFrequentlyUsedList(emoji)
...@@ -39,7 +58,7 @@ class @AwardsHandler ...@@ -39,7 +58,7 @@ class @AwardsHandler
if @isActive(emoji) if @isActive(emoji)
@decrementCounter(emoji) @decrementCounter(emoji)
else else
counter = @findEmojiIcon(emoji).siblings(".counter") counter = @findEmojiIcon(emoji).siblings(".js-counter")
counter.text(parseInt(counter.text()) + 1) counter.text(parseInt(counter.text()) + 1)
counter.parent().addClass("active") counter.parent().addClass("active")
@addMeToAuthorList(emoji) @addMeToAuthorList(emoji)
...@@ -53,7 +72,7 @@ class @AwardsHandler ...@@ -53,7 +72,7 @@ class @AwardsHandler
@findEmojiIcon(emoji).parent().hasClass("active") @findEmojiIcon(emoji).parent().hasClass("active")
decrementCounter: (emoji) -> decrementCounter: (emoji) ->
counter = @findEmojiIcon(emoji).siblings(".counter") counter = @findEmojiIcon(emoji).siblings(".js-counter")
emojiIcon = counter.parent() emojiIcon = counter.parent()
if parseInt(counter.text()) > 1 if parseInt(counter.text()) > 1
counter.text(parseInt(counter.text()) - 1) counter.text(parseInt(counter.text()) - 1)
...@@ -70,9 +89,13 @@ class @AwardsHandler ...@@ -70,9 +89,13 @@ class @AwardsHandler
removeMeFromAuthorList: (emoji) -> removeMeFromAuthorList: (emoji) ->
award_block = @findEmojiIcon(emoji).parent() award_block = @findEmojiIcon(emoji).parent()
authors = award_block.attr("data-original-title").split(", ") authors = award_block
.attr("data-original-title")
.split(", ")
authors.splice(authors.indexOf("me"),1) authors.splice(authors.indexOf("me"),1)
award_block.closest(".award").attr("data-original-title", authors.join(", ")) award_block
.closest(".js-emoji-btn")
.attr("data-original-title", authors.join(", "))
@resetTooltip(award_block) @resetTooltip(award_block)
addMeToAuthorList: (emoji) -> addMeToAuthorList: (emoji) ->
...@@ -98,14 +121,18 @@ class @AwardsHandler ...@@ -98,14 +121,18 @@ class @AwardsHandler
emojiCssClass = @resolveNameToCssClass(emoji) emojiCssClass = @resolveNameToCssClass(emoji)
nodes = [] nodes = []
nodes.push("<div class='award active' title='me'>") nodes.push(
nodes.push("<div class='icon emoji-icon #{emojiCssClass}' data-emoji='#{emoji}'></div>") "<button class='btn award-control js-emoji-btn has_tooltip active' title='me'>",
nodes.push("<div class='counter'>1</div>") "<div class='icon emoji-icon #{emojiCssClass}' data-emoji='#{emoji}'></div>",
nodes.push("</div>") "<span class='award-control-text js-counter'>1</span>",
"</button>"
emoji_node = $(nodes.join("\n")).insertBefore(".awards-controls").find(".emoji-icon").data("emoji", emoji) )
$(".award").tooltip() emoji_node = $(nodes.join("\n"))
.insertBefore(".js-award-holder")
.find(".emoji-icon")
.data("emoji", emoji)
$('.award-control').tooltip()
resolveNameToCssClass: (emoji) -> resolveNameToCssClass: (emoji) ->
emoji_icon = $(".emoji-menu-content [data-emoji='#{emoji}']") emoji_icon = $(".emoji-menu-content [data-emoji='#{emoji}']")
...@@ -128,7 +155,7 @@ class @AwardsHandler ...@@ -128,7 +155,7 @@ class @AwardsHandler
callback.call() callback.call()
findEmojiIcon: (emoji) -> findEmojiIcon: (emoji) ->
$(".award [data-emoji='#{emoji}']") $(".awards > .js-emoji-btn [data-emoji='#{emoji}']")
scrollToAwards: -> scrollToAwards: ->
$('body, html').animate({ $('body, html').animate({
...@@ -164,13 +191,13 @@ class @AwardsHandler ...@@ -164,13 +191,13 @@ class @AwardsHandler
term = $(ev.target).val() term = $(ev.target).val()
# Clean previous search results # Clean previous search results
$("ul.emoji-search,h5.emoji-search").remove() $("ul.emoji-menu-search, h5.emoji-search").remove()
if term if term
# Generate a search result block # Generate a search result block
h5 = $("<h5>").text("Search results").addClass("emoji-search") h5 = $("<h5>").text("Search results").addClass("emoji-search")
found_emojis = @searchEmojis(term).show() found_emojis = @searchEmojis(term).show()
ul = $("<ul>").addClass("emoji-search").append(found_emojis) ul = $("<ul>").addClass("emoji-menu-list emoji-menu-search").append(found_emojis)
$(".emoji-menu-content ul, .emoji-menu-content h5").hide() $(".emoji-menu-content ul, .emoji-menu-content h5").hide()
$(".emoji-menu-content").append(h5).append(ul) $(".emoji-menu-content").append(h5).append(ul)
else else
......
# Quick Submit behavior # Quick Submit behavior
# #
# When an input field with the `js-quick-submit` class receives a "Meta+Enter" # When a child field of a form with a `js-quick-submit` class receives a
# (Mac) or "Ctrl+Enter" (Linux/Windows) key combination, its parent form is # "Meta+Enter" (Mac) or "Ctrl+Enter" (Linux/Windows) key combination, the form
# submitted. # is submitted.
# #
#= require extensions/jquery #= require extensions/jquery
# #
# ### Example Markup # ### Example Markup
# #
# <form action="/foo"> # <form action="/foo" class="js-quick-submit">
# <input type="text" class="js-quick-submit" /> # <input type="text" />
# <textarea class="js-quick-submit"></textarea> # <textarea></textarea>
# <input type="submit" value="Submit" />
# </form> # </form>
# #
isMac = ->
navigator.userAgent.match(/Macintosh/)
keyCodeIs = (e, keyCode) ->
return false if (e.originalEvent && e.originalEvent.repeat) || e.repeat
return e.keyCode == keyCode
$(document).on 'keydown.quick_submit', '.js-quick-submit', (e) -> $(document).on 'keydown.quick_submit', '.js-quick-submit', (e) ->
return if (e.originalEvent && e.originalEvent.repeat) || e.repeat return unless keyCodeIs(e, 13) # Enter
return unless e.keyCode == 13 # Enter
if navigator.userAgent.match(/Macintosh/) return unless (e.metaKey && !e.altKey && !e.ctrlKey && !e.shiftKey) || (e.ctrlKey && !e.altKey && !e.metaKey && !e.shiftKey)
return unless (e.metaKey && !e.altKey && !e.ctrlKey && !e.shiftKey)
else
return unless (e.ctrlKey && !e.altKey && !e.metaKey && !e.shiftKey)
e.preventDefault() e.preventDefault()
$form = $(e.target).closest('form') $form = $(e.target).closest('form')
$form.find('input[type=submit], button[type=submit]').disable() $form.find('input[type=submit], button[type=submit]').disable()
$form.submit() $form.submit()
# If the user tabs to a submit button on a `js-quick-submit` form, display a
# tooltip to let them know they could've used the hotkey
$(document).on 'keyup.quick_submit', '.js-quick-submit input[type=submit], .js-quick-submit button[type=submit]', (e) ->
return unless keyCodeIs(e, 9) # Tab
if isMac()
title = "You can also press &#8984;-Enter"
else
title = "You can also press Ctrl-Enter"
$this = $(@)
$this.tooltip(
container: 'body'
html: 'true'
placement: 'auto top'
title: title
trigger: 'manual'
).tooltip('show').one('blur', -> $this.tooltip('hide'))
class @Breakpoints
instance = null;
class BreakpointInstance
BREAKPOINTS = ["xs", "sm", "md", "lg"]
constructor: ->
@setup()
setup: ->
allDeviceSelector = BREAKPOINTS.map (breakpoint) ->
".device-#{breakpoint}"
return if $(allDeviceSelector.join(",")).length
# Create all the elements
els = $.map BREAKPOINTS, (breakpoint) ->
"<div class='device-#{breakpoint} visible-#{breakpoint}'></div>"
$("body").append els.join('')
visibleDevice: ->
allDeviceSelector = BREAKPOINTS.map (breakpoint) ->
".device-#{breakpoint}"
$(allDeviceSelector.join(",")).filter(":visible")
getBreakpointSize: ->
$visibleDevice = @visibleDevice
# the page refreshed via turbolinks
if not $visibleDevice().length
@setup()
$visibleDevice = @visibleDevice()
return $visibleDevice.attr("class").split("visible-")[1]
@get: ->
return instance ?= new BreakpointInstance
$ =>
@bp = Breakpoints.get()
...@@ -4,6 +4,8 @@ class CiBuild ...@@ -4,6 +4,8 @@ class CiBuild
constructor: (build_url, build_status) -> constructor: (build_url, build_status) ->
clearInterval(CiBuild.interval) clearInterval(CiBuild.interval)
@initScrollButtonAffix()
if build_status == "running" || build_status == "pending" if build_status == "running" || build_status == "pending"
# #
# Bind autoscroll button to follow build output # Bind autoscroll button to follow build output
...@@ -38,4 +40,15 @@ class CiBuild ...@@ -38,4 +40,15 @@ class CiBuild
checkAutoscroll: -> checkAutoscroll: ->
$("html,body").scrollTop $("#build-trace").height() if "enabled" is $("#autoscroll-button").data("state") $("html,body").scrollTop $("#build-trace").height() if "enabled" is $("#autoscroll-button").data("state")
initScrollButtonAffix: ->
$buildScroll = $('#js-build-scroll')
$body = $('body')
$buildTrace = $('#build-trace')
$buildScroll.affix(
offset:
bottom: ->
$body.outerHeight() - ($buildTrace.outerHeight() + $buildTrace.offset().top)
)
@CiBuild = CiBuild @CiBuild = CiBuild
@Dashboard =
init: ->
$(".projects-list-filter").off('keyup')
this.initSearch()
initSearch: ->
@timer = null
$(".projects-list-filter").on('keyup', ->
clearTimeout(@timer)
@timer = setTimeout(Dashboard.filterResults, 500)
)
filterResults: =>
$('.projects-list-holder').fadeTo(250, 0.5)
form = null
form = $("form#project-filter-form")
search = $(".projects-list-filter").val()
project_filter_url = form.attr('action') + '?' + form.serialize()
$.ajax
type: "GET"
url: form.attr('action')
data: form.serialize()
complete: ->
$('.projects-list-holder').fadeTo(250, 1)
success: (data) ->
$('.projects-list-holder').replaceWith(data.html)
# Change url so if user reload a page - search results are saved
history.replaceState {page: project_filter_url}, document.title, project_filter_url
dataType: "json"
...@@ -14,10 +14,7 @@ class Dispatcher ...@@ -14,10 +14,7 @@ class Dispatcher
path = page.split(':') path = page.split(':')
shortcut_handler = null shortcut_handler = null
switch page switch page
when 'explore:projects:index', 'explore:projects:starred', 'explore:projects:trending'
Dashboard.init()
when 'projects:issues:index' when 'projects:issues:index'
Issues.init() Issues.init()
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
...@@ -25,8 +22,10 @@ class Dispatcher ...@@ -25,8 +22,10 @@ class Dispatcher
new Issue() new Issue()
shortcut_handler = new ShortcutsIssuable() shortcut_handler = new ShortcutsIssuable()
new ZenMode() new ZenMode()
when 'projects:milestones:show' when 'projects:milestones:show', 'groups:milestones:show', 'dashboard:milestones:show'
new Milestone() new Milestone()
when 'dashboard:todos:index'
new Todos()
when 'projects:milestones:new', 'projects:milestones:edit' when 'projects:milestones:new', 'projects:milestones:edit'
new ZenMode() new ZenMode()
new DropzoneInput($('.milestone-form')) new DropzoneInput($('.milestone-form'))
...@@ -59,8 +58,6 @@ class Dispatcher ...@@ -59,8 +58,6 @@ class Dispatcher
when 'projects:merge_requests:index' when 'projects:merge_requests:index'
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
MergeRequests.init() MergeRequests.init()
when 'dashboard:show', 'root:show'
Dashboard.init()
when 'dashboard:activity' when 'dashboard:activity'
new Activities() new Activities()
when 'dashboard:projects:starred' when 'dashboard:projects:starred'
...@@ -78,8 +75,9 @@ class Dispatcher ...@@ -78,8 +75,9 @@ class Dispatcher
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
new TreeView() if $('#tree-slider').length new TreeView() if $('#tree-slider').length
when 'groups:show' when 'groups:activity'
new Activities() new Activities()
when 'groups:show'
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
when 'groups:group_members:index' when 'groups:group_members:index'
new GroupMembers() new GroupMembers()
...@@ -107,9 +105,8 @@ class Dispatcher ...@@ -107,9 +105,8 @@ class Dispatcher
new ProjectFork() new ProjectFork()
when 'projects:artifacts:browse' when 'projects:artifacts:browse'
new BuildArtifacts() new BuildArtifacts()
when 'users:show' when 'projects:group_links:index'
new User() new GroupsSelect()
new Activities()
switch path.first() switch path.first()
when 'admin' when 'admin'
......
class GitLabDropdownFilter
BLUR_KEYCODES = [27, 40]
constructor: (@dropdown, @options) ->
@input = @dropdown.find(".dropdown-input .dropdown-input-field")
# Key events
timeout = ""
@input.on "keyup", (e) =>
if e.keyCode is 13 && @input.val() isnt ""
if @options.enterCallback
@options.enterCallback()
return
clearTimeout timeout
timeout = setTimeout =>
blur_field = @shouldBlur e.keyCode
search_text = @input.val()
if blur_field
@input.blur()
if @options.remote
@options.query search_text, (data) =>
@options.callback(data)
else
@filter search_text
, 250
shouldBlur: (keyCode) ->
return BLUR_KEYCODES.indexOf(keyCode) >= 0
filter: (search_text) ->
data = @options.data()
results = data
if search_text isnt ""
results = fuzzaldrinPlus.filter(data, search_text,
key: @options.keys
)
@options.callback results
class GitLabDropdownRemote
constructor: (@dataEndpoint, @options) ->
execute: ->
if typeof @dataEndpoint is "string"
@fetchData()
else if typeof @dataEndpoint is "function"
if @options.beforeSend
@options.beforeSend()
# Fetch the data by calling the data funcfion
@dataEndpoint "", (data) =>
if @options.success
@options.success(data)
if @options.beforeSend
@options.beforeSend()
# Fetch the data through ajax if the data is a string
fetchData: ->
$.ajax(
url: @dataEndpoint,
dataType: @options.dataType,
beforeSend: =>
if @options.beforeSend
@options.beforeSend()
success: (data) =>
if @options.success
@options.success(data)
)
class GitLabDropdown
LOADING_CLASS = "is-loading"
PAGE_TWO_CLASS = "is-page-two"
ACTIVE_CLASS = "is-active"
constructor: (@el, @options) ->
self = @
@dropdown = $(@el).parent()
search_fields = if @options.search then @options.search.fields else [];
if @options.data
# Remote data
@remote = new GitLabDropdownRemote @options.data, {
dataType: @options.dataType,
beforeSend: @toggleLoading.bind(@)
success: (data) =>
@fullData = data
@parseData @fullData
}
# Init filiterable
if @options.filterable
@filter = new GitLabDropdownFilter @dropdown,
remote: @options.filterRemote
query: @options.data
keys: @options.search.fields
data: =>
return @fullData
callback: (data) =>
@parseData data
enterCallback: =>
@selectFirstRow()
# Event listeners
@dropdown.on "shown.bs.dropdown", @opened
@dropdown.on "hidden.bs.dropdown", @hidden
if @dropdown.find(".dropdown-toggle-page").length
@dropdown.find(".dropdown-toggle-page, .dropdown-menu-back").on "click", (e) =>
e.preventDefault()
e.stopPropagation()
@togglePage()
if @options.selectable
selector = ".dropdown-content a"
if @dropdown.find(".dropdown-toggle-page").length
selector = ".dropdown-page-one .dropdown-content a"
@dropdown.on "click", selector, (e) ->
self.rowClicked $(@)
if self.options.clicked
self.options.clicked()
toggleLoading: ->
$('.dropdown-menu', @dropdown).toggleClass LOADING_CLASS
togglePage: ->
menu = $('.dropdown-menu', @dropdown)
if menu.hasClass(PAGE_TWO_CLASS)
if @remote
@remote.execute()
menu.toggleClass PAGE_TWO_CLASS
parseData: (data) ->
@renderedData = data
# Render each row
html = $.map data, (obj) =>
return @renderItem(obj)
if @options.filterable and data.length is 0
# render no matching results
html = [@noResults()]
# Render the full menu
full_html = @renderMenu(html.join(""))
@appendMenu(full_html)
opened: =>
contentHtml = $('.dropdown-content', @dropdown).html()
if @remote && contentHtml is ""
@remote.execute()
if @options.filterable
@dropdown.find(".dropdown-input-field").focus()
hidden: =>
if @options.filterable
@dropdown.find(".dropdown-input-field").blur().val("")
if @dropdown.find(".dropdown-toggle-page").length
$('.dropdown-menu', @dropdown).removeClass PAGE_TWO_CLASS
# Render the full menu
renderMenu: (html) ->
menu_html = ""
if @options.renderMenu
menu_html = @options.renderMenu(html)
else
menu_html = "<ul>#{html}</ul>"
return menu_html
# Append the menu into the dropdown
appendMenu: (html) ->
selector = '.dropdown-content'
if @dropdown.find(".dropdown-toggle-page").length
selector = ".dropdown-page-one .dropdown-content"
$(selector, @dropdown).html html
# Render the row
renderItem: (data) ->
html = ""
return "<li class='divider'></li>" if data is "divider"
if @options.renderRow
# Call the render function
html = @options.renderRow(data)
else
selected = if @options.isSelected then @options.isSelected(data) else false
url = if @options.url then @options.url(data) else "#"
text = if @options.text then @options.text(data) else ""
cssClass = "";
if selected
cssClass = "is-active"
html = "<li>"
html += "<a href='#{url}' class='#{cssClass}'>"
html += text
html += "</a>"
html += "</li>"
return html
noResults: ->
html = "<li>"
html += "<a href='#' class='is-focused'>"
html += "No matching results."
html += "</a>"
html += "</li>"
rowClicked: (el) ->
fieldName = @options.fieldName
field = @dropdown.parent().find("input[name='#{fieldName}']")
if el.hasClass(ACTIVE_CLASS)
field.remove()
else
fieldName = @options.fieldName
selectedIndex = el.parent().index()
if @renderedData
selectedObject = @renderedData[selectedIndex]
value = if @options.id then @options.id(selectedObject, el) else selectedObject.id
if !value?
field.remove()
if @options.multiSelect
oldValue = field.val()
if oldValue
value = "#{oldValue},#{value}"
else
@dropdown.find(".#{ACTIVE_CLASS}").removeClass ACTIVE_CLASS
# Toggle active class for the tick mark
el.toggleClass "is-active"
# Toggle the dropdown label
if @options.toggleLabel
$(@el).find(".dropdown-toggle-text").text @options.toggleLabel(selectedObject)
if value?
if !field.length
# Create hidden input for form
input = "<input type='hidden' name='#{fieldName}' />"
@dropdown.before input
@dropdown.parent().find("input[name='#{fieldName}']").val value
selectFirstRow: ->
selector = '.dropdown-content li:first-child a'
if @dropdown.find(".dropdown-toggle-page").length
selector = ".dropdown-page-one .dropdown-content li:first-child a"
# similute a click on the first link
$(selector).trigger "click"
$.fn.glDropdown = (opts) ->
return @.each ->
new GitLabDropdown @, opts
...@@ -7,6 +7,7 @@ class @Issue ...@@ -7,6 +7,7 @@ class @Issue
# Prevent duplicate event bindings # Prevent duplicate event bindings
@disableTaskList() @disableTaskList()
@fixAffixScroll() @fixAffixScroll()
@initParticipants()
if $('a.btn-close').length if $('a.btn-close').length
@initTaskList() @initTaskList()
@initIssueBtnEventListeners() @initIssueBtnEventListeners()
...@@ -84,3 +85,27 @@ class @Issue ...@@ -84,3 +85,27 @@ class @Issue
type: 'PATCH' type: 'PATCH'
url: $('form.js-issuable-update').attr('action') url: $('form.js-issuable-update').attr('action')
data: patchData data: patchData
initParticipants: ->
_this = @
$(document).on "click", ".js-participants-more", @toggleHiddenParticipants
$(".js-participants-author").each (i) ->
if i >= _this.PARTICIPANTS_ROW_COUNT
$(@)
.addClass "js-participants-hidden"
.hide()
toggleHiddenParticipants: (e) ->
e.preventDefault()
currentText = $(this).text().trim()
lessText = $(this).data("less-text")
originalText = $(this).data("original-text")
if currentText is originalText
$(this).text(lessText)
else
$(this).text(originalText)
$(".js-participants-hidden").toggle()
class @IssueStatusSelect
constructor: ->
$('.js-issue-status').each (i, el) ->
fieldName = $(el).data("field-name")
$(el).glDropdown(
selectable: true
fieldName: fieldName
id: (obj, el) ->
$(el).data("id")
)
...@@ -41,24 +41,28 @@ ...@@ -41,24 +41,28 @@
@timer = null @timer = null
$("#issue_search").keyup -> $("#issue_search").keyup ->
clearTimeout(@timer) clearTimeout(@timer)
@timer = setTimeout(Issues.filterResults, 500) @timer = setTimeout( ->
Issues.filterResults $("#issue_search_form")
, 500)
filterResults: => filterResults: (form) =>
form = $("#issue_search_form") $('.issues-holder, .merge-requests-holder').css("opacity", '0.5')
search = $("#issue_search").val() formAction = form.attr('action')
$('.issues-holder').css("opacity", '0.5') formData = form.serialize()
issues_url = form.attr('action') + '?' + form.serialize() issuesUrl = formAction
issuesUrl += ("#{if formAction.indexOf("?") < 0 then '?' else '&'}")
issuesUrl += formData
$.ajax $.ajax
type: "GET" type: "GET"
url: form.attr('action') url: formAction
data: form.serialize() data: formData
complete: -> complete: ->
$('.issues-holder').css("opacity", '1.0') $('.issues-holder, .merge-requests-holder').css("opacity", '1.0')
success: (data) -> success: (data) ->
$('.issues-holder').html(data.html) $('.issues-holder, .merge-requests-holder').html(data.html)
# Change url so if user reload a page - search results are saved # Change url so if user reload a page - search results are saved
history.replaceState {page: issues_url}, document.title, issues_url history.replaceState {page: issuesUrl}, document.title, issuesUrl
Issues.reload() Issues.reload()
dataType: "json" dataType: "json"
......
class @LabelsSelect
constructor: ->
$('.js-label-select').each (i, dropdown) ->
$dropdown = $(dropdown)
projectId = $dropdown.data('project-id')
labelUrl = $dropdown.data('labels')
selectedLabel = $dropdown.data('selected')
if selectedLabel
selectedLabel = selectedLabel.split(',')
newLabelField = $('#new_label_name')
newColorField = $('#new_label_color')
showNo = $dropdown.data('show-no')
showAny = $dropdown.data('show-any')
defaultLabel = $dropdown.data('default-label')
if newLabelField.length
$('.suggest-colors-dropdown a').on 'click', (e) ->
e.preventDefault()
e.stopPropagation()
newColorField.val $(this).data('color')
$('.js-dropdown-label-color-preview')
.css 'background-color', $(this).data('color')
.addClass 'is-active'
$('.js-new-label-btn').on 'click', (e) ->
e.preventDefault()
e.stopPropagation()
if newLabelField.val() isnt '' and newColorField.val() isnt ''
$('.js-new-label-btn').disable()
# Create new label with API
Api.newLabel projectId, {
name: newLabelField.val()
color: newColorField.val()
}, (label) ->
$('.js-new-label-btn').enable()
$('.dropdown-menu-back', $dropdown.parent()).trigger 'click'
$dropdown.glDropdown(
data: (term, callback) ->
$.ajax(
url: labelUrl
).done (data) ->
if showNo
data.unshift(
id: 0
title: 'No Label'
)
if showAny
data.unshift(
isAny: true
title: 'Any Label'
)
if data.length > 2
data.splice 2, 0, 'divider'
callback data
renderRow: (label) ->
if $.isArray(selectedLabel)
selected = ''
$.each selectedLabel, (i, selectedLbl) ->
selectedLbl = selectedLbl.trim()
if selected is '' and label.title is selectedLbl
selected = 'is-active'
else
selected = if label.title is selectedLabel then 'is-active' else ''
"<li>
<a href='#' class='#{selected}'>
#{label.title}
</a>
</li>"
filterable: true
search:
fields: ['title']
selectable: true
toggleLabel: (selected) ->
if selected and selected.title isnt 'Any Label'
selected.title
else
defaultLabel
fieldName: $dropdown.data('field-name')
id: (label) ->
if label.isAny?
''
else
label.title
clicked: ->
page = $('body').data 'page'
isIssueIndex = page is 'projects:issues:index'
isMRIndex = page is page is 'projects:merge_requests:index'
if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
Issues.filterResults $dropdown.closest('form')
else if $dropdown.hasClass 'js-filter-submit'
$dropdown.closest('form').submit()
)
NProgress.configure(showSpinner: false) Turbolinks.enableProgressBar();
defaultClass = 'tanuki-shape' defaultClass = 'tanuki-shape'
pieces = [ pieces = [
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
class @MarkdownPreview class @MarkdownPreview
# Minimum number of users referenced before triggering a warning # Minimum number of users referenced before triggering a warning
referenceThreshold: 10 referenceThreshold: 10
ajaxCache: {}
showPreview: (form) -> showPreview: (form) ->
preview = form.find('.js-md-preview') preview = form.find('.js-md-preview')
...@@ -24,12 +25,16 @@ class @MarkdownPreview ...@@ -24,12 +25,16 @@ class @MarkdownPreview
renderMarkdown: (text, success) -> renderMarkdown: (text, success) ->
return unless window.markdown_preview_path return unless window.markdown_preview_path
return success(@ajaxCache.response) if text == @ajaxCache.text
$.ajax $.ajax
type: 'POST' type: 'POST'
url: window.markdown_preview_path url: window.markdown_preview_path
data: { text: text } data: { text: text }
dataType: 'json' dataType: 'json'
success: success success: (response) =>
@ajaxCache = text: text, response: response
success(response)
hideReferencedUsers: (form) -> hideReferencedUsers: (form) ->
referencedUsers = form.find('.referenced-users') referencedUsers = form.find('.referenced-users')
...@@ -49,6 +54,7 @@ markdownPreview = new MarkdownPreview() ...@@ -49,6 +54,7 @@ markdownPreview = new MarkdownPreview()
previewButtonSelector = '.js-md-preview-button' previewButtonSelector = '.js-md-preview-button'
writeButtonSelector = '.js-md-write-button' writeButtonSelector = '.js-md-write-button'
lastTextareaPreviewed = null
$.fn.setupMarkdownPreview = -> $.fn.setupMarkdownPreview = ->
$form = $(this) $form = $(this)
...@@ -58,10 +64,10 @@ $.fn.setupMarkdownPreview = -> ...@@ -58,10 +64,10 @@ $.fn.setupMarkdownPreview = ->
form_textarea.on 'input', -> markdownPreview.hideReferencedUsers($form) form_textarea.on 'input', -> markdownPreview.hideReferencedUsers($form)
form_textarea.on 'blur', -> markdownPreview.showPreview($form) form_textarea.on 'blur', -> markdownPreview.showPreview($form)
$(document).on 'click', previewButtonSelector, (e) -> $(document).on 'markdown-preview:show', (e, $form) ->
e.preventDefault() return unless $form
$form = $(this).closest('form') lastTextareaPreviewed = $form.find('textarea.markdown-area')
# toggle tabs # toggle tabs
$form.find(writeButtonSelector).parent().removeClass('active') $form.find(writeButtonSelector).parent().removeClass('active')
...@@ -73,10 +79,10 @@ $(document).on 'click', previewButtonSelector, (e) -> ...@@ -73,10 +79,10 @@ $(document).on 'click', previewButtonSelector, (e) ->
markdownPreview.showPreview($form) markdownPreview.showPreview($form)
$(document).on 'click', writeButtonSelector, (e) -> $(document).on 'markdown-preview:hide', (e, $form) ->
e.preventDefault() return unless $form
$form = $(this).closest('form') lastTextareaPreviewed = null
# toggle tabs # toggle tabs
$form.find(writeButtonSelector).parent().addClass('active') $form.find(writeButtonSelector).parent().addClass('active')
...@@ -84,4 +90,30 @@ $(document).on 'click', writeButtonSelector, (e) -> ...@@ -84,4 +90,30 @@ $(document).on 'click', writeButtonSelector, (e) ->
# toggle content # toggle content
$form.find('.md-write-holder').show() $form.find('.md-write-holder').show()
$form.find('textarea.markdown-area').focus()
$form.find('.md-preview-holder').hide() $form.find('.md-preview-holder').hide()
$(document).on 'markdown-preview:toggle', (e, keyboardEvent) ->
$target = $(keyboardEvent.target)
if $target.is('textarea.markdown-area')
$(document).triggerHandler('markdown-preview:show', [$target.closest('form')])
keyboardEvent.preventDefault()
else if lastTextareaPreviewed
$target = lastTextareaPreviewed
$(document).triggerHandler('markdown-preview:hide', [$target.closest('form')])
keyboardEvent.preventDefault()
$(document).on 'click', previewButtonSelector, (e) ->
e.preventDefault()
$form = $(this).closest('form')
$(document).triggerHandler('markdown-preview:show', [$form])
$(document).on 'click', writeButtonSelector, (e) ->
e.preventDefault()
$form = $(this).closest('form')
$(document).triggerHandler('markdown-preview:hide', [$form])
...@@ -146,6 +146,7 @@ class @MergeRequestTabs ...@@ -146,6 +146,7 @@ class @MergeRequestTabs
url: "#{source}.json" + @_location.search url: "#{source}.json" + @_location.search
success: (data) => success: (data) =>
document.querySelector("div#diffs").innerHTML = data.html document.querySelector("div#diffs").innerHTML = data.html
$('.js-timeago').timeago()
$('div#diffs .js-syntax-highlight').syntaxHighlight() $('div#diffs .js-syntax-highlight').syntaxHighlight()
@expandViewContainer() if @diffViewType() is 'parallel' @expandViewContainer() if @diffViewType() is 'parallel'
@diffsLoaded = true @diffsLoaded = true
...@@ -188,12 +189,11 @@ class @MergeRequestTabs ...@@ -188,12 +189,11 @@ class @MergeRequestTabs
$('.container-fluid').removeClass('container-limited') $('.container-fluid').removeClass('container-limited')
shrinkView: -> shrinkView: ->
$gutterIcon = $('.gutter-toggle i') $gutterIcon = $('.js-sidebar-toggle i')
# Wait until listeners are set # Wait until listeners are set
setTimeout( -> setTimeout( ->
# Only when sidebar is collapsed # Only when sidebar is collapsed
if $gutterIcon.is('.fa-angle-double-right') if $gutterIcon.is('.fa-angle-double-right')
$gutterIcon.closest('a').trigger('click') $gutterIcon.closest('a').trigger('click',[true])
, 0) , 0)
...@@ -69,7 +69,7 @@ class @Milestone ...@@ -69,7 +69,7 @@ class @Milestone
@bindIssuesSorting() @bindIssuesSorting()
@bindMergeRequestSorting() @bindMergeRequestSorting()
@bindTabsSwitching @bindTabsSwitching()
bindIssuesSorting: -> bindIssuesSorting: ->
$("#issues-list-unassigned, #issues-list-ongoing, #issues-list-closed").sortable( $("#issues-list-unassigned, #issues-list-ongoing, #issues-list-closed").sortable(
...@@ -104,7 +104,7 @@ class @Milestone ...@@ -104,7 +104,7 @@ class @Milestone
).disableSelection() ).disableSelection()
bindMergeRequestSorting: -> bindTabsSwitching: ->
$('a[data-toggle="tab"]').on 'show.bs.tab', (e) -> $('a[data-toggle="tab"]').on 'show.bs.tab', (e) ->
currentTabClass = $(e.target).data('show') currentTabClass = $(e.target).data('show')
previousTabClass = $(e.relatedTarget).data('show') previousTabClass = $(e.relatedTarget).data('show')
...@@ -112,7 +112,8 @@ class @Milestone ...@@ -112,7 +112,8 @@ class @Milestone
$(previousTabClass).hide() $(previousTabClass).hide()
$(currentTabClass).removeClass('hidden') $(currentTabClass).removeClass('hidden')
$(currentTabClass).show() $(currentTabClass).show()
bindMergeRequestSorting: ->
$("#merge_requests-list-unassigned, #merge_requests-list-ongoing, #merge_requests-list-closed").sortable( $("#merge_requests-list-unassigned, #merge_requests-list-ongoing, #merge_requests-list-closed").sortable(
connectWith: ".merge_requests-sortable-list", connectWith: ".merge_requests-sortable-list",
dropOnEmpty: true, dropOnEmpty: true,
......
class @MilestoneSelect
constructor: ->
$('.js-milestone-select').each (i, dropdown) ->
$dropdown = $(dropdown)
projectId = $dropdown.data('project-id')
milestonesUrl = $dropdown.data('milestones')
selectedMilestone = $dropdown.data('selected')
showNo = $dropdown.data('show-no')
showAny = $dropdown.data('show-any')
useId = $dropdown.data('use-id')
defaultLabel = $dropdown.data('default-label')
$dropdown.glDropdown(
data: (term, callback) ->
$.ajax(
url: milestonesUrl
).done (data) ->
if showNo
data.unshift(
id: '0'
title: 'No Milestone'
)
if showAny
data.unshift(
isAny: true
title: 'Any Milestone'
)
if data.length > 2
data.splice 2, 0, 'divider'
callback(data)
filterable: true
search:
fields: ['title']
selectable: true
toggleLabel: (selected) ->
if selected && 'id' of selected
selected.title
else
defaultLabel
fieldName: $dropdown.data('field-name')
text: (milestone) ->
milestone.title
id: (milestone) ->
if !useId
if !milestone.isAny?
milestone.title
else
''
else
milestone.id
isSelected: (milestone) ->
milestone.title is selectedMilestone
clicked: ->
page = $('body').data 'page'
isIssueIndex = page is 'projects:issues:index'
isMRIndex = page is page is 'projects:merge_requests:index'
if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
Issues.filterResults $dropdown.closest('form')
else if $dropdown.hasClass 'js-filter-submit'
$dropdown.closest('form').submit()
)
...@@ -16,11 +16,13 @@ class @Notes ...@@ -16,11 +16,13 @@ class @Notes
@view = view @view = view
@noteable_url = document.URL @noteable_url = document.URL
@notesCountBadge ||= $(".issuable-details").find(".notes-tab .badge") @notesCountBadge ||= $(".issuable-details").find(".notes-tab .badge")
@basePollingInterval = 15000
@maxPollingSteps = 4
@initRefresh()
@setupMainTargetNoteForm()
@cleanBinding() @cleanBinding()
@addBinding() @addBinding()
@setPollingInterval()
@setupMainTargetNoteForm()
@initTaskList() @initTaskList()
addBinding: -> addBinding: ->
...@@ -28,8 +30,11 @@ class @Notes ...@@ -28,8 +30,11 @@ class @Notes
$(document).on "ajax:success", ".js-main-target-form", @addNote $(document).on "ajax:success", ".js-main-target-form", @addNote
$(document).on "ajax:success", ".js-discussion-note-form", @addDiscussionNote $(document).on "ajax:success", ".js-discussion-note-form", @addDiscussionNote
# catch note ajax errors
$(document).on "ajax:error", ".js-main-target-form", @addNoteError
# change note in UI after update # change note in UI after update
$(document).on "ajax:success", "form.edit_note", @updateNote $(document).on "ajax:success", "form.edit-note", @updateNote
# Edit note link # Edit note link
$(document).on "click", ".js-note-edit", @showEditForm $(document).on "click", ".js-note-edit", @showEditForm
...@@ -37,7 +42,7 @@ class @Notes ...@@ -37,7 +42,7 @@ class @Notes
# Reopen and close actions for Issue/MR combined with note form submit # Reopen and close actions for Issue/MR combined with note form submit
$(document).on "click", ".js-comment-button", @updateCloseButton $(document).on "click", ".js-comment-button", @updateCloseButton
$(document).on "keyup", ".js-note-text", @updateTargetButtons $(document).on "keyup input", ".js-note-text", @updateTargetButtons
# remove a note (in general) # remove a note (in general)
$(document).on "click", ".js-note-delete", @removeNote $(document).on "click", ".js-note-delete", @removeNote
...@@ -49,6 +54,9 @@ class @Notes ...@@ -49,6 +54,9 @@ class @Notes
$(document).on "ajax:complete", ".js-main-target-form", @reenableTargetFormSubmitButton $(document).on "ajax:complete", ".js-main-target-form", @reenableTargetFormSubmitButton
$(document).on "ajax:success", ".js-main-target-form", @resetMainTargetForm $(document).on "ajax:success", ".js-main-target-form", @resetMainTargetForm
# reset main target form when clicking discard
$(document).on "click", ".js-note-discard", @resetMainTargetForm
# update the file name when an attachment is selected # update the file name when an attachment is selected
$(document).on "change", ".js-note-attachment-input", @updateFormAttachment $(document).on "change", ".js-note-attachment-input", @updateFormAttachment
...@@ -70,7 +78,7 @@ class @Notes ...@@ -70,7 +78,7 @@ class @Notes
cleanBinding: -> cleanBinding: ->
$(document).off "ajax:success", ".js-main-target-form" $(document).off "ajax:success", ".js-main-target-form"
$(document).off "ajax:success", ".js-discussion-note-form" $(document).off "ajax:success", ".js-discussion-note-form"
$(document).off "ajax:success", "form.edit_note" $(document).off "ajax:success", "form.edit-note"
$(document).off "click", ".js-note-edit" $(document).off "click", ".js-note-edit"
$(document).off "click", ".note-edit-cancel" $(document).off "click", ".note-edit-cancel"
$(document).off "click", ".js-note-delete" $(document).off "click", ".js-note-delete"
...@@ -83,6 +91,7 @@ class @Notes ...@@ -83,6 +91,7 @@ class @Notes
$(document).off "keyup", ".js-note-text" $(document).off "keyup", ".js-note-text"
$(document).off "click", ".js-note-target-reopen" $(document).off "click", ".js-note-target-reopen"
$(document).off "click", ".js-note-target-close" $(document).off "click", ".js-note-target-close"
$(document).off "click", ".js-note-discard"
$('.note .js-task-list-container').taskList('disable') $('.note .js-task-list-container').taskList('disable')
$(document).off 'tasklist:changed', '.note .js-task-list-container' $(document).off 'tasklist:changed', '.note .js-task-list-container'
...@@ -91,9 +100,11 @@ class @Notes ...@@ -91,9 +100,11 @@ class @Notes
clearInterval(Notes.interval) clearInterval(Notes.interval)
Notes.interval = setInterval => Notes.interval = setInterval =>
@refresh() @refresh()
, 15000 , @pollingInterval
refresh: -> refresh: ->
return if @refreshing is true
refreshing = true
if not document.hidden and document.URL.indexOf(@noteable_url) is 0 if not document.hidden and document.URL.indexOf(@noteable_url) is 0
@getContent() @getContent()
...@@ -105,12 +116,31 @@ class @Notes ...@@ -105,12 +116,31 @@ class @Notes
success: (data) => success: (data) =>
notes = data.notes notes = data.notes
@last_fetched_at = data.last_fetched_at @last_fetched_at = data.last_fetched_at
@setPollingInterval(data.notes.length)
$.each notes, (i, note) => $.each notes, (i, note) =>
if note.discussion_with_diff_html? if note.discussion_with_diff_html?
@renderDiscussionNote(note) @renderDiscussionNote(note)
else else
@renderNote(note) @renderNote(note)
always: =>
@refreshing = false
###
Increase @pollingInterval up to 120 seconds on every function call,
if `shouldReset` has a truthy value, 'null' or 'undefined' the variable
will reset to @basePollingInterval.
Note: this function is used to gradually increase the polling interval
if there aren't new notes coming from the server
###
setPollingInterval: (shouldReset = true) ->
nthInterval = @basePollingInterval * Math.pow(2, @maxPollingSteps - 1)
if shouldReset
@pollingInterval = @basePollingInterval
else if @pollingInterval < nthInterval
@pollingInterval *= 2
@initRefresh()
### ###
Render note in main comments area. Render note in main comments area.
...@@ -196,7 +226,7 @@ class @Notes ...@@ -196,7 +226,7 @@ class @Notes
Resets text and preview. Resets text and preview.
Resets buttons. Resets buttons.
### ###
resetMainTargetForm: -> resetMainTargetForm: (e) =>
form = $(".js-main-target-form") form = $(".js-main-target-form")
# remove validation errors # remove validation errors
...@@ -208,6 +238,8 @@ class @Notes ...@@ -208,6 +238,8 @@ class @Notes
form.find(".js-note-text").data("autosave").reset() form.find(".js-note-text").data("autosave").reset()
@updateTargetButtons(e)
reenableTargetFormSubmitButton: -> reenableTargetFormSubmitButton: ->
form = $(".js-main-target-form") form = $(".js-main-target-form")
...@@ -251,8 +283,10 @@ class @Notes ...@@ -251,8 +283,10 @@ class @Notes
form.removeClass "js-new-note-form" form.removeClass "js-new-note-form"
form.find('.div-dropzone').remove() form.find('.div-dropzone').remove()
# hide discard button
form.find('.js-note-discard').hide()
# setup preview buttons # setup preview buttons
form.find(".js-md-write-button, .js-md-preview-button").tooltip placement: "left"
previewButton = form.find(".js-md-preview-button") previewButton = form.find(".js-md-preview-button")
textarea = form.find(".js-note-text") textarea = form.find(".js-note-text")
...@@ -286,6 +320,10 @@ class @Notes ...@@ -286,6 +320,10 @@ class @Notes
addNote: (xhr, note, status) => addNote: (xhr, note, status) =>
@renderNote(note) @renderNote(note)
addNoteError: (xhr, note, status) =>
flash = new Flash('Your comment could not be submitted! Please check your network connection and try again.', 'alert')
flash.pinTo('.md-area')
### ###
Called in response to the new note form being submitted Called in response to the new note form being submitted
...@@ -305,6 +343,7 @@ class @Notes ...@@ -305,6 +343,7 @@ class @Notes
updateNote: (_xhr, note, _status) => updateNote: (_xhr, note, _status) =>
# Convert returned HTML to a jQuery object so we can modify it further # Convert returned HTML to a jQuery object so we can modify it further
$html = $(note.html) $html = $(note.html)
$('.js-timeago', $html).timeago()
$html.syntaxHighlight() $html.syntaxHighlight()
$html.find('.js-task-list-container').taskList('enable') $html.find('.js-task-list-container').taskList('enable')
...@@ -324,22 +363,26 @@ class @Notes ...@@ -324,22 +363,26 @@ class @Notes
note = $(this).closest(".note") note = $(this).closest(".note")
note.find(".note-body > .note-text").hide() note.find(".note-body > .note-text").hide()
note.find(".note-header").hide() note.find(".note-header").hide()
base_form = note.find(".note-edit-form") form = note.find(".note-edit-form")
form = base_form.clone().insertAfter(base_form) isNewForm = form.is(':not(.gfm-form)')
form.addClass('current-note-edit-form gfm-form') if isNewForm
form.find('.div-dropzone').remove() form.addClass('gfm-form')
form.addClass('current-note-edit-form')
form.show()
# Show the attachment delete link # Show the attachment delete link
note.find(".js-note-attachment-delete").show() note.find(".js-note-attachment-delete").show()
# Setup markdown form # Setup markdown form
GitLab.GfmAutoComplete.setup() if isNewForm
new DropzoneInput(form) GitLab.GfmAutoComplete.setup()
new DropzoneInput(form)
form.show()
textarea = form.find("textarea") textarea = form.find("textarea")
textarea.focus() textarea.focus()
autosize(textarea)
if isNewForm
autosize(textarea)
# HACK (rspeicher/DouweM): Work around a Chrome 43 bug(?). # HACK (rspeicher/DouweM): Work around a Chrome 43 bug(?).
# The textarea has the correct value, Chrome just won't show it unless we # The textarea has the correct value, Chrome just won't show it unless we
...@@ -348,7 +391,8 @@ class @Notes ...@@ -348,7 +391,8 @@ class @Notes
textarea.val "" textarea.val ""
textarea.val value textarea.val value
disableButtonIfEmptyField textarea, form.find(".js-comment-button") if isNewForm
disableButtonIfEmptyField textarea, form.find(".js-comment-button")
### ###
Called in response to clicking the edit note link Called in response to clicking the edit note link
...@@ -360,7 +404,9 @@ class @Notes ...@@ -360,7 +404,9 @@ class @Notes
note = $(this).closest(".note") note = $(this).closest(".note")
note.find(".note-body > .note-text").show() note.find(".note-body > .note-text").show()
note.find(".note-header").show() note.find(".note-header").show()
note.find(".current-note-edit-form").remove() note.find(".current-note-edit-form")
.removeClass("current-note-edit-form")
.hide()
### ###
Called in response to deleting a note of any kind. Called in response to deleting a note of any kind.
...@@ -439,6 +485,11 @@ class @Notes ...@@ -439,6 +485,11 @@ class @Notes
form.find("#note_line_code").val dataHolder.data("lineCode") form.find("#note_line_code").val dataHolder.data("lineCode")
form.find("#note_noteable_type").val dataHolder.data("noteableType") form.find("#note_noteable_type").val dataHolder.data("noteableType")
form.find("#note_noteable_id").val dataHolder.data("noteableId") form.find("#note_noteable_id").val dataHolder.data("noteableId")
form.find('.js-note-discard')
.show()
.removeClass('js-note-discard')
.addClass('js-close-discussion-note-form')
.text(form.find('.js-close-discussion-note-form').data('cancel-text'))
@setupNoteForm form @setupNoteForm form
form.find(".js-note-text").focus() form.find(".js-note-text").focus()
form.addClass "js-discussion-note-form" form.addClass "js-discussion-note-form"
...@@ -538,21 +589,52 @@ class @Notes ...@@ -538,21 +589,52 @@ class @Notes
updateCloseButton: (e) => updateCloseButton: (e) =>
textarea = $(e.target) textarea = $(e.target)
form = textarea.parents('form') form = textarea.parents('form')
form.find('.js-note-target-close').text('Close') closebtn = form.find('.js-note-target-close')
closebtn.text(closebtn.data('original-text'))
updateTargetButtons: (e) => updateTargetButtons: (e) =>
textarea = $(e.target) textarea = $(e.target)
form = textarea.parents('form') form = textarea.parents('form')
reopenbtn = form.find('.js-note-target-reopen')
closebtn = form.find('.js-note-target-close')
discardbtn = form.find('.js-note-discard')
if textarea.val().trim().length > 0 if textarea.val().trim().length > 0
form.find('.js-note-target-reopen').text('Comment & reopen') reopentext = reopenbtn.data('alternative-text')
form.find('.js-note-target-close').text('Comment & close') closetext = closebtn.data('alternative-text')
form.find('.js-note-target-reopen').addClass('btn-comment-and-reopen')
form.find('.js-note-target-close').addClass('btn-comment-and-close') if reopenbtn.text() isnt reopentext
reopenbtn.text(reopentext)
if closebtn.text() isnt closetext
closebtn.text(closetext)
if reopenbtn.is(':not(.btn-comment-and-reopen)')
reopenbtn.addClass('btn-comment-and-reopen')
if closebtn.is(':not(.btn-comment-and-close)')
closebtn.addClass('btn-comment-and-close')
if discardbtn.is(':hidden')
discardbtn.show()
else else
form.find('.js-note-target-reopen').text('Reopen') reopentext = reopenbtn.data('original-text')
form.find('.js-note-target-close').text('Close') closetext = closebtn.data('original-text')
form.find('.js-note-target-reopen').removeClass('btn-comment-and-reopen')
form.find('.js-note-target-close').removeClass('btn-comment-and-close') if reopenbtn.text() isnt reopentext
reopenbtn.text(reopentext)
if closebtn.text() isnt closetext
closebtn.text(closetext)
if reopenbtn.is('.btn-comment-and-reopen')
reopenbtn.removeClass('btn-comment-and-reopen')
if closebtn.is('.btn-comment-and-close')
closebtn.removeClass('btn-comment-and-close')
if discardbtn.is(':visible')
discardbtn.hide()
initTaskList: -> initTaskList: ->
@enableTaskList() @enableTaskList()
......
@Pager = @Pager =
init: (@limit = 0, preload, @disable = false) -> init: (@limit = 0, preload, @disable = false) ->
@loading = $(".loading") @loading = $('.loading').first()
if preload if preload
@offset = 0 @offset = 0
@getOld() @getOld()
......
...@@ -4,62 +4,33 @@ class @Profile ...@@ -4,62 +4,33 @@ class @Profile
$('.js-preferences-form').on 'change.preference', 'input[type=radio]', -> $('.js-preferences-form').on 'change.preference', 'input[type=radio]', ->
$(this).parents('form').submit() $(this).parents('form').submit()
$('.update-username form').on 'ajax:before', -> $('.update-username').on 'ajax:before', ->
$('.loading-gif').show() $('.loading-username').show()
$(this).find('.update-success').hide() $(this).find('.update-success').hide()
$(this).find('.update-failed').hide() $(this).find('.update-failed').hide()
$('.update-username form').on 'ajax:complete', -> $('.update-username').on 'ajax:complete', ->
$('.loading-username').hide()
$(this).find('.btn-save').enable() $(this).find('.btn-save').enable()
$(this).find('.loading-gif').hide() $(this).find('.loading-gif').hide()
$('.update-notifications').on 'ajax:complete', -> $('.update-notifications').on 'ajax:complete', ->
$(this).find('.btn-save').enable() $(this).find('.btn-save').enable()
# Avatar management $('.js-choose-user-avatar-button').bind "click", ->
form = $(this).closest("form")
$avatarInput = $('.js-user-avatar-input') form.find(".js-user-avatar-input").click()
$filename = $('.js-avatar-filename')
$modalCrop = $('.modal-profile-crop')
$modalCropImg = $('.modal-profile-crop-image')
$('.js-choose-user-avatar-button').on "click", ->
$form = $(this).closest("form")
$form.find(".js-user-avatar-input").click()
$modalCrop.on 'shown.bs.modal', ->
setTimeout ( -> # The cropper must be asynchronously initialized
$modalCropImg.cropper
aspectRatio: 1
modal: false
scalable: false
rotatable: false
zoomable: false
crop: (event) ->
['x', 'y'].forEach (key) ->
$("#user_avatar_crop_#{key}").val(Math.floor(event[key]))
$("#user_avatar_crop_size").val(Math.floor(event.width))
), 0
$modalCrop.on 'hidden.bs.modal', ->
$modalCropImg.attr('src', '').cropper('destroy')
$avatarInput.val('')
$filename.text($filename.data('label'))
$('.js-upload-user-avatar').on 'click', ->
$('.edit_user').submit()
$avatarInput.on "change", -> $('.js-user-avatar-input').bind "change", ->
form = $(this).closest("form") form = $(this).closest("form")
filename = $(this).val().replace(/^.*[\\\/]/, '') filename = $(this).val().replace(/^.*[\\\/]/, '')
$filename.data('label', $filename.text()).text(filename) form.find(".js-avatar-filename").text(filename)
reader = new FileReader
reader.onload = (event) ->
$modalCrop.modal('show')
$modalCropImg.attr('src', event.target.result)
fileData = reader.readAsDataURL(this.files[0]) $ ->
# Extract the SSH Key title from its comment
$(document).on 'focusout.ssh_key', '#key_key', ->
$title = $('#key_title')
comment = $(@).val().match(/^\S+ \S+ (.+)\n?$/)
if comment && comment.length > 1 && $title.val() == ''
$title.val(comment[1]).change()
...@@ -3,3 +3,16 @@ class @ProjectNew ...@@ -3,3 +3,16 @@ class @ProjectNew
$('.project-edit-container').on 'ajax:before', => $('.project-edit-container').on 'ajax:before', =>
$('.project-edit-container').hide() $('.project-edit-container').hide()
$('.save-project-loader').show() $('.save-project-loader').show()
@toggleSettings()
@toggleSettingsOnclick()
toggleSettings: ->
checked = $("#project_builds_enabled").prop("checked")
if checked
$('.builds-feature').show()
else
$('.builds-feature').hide()
toggleSettingsOnclick: ->
$("#project_builds_enabled").on 'click', @toggleSettings
class @ProjectsList @ProjectsList =
constructor: -> init: ->
$(".projects-list .js-expand").on 'click', (e) -> $(".projects-list-filter").off('keyup')
e.preventDefault() this.initSearch()
list = $(this).closest('.projects-list') this.initPagination()
$("#filter_projects").on 'keyup', -> initSearch: ->
ProjectsList.filter_results($("#filter_projects")) @timer = null
$(".projects-list-filter").on('keyup', ->
clearTimeout(@timer)
@timer = setTimeout(ProjectsList.filterResults, 500)
)
@filter_results: ($element) -> filterResults: =>
terms = $element.val() $('.projects-list-holder').fadeTo(250, 0.5)
filterSelector = $element.data('filter-selector') || 'span.filter-title'
if not terms form = null
$(".projects-list li").show() form = $("form#project-filter-form")
$('.gl-pagination').show() search = $(".projects-list-filter").val()
else project_filter_url = form.attr('action') + '?' + form.serialize()
$(".projects-list li").each (index) ->
$this = $(this)
name = $this.find(filterSelector).text()
if name.toLowerCase().indexOf(terms.toLowerCase()) == -1 $.ajax
$this.hide() type: "GET"
else url: form.attr('action')
$this.show() data: form.serialize()
$('.gl-pagination').hide() complete: ->
$('.projects-list-holder').fadeTo(250, 1)
success: (data) ->
$('.projects-list-holder').replaceWith(data.html)
# Change url so if user reload a page - search results are saved
history.replaceState {page: project_filter_url}, document.title, project_filter_url
dataType: "json"
initPagination: ->
$('.projects-list-holder .pagination').on('ajax:success', (e, data) ->
$('.projects-list-holder').replaceWith(data.html)
)
...@@ -4,17 +4,23 @@ class @Shortcuts ...@@ -4,17 +4,23 @@ class @Shortcuts
Mousetrap.reset() Mousetrap.reset()
Mousetrap.bind('?', @selectiveHelp) Mousetrap.bind('?', @selectiveHelp)
Mousetrap.bind('s', Shortcuts.focusSearch) Mousetrap.bind('s', Shortcuts.focusSearch)
Mousetrap.bind(['ctrl+shift+p', 'command+shift+p'], @toggleMarkdownPreview)
Mousetrap.bind('t', -> Turbolinks.visit(findFileURL)) if findFileURL? Mousetrap.bind('t', -> Turbolinks.visit(findFileURL)) if findFileURL?
selectiveHelp: (e) => selectiveHelp: (e) =>
Shortcuts.showHelp(e, @enabledHelp) Shortcuts.showHelp(e, @enabledHelp)
toggleMarkdownPreview: (e) =>
$(document).triggerHandler('markdown-preview:toggle', [e])
@showHelp: (e, location) -> @showHelp: (e, location) ->
if $('#modal-shortcuts').length > 0 if $('#modal-shortcuts').length > 0
$('#modal-shortcuts').modal('show') $('#modal-shortcuts').modal('show')
else else
url = '/help/shortcuts'
url = gon.relative_url_root + url if gon.relative_url_root?
$.ajax( $.ajax(
url: '/help/shortcuts', url: url,
dataType: 'script', dataType: 'script',
success: (e) -> success: (e) ->
if location and location.length > 0 if location and location.length > 0
...@@ -33,3 +39,14 @@ $(document).on 'click.more_help', '.js-more-help-button', (e) -> ...@@ -33,3 +39,14 @@ $(document).on 'click.more_help', '.js-more-help-button', (e) ->
$(@).remove() $(@).remove()
$('.hidden-shortcut').show() $('.hidden-shortcut').show()
e.preventDefault() e.preventDefault()
Mousetrap.stopCallback = (->
defaultStopCallback = Mousetrap.stopCallback
return (e, element, combo) ->
# allowed shortcuts if textarea, input, contenteditable are focused
if ['ctrl+shift+p', 'command+shift+p'].indexOf(combo) != -1
return false
else
return defaultStopCallback.apply(@, arguments)
)()
$(document).on("click", '.toggle-nav-collapse', (e) -> collapsed = 'page-sidebar-collapsed'
e.preventDefault() expanded = 'page-sidebar-expanded'
collapsed = 'page-sidebar-collapsed'
expanded = 'page-sidebar-expanded'
toggleSidebar = ->
$('.page-with-sidebar').toggleClass("#{collapsed} #{expanded}") $('.page-with-sidebar').toggleClass("#{collapsed} #{expanded}")
$('header').toggleClass("header-collapsed header-expanded") $('header').toggleClass("header-collapsed header-expanded")
$('.sidebar-wrapper').toggleClass("sidebar-collapsed sidebar-expanded") $('.sidebar-wrapper').toggleClass("sidebar-collapsed sidebar-expanded")
...@@ -14,4 +13,15 @@ $(document).on("click", '.toggle-nav-collapse', (e) -> ...@@ -14,4 +13,15 @@ $(document).on("click", '.toggle-nav-collapse', (e) ->
niceScrollBars.updateScrollBar(); niceScrollBars.updateScrollBar();
), 300 ), 300
$(document).on("click", '.toggle-nav-collapse', (e) ->
e.preventDefault()
toggleSidebar()
) )
$ ->
size = bp.getBreakpointSize()
if size is "xs" or size is "sm"
if $('.page-with-sidebar').hasClass(expanded)
toggleSidebar()
class @Subscription class @Subscription
constructor: (url) -> constructor: (container) ->
$(".subscribe-button").unbind("click").click (event)=> $container = $(container)
btn = $(event.currentTarget) @url = $container.attr('data-url')
action = btn.find("span").text() @subscribe_button = $container.find('.subscribe-button')
current_status = $(".subscription-status").attr("data-status") @subscription_status = $container.find('.subscription-status')
btn.prop("disabled", true) @subscribe_button.unbind('click').click(@toggleSubscription)
$.post url, =>
btn.prop("disabled", false)
status = if current_status == "subscribed" then "unsubscribed" else "subscribed"
$(".subscription-status").attr("data-status", status)
action = if status == "subscribed" then "Unsubscribe" else "Subscribe"
btn.find("span").text(action)
$(".subscription-status>div").toggleClass("hidden")
toggleSubscription: (event) =>
btn = $(event.currentTarget)
action = btn.find('span').text()
current_status = @subscription_status.attr('data-status')
btn.prop('disabled', true)
$.post @url, =>
btn.prop('disabled', false)
status = if current_status == 'subscribed' then 'unsubscribed' else 'subscribed'
@subscription_status.attr('data-status', status)
action = if status == 'subscribed' then 'Unsubscribe' else 'Subscribe'
btn.find('span').text(action)
@subscription_status.find('>div').toggleClass('hidden')
class @Todos
constructor: (@name) ->
@clearListeners()
@initBtnListeners()
clearListeners: ->
$('.done-todo').off('click')
$('.js-todos-mark-all').off('click')
initBtnListeners: ->
$('.done-todo').on('click', @doneClicked)
$('.js-todos-mark-all').on('click', @allDoneClicked)
doneClicked: (e) =>
e.preventDefault()
e.stopImmediatePropagation()
$this = $(e.currentTarget)
$this.disable()
$.ajax
type: 'POST'
url: $this.attr('href')
dataType: 'json'
data: '_method': 'delete'
success: (data) =>
@clearDone $this.closest('li')
@updateBadges data
allDoneClicked: (e) =>
e.preventDefault()
e.stopImmediatePropagation()
$this = $(e.currentTarget)
$this.disable()
$.ajax
type: 'POST'
url: $this.attr('href')
dataType: 'json'
data: '_method': 'delete'
success: (data) =>
$this.remove()
$('.js-todos-list').remove()
@updateBadges data
clearDone: ($row) ->
$ul = $row.closest('ul')
$row.remove()
if not $ul.find('li').length
$ul.parents('.panel').remove()
updateBadges: (data) ->
$('.todos-pending .badge, .todos-pending-count').text data.count
$('.todos-done .badge').text data.done_count
class @User class @User
constructor: -> constructor: (@opts) ->
$('.profile-groups-avatars').tooltip("placement": "top") $('.profile-groups-avatars').tooltip("placement": "top")
new ProjectsList()
@initTabs()
$('.hide-project-limit-message').on 'click', (e) -> $('.hide-project-limit-message').on 'click', (e) ->
path = '/' path = '/'
$.cookie('hide_project_limit_message', 'false', { path: path }) $.cookie('hide_project_limit_message', 'false', { path: path })
$(@).parents('.project-limit-message').remove() $(@).parents('.project-limit-message').remove()
e.preventDefault() e.preventDefault()
initTabs: ->
new UserTabs(
parentEl: '.user-profile'
action: @opts.action
)
# UserTabs
#
# Handles persisting and restoring the current tab selection and lazily-loading
# content on the Users#show page.
#
# ### Example Markup
#
# <ul class="nav-links">
# <li class="activity-tab active">
# <a data-action="activity" data-target="#activity" data-toggle="tab" href="/u/username">
# Activity
# </a>
# </li>
# <li class="groups-tab">
# <a data-action="groups" data-target="#groups" data-toggle="tab" href="/u/username/groups">
# Groups
# </a>
# </li>
# <li class="contributed-tab">
# <a data-action="contributed" data-target="#contributed" data-toggle="tab" href="/u/username/contributed">
# Contributed projects
# </a>
# </li>
# <li class="projects-tab">
# <a data-action="projects" data-target="#projects" data-toggle="tab" href="/u/username/projects">
# Personal projects
# </a>
# </li>
# </ul>
#
# <div class="tab-content">
# <div class="tab-pane" id="activity">
# Activity Content
# </div>
# <div class="tab-pane" id="groups">
# Groups Content
# </div>
# <div class="tab-pane" id="contributed">
# Contributed projects content
# </div>
# <div class="tab-pane" id="projects">
# Projects content
# </div>
# </div>
#
# <div class="loading-status">
# <div class="loading">
# Loading Animation
# </div>
# </div>
#
class @UserTabs
constructor: (opts) ->
{
@action = 'activity'
@defaultAction = 'activity'
@parentEl = $(document)
} = opts
# Make jQuery object if selector is provided
@parentEl = $(@parentEl) if typeof @parentEl is 'string'
# Store the `location` object, allowing for easier stubbing in tests
@_location = location
# Set tab states
@loaded = {}
for item in @parentEl.find('.nav-links a')
@loaded[$(item).attr 'data-action'] = false
# Actions
@actions = Object.keys @loaded
@bindEvents()
# Set active tab
@action = @defaultAction if @action is 'show'
@activateTab(@action)
bindEvents: ->
# Toggle event listeners
@parentEl
.off 'shown.bs.tab', '.nav-links a[data-toggle="tab"]'
.on 'shown.bs.tab', '.nav-links a[data-toggle="tab"]', @tabShown
tabShown: (event) =>
$target = $(event.target)
action = $target.data('action')
source = $target.attr('href')
@setTab(source, action)
@setCurrentAction(action)
activateTab: (action) ->
@parentEl.find(".nav-links .#{action}-tab a").tab('show')
setTab: (source, action) ->
return if @loaded[action] is true
if action is 'activity'
@loadActivities(source)
if action in ['groups', 'contributed', 'projects']
@loadTab(source, action)
loadTab: (source, action) ->
$.ajax
beforeSend: => @toggleLoading(true)
complete: => @toggleLoading(false)
dataType: 'json'
type: 'GET'
url: "#{source}.json"
success: (data) =>
tabSelector = 'div#' + action
@parentEl.find(tabSelector).html(data.html)
@loaded[action] = true
loadActivities: (source) ->
return if @loaded['activity'] is true
$calendarWrap = @parentEl.find('.user-calendar')
$calendarWrap.load($calendarWrap.data('href'))
new Activities()
@loaded['activity'] = true
toggleLoading: (status) ->
@parentEl.find('.loading-status .loading').toggle(status)
setCurrentAction: (action) ->
# Remove possible actions from URL
regExp = new RegExp('\/(' + @actions.join('|') + ')(\.html)?\/?$')
new_state = @_location.pathname
new_state = new_state.replace(/\/+$/, "") # remove trailing slashes
new_state = new_state.replace(regExp, '')
# Append the new action if we're on a tab other than 'activity'
unless action == @defaultAction
new_state += "/#{action}"
# Ensure parameters and hash come along for the ride
new_state += @_location.search + @_location.hash
history.replaceState {turbolinks: true, url: new_state}, document.title, new_state
new_state
...@@ -3,6 +3,94 @@ class @UsersSelect ...@@ -3,6 +3,94 @@ class @UsersSelect
@usersPath = "/autocomplete/users.json" @usersPath = "/autocomplete/users.json"
@userPath = "/autocomplete/users/:id.json" @userPath = "/autocomplete/users/:id.json"
$('.js-user-search').each (i, dropdown) =>
$dropdown = $(dropdown)
@projectId = $dropdown.data('project-id')
@showCurrentUser = $dropdown.data('current-user')
showNullUser = $dropdown.data('null-user')
showAnyUser = $dropdown.data('any-user')
firstUser = $dropdown.data('first-user')
selectedId = $dropdown.data('selected')
defaultLabel = $dropdown.data('default-label')
$dropdown.glDropdown(
data: (term, callback) =>
@users term, (users) =>
if term.length is 0
showDivider = 0
if firstUser
# Move current user to the front of the list
for obj, index in users
if obj.username == firstUser
users.splice(index, 1)
users.unshift(obj)
break
if showNullUser
showDivider += 1
users.unshift(
name: 'Unassigned',
id: 0
)
if showAnyUser
showDivider += 1
name = showAnyUser
name = 'Any User' if name == true
anyUser = {
name: name,
id: null
}
users.unshift(anyUser)
if showDivider
users.splice(showDivider, 0, "divider")
# Send the data back
callback users
filterable: true
filterRemote: true
search:
fields: ['name', 'username']
selectable: true
fieldName: $dropdown.data('field-name')
toggleLabel: (selected) ->
if selected && 'id' of selected
selected.name
else
defaultLabel
clicked: ->
page = $('body').data 'page'
isIssueIndex = page is 'projects:issues:index'
isMRIndex = page is page is 'projects:merge_requests:index'
if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
Issues.filterResults $dropdown.closest('form')
else if $dropdown.hasClass 'js-filter-submit'
$dropdown.closest('form').submit()
renderRow: (user) ->
username = if user.username then "@#{user.username}" else ""
avatar = if user.avatar_url then user.avatar_url else false
selected = if user.id is selectedId then "is-active" else ""
img = ""
if avatar
img = "<img src='#{avatar}' class='avatar avatar-inline' width='30' />"
"<li>
<a href='#' class='dropdown-menu-user-link #{selected}'>
#{img}
<strong class='dropdown-menu-user-full-name'>
#{user.name}
</strong>
<span class='dropdown-menu-user-username'>
#{username}
</span>
</a>
</li>"
)
$('.ajax-users-select').each (i, select) => $('.ajax-users-select').each (i, select) =>
@projectId = $(select).data('project-id') @projectId = $(select).data('project-id')
@groupId = $(select).data('group-id') @groupId = $(select).data('group-id')
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
*= require_self *= require_self
*= require dropzone/basic *= require dropzone/basic
*= require cal-heatmap *= require cal-heatmap
*= require cropper.css
*/ */
/* /*
...@@ -25,12 +24,6 @@ ...@@ -25,12 +24,6 @@
*/ */
@import "framework"; @import "framework";
/*
* NProgress load bar css
*/
@import 'nprogress';
@import 'nprogress-bootstrap';
/* /*
* Font icons * Font icons
*/ */
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
@import "framework/calendar.scss"; @import "framework/calendar.scss";
@import "framework/callout.scss"; @import "framework/callout.scss";
@import "framework/common.scss"; @import "framework/common.scss";
@import "framework/dropdowns.scss";
@import "framework/files.scss"; @import "framework/files.scss";
@import "framework/filters.scss"; @import "framework/filters.scss";
@import "framework/flash.scss"; @import "framework/flash.scss";
...@@ -26,6 +27,7 @@ ...@@ -26,6 +27,7 @@
@import "framework/mobile.scss"; @import "framework/mobile.scss";
@import "framework/nav.scss"; @import "framework/nav.scss";
@import "framework/pagination.scss"; @import "framework/pagination.scss";
@import "framework/progress.scss";
@import "framework/panels.scss"; @import "framework/panels.scss";
@import "framework/selects.scss"; @import "framework/selects.scss";
@import "framework/sidebar.scss"; @import "framework/sidebar.scss";
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
margin-bottom: -$gl-padding; margin-bottom: -$gl-padding;
background-color: $background-color; background-color: $background-color;
padding: $gl-padding; padding: $gl-padding;
margin-bottom: 0px; margin-bottom: 0;
border-top: 1px solid $border-color; border-top: 1px solid $border-color;
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
color: $gl-gray; color: $gl-gray;
...@@ -116,6 +116,10 @@ ...@@ -116,6 +116,10 @@
.cover-desc { .cover-desc {
padding: 0 $gl-padding 3px; padding: 0 $gl-padding 3px;
color: $gl-text-color; color: $gl-text-color;
&.username:last-child {
padding-bottom: $gl-padding;
}
} }
.cover-controls { .cover-controls {
...@@ -153,3 +157,7 @@ ...@@ -153,3 +157,7 @@
float: right; float: right;
} }
} }
.content-block-small {
padding: 10px 0;
}
...@@ -37,23 +37,23 @@ ...@@ -37,23 +37,23 @@
} }
@mixin btn-green { @mixin btn-green {
@include btn-color($green-light, $border-green-light, $green-normal, $border-green-normal, $green-dark, $border-green-dark, #FFFFFF); @include btn-color($green-light, $border-green-light, $green-normal, $border-green-normal, $green-dark, $border-green-dark, #fff);
} }
@mixin btn-blue { @mixin btn-blue {
@include btn-color($blue-light, $border-blue-light, $blue-normal, $border-blue-normal, $blue-dark, $border-blue-dark, #FFFFFF); @include btn-color($blue-light, $border-blue-light, $blue-normal, $border-blue-normal, $blue-dark, $border-blue-dark, #fff);
} }
@mixin btn-blue-medium { @mixin btn-blue-medium {
@include btn-color($blue-medium-light, $border-blue-light, $blue-medium, $border-blue-normal, $blue-medium-dark, $border-blue-dark, #FFFFFF); @include btn-color($blue-medium-light, $border-blue-light, $blue-medium, $border-blue-normal, $blue-medium-dark, $border-blue-dark, #fff);
} }
@mixin btn-orange { @mixin btn-orange {
@include btn-color($orange-light, $border-orange-light, $orange-normal, $border-orange-normal, $orange-dark, $border-orange-dark, #FFFFFF); @include btn-color($orange-light, $border-orange-light, $orange-normal, $border-orange-normal, $orange-dark, $border-orange-dark, #fff);
} }
@mixin btn-red { @mixin btn-red {
@include btn-color($red-light, $border-red-light, $red-normal, $border-red-normal, $red-dark, $border-red-dark, #FFFFFF); @include btn-color($red-light, $border-red-light, $red-normal, $border-red-normal, $red-dark, $border-red-dark, #fff);
} }
@mixin btn-gray { @mixin btn-gray {
...@@ -127,7 +127,7 @@ ...@@ -127,7 +127,7 @@
margin-right: 7px; margin-right: 7px;
float: left; float: left;
&:last-child { &:last-child {
margin-right: 0px; margin-right: 0;
} }
&.btn-xs { &.btn-xs {
margin-right: 3px; margin-right: 3px;
...@@ -139,7 +139,19 @@ ...@@ -139,7 +139,19 @@
.caret { .caret {
margin-left: 5px; margin-left: 5px;
color: $gray-darkest; }
}
.btn-transparent {
color: $btn-transparent-color;
background-color: transparent;
border: 0;
&:hover,
&:active,
&:focus {
background-color: transparent;
box-shadow: none;
} }
} }
...@@ -157,7 +169,7 @@ ...@@ -157,7 +169,7 @@
margin-right: 7px; margin-right: 7px;
float: left; float: left;
&:last-child { &:last-child {
margin-right: 0px; margin-right: 0;
} }
} }
} }
...@@ -196,3 +208,13 @@ ...@@ -196,3 +208,13 @@
background-color: #e4e7ed !important; background-color: #e4e7ed !important;
} }
} }
.btn-loading {
&:not(.disabled) .fa {
display: none;
}
.fa {
margin-right: 5px;
}
}
...@@ -33,19 +33,19 @@ ...@@ -33,19 +33,19 @@
} }
.q2 { .q2 {
fill: #ACD5F2 !important; fill: #acd5f2 !important;
} }
.q3 { .q3 {
fill: #7FA8D1 !important; fill: #7fa8d1 !important;
} }
.q4 { .q4 {
fill: #49729B !important; fill: #49729b !important;
} }
.q5 { .q5 {
fill: #254E77 !important; fill: #254e77 !important;
} }
.domain-background { .domain-background {
......
...@@ -39,6 +39,6 @@ ...@@ -39,6 +39,6 @@
} }
.bs-callout-success { .bs-callout-success {
background-color: #dff0d8; background-color: #dff0d8;
border-color: #5cA64d; border-color: #5ca64d;
color: #3c763d; color: #3c763d;
} }
/** 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-10 { margin-top:10px } .prepend-top-0 { margin-top: 0; }
.prepend-top-5 { margin-top: 5px; }
.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-10 { margin-left:10px } .prepend-left-10 { margin-left: 10px }
.prepend-left-20 { margin-left:20px } .prepend-left-default { margin-left: $gl-padding; }
.append-right-10 { margin-right:10px } .prepend-left-20 { margin-left: 20px }
.append-right-20 { margin-right:20px } .append-right-5 { margin-right: 5px }
.append-bottom-10 { margin-bottom:10px } .append-right-10 { margin-right: 10px }
.append-bottom-15 { margin-bottom:15px } .append-right-default { margin-right: $gl-padding; }
.append-bottom-20 { margin-bottom:20px } .append-right-20 { margin-right: 20px }
.append-bottom-0 { margin-bottom: 0 }
.append-bottom-10 { margin-bottom: 10px }
.append-bottom-15 { margin-bottom: 15px }
.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 }
...@@ -45,7 +51,7 @@ pre { ...@@ -45,7 +51,7 @@ pre {
} }
&.well-pre { &.well-pre {
border: 1px solid #EEE; border: 1px solid #eee;
background: #f9f9f9; background: #f9f9f9;
border-radius: 0; border-radius: 0;
color: #555; color: #555;
...@@ -56,25 +62,6 @@ hr { ...@@ -56,25 +62,6 @@ hr {
margin: $gl-padding 0; margin: $gl-padding 0;
} }
.dropdown-menu {
margin: 6px 0 0;
}
.dropdown-menu > li > a {
text-shadow: none;
}
.dropdown-menu-align-right {
left: auto;
right: 0px;
}
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
background: $gl-primary;
color: #FFF;
}
.str-truncated { .str-truncated {
@include str-truncated; @include str-truncated;
} }
...@@ -116,7 +103,7 @@ span.update-author { ...@@ -116,7 +103,7 @@ span.update-author {
} }
.user-mention { .user-mention {
color: #2FA0BB; color: #2fa0bb;
font-weight: bold; font-weight: bold;
} }
...@@ -147,10 +134,10 @@ p.time { ...@@ -147,10 +134,10 @@ 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;
} }
} }
} }
...@@ -200,9 +187,9 @@ li.note { ...@@ -200,9 +187,9 @@ li.note {
.error-message { .error-message {
padding: 10px; padding: 10px;
background: #C67; background: #c67;
margin: 0; margin: 0;
color: #FFF; color: #fff;
a { a {
color: #fff; color: #fff;
...@@ -213,7 +200,7 @@ li.note { ...@@ -213,7 +200,7 @@ li.note {
.browser-alert { .browser-alert {
padding: 10px; padding: 10px;
text-align: center; text-align: center;
background: #C67; background: #c67;
color: #fff; color: #fff;
font-weight: bold; font-weight: bold;
a { a {
...@@ -284,7 +271,7 @@ img.emoji { ...@@ -284,7 +271,7 @@ img.emoji {
table { table {
td.permission-x { td.permission-x {
background: #D9EDF7 !important; background: #d9edf7 !important;
text-align: center; text-align: center;
} }
} }
...@@ -293,7 +280,7 @@ table { ...@@ -293,7 +280,7 @@ table {
float: left; float: left;
text-align: center; text-align: center;
font-size: 32px; font-size: 32px;
color: #AAA; color: #aaa;
width: 60px; width: 60px;
} }
...@@ -305,7 +292,7 @@ table { ...@@ -305,7 +292,7 @@ table {
} }
.btn-sign-in { .btn-sign-in {
margin-top: 8px; margin-top: 10px;
text-shadow: none; text-shadow: none;
} }
...@@ -360,7 +347,7 @@ table { ...@@ -360,7 +347,7 @@ table {
.profiler-button, .profiler-button,
.profiler-controls { .profiler-controls {
border-color: #EEE !important; border-color: #eee !important;
} }
} }
......
.caret {
display: inline-block;
width: 0;
height: 0;
margin-left: 2px;
vertical-align: middle;
border-top: $caret-width-base dashed;
border-right: $caret-width-base solid transparent;
border-left: $caret-width-base solid transparent;
}
.btn-group {
.caret {
margin-left: 0;
}
}
.dropdown {
position: relative;
}
.open {
.dropdown-menu {
display: block;
}
.dropdown-menu-toggle {
border-color: $dropdown-toggle-hover-border-color;
.fa {
color: $dropdown-toggle-hover-icon-color;
}
}
}
.dropdown-menu-toggle {
position: relative;
width: 160px;
padding: 6px 20px 6px 10px;
background-color: $dropdown-toggle-bg;
color: $dropdown-toggle-color;
font-size: 15px;
text-align: left;
border: 1px solid $dropdown-toggle-border-color;
border-radius: 2px;
outline: 0;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
.fa {
position: absolute;
top: 50%;
right: 6px;
margin-top: -4px;
color: $dropdown-toggle-icon-color;
font-size: 10px;
}
&:hover, {
border-color: $dropdown-toggle-hover-border-color;
.fa {
color: $dropdown-toggle-hover-icon-color;
}
}
}
.dropdown-menu {
display: none;
position: absolute;
top: 100%;
left: 0;
z-index: 9;
width: 240px;
margin-top: 2px;
margin-bottom: 0;
padding: 10px 10px;
font-size: 14px;
font-weight: normal;
background-color: $dropdown-bg;
border: 1px solid $dropdown-border-color;
border-radius: $border-radius-base;
box-shadow: 0 2px 4px $dropdown-shadow-color;
&.is-loading {
.dropdown-content {
display: none;
}
.dropdown-loading {
display: block;
}
}
ul {
margin: 0;
padding: 0;
}
li {
text-align: left;
list-style: none;
}
.divider {
width: 100%;
height: 1px;
margin-top: 8px;
margin-bottom: 8px;
background-color: $dropdown-divider-color;
}
a {
display: block;
position: relative;
padding-left: 10px;
padding-right: 10px;
color: $dropdown-link-color;
line-height: 34px;
text-overflow: ellipsis;
border-radius: 2px;
white-space: nowrap;
overflow: hidden;
&:hover,
&:focus,
&.is-focused {
background-color: $dropdown-link-hover-bg;
text-decoration: none;
outline: 0;
}
}
}
.dropdown-menu-paging {
.dropdown-page-two,
.dropdown-menu-back {
display: none;
}
&.is-page-two {
.dropdown-page-one {
display: none;
}
.dropdown-page-two,
.dropdown-menu-back {
display: block;
}
}
}
.dropdown-menu-user {
.avatar {
float: left;
width: 30px;
height: 30px;
margin: 0 10px 0 0;
}
}
.dropdown-menu-user-link {
padding-top: 7px;
padding-bottom: 7px;
}
.dropdown-menu-user-full-name {
display: block;
font-weight: 600;
line-height: 16px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.dropdown-menu-user-username {
display: block;
line-height: 16px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.dropdown-select {
width: 280px;
}
.dropdown-menu-align-right {
left: auto;
right: 0;
}
.dropdown-menu-selectable {
a {
padding-left: 25px;
&.is-active {
&::before {
content: "\f00c";
position: absolute;
left: 5px;
top: 50%;
margin-top: -7px;
font: normal normal normal 14px/1 FontAwesome;
font-size: inherit;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
}
}
}
.dropdown-header {
padding-left: 5px;
padding-right: 5px;
color: $dropdown-header-color;
font-size: 13px;
line-height: 22px;
}
.dropdown-title {
position: relative;
margin-bottom: 10px;
padding-left: 30px;
padding-right: 30px;
padding-bottom: 10px;
font-weight: 600;
line-height: 1;
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
border-bottom: 1px solid $dropdown-divider-color;
overflow: hidden;
}
.dropdown-title-button {
position: absolute;
top: -1px;
padding: 0;
color: $dropdown-title-btn-color;
font-size: 14px;
border: 0;
background: none;
outline: 0;
&:hover {
color: darken($dropdown-title-btn-color, 15%);
}
}
.dropdown-menu-close {
right: 0;
}
.dropdown-menu-back {
left: 0;
}
.dropdown-input {
position: relative;
margin-bottom: 10px;
.fa {
position: absolute;
top: 10px;
right: 10px;
color: #c7c7c7;
font-size: 12px;
pointer-events: none;
}
}
.dropdown-input-field {
width: 100%;
padding: 0 7px;
color: $dropdown-input-color;
line-height: 30px;
border: 1px solid $dropdown-divider-color;
border-radius: 2px;
outline: 0;
&:focus {
color: $dropdown-link-color;
border-color: $dropdown-input-focus-border;
box-shadow: 0 0 4px $dropdown-input-focus-shadow;
+ .fa {
color: $dropdown-link-color;
}
}
&:hover {
+ .fa {
color: $dropdown-link-color;
}
}
}
.dropdown-content {
max-height: 215px;
overflow-y: scroll;
}
.dropdown-footer {
padding-top: 10px;
margin-top: 10px;
font-size: 13px;
border-top: 1px solid $dropdown-divider-color;
}
.dropdown-footer-list {
font-size: 14px;
a {
padding-left: 10px;
}
}
.dropdown-loading {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: none;
z-index: 9;
background-color: $dropdown-loading-bg;
font-size: 28px;
.fa {
position: absolute;
top: 50%;
left: 50%;
margin-top: -14px;
margin-left: -14px;
}
}
.dropdown-menu-labels {
.label {
position: relative;
width: 30px;
margin-right: 5px;
text-indent: -99999px;
}
}
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
right: 15px; right: 15px;
.btn { .btn {
padding: 0px 10px; padding: 0 10px;
font-size: 13px; font-size: 13px;
line-height: 28px; line-height: 28px;
} }
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
&.blob-no-preview { &.blob-no-preview {
background: #eee; background: #eee;
text-shadow: 0 1px 2px #FFF; text-shadow: 0 1px 2px #fff;
padding: 100px 0; padding: 100px 0;
} }
...@@ -124,7 +124,7 @@ ...@@ -124,7 +124,7 @@
} }
td.line-numbers { td.line-numbers {
float: none; float: none;
border-left: 1px solid #DDD; border-left: 1px solid #ddd;
} }
td.lines { td.lines {
padding: 0; padding: 0;
...@@ -169,6 +169,7 @@ ...@@ -169,6 +169,7 @@
*/ */
&.code { &.code {
padding: 0; padding: 0;
-webkit-overflow-scrolling: auto; // See https://gitlab.com/gitlab-org/gitlab-ce/issues/13987
} }
} }
} }
......
.filter-item { .filter-item {
margin-right: 6px; margin-right: 6px;
vertical-align: top;
} }
@media (min-width: 800px) { @media (min-width: $screen-sm-min) {
.issues-filters, .issues-filters,
.issues_bulk_update { .issues_bulk_update {
select, .select2-container { .dropdown-menu-toggle {
width: 120px !important; width: 132px;
display: inline-block;
}
}
}
@media (min-width: 1200px) {
.issues-filters,
.issues_bulk_update {
select, .select2-container {
width: 150px !important;
display: inline-block;
} }
} }
} }
...@@ -28,21 +28,21 @@ input[type='search'].search-input { ...@@ -28,21 +28,21 @@ input[type='search'].search-input {
} }
&.search-input:-moz-placeholder { /* Firefox 18- */ &.search-input:-moz-placeholder { /* Firefox 18- */
text-align: center; text-align: center;
} }
&.search-input::-moz-placeholder { /* Firefox 19+ */ &.search-input::-moz-placeholder { /* Firefox 19+ */
text-align: center; text-align: center;
} }
&.search-input:-ms-input-placeholder { &.search-input:-ms-input-placeholder {
text-align: center; text-align: center;
} }
} }
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
} }
...@@ -69,6 +69,10 @@ label { ...@@ -69,6 +69,10 @@ label {
&.inline-label { &.inline-label {
margin: 0; margin: 0;
} }
&.label-light {
font-weight: 600;
}
} }
.inline-input-group { .inline-input-group {
......
...@@ -23,13 +23,13 @@ ...@@ -23,13 +23,13 @@
&:hover { &:hover {
background-color: $color-darker; background-color: $color-darker;
a { a {
color: #FFF; color: #fff;
} }
} }
} }
.collapse-nav a { .collapse-nav a {
color: #FFF; color: #fff;
background: $color; background: $color;
} }
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
&:hover { &:hover {
background-color: $color-dark; background-color: $color-dark;
color: #FFF; color: #fff;
text-decoration: none; text-decoration: none;
} }
} }
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
} }
&.active a { &.active a {
color: #FFF; color: #fff;
background: $color-dark; background: $color-dark;
&.no-highlight { &.no-highlight {
...@@ -79,42 +79,42 @@ ...@@ -79,42 +79,42 @@
} }
i { i {
color: #FFF color: #fff
} }
} }
} }
} }
} }
$theme-blue: #2980B9; $theme-blue: #2980b9;
$theme-charcoal: #333c47; $theme-charcoal: #333c47;
$theme-graphite: #888888; $theme-graphite: #888;
$theme-gray: #373737; $theme-gray: #373737;
$theme-green: #019875; $theme-green: #019875;
$theme-violet: #554488; $theme-violet: #548;
body { body {
&.ui_blue { &.ui_blue {
@include gitlab-theme(#BECDE9, $theme-blue, #1970A9, #096099); @include gitlab-theme(#becde9, $theme-blue, #1970a9, #096099);
} }
&.ui_charcoal { &.ui_charcoal {
@include gitlab-theme(#c5d0de, $theme-charcoal, #2b333d, #24272D); @include gitlab-theme(#c5d0de, $theme-charcoal, #2b333d, #24272d);
} }
&.ui_graphite { &.ui_graphite {
@include gitlab-theme(#CCCCCC, $theme-graphite, #777777, #666666); @include gitlab-theme(#ccc, $theme-graphite, #777, #666);
} }
&.ui_gray { &.ui_gray {
@include gitlab-theme(#979797, $theme-gray, #272727, #222222); @include gitlab-theme(#979797, $theme-gray, #272727, #222);
} }
&.ui_green { &.ui_green {
@include gitlab-theme(#AADDCC, $theme-green, #018865, #017855); @include gitlab-theme(#adc, $theme-green, #018865, #017855);
} }
&.ui_violet { &.ui_violet {
@include gitlab-theme(#9988CC, $theme-violet, #443366, #332255); @include gitlab-theme(#98c, $theme-violet, #436, #325);
} }
} }
\ No newline at end of file
...@@ -7,8 +7,8 @@ header { ...@@ -7,8 +7,8 @@ header {
&.navbar-empty { &.navbar-empty {
height: 58px; height: 58px;
background: #FFF; background: #fff;
border-bottom: 1px solid #EEE; border-bottom: 1px solid #eee;
.center-logo { .center-logo {
margin: 11px 0; margin: 11px 0;
...@@ -28,7 +28,7 @@ header { ...@@ -28,7 +28,7 @@ header {
min-height: $header-height; min-height: $header-height;
background-color: #fff; background-color: #fff;
border: none; border: none;
border-bottom: 1px solid #EEE; border-bottom: 1px solid #eee;
.container-fluid { .container-fluid {
width: 100% !important; width: 100% !important;
...@@ -47,7 +47,7 @@ header { ...@@ -47,7 +47,7 @@ header {
text-align: center; text-align: center;
&:hover, &:focus, &:active { &:hover, &:focus, &:active {
background-color: #FFF; background-color: #fff;
} }
} }
...@@ -59,7 +59,7 @@ header { ...@@ -59,7 +59,7 @@ header {
right: 2px; right: 2px;
&:hover { &:hover {
background-color: #EEE; background-color: #eee;
} }
&.active { &.active {
color: #7f8fa4; color: #7f8fa4;
...@@ -141,22 +141,18 @@ header { ...@@ -141,22 +141,18 @@ header {
margin-left: $sidebar_collapsed_width; margin-left: $sidebar_collapsed_width;
} }
@media (max-width: $screen-md-max) { .header-collapsed {
.header-collapsed { margin-left: $sidebar_collapsed_width;
margin-left: $sidebar_collapsed_width;
}
.header-expanded {
margin-left: $sidebar_width;
}
}
@media(min-width: $screen-md-max) { @media (min-width: $screen-md-min) {
.header-collapsed {
@include collapsed-header; @include collapsed-header;
} }
}
.header-expanded {
margin-left: $sidebar_collapsed_width;
.header-expanded { @media (min-width: $screen-md-min) {
margin-left: $sidebar_width; margin-left: $sidebar_width;
} }
} }
...@@ -166,7 +162,7 @@ header { ...@@ -166,7 +162,7 @@ header {
font-size: 18px; font-size: 18px;
.navbar-nav { .navbar-nav {
margin: 0px; margin: 0;
float: none !important; float: none !important;
.visible-xs, .visable-sm { .visible-xs, .visable-sm {
......
.file-content.code { .file-content.code {
border: none; border: none;
box-shadow: none; box-shadow: none;
margin: 0px; margin: 0;
padding: 0px; padding: 0;
table-layout: fixed; table-layout: fixed;
pre { pre {
......
...@@ -5,13 +5,22 @@ ...@@ -5,13 +5,22 @@
*/ */
.status-box { .status-box {
/* Extra small devices (phones, less than 768px) */
/* No media query since this is the default in Bootstrap */
padding: 5px 11px;
margin-top: 4px;
/* Small devices (tablets, 768px and up) */
@media (min-width: $screen-sm-min) {
padding: 0 $gl-btn-padding;
margin-top: 5px;
}
@include border-radius(3px); @include border-radius(3px);
display: block; display: block;
float: left; float: left;
padding: 0 $gl-btn-padding;
margin-top: 5px;
margin-right: 10px; margin-right: 10px;
color: #FFF; color: #fff;
font-size: $gl-font-size; font-size: $gl-font-size;
line-height: 25px; line-height: 25px;
......
...@@ -3,13 +3,13 @@ ...@@ -3,13 +3,13 @@
font-size: $font-size-base; font-size: $font-size-base;
&.ui-datepicker-inline { &.ui-datepicker-inline {
border: 1px solid #DDD; border: 1px solid #ddd;
padding: 10px; padding: 10px;
width: 270px; width: 270px;
.ui-datepicker-header { .ui-datepicker-header {
background: #FFF; background: #fff;
border-color: #DDD; border-color: #ddd;
} }
.ui-datepicker-calendar td a { .ui-datepicker-calendar td a {
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
} }
&.ui-autocomplete { &.ui-autocomplete {
border-color: #DDD; border-color: #ddd;
padding: 0; padding: 0;
margin-top: 2px; margin-top: 2px;
z-index: 1001; z-index: 1001;
...@@ -30,20 +30,20 @@ ...@@ -30,20 +30,20 @@
} }
.ui-state-default { .ui-state-default {
border: 1px solid #FFF; border: 1px solid #fff;
background: #FFF; background: #fff;
color: #777; color: #777;
} }
.ui-state-highlight { .ui-state-highlight {
border: 1px solid #EEE; border: 1px solid #eee;
background: #EEE; background: #eee;
} }
.ui-state-active { .ui-state-active {
border: 1px solid $gl-primary; border: 1px solid $gl-primary;
background: $gl-primary; background: $gl-primary;
color: #FFF; color: #fff;
} }
.ui-state-hover, .ui-state-hover,
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* *
*/ */
.well-list { .well-list {
position: relative;
margin: 0; margin: 0;
padding: 0; padding: 0;
list-style: none; list-style: none;
...@@ -110,14 +111,17 @@ ul.content-list { ...@@ -110,14 +111,17 @@ ul.content-list {
> li { > li {
border-color: $table-border-color; border-color: $table-border-color;
color: $list-text-color;
font-size: $list-font-size; font-size: $list-font-size;
color: $list-text-color;
.title { .title {
color: $list-title-color;
font-weight: 600; font-weight: 600;
} }
a {
color: $gl-dark-link-color;
}
.description { .description {
p { p {
@include str-truncated; @include str-truncated;
...@@ -140,6 +144,10 @@ ul.content-list { ...@@ -140,6 +144,10 @@ ul.content-list {
} }
} }
.panel > .content-list > li {
padding: $gl-padding-top $gl-padding;
}
ul.controls { ul.controls {
padding-top: 1px; padding-top: 1px;
float: right; float: right;
......
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
} }
.md-preview-holder { .md-preview-holder {
background: #FFF; background: #fff;
border: 1px solid #ddd; border: 1px solid #ddd;
min-height: 169px; min-height: 169px;
padding: 5px; padding: 5px;
...@@ -80,7 +80,7 @@ ...@@ -80,7 +80,7 @@
.markdown-area { .markdown-area {
@include border-radius(0); @include border-radius(0);
background: #FFF; background: #fff;
border: 1px solid #ddd; border: 1px solid #ddd;
min-height: 140px; min-height: 140px;
max-height: 500px; max-height: 500px;
......
...@@ -41,12 +41,6 @@ ...@@ -41,12 +41,6 @@
transition: $transition; transition: $transition;
} }
@mixin transform($transform) {
-webkit-transform: $transform;
-ms-transform: $transform;
transform: $transform;
}
/** /**
* Prefilled mixins * Prefilled mixins
* Mixins with fixed values * Mixins with fixed values
...@@ -73,17 +67,17 @@ ...@@ -73,17 +67,17 @@
* Base mixin for lists in GitLab * Base mixin for lists in GitLab
*/ */
@mixin basic-list { @mixin basic-list {
margin: 5px 0px; margin: 5px 0;
padding: 0px; padding: 0;
list-style: none; list-style: none;
> li { > li {
@include clearfix; @include clearfix;
padding: 10px 0; padding: 10px 0;
border-bottom: 1px solid #EEE; border-bottom: 1px solid #eee;
display: block; display: block;
margin: 0px; margin: 0;
&:last-child { &:last-child {
border-bottom: none; border-bottom: none;
......
...@@ -128,12 +128,12 @@ ...@@ -128,12 +128,12 @@
.show-aside { .show-aside {
display: none; display: none;
position: fixed; position: fixed;
right: 0px; right: 0;
top: 30%; top: 30%;
padding: 5px 15px; padding: 5px 15px;
background: #EEE; background: #eee;
font-size: 20px; font-size: 20px;
color: #777; color: #777;
z-index: 100; z-index: 100;
@include box-shadow(0 1px 2px #DDD); @include box-shadow(0 1px 2px #ddd);
} }
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
} }
&.active a { &.active a {
color: #000000; color: #000;
border-bottom: 2px solid #4688f1; border-bottom: 2px solid #4688f1;
} }
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
.top-area { .top-area {
@include clearfix; @include clearfix;
border-bottom: 1px solid #EEE; border-bottom: 1px solid #eee;
.nav-text { .nav-text {
padding-top: 16px; padding-top: 16px;
...@@ -59,11 +59,11 @@ ...@@ -59,11 +59,11 @@
.nav-links { .nav-links {
display: inline-block; display: inline-block;
width: 50%; width: 50%;
margin-bottom: 0px; margin-bottom: 0;
border-bottom: none; border-bottom: none;
/* Small devices (phones, tablets, 768px and lower) */ /* Small devices (phones, tablets, 768px and lower) */
@media (max-width: $screen-sm-min) { @media (max-width: $screen-sm-max) {
width: 100%; width: 100%;
} }
} }
...@@ -74,11 +74,15 @@ ...@@ -74,11 +74,15 @@
float: right; float: right;
text-align: right; text-align: right;
padding: 11px 0; padding: 11px 0;
margin-bottom: 0px; margin-bottom: 0;
> .dropdown { > .dropdown {
margin-right: $gl-padding-top; margin-right: $gl-padding-top;
display: inline-block; display: inline-block;
&:last-child {
margin-right: 0;
}
} }
> .btn { > .btn {
......
html.turbolinks-progress-bar::before {
background-color: $progress-color!important;
height: 2px!important;
box-shadow: 0 0 10px $progress-color, 0 0 5px $progress-color;
}
...@@ -151,7 +151,7 @@ ...@@ -151,7 +151,7 @@
padding: 2px 25px 2px 5px; padding: 2px 25px 2px 5px;
background: #fff image-url('select2.png'); background: #fff image-url('select2.png');
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: right 0px bottom 6px; background-position: right 0 bottom 6px;
border: 1px solid $input-border; border: 1px solid $input-border;
@include border-radius($border-radius-default); @include border-radius($border-radius-default);
@include transition(border-color ease-in-out .15s, box-shadow ease-in-out .15s); @include transition(border-color ease-in-out .15s, box-shadow ease-in-out .15s);
...@@ -229,7 +229,7 @@ ...@@ -229,7 +229,7 @@
.namespace-result { .namespace-result {
.namespace-kind { .namespace-kind {
color: #AAA; color: #aaa;
font-weight: normal; font-weight: normal;
} }
.namespace-path { .namespace-path {
......
...@@ -13,13 +13,33 @@ ...@@ -13,13 +13,33 @@
transition-duration: .3s; transition-duration: .3s;
} }
.gitlab-text-container-link {
z-index: 1;
position: absolute;
left: 0;
}
#logo {
z-index: 2;
position: absolute;
width: 58px;
cursor: pointer;
}
&.right-sidebar-expanded { &.right-sidebar-expanded {
padding-right: $gutter_width; /* Extra small devices (phones, less than 768px) */
/* No media query since this is the default in Bootstrap */
padding-right: 0;
/* Small devices (tablets, 768px and up) */
@media (min-width: $screen-sm-min) {
padding-right: $gutter_width;
}
} }
} }
.sidebar-wrapper { .sidebar-wrapper {
z-index: 99; z-index: 999;
background: $background-color; background: $background-color;
} }
...@@ -27,7 +47,7 @@ ...@@ -27,7 +47,7 @@
width: 100%; width: 100%;
.container-fluid { .container-fluid {
background: #FFF; background: #fff;
padding: 0 $gl-padding; padding: 0 $gl-padding;
&.container-blank { &.container-blank {
...@@ -74,7 +94,7 @@ ...@@ -74,7 +94,7 @@
width: 158px; width: 158px;
float: left; float: left;
margin: 0; margin: 0;
margin-left: 14px; margin-left: 50px;
font-size: 19px; font-size: 19px;
line-height: 41px; line-height: 41px;
font-weight: normal; font-weight: normal;
...@@ -83,7 +103,7 @@ ...@@ -83,7 +103,7 @@
} }
&:hover { &:hover {
background-color: #EEE; background-color: #eee;
} }
} }
...@@ -123,7 +143,7 @@ ...@@ -123,7 +143,7 @@
overflow: hidden; overflow: hidden;
&.navbar-collapse { &.navbar-collapse {
padding: 0px !important; padding: 0 !important;
} }
li { li {
...@@ -162,7 +182,7 @@ ...@@ -162,7 +182,7 @@
.count { .count {
float: right; float: right;
background: #eee; background: #eee;
padding: 0px 8px; padding: 0 8px;
@include border-radius(6px); @include border-radius(6px);
} }
...@@ -174,8 +194,8 @@ ...@@ -174,8 +194,8 @@
} }
.sidebar-subnav { .sidebar-subnav {
margin-left: 0px; margin-left: 0;
padding-left: 0px; padding-left: 0;
li { li {
list-style: none; list-style: none;
...@@ -183,10 +203,19 @@ ...@@ -183,10 +203,19 @@
} }
@mixin expanded-sidebar { @mixin expanded-sidebar {
padding-left: $sidebar_width; padding-left: $sidebar_collapsed_width;
@media (min-width: $screen-md-min) {
padding-left: $sidebar_width;
}
&.right-sidebar-collapsed { &.right-sidebar-collapsed {
padding-right: $sidebar_collapsed_width; /* Extra small devices (phones, less than 768px) */
padding-right: 0;
/* Small devices (tablets, 768px and up) */
@media (min-width: $screen-sm-min) {
padding-right: $sidebar_collapsed_width;
}
} }
.sidebar-wrapper { .sidebar-wrapper {
...@@ -212,7 +241,12 @@ ...@@ -212,7 +241,12 @@
padding-left: $sidebar_collapsed_width; padding-left: $sidebar_collapsed_width;
&.right-sidebar-collapsed { &.right-sidebar-collapsed {
padding-right: $sidebar_collapsed_width; /* Extra small devices (phones, less than 768px) */
padding-right: 0;
/* Small devices (tablets, 768px and up) */
@media (min-width: $screen-sm-min) {
padding-right: $sidebar_collapsed_width;
}
} }
.sidebar-wrapper { .sidebar-wrapper {
...@@ -279,7 +313,13 @@ ...@@ -279,7 +313,13 @@
} }
.page-sidebar-collapsed { .page-sidebar-collapsed {
/* Extra small devices (phones, less than 768px) */
@include collapsed-sidebar; @include collapsed-sidebar;
padding-right: 0;
/* Small devices (tablets, 768px and up) */
@media (min-width: $screen-sm-min) {
@include collapsed-sidebar;
}
} }
.page-sidebar-expanded { .page-sidebar-expanded {
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
// Components // Components
@import "bootstrap/component-animations"; @import "bootstrap/component-animations";
@import "bootstrap/dropdowns"; // @import "bootstrap/dropdowns";
@import "bootstrap/button-groups"; @import "bootstrap/button-groups";
@import "bootstrap/input-groups"; @import "bootstrap/input-groups";
@import "bootstrap/navs"; @import "bootstrap/navs";
...@@ -95,7 +95,7 @@ ...@@ -95,7 +95,7 @@
} }
&.label-inverse { &.label-inverse {
background-color: #333333; background-color: #333;
} }
} }
...@@ -138,7 +138,7 @@ ...@@ -138,7 +138,7 @@
} }
.btn-clipboard { .btn-clipboard {
min-width: 0px; min-width: 0;
} }
} }
...@@ -167,12 +167,6 @@ ...@@ -167,12 +167,6 @@
} }
} }
.alert-help {
background-color: $background-color;
border: 1px solid $border-color;
color: $gl-gray;
}
// Typography ================================================================= // Typography =================================================================
.text-primary, .text-primary,
......
...@@ -57,7 +57,7 @@ $component-active-bg: $brand-info; ...@@ -57,7 +57,7 @@ $component-active-bg: $brand-info;
$input-color: $text-color; $input-color: $text-color;
$input-border: #e7e9ed; $input-border: #e7e9ed;
$input-border-focus: #7F8FA4; $input-border-focus: #7f8fa4;
$legend-color: $text-color; $legend-color: $text-color;
...@@ -125,8 +125,8 @@ $panel-inner-border: $border-color; ...@@ -125,8 +125,8 @@ $panel-inner-border: $border-color;
// //
//## //##
$well-bg: #F9F9F9; $well-bg: #f9f9f9;
$well-border: #EEE; $well-border: #eee;
//== Code //== Code
// //
......
...@@ -27,13 +27,13 @@ ...@@ -27,13 +27,13 @@
line-height: 10px; line-height: 10px;
color: #555; color: #555;
vertical-align: middle; vertical-align: middle;
background-color: #FCFCFC; background-color: #fcfcfc;
border-width: 1px; border-width: 1px;
border-style: solid; border-style: solid;
border-color: #CCC #CCC #BBB; border-color: #ccc #ccc #bbb;
border-image: none; border-image: none;
border-radius: 3px; border-radius: 3px;
box-shadow: 0px -1px 0px #BBB inset; box-shadow: 0 -1px 0 #bbb inset;
} }
h1 { h1 {
...@@ -149,13 +149,13 @@ ...@@ -149,13 +149,13 @@
} }
&:hover > a.anchor { &:hover > a.anchor {
$size: 16px; $size: 14px;
position: absolute; position: absolute;
right: 100%; right: 100%;
top: 50%; top: 50%;
margin-top: -$size/2; margin-top: -11px;
margin-right: 0px; margin-right: 0;
padding-right: 20px; padding-right: 15px;
display: inline-block; display: inline-block;
width: $size; width: $size;
height: $size; height: $size;
...@@ -187,7 +187,7 @@ body { ...@@ -187,7 +187,7 @@ body {
} }
.page-title-empty { .page-title-empty {
margin-top: 0px; margin-top: 0;
line-height: 1.3; line-height: 1.3;
font-size: 1.25em; font-size: 1.25em;
font-weight: 600; font-weight: 600;
...@@ -196,7 +196,7 @@ body { ...@@ -196,7 +196,7 @@ body {
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
color: $gl-header-color; color: $gl-header-color;
font-weight: 500; font-weight: 600;
} }
/** CODE **/ /** CODE **/
......
$row-hover: #f4f8fe; /*
$gl-text-color: #54565B; * Layout
$gl-text-green: #4A2; */
$gl-text-red: #D12F19;
$gl-text-orange: #D90;
$gl-header-color: #323232;
$gl-link-color: #333c48;
$md-text-color: #444;
$md-link-color: #3084bb;
$nprogress-color: #c0392b;
$gl-font-size: 15px;
$list-font-size: 15px;
$sidebar_collapsed_width: 62px; $sidebar_collapsed_width: 62px;
$sidebar_width: 230px; $sidebar_width: 230px;
$gutter_collapsed_width: 62px; $gutter_collapsed_width: 62px;
$gutter_width: 290px; $gutter_width: 290px;
$gutter_inner_width: 258px; $gutter_inner_width: 258px;
$avatar_radius: 50%;
/*
* UI elements
*/
$border-color: #efeff1;
$table-border-color: #eef0f2;
$background-color: #faf9f9;
/*
* Text
*/
$gl-font-size: 15px;
$gl-title-color: #333;
$gl-text-color: #555;
$gl-text-green: #4a2;
$gl-text-red: #d12f19;
$gl-text-orange: #d90;
$gl-link-color: #3084bb;
$gl-dark-link-color: #333;
$gl-placeholder-color: #8f8f8f;
$gl-gray: $gl-text-color;
$gl-header-color: $gl-title-color;
/*
* Lists
*/
$list-font-size: $gl-font-size;
$list-title-color: $gl-title-color;
$list-text-color: $gl-text-color;
/*
* Markdown
*/
$md-text-color: $gl-text-color;
$md-link-color: $gl-link-color;
/*
* Code
*/
$code_font_size: 13px; $code_font_size: 13px;
$code_line_height: 1.5; $code_line_height: 1.5;
$border-color: #efeff1;
$table-border-color: #eef0f2; /*
$background-color: #faf9f9; * Padding
$header-height: 58px; */
$fixed-layout-width: 1280px;
$gl-gray: #5a5a5a;
$gl-padding: 16px; $gl-padding: 16px;
$gl-btn-padding: 10px; $gl-btn-padding: 10px;
$gl-vert-padding: 6px; $gl-vert-padding: 6px;
$gl-padding-top:10px; $gl-padding-top: 10px;
/*
* Misc
*/
$row-hover: #f4f8fe;
$progress-color: #c0392b;
$avatar_radius: 50%;
$header-height: 58px;
$fixed-layout-width: 1280px;
$gl-avatar-size: 40px; $gl-avatar-size: 40px;
$secondary-text: #7f8fa4; $error-exclamation-point: #e62958;
$error-exclamation-point: #E62958;
$border-radius-default: 3px; $border-radius-default: 3px;
$list-title-color: #333333; $btn-transparent-color: #8f8f8f;
$list-text-color: #555555; $ssh-key-icon-color: #8f8f8f;
$ssh-key-icon-size: 18px;
$provider-btn-group-border: #e5e5e5;
$provider-btn-not-active-color: #4688f1;
/* /*
* Color schema * Color schema
*/ */
$white-light: #FFFFFF; $white-light: #fff;
$white-normal: #ededed; $white-normal: #ededed;
$white-dark: #ededed; $white-dark: #ededed;
...@@ -49,48 +87,55 @@ $gray-dark: #ededed; ...@@ -49,48 +87,55 @@ $gray-dark: #ededed;
$gray-darkest: #c9c9c9; $gray-darkest: #c9c9c9;
$green-light: #38ae67; $green-light: #38ae67;
$green-normal: #2FAA60; $green-normal: #2faa60;
$green-dark: #2CA05B; $green-dark: #2ca05b;
$blue-light: #2EA8E5; $blue-light: #2ea8e5;
$blue-normal: #2D9FD8; $blue-normal: #2d9fd8;
$blue-dark: #2897CE; $blue-dark: #2897ce;
$blue-medium-light: #3498CB; $blue-medium-light: #3498cb;
$blue-medium: #2F8EBF; $blue-medium: #2f8ebf;
$blue-medium-dark: #2D86B4; $blue-medium-dark: #2d86b4;
$orange-light: rgba(252, 109, 38, 0.80); $orange-light: rgba(252, 109, 38, 0.80);
$orange-normal: #E75E40; $orange-normal: #e75e40;
$orange-dark: #CE5237; $orange-dark: #ce5237;
$red-light: #F43263; $red-light: #f06559;
$red-normal: #E52C5A; $red-normal: #e52c5a;
$red-dark: #D22852; $red-dark: #d22852;
$border-white-light: #F1F2F4; $border-white-light: #f1f2f4;
$border-white-normal: #D6DAE2; $border-white-normal: #d6dae2;
$border-white-dark: #C6CACF; $border-white-dark: #c6cacf;
$border-gray-light: rgba(0, 0, 0, 0.06); $border-gray-light: rgba(0, 0, 0, 0.06);
$border-gray-normal: rgba(0, 0, 0, 0.10);; $border-gray-normal: rgba(0, 0, 0, 0.10);;
$border-gray-dark: #C6CACF; $border-gray-dark: #c6cacf;
$border-green-light: #2FAA60; $border-green-light: #2faa60;
$border-green-normal: #2CA05B; $border-green-normal: #2ca05b;
$border-green-dark: #279654; $border-green-dark: #279654;
$border-blue-light: #2D9FD8; $border-blue-light: #2d9fd8;
$border-blue-normal: #2897CE; $border-blue-normal: #2897ce;
$border-blue-dark: #258DC1; $border-blue-dark: #258dc1;
$border-orange-light: #fc6d26; $border-orange-light: #fc6d26;
$border-orange-normal: #CE5237; $border-orange-normal: #ce5237;
$border-orange-dark: #C14E35; $border-orange-dark: #c14e35;
$border-red-light: #f24f41;
$border-red-normal: #d22852;
$border-red-dark: #ca264f;
$help-well-bg: #fafafa;
$help-well-border: #e5e5e5;
$border-red-light: #E52C5A; $warning-message-bg: #fbf2d9;
$border-red-normal: #D22852; $warning-message-color: #9e8e60;
$border-red-dark: #CA264F; $warning-message-border: #f0e2bb;
/* header */ /* header */
$light-grey-header: #faf9f9; $light-grey-header: #faf9f9;
...@@ -117,3 +162,33 @@ $deleted: #f77; ...@@ -117,3 +162,33 @@ $deleted: #f77;
*/ */
$monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Courier New', 'andale mono', 'lucida console', monospace; $monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Courier New', 'andale mono', 'lucida console', monospace;
$regular_font: 'Source Sans Pro', "Helvetica Neue", Helvetica, Arial, sans-serif; $regular_font: 'Source Sans Pro', "Helvetica Neue", Helvetica, Arial, sans-serif;
/*
* Dropdowns
*/
$dropdown-bg: #fff;
$dropdown-link-color: #555;
$dropdown-link-hover-bg: rgba(#000, .04);
$dropdown-border-color: rgba(#000, .1);
$dropdown-shadow-color: rgba(#000, .1);
$dropdown-divider-color: rgba(#000, .1);
$dropdown-header-color: #959494;
$dropdown-title-btn-color: #bfbfbf;
$dropdown-input-color: #c7c7c7;
$dropdown-input-focus-border: rgb(58, 171, 240);
$dropdown-input-focus-shadow: rgba(#000, .2);
$dropdown-loading-bg: rgba(#fff, .6);
$dropdown-toggle-bg: #fff;
$dropdown-toggle-color: #626262;
$dropdown-toggle-border-color: #eaeaea;
$dropdown-toggle-hover-border-color: darken($dropdown-toggle-border-color, 15%);
$dropdown-toggle-icon-color: #c4c4c4;
$dropdown-toggle-hover-icon-color: $dropdown-toggle-hover-border-color;
/*
* Award emoji
*/
$award-emoji-menu-bg: #fff;
$award-emoji-menu-border: #f1f2f4;
$award-emoji-new-btn-icon-color: #dcdcdc;
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
a.js-zen-enter { a.js-zen-enter {
color: $gl-gray; color: $gl-gray;
position: absolute; position: absolute;
top: 0px; top: 0;
right: 4px; right: 4px;
line-height: 56px; line-height: 56px;
} }
......
...@@ -43,12 +43,12 @@ ...@@ -43,12 +43,12 @@
// Search result highlight // Search result highlight
span.highlight_word { span.highlight_word {
background-color: #ffe792 !important; background-color: #ffe792 !important;
color: #000000 !important; color: #000 !important;
} }
.hll { background-color: #373b41 } .hll { background-color: #373b41 }
.c { color: #969896 } /* Comment */ .c { color: #969896 } /* Comment */
.err { color: #cc6666 } /* Error */ .err { color: #c66 } /* Error */
.k { color: #b294bb } /* Keyword */ .k { color: #b294bb } /* Keyword */
.l { color: #de935f } /* Literal */ .l { color: #de935f } /* Literal */
.n { color: #c5c8c6 } /* Name */ .n { color: #c5c8c6 } /* Name */
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
.cp { color: #969896 } /* Comment.Preproc */ .cp { color: #969896 } /* Comment.Preproc */
.c1 { color: #969896 } /* Comment.Single */ .c1 { color: #969896 } /* Comment.Single */
.cs { color: #969896 } /* Comment.Special */ .cs { color: #969896 } /* Comment.Special */
.gd { color: #cc6666 } /* Generic.Deleted */ .gd { color: #c66 } /* Generic.Deleted */
.ge { font-style: italic } /* Generic.Emph */ .ge { font-style: italic } /* Generic.Emph */
.gh { color: #c5c8c6; font-weight: bold } /* Generic.Heading */ .gh { color: #c5c8c6; font-weight: bold } /* Generic.Heading */
.gi { color: #b5bd68 } /* Generic.Inserted */ .gi { color: #b5bd68 } /* Generic.Inserted */
...@@ -77,17 +77,17 @@ ...@@ -77,17 +77,17 @@
.na { color: #81a2be } /* Name.Attribute */ .na { color: #81a2be } /* Name.Attribute */
.nb { color: #c5c8c6 } /* Name.Builtin */ .nb { color: #c5c8c6 } /* Name.Builtin */
.nc { color: #f0c674 } /* Name.Class */ .nc { color: #f0c674 } /* Name.Class */
.no { color: #cc6666 } /* Name.Constant */ .no { color: #c66 } /* Name.Constant */
.nd { color: #8abeb7 } /* Name.Decorator */ .nd { color: #8abeb7 } /* Name.Decorator */
.ni { color: #c5c8c6 } /* Name.Entity */ .ni { color: #c5c8c6 } /* Name.Entity */
.ne { color: #cc6666 } /* Name.Exception */ .ne { color: #c66 } /* Name.Exception */
.nf { color: #81a2be } /* Name.Function */ .nf { color: #81a2be } /* Name.Function */
.nl { color: #c5c8c6 } /* Name.Label */ .nl { color: #c5c8c6 } /* Name.Label */
.nn { color: #f0c674 } /* Name.Namespace */ .nn { color: #f0c674 } /* Name.Namespace */
.nx { color: #81a2be } /* Name.Other */ .nx { color: #81a2be } /* Name.Other */
.py { color: #c5c8c6 } /* Name.Property */ .py { color: #c5c8c6 } /* Name.Property */
.nt { color: #8abeb7 } /* Name.Tag */ .nt { color: #8abeb7 } /* Name.Tag */
.nv { color: #cc6666 } /* Name.Variable */ .nv { color: #c66 } /* Name.Variable */
.ow { color: #8abeb7 } /* Operator.Word */ .ow { color: #8abeb7 } /* Operator.Word */
.w { color: #c5c8c6 } /* Text.Whitespace */ .w { color: #c5c8c6 } /* Text.Whitespace */
.mf { color: #de935f } /* Literal.Number.Float */ .mf { color: #de935f } /* Literal.Number.Float */
...@@ -106,8 +106,8 @@ ...@@ -106,8 +106,8 @@
.s1 { color: #b5bd68 } /* Literal.String.Single */ .s1 { color: #b5bd68 } /* Literal.String.Single */
.ss { color: #b5bd68 } /* Literal.String.Symbol */ .ss { color: #b5bd68 } /* Literal.String.Symbol */
.bp { color: #c5c8c6 } /* Name.Builtin.Pseudo */ .bp { color: #c5c8c6 } /* Name.Builtin.Pseudo */
.vc { color: #cc6666 } /* Name.Variable.Class */ .vc { color: #c66 } /* Name.Variable.Class */
.vg { color: #cc6666 } /* Name.Variable.Global */ .vg { color: #c66 } /* Name.Variable.Global */
.vi { color: #cc6666 } /* Name.Variable.Instance */ .vi { color: #c66 } /* Name.Variable.Instance */
.il { color: #de935f } /* Literal.Number.Integer.Long */ .il { color: #de935f } /* Literal.Number.Integer.Long */
} }
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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