Commit 7b1bb0f4 authored by Jacob Vosmaer's avatar Jacob Vosmaer

Merge branch 'master' of https://gitlab.com/gitlab-org/gitlab-ce into auto-fsck

parents ea787165 d65d5c2d
...@@ -2,7 +2,6 @@ image: "ruby:2.1" ...@@ -2,7 +2,6 @@ image: "ruby:2.1"
services: services:
- mysql:latest - mysql:latest
- postgres:latest
- redis:latest - redis:latest
cache: cache:
...@@ -35,134 +34,86 @@ spec:feature: ...@@ -35,134 +34,86 @@ spec:feature:
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
tags:
- ruby
- mysql
spec:api: spec:api:
stage: test stage: test
script: script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:api - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:api
tags:
- ruby
- mysql
spec:models: spec:models:
stage: test stage: test
script: script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:models - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:models
tags:
- ruby
- mysql
spec:lib: spec:lib:
stage: test stage: test
script: script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:lib - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:lib
tags:
- ruby
- mysql
spec:services: spec:services:
stage: test stage: test
script: script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:services - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:services
tags:
- ruby
- mysql
spec:other: spec:other:
stage: test stage: test
script: script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:other - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:other
tags:
- ruby
- mysql
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 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:
- ruby
- mysql
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 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:
- ruby
- mysql
spinach:other: spinach:other:
stage: test stage: test
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 spinach:other - RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:other
tags:
- ruby
- mysql
teaspoon: teaspoon:
stage: test stage: test
script: script:
- RAILS_ENV=test bundle exec teaspoon - RAILS_ENV=test bundle exec teaspoon
tags:
- ruby
- mysql
rubocop: rubocop:
stage: test stage: test
script: script:
- bundle exec rubocop - bundle exec rubocop
tags:
- ruby
- mysql
scss-lint: scss-lint:
stage: test stage: test
script: script:
- bundle exec rake scss_lint - bundle exec rake scss_lint
tags:
- ruby
brakeman: brakeman:
stage: test stage: test
script: script:
- bundle exec rake brakeman - bundle exec rake brakeman
tags:
- ruby
- mysql
flog: flog:
stage: test stage: test
script: script:
- bundle exec rake flog - bundle exec rake flog
tags:
- ruby
- mysql
flay: flay:
stage: test stage: test
script: script:
- bundle exec rake flay - bundle exec rake flay
tags:
- ruby
- mysql
bundler:audit: bundler:audit:
stage: test stage: test
only: only:
- master - master
script: script:
- "bundle exec bundle-audit update" - "bundle exec bundle-audit check --update --ignore OSVDB-115941"
- "bundle exec bundle-audit check --ignore OSVDB-115941"
tags:
- ruby
- mysql
# Ruby 2.2 jobs # Ruby 2.2 jobs
...@@ -178,9 +129,6 @@ spec:feature:ruby22: ...@@ -178,9 +129,6 @@ spec:feature:ruby22:
key: "ruby22" key: "ruby22"
paths: paths:
- vendor - vendor
tags:
- ruby
- mysql
spec:api:ruby22: spec:api:ruby22:
stage: test stage: test
...@@ -193,9 +141,6 @@ spec:api:ruby22: ...@@ -193,9 +141,6 @@ spec:api:ruby22:
key: "ruby22" key: "ruby22"
paths: paths:
- vendor - vendor
tags:
- ruby
- mysql
spec:models:ruby22: spec:models:ruby22:
stage: test stage: test
...@@ -208,9 +153,6 @@ spec:models:ruby22: ...@@ -208,9 +153,6 @@ spec:models:ruby22:
key: "ruby22" key: "ruby22"
paths: paths:
- vendor - vendor
tags:
- ruby
- mysql
spec:lib:ruby22: spec:lib:ruby22:
stage: test stage: test
...@@ -223,9 +165,6 @@ spec:lib:ruby22: ...@@ -223,9 +165,6 @@ spec:lib:ruby22:
key: "ruby22" key: "ruby22"
paths: paths:
- vendor - vendor
tags:
- ruby
- mysql
spec:services:ruby22: spec:services:ruby22:
stage: test stage: test
...@@ -238,9 +177,6 @@ spec:services:ruby22: ...@@ -238,9 +177,6 @@ spec:services:ruby22:
key: "ruby22" key: "ruby22"
paths: paths:
- vendor - vendor
tags:
- ruby
- mysql
spec:other:ruby22: spec:other:ruby22:
stage: test stage: test
...@@ -253,9 +189,6 @@ spec:other:ruby22: ...@@ -253,9 +189,6 @@ spec:other:ruby22:
key: "ruby22" key: "ruby22"
paths: paths:
- vendor - vendor
tags:
- ruby
- mysql
spinach:project:half:ruby22: spinach:project:half:ruby22:
stage: test stage: test
...@@ -269,9 +202,6 @@ spinach:project:half:ruby22: ...@@ -269,9 +202,6 @@ spinach:project:half:ruby22:
key: "ruby22" key: "ruby22"
paths: paths:
- vendor - vendor
tags:
- ruby
- mysql
spinach:project:rest:ruby22: spinach:project:rest:ruby22:
stage: test stage: test
...@@ -285,9 +215,6 @@ spinach:project:rest:ruby22: ...@@ -285,9 +215,6 @@ spinach:project:rest:ruby22:
key: "ruby22" key: "ruby22"
paths: paths:
- vendor - vendor
tags:
- ruby
- mysql
spinach:other:ruby22: spinach:other:ruby22:
stage: test stage: test
...@@ -301,10 +228,6 @@ spinach:other:ruby22: ...@@ -301,10 +228,6 @@ spinach:other:ruby22:
key: "ruby22" key: "ruby22"
paths: paths:
- vendor - vendor
tags:
- ruby
- mysql
notify:slack: notify:slack:
stage: notifications stage: notifications
......
...@@ -691,7 +691,7 @@ Style/ZeroLengthPredicate: ...@@ -691,7 +691,7 @@ Style/ZeroLengthPredicate:
# branches, and conditions. # branches, and conditions.
Metrics/AbcSize: Metrics/AbcSize:
Enabled: true Enabled: true
Max: 70 Max: 60
# Avoid excessive block nesting. # Avoid excessive block nesting.
Metrics/BlockNesting: Metrics/BlockNesting:
......
...@@ -7,21 +7,44 @@ exclude: ...@@ -7,21 +7,44 @@ exclude:
- 'app/assets/stylesheets/pages/emojis.scss' - 'app/assets/stylesheets/pages/emojis.scss'
linters: linters:
# Reports when you use improper spacing around ! (the "bang") in !default,
# !global, !important, and !optional flags.
BangFormat: BangFormat:
enabled: false enabled: false
# Whether or not to prefer `border: 0` over `border: none`.
BorderZero: BorderZero:
enabled: false enabled: false
# Reports when you define a rule set using a selector with chained classes
# (a.k.a. adjoining classes).
ChainedClasses:
enabled: false
# Prefer hexadecimal color codes over color keywords.
# (e.g. `color: green` is a color keyword)
ColorKeyword: ColorKeyword:
enabled: false enabled: false
# Prefer color literals (keywords or hexadecimal codes) to be used only in
# variable declarations. They should be referred to via variables everywhere
# else.
ColorVariable: ColorVariable:
enabled: false enabled: false
# Which form of comments to prefer in CSS.
Comment: Comment:
enabled: false enabled: false
# Reports @debug statements (which you probably left behind accidentally).
DebugStatement:
enabled: false
# Rule sets should be ordered as follows:
# - @extend declarations
# - @include declarations without inner @content
# - properties, @include declarations with inner @content
# - nested rule sets.
DeclarationOrder: DeclarationOrder:
enabled: false enabled: false
...@@ -32,15 +55,25 @@ linters: ...@@ -32,15 +55,25 @@ linters:
DisableLinterReason: DisableLinterReason:
enabled: true enabled: true
# Reports when you define the same property twice in a single rule set.
DuplicateProperty: DuplicateProperty:
enabled: false enabled: false
# Separate rule, function, and mixin declarations with empty lines.
EmptyLineBetweenBlocks: EmptyLineBetweenBlocks:
enabled: false enabled: false
# Reports when you have an empty rule set.
EmptyRule: EmptyRule:
enabled: false enabled: false
# Reports when you have an @extend directive.
ExtendDirective:
enabled: false
# Files should always have a final newline. This results in better diffs
# when adding lines to the file, since SCM systems such as git won't
# think that you touched the last line.
FinalNewline: FinalNewline:
enabled: false enabled: false
...@@ -53,12 +86,17 @@ linters: ...@@ -53,12 +86,17 @@ linters:
HexNotation: HexNotation:
enabled: true enabled: true
# Avoid using ID selectors.
IdSelector: IdSelector:
enabled: false enabled: false
# The basenames of @imported SCSS partials should not begin with an
# underscore and should not include the filename extension.
ImportPath: ImportPath:
enabled: false enabled: false
# Avoid using !important in properties. It is usually indicative of a
# misunderstanding of CSS specificity and can lead to brittle code.
ImportantRule: ImportantRule:
enabled: false enabled: false
...@@ -67,33 +105,51 @@ linters: ...@@ -67,33 +105,51 @@ linters:
enabled: true enabled: true
width: 2 width: 2
# Don't write leading zeros for numeric values with a decimal point.
LeadingZero: LeadingZero:
enabled: false enabled: false
# Reports when you define the same selector twice in a single sheet.
MergeableSelector: MergeableSelector:
enabled: false enabled: false
# Functions, mixins, variables, and placeholders should be declared
# with all lowercase letters and hyphens instead of underscores.
NameFormat: NameFormat:
enabled: false enabled: false
# Avoid nesting selectors too deeply.
NestingDepth: NestingDepth:
enabled: false enabled: false
# Always use placeholder selectors in @extend.
PlaceholderInExtend: PlaceholderInExtend:
enabled: false enabled: false
# Sort properties in a strict order.
PropertySortOrder: PropertySortOrder:
enabled: false enabled: false
# Reports when you use an unknown or disabled CSS property
# (ignoring vendor-prefixed properties).
PropertySpelling: PropertySpelling:
enabled: false enabled: false
# Configure which units are allowed for property values.
PropertyUnits:
enabled: false
# Pseudo-elements, like ::before, and ::first-letter, should be declared
# with two colons. Pseudo-classes, like :hover and :first-child, should
# be declared with one colon.
PseudoElement: PseudoElement:
enabled: false enabled: false
# Avoid qualifying elements in selectors (also known as "tag-qualifying").
QualifyingElement: QualifyingElement:
enabled: false enabled: false
# Don't write selectors with a depth of applicability greater than 3.
SelectorDepth: SelectorDepth:
enabled: false enabled: false
...@@ -113,9 +169,12 @@ linters: ...@@ -113,9 +169,12 @@ linters:
enabled: true enabled: true
allow_single_line_rule_sets: true allow_single_line_rule_sets: true
# Split selectors onto separate lines after each comma, and have each
# individual selector occupy a single line.
SingleLinePerSelector: SingleLinePerSelector:
enabled: false enabled: false
# Commas in lists should be followed by a space.
SpaceAfterComma: SpaceAfterComma:
enabled: false enabled: false
...@@ -128,29 +187,75 @@ linters: ...@@ -128,29 +187,75 @@ linters:
# colon. # colon.
SpaceAfterPropertyName: SpaceAfterPropertyName:
enabled: true enabled: true
# Variables should be formatted with a single space separating the colon
# from the variable's value.
SpaceAfterVariableColon:
enabled: false
# Variables should be formatted with no space between the name and the
# colon.
SpaceAfterVariableName:
enabled: false
# Operators should be formatted with a single space on both sides of an
# infix operator.
SpaceAroundOperator: SpaceAroundOperator:
enabled: false enabled: false
# Opening braces should be preceded by a single space. # Opening braces should be preceded by a single space.
SpaceBeforeBrace: SpaceBeforeBrace:
enabled: true enabled: true
# Parentheses should not be padded with spaces.
SpaceBetweenParens:
enabled: false
# Enforces that string literals should be written with a consistent form
# of quotes (single or double).
StringQuotes: StringQuotes:
enabled: false enabled: false
# Property values, @extend, @include, and @import directives, and variable
# declarations should always end with a semicolon.
TrailingSemicolon: TrailingSemicolon:
enabled: false enabled: false
# Reports lines containing trailing whitespace.
TrailingWhitespace: TrailingWhitespace:
enabled: false enabled: false
# Don't write trailing zeros for numeric values with a decimal point.
TrailingZero:
enabled: false
# Don't use the `all` keyword to specify transition properties.
TransitionAll:
enabled: false
# Numeric values should not contain unnecessary fractional portions.
UnnecessaryMantissa: UnnecessaryMantissa:
enabled: false enabled: false
# Do not use parent selector references (&) when they would otherwise
# be unnecessary.
UnnecessaryParentReference: UnnecessaryParentReference:
enabled: false enabled: false
# URLs should be valid and not contain protocols or domain names.
UrlFormat:
enabled: false
# URLs should always be enclosed within quotes.
UrlQuotes:
enabled: false
# Properties, like color and font, are easier to read and maintain
# when defined using variables rather than literals.
VariableForProperty:
enabled: false
# Avoid vendor prefixes. Or rather: don't write them yourself.
VendorPrefix: VendorPrefix:
enabled: false enabled: false
......
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 8.7.0 (unreleased) v 8.7.0 (unreleased)
- All service classes (those residing in app/services) are now instrumented (Yorick Peterse)
- Enable gzip for assets, makes the page size significantly smaller. !3544 / !3632 (Connor Shea)
- Load award emoji images separately unless opening the full picker. Saves several hundred KBs of data for most pages. (Connor Shea)
- All images in discussions and wikis now link to their source files !3464 (Connor Shea).
- Return status code 303 after a branch DELETE operation to avoid project deletion (Stan Hu)
- Improved Markdown rendering performance !3389 (Yorick Peterse) - Improved Markdown rendering performance !3389 (Yorick Peterse)
- Don't attempt to look up an avatar in repo if repo directory does not exist (Stan hu) - Don't attempt to look up an avatar in repo if repo directory does not exist (Stan Hu)
- Expose project badges in project settings
- Preserve time notes/comments have been updated at when moving issue - Preserve time notes/comments have been updated at when moving issue
- Make HTTP(s) label consistent on clone bar (Stan Hu) - Make HTTP(s) label consistent on clone bar (Stan Hu)
- Expose label description in API (Mariusz Jachimowicz) - Expose label description in API (Mariusz Jachimowicz)
- Allow back dating on issues when created through the API - Allow back dating on issues when created through the API
- Fix Error 500 after renaming a project path (Stan Hu)
- Fix avatar stretching by providing a cropping feature - Fix avatar stretching by providing a cropping feature
- API: Expose `subscribed` for issues and merge requests (Robert Schilling)
- Allow SAML to handle external users based on user's information !3530
- Add endpoints to archive or unarchive a project !3372 - Add endpoints to archive or unarchive a project !3372
- Add links to CI setup documentation from project settings and builds pages - Add links to CI setup documentation from project settings and builds pages
- Handle nil descriptions in Slack issue messages (Stan Hu) - Handle nil descriptions in Slack issue messages (Stan Hu)
- API: Expose open_issues_count, closed_issues_count, open_merge_requests_count for labels (Robert Schilling)
- Add default scope to projects to exclude projects pending deletion - Add default scope to projects to exclude projects pending deletion
- Ensure empty recipients are rejected in BuildsEmailService
- API: Ability to filter milestones by state `active` and `closed` (Robert Schilling)
- API: Fix milestone filtering by `iid` (Robert Schilling)
- API: Delete notes of issues, snippets, and merge requests (Robert Schilling)
- Implement 'Groups View' as an option for dashboard preferences !3379 (Elias W.) - Implement 'Groups View' as an option for dashboard preferences !3379 (Elias W.)
- Better errors handling when creating milestones inside groups
- Hide `Create a group` help block when creating a new project in a group
- Implement 'TODOs View' as an option for dashboard preferences !3379 (Elias W.) - Implement 'TODOs View' as an option for dashboard preferences !3379 (Elias W.)
- Gracefully handle notes on deleted commits in merge requests (Stan Hu) - Gracefully handle notes on deleted commits in merge requests (Stan Hu)
- Fix creation of merge requests for orphaned branches (Stan Hu) - Fix creation of merge requests for orphaned branches (Stan Hu)
- API: Ability to retrieve a single tag (Robert Schilling)
- Fall back to `In-Reply-To` and `References` headers when sub-addressing is not available (David Padilla) - Fall back to `In-Reply-To` and `References` headers when sub-addressing is not available (David Padilla)
- Remove "Congratulations!" tweet button on newly-created project. (Connor Shea) - Remove "Congratulations!" tweet button on newly-created project. (Connor Shea)
- Fix admin/projects when using visibility levels on search (PotHix)
- Build status notifications
- API: Expose user location (Robert Schilling)
- ClosingIssueExtractor regex now also works with colons. e.g. "Fixes: #1234" !3591
- Update number of Todos in the sidebar when it's marked as "Done". !3600
- API: Expose 'updated_at' for issue, snippet, and merge request notes (Robert Schilling)
- API: User can leave a project through the API when not master or owner. !3613
v 8.6.6
- Fix error on language detection when repository has no HEAD (e.g., master branch). !3654 (Jeroen Bobbeldijk)
v 8.6.5
- Fix importing from GitHub Enterprise. !3529
- Perform the language detection after updating merge requests in `GitPushService`, leading to faster visual feedback for the end-user. !3533
- Check permissions when user attempts to import members from another project. !3535
- Only update repository language if it is not set to improve performance. !3556
- Return status code 303 after a branch DELETE operation to avoid project deletion (Stan Hu). !3583
- Unblock user when active_directory is disabled and it can be found !3550
- Fix a 2FA authentication spoofing vulnerability.
v 8.6.4 v 8.6.4
- Don't attempt to fetch any tags from a forked repo (Stan Hu) - Don't attempt to fetch any tags from a forked repo (Stan Hu)
- Redesign the Labels page
v 8.6.3 v 8.6.3
- Mentions on confidential issues doesn't create todos for non-members. !3374 - Mentions on confidential issues doesn't create todos for non-members. !3374
...@@ -128,6 +165,7 @@ v 8.6.0 ...@@ -128,6 +165,7 @@ v 8.6.0
- Add main language of a project in the list of projects (Tiago Botelho) - Add main language of a project in the list of projects (Tiago Botelho)
- Add #upcoming filter to Milestone filter (Tiago Botelho) - Add #upcoming filter to Milestone filter (Tiago Botelho)
- Add ability to show archived projects on dashboard, explore and group pages - Add ability to show archived projects on dashboard, explore and group pages
- Remove fork link closes all merge requests opened on source project (Florent Baldino)
- Move group activity to separate page - Move group activity to separate page
- Create external users which are excluded of internal and private projects unless access was explicitly granted - Create external users which are excluded of internal and private projects unless access was explicitly granted
- Continue parameters are checked to ensure redirection goes to the same instance - Continue parameters are checked to ensure redirection goes to the same instance
...@@ -136,6 +174,12 @@ v 8.6.0 ...@@ -136,6 +174,12 @@ v 8.6.0
- Trigger a todo for mentions on commits page - Trigger a todo for mentions on commits page
- Let project owners and admins soft delete issues and merge requests - Let project owners and admins soft delete issues and merge requests
v 8.5.10
- Fix a 2FA authentication spoofing vulnerability.
v 8.5.9
- Don't attempt to fetch any tags from a forked repo (Stan Hu).
v 8.5.8 v 8.5.8
- Bump Git version requirement to 2.7.4 - Bump Git version requirement to 2.7.4
...@@ -277,6 +321,15 @@ v 8.5.0 ...@@ -277,6 +321,15 @@ v 8.5.0
- Show label row when filtering issues or merge requests by label (Nuttanart Pornprasitsakul) - Show label row when filtering issues or merge requests by label (Nuttanart Pornprasitsakul)
- Add Todos - Add Todos
v 8.4.8
- Fix a 2FA authentication spoofing vulnerability.
v 8.4.7
- Don't attempt to fetch any tags from a forked repo (Stan Hu).
v 8.4.6
- Bump Git version requirement to 2.7.4
v 8.4.5 v 8.4.5
- No CE-specific changes - No CE-specific changes
...@@ -390,6 +443,15 @@ v 8.4.0 ...@@ -390,6 +443,15 @@ v 8.4.0
- Add IP check against DNSBLs at account sign-up - Add IP check against DNSBLs at account sign-up
- Added cache:key to .gitlab-ci.yml allowing to fine tune the caching - Added cache:key to .gitlab-ci.yml allowing to fine tune the caching
v 8.3.7
- Fix a 2FA authentication spoofing vulnerability.
v 8.3.6
- Don't attempt to fetch any tags from a forked repo (Stan Hu).
v 8.3.5
- Bump Git version requirement to 2.7.4
v 8.3.4 v 8.3.4
- Use gitlab-workhorse 0.5.4 (fixes API routing bug) - Use gitlab-workhorse 0.5.4 (fixes API routing bug)
......
...@@ -448,7 +448,7 @@ merge request: ...@@ -448,7 +448,7 @@ merge request:
- multi-line method chaining style **Option B**: dot `.` on previous line - multi-line method chaining style **Option B**: dot `.` on previous line
- string literal quoting style **Option A**: single quoted by default - string literal quoting style **Option A**: single quoted by default
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](doc/development/testing.md)
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. [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
......
source "https://rubygems.org" source "https://rubygems.org"
gem 'rails', '4.2.5.2' gem 'rails', '4.2.6'
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
...@@ -8,7 +8,7 @@ gem 'responders', '~> 2.0' ...@@ -8,7 +8,7 @@ gem 'responders', '~> 2.0'
# Specify a sprockets version due to increased performance # Specify a sprockets version due to increased performance
# See https://gitlab.com/gitlab-org/gitlab-ce/issues/6069 # See https://gitlab.com/gitlab-org/gitlab-ce/issues/6069
gem 'sprockets', '~> 3.3.5' gem 'sprockets', '~> 3.6.0'
# Default values for AR models # Default values for AR models
gem "default_value_for", "~> 3.0.0" gem "default_value_for", "~> 3.0.0"
...@@ -149,6 +149,10 @@ gem 'version_sorter', '~> 2.0.0' ...@@ -149,6 +149,10 @@ gem 'version_sorter', '~> 2.0.0'
# Cache # Cache
gem "redis-rails", '~> 4.0.0' gem "redis-rails", '~> 4.0.0'
# Redis
gem 'redis', '~> 3.2'
gem 'connection_pool', '~> 2.0'
# Campfire integration # Campfire integration
gem 'tinder', '~> 1.10.0' gem 'tinder', '~> 1.10.0'
...@@ -229,14 +233,13 @@ group :metrics do ...@@ -229,14 +233,13 @@ group :metrics do
gem 'allocations', '~> 1.0', require: false, platform: :mri gem 'allocations', '~> 1.0', require: false, platform: :mri
gem 'method_source', '~> 0.8', require: false gem 'method_source', '~> 0.8', require: false
gem 'influxdb', '~> 0.2', require: false gem 'influxdb', '~> 0.2', require: false
gem 'connection_pool', '~> 2.0', require: false
end end
group :development do group :development do
gem "foreman" gem "foreman"
gem 'brakeman', '~> 3.2.0', require: false gem 'brakeman', '~> 3.2.0', require: false
gem "annotate", "~> 2.6.0" gem "annotate", "~> 2.7.0"
gem "letter_opener", '~> 1.1.2' gem "letter_opener", '~> 1.1.2'
gem 'quiet_assets', '~> 1.0.2' gem 'quiet_assets', '~> 1.0.2'
gem 'rerun', '~> 0.11.0' gem 'rerun', '~> 0.11.0'
...@@ -290,7 +293,7 @@ group :development, :test do ...@@ -290,7 +293,7 @@ group :development, :test do
gem 'rubocop', '~> 0.38.0', require: false gem 'rubocop', '~> 0.38.0', require: false
gem 'scss_lint', '~> 0.47.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.11.0', require: false
gem 'flog', require: false gem 'flog', require: false
gem 'flay', require: false gem 'flay', require: false
gem 'bundler-audit', require: false gem 'bundler-audit', require: false
......
...@@ -4,41 +4,41 @@ GEM ...@@ -4,41 +4,41 @@ GEM
CFPropertyList (2.3.2) CFPropertyList (2.3.2)
RedCloth (4.2.9) RedCloth (4.2.9)
ace-rails-ap (2.0.1) ace-rails-ap (2.0.1)
actionmailer (4.2.5.2) actionmailer (4.2.6)
actionpack (= 4.2.5.2) actionpack (= 4.2.6)
actionview (= 4.2.5.2) actionview (= 4.2.6)
activejob (= 4.2.5.2) activejob (= 4.2.6)
mail (~> 2.5, >= 2.5.4) mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 1.0, >= 1.0.5) rails-dom-testing (~> 1.0, >= 1.0.5)
actionpack (4.2.5.2) actionpack (4.2.6)
actionview (= 4.2.5.2) actionview (= 4.2.6)
activesupport (= 4.2.5.2) activesupport (= 4.2.6)
rack (~> 1.6) rack (~> 1.6)
rack-test (~> 0.6.2) rack-test (~> 0.6.2)
rails-dom-testing (~> 1.0, >= 1.0.5) rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (4.2.5.2) actionview (4.2.6)
activesupport (= 4.2.5.2) activesupport (= 4.2.6)
builder (~> 3.1) builder (~> 3.1)
erubis (~> 2.7.0) erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5) rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.0.2)
activejob (4.2.5.2) activejob (4.2.6)
activesupport (= 4.2.5.2) activesupport (= 4.2.6)
globalid (>= 0.3.0) globalid (>= 0.3.0)
activemodel (4.2.5.2) activemodel (4.2.6)
activesupport (= 4.2.5.2) activesupport (= 4.2.6)
builder (~> 3.1) builder (~> 3.1)
activerecord (4.2.5.2) activerecord (4.2.6)
activemodel (= 4.2.5.2) activemodel (= 4.2.6)
activesupport (= 4.2.5.2) activesupport (= 4.2.6)
arel (~> 6.0) arel (~> 6.0)
activerecord-deprecated_finders (1.0.4) activerecord-deprecated_finders (1.0.4)
activerecord-session_store (0.1.2) activerecord-session_store (0.1.2)
actionpack (>= 4.0.0, < 5) actionpack (>= 4.0.0, < 5)
activerecord (>= 4.0.0, < 5) activerecord (>= 4.0.0, < 5)
railties (>= 4.0.0, < 5) railties (>= 4.0.0, < 5)
activesupport (4.2.5.2) activesupport (4.2.6)
i18n (~> 0.7) i18n (~> 0.7)
json (~> 1.7, >= 1.7.7) json (~> 1.7, >= 1.7.7)
minitest (~> 5.1) minitest (~> 5.1)
...@@ -51,8 +51,8 @@ GEM ...@@ -51,8 +51,8 @@ GEM
activerecord (>= 3.0) activerecord (>= 3.0)
akismet (2.0.0) akismet (2.0.0)
allocations (1.0.4) allocations (1.0.4)
annotate (2.6.10) annotate (2.7.0)
activerecord (>= 3.2, <= 4.3) activerecord (>= 3.2, < 6.0)
rake (~> 10.4) rake (~> 10.4)
arel (6.0.3) arel (6.0.3)
asana (0.4.0) asana (0.4.0)
...@@ -99,7 +99,7 @@ GEM ...@@ -99,7 +99,7 @@ GEM
bullet (5.0.0) bullet (5.0.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
uniform_notifier (~> 1.9.0) uniform_notifier (~> 1.9.0)
bundler-audit (0.4.0) bundler-audit (0.5.0)
bundler (~> 1.2) bundler (~> 1.2)
thor (~> 0.18) thor (~> 0.18)
byebug (8.2.1) byebug (8.2.1)
...@@ -136,17 +136,16 @@ GEM ...@@ -136,17 +136,16 @@ GEM
colorize (0.7.7) colorize (0.7.7)
concurrent-ruby (1.0.0) concurrent-ruby (1.0.0)
connection_pool (2.2.0) connection_pool (2.2.0)
coveralls (0.8.9) coveralls (0.8.13)
json (~> 1.8) json (~> 1.8)
rest-client (>= 1.6.8, < 2) simplecov (~> 0.11.0)
simplecov (~> 0.10.0)
term-ansicolor (~> 1.3) term-ansicolor (~> 1.3)
thor (~> 0.19.1) thor (~> 0.19.1)
tins (~> 1.6.0) tins (~> 1.6.0)
crack (0.4.3) crack (0.4.3)
safe_yaml (~> 1.0.0) safe_yaml (~> 1.0.0)
creole (0.5.0) creole (0.5.0)
css_parser (1.3.7) css_parser (1.4.1)
addressable addressable
d3_rails (3.5.11) d3_rails (3.5.11)
railties (>= 3.1.0) railties (>= 3.1.0)
...@@ -176,8 +175,6 @@ GEM ...@@ -176,8 +175,6 @@ GEM
diff-lcs (1.2.5) diff-lcs (1.2.5)
diffy (3.0.7) diffy (3.0.7)
docile (1.1.5) docile (1.1.5)
domain_name (0.5.25)
unf (>= 0.0.5, < 1.0.0)
doorkeeper (2.2.2) doorkeeper (2.2.2)
railties (>= 3.2) railties (>= 3.2)
dropzonejs-rails (0.7.2) dropzonejs-rails (0.7.2)
...@@ -421,8 +418,6 @@ GEM ...@@ -421,8 +418,6 @@ GEM
nokogiri (~> 1.6.0) nokogiri (~> 1.6.0)
ruby_parser (~> 3.5) ruby_parser (~> 3.5)
htmlentities (4.3.4) htmlentities (4.3.4)
http-cookie (1.0.2)
domain_name (~> 0.5)
http_parser.rb (0.5.3) http_parser.rb (0.5.3)
httparty (0.13.7) httparty (0.13.7)
json (~> 1.8) json (~> 1.8)
...@@ -464,8 +459,8 @@ GEM ...@@ -464,8 +459,8 @@ GEM
nokogiri (>= 1.5.9) nokogiri (>= 1.5.9)
macaddr (1.7.1) macaddr (1.7.1)
systemu (~> 2.6.2) systemu (~> 2.6.2)
mail (2.6.3) mail (2.6.4)
mime-types (>= 1.16, < 3) mime-types (>= 1.16, < 4)
mail_room (0.6.1) mail_room (0.6.1)
method_source (0.8.2) method_source (0.8.2)
mime-types (1.25.1) mime-types (1.25.1)
...@@ -480,7 +475,6 @@ GEM ...@@ -480,7 +475,6 @@ GEM
nested_form (0.3.2) nested_form (0.3.2)
net-ldap (0.12.1) net-ldap (0.12.1)
net-ssh (3.0.1) net-ssh (3.0.1)
netrc (0.11.0)
newrelic_rpm (3.14.1.311) newrelic_rpm (3.14.1.311)
nokogiri (1.6.7.2) nokogiri (1.6.7.2)
mini_portile2 (~> 2.0.0.rc2) mini_portile2 (~> 2.0.0.rc2)
...@@ -565,8 +559,8 @@ GEM ...@@ -565,8 +559,8 @@ GEM
premailer (1.8.6) premailer (1.8.6)
css_parser (>= 1.3.6) css_parser (>= 1.3.6)
htmlentities (>= 4.0.0) htmlentities (>= 4.0.0)
premailer-rails (1.9.0) premailer-rails (1.9.2)
actionmailer (>= 3, < 5) actionmailer (>= 3, < 6)
premailer (~> 1.7, >= 1.7.9) premailer (~> 1.7, >= 1.7.9)
pry (0.10.3) pry (0.10.3)
coderay (~> 1.1.0) coderay (~> 1.1.0)
...@@ -595,16 +589,16 @@ GEM ...@@ -595,16 +589,16 @@ GEM
rack rack
rack-test (0.6.3) rack-test (0.6.3)
rack (>= 1.0) rack (>= 1.0)
rails (4.2.5.2) rails (4.2.6)
actionmailer (= 4.2.5.2) actionmailer (= 4.2.6)
actionpack (= 4.2.5.2) actionpack (= 4.2.6)
actionview (= 4.2.5.2) actionview (= 4.2.6)
activejob (= 4.2.5.2) activejob (= 4.2.6)
activemodel (= 4.2.5.2) activemodel (= 4.2.6)
activerecord (= 4.2.5.2) activerecord (= 4.2.6)
activesupport (= 4.2.5.2) activesupport (= 4.2.6)
bundler (>= 1.3.0, < 2.0) bundler (>= 1.3.0, < 2.0)
railties (= 4.2.5.2) railties (= 4.2.6)
sprockets-rails sprockets-rails
rails-deprecated_sanitizer (1.0.3) rails-deprecated_sanitizer (1.0.3)
activesupport (>= 4.2.0.alpha) activesupport (>= 4.2.0.alpha)
...@@ -614,9 +608,9 @@ GEM ...@@ -614,9 +608,9 @@ GEM
rails-deprecated_sanitizer (>= 1.0.1) rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.0.3) rails-html-sanitizer (1.0.3)
loofah (~> 2.0) loofah (~> 2.0)
railties (4.2.5.2) railties (4.2.6)
actionpack (= 4.2.5.2) actionpack (= 4.2.6)
activesupport (= 4.2.5.2) activesupport (= 4.2.6)
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
rainbow (2.1.0) rainbow (2.1.0)
...@@ -657,10 +651,6 @@ GEM ...@@ -657,10 +651,6 @@ GEM
listen (~> 3.0) listen (~> 3.0)
responders (2.1.1) responders (2.1.1)
railties (>= 4.2.0, < 5.1) railties (>= 4.2.0, < 5.1)
rest-client (1.8.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 3.0)
netrc (~> 0.7)
rinku (1.7.3) rinku (1.7.3)
rotp (2.1.1) rotp (2.1.1)
rouge (1.10.1) rouge (1.10.1)
...@@ -754,7 +744,7 @@ GEM ...@@ -754,7 +744,7 @@ GEM
rufus-scheduler (>= 2.0.24) rufus-scheduler (>= 2.0.24)
sidekiq (>= 4.0.0) sidekiq (>= 4.0.0)
simple_oauth (0.1.9) simple_oauth (0.1.9)
simplecov (0.10.0) simplecov (0.11.2)
docile (~> 1.1.0) docile (~> 1.1.0)
json (~> 1.8) json (~> 1.8)
simplecov-html (~> 0.10.0) simplecov-html (~> 0.10.0)
...@@ -786,12 +776,13 @@ GEM ...@@ -786,12 +776,13 @@ GEM
spring (>= 0.9.1) spring (>= 0.9.1)
spring-commands-teaspoon (0.0.2) spring-commands-teaspoon (0.0.2)
spring (>= 0.9.1) spring (>= 0.9.1)
sprockets (3.3.5) sprockets (3.6.0)
concurrent-ruby (~> 1.0)
rack (> 1, < 3) rack (> 1, < 3)
sprockets-rails (2.3.3) sprockets-rails (3.0.4)
actionpack (>= 3.0) actionpack (>= 4.0)
activesupport (>= 3.0) activesupport (>= 4.0)
sprockets (>= 2.8, < 4.0) sprockets (>= 3.0.0)
state_machines (0.4.0) state_machines (0.4.0)
state_machines-activemodel (0.3.0) state_machines-activemodel (0.3.0)
activemodel (~> 4.1) activemodel (~> 4.1)
...@@ -845,7 +836,7 @@ GEM ...@@ -845,7 +836,7 @@ GEM
underscore-rails (1.8.3) underscore-rails (1.8.3)
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.7.1) unf_ext (0.0.7.2)
unicode-display_width (1.0.2) unicode-display_width (1.0.2)
unicorn (4.9.0) unicorn (4.9.0)
kgio (~> 2.6) kgio (~> 2.6)
...@@ -897,7 +888,7 @@ DEPENDENCIES ...@@ -897,7 +888,7 @@ DEPENDENCIES
after_commit_queue after_commit_queue
akismet (~> 2.0) akismet (~> 2.0)
allocations (~> 1.0) allocations (~> 1.0)
annotate (~> 2.6.0) annotate (~> 2.7.0)
asana (~> 0.4.0) asana (~> 0.4.0)
asciidoctor (~> 1.5.2) asciidoctor (~> 1.5.2)
attr_encrypted (~> 1.3.4) attr_encrypted (~> 1.3.4)
...@@ -1002,13 +993,14 @@ DEPENDENCIES ...@@ -1002,13 +993,14 @@ DEPENDENCIES
rack-attack (~> 4.3.1) rack-attack (~> 4.3.1)
rack-cors (~> 0.4.0) rack-cors (~> 0.4.0)
rack-oauth2 (~> 1.2.1) rack-oauth2 (~> 1.2.1)
rails (= 4.2.5.2) rails (= 4.2.6)
rails-deprecated_sanitizer (~> 1.0.3) rails-deprecated_sanitizer (~> 1.0.3)
raphael-rails (~> 2.1.2) raphael-rails (~> 2.1.2)
rblineprof rblineprof
rdoc (~> 3.6) rdoc (~> 3.6)
recaptcha recaptcha
redcarpet (~> 3.3.3) redcarpet (~> 3.3.3)
redis (~> 3.2)
redis-namespace redis-namespace
redis-rails (~> 4.0.0) redis-rails (~> 4.0.0)
request_store (~> 1.3.0) request_store (~> 1.3.0)
...@@ -1032,7 +1024,7 @@ DEPENDENCIES ...@@ -1032,7 +1024,7 @@ DEPENDENCIES
shoulda-matchers (~> 2.8.0) shoulda-matchers (~> 2.8.0)
sidekiq (~> 4.0) sidekiq (~> 4.0)
sidekiq-cron (~> 0.4.0) sidekiq-cron (~> 0.4.0)
simplecov (~> 0.10.0) simplecov (~> 0.11.0)
sinatra (~> 1.4.4) sinatra (~> 1.4.4)
six (~> 0.2.0) six (~> 0.2.0)
slack-notifier (~> 1.2.0) slack-notifier (~> 1.2.0)
...@@ -1042,7 +1034,7 @@ DEPENDENCIES ...@@ -1042,7 +1034,7 @@ DEPENDENCIES
spring-commands-rspec (~> 1.0.4) spring-commands-rspec (~> 1.0.4)
spring-commands-spinach (~> 1.0.0) spring-commands-spinach (~> 1.0.0)
spring-commands-teaspoon (~> 0.0.2) spring-commands-teaspoon (~> 0.0.2)
sprockets (~> 3.3.5) sprockets (~> 3.6.0)
state_machines-activerecord (~> 0.3.0) state_machines-activerecord (~> 0.3.0)
task_list (~> 1.0.2) task_list (~> 1.0.2)
teaspoon (~> 1.1.0) teaspoon (~> 1.1.0)
......
class @AwardsHandler class @AwardsHandler
constructor: (@post_emoji_url, @noteable_type, @noteable_id, @aliases) -> constructor: (@get_emojis_url, @post_emoji_url, @noteable_type, @noteable_id, @aliases) ->
$(".js-add-award").on "click", (event) => $(".js-add-award").on "click", (event) =>
event.stopPropagation() event.stopPropagation()
event.preventDefault() event.preventDefault()
...@@ -22,8 +22,19 @@ class @AwardsHandler ...@@ -22,8 +22,19 @@ class @AwardsHandler
emoji = $(this) emoji = $(this)
.find(".icon") .find(".icon")
.data "emoji" .data "emoji"
if emoji is "thumbsup" and awards_handler.didUserClickEmoji $(this), "thumbsdown"
awards_handler.addAward "thumbsdown"
else if emoji is "thumbsdown" and awards_handler.didUserClickEmoji $(this), "thumbsup"
awards_handler.addAward "thumbsup"
awards_handler.addAward emoji awards_handler.addAward emoji
didUserClickEmoji: (that, emoji) ->
if $(that).siblings("button:has([data-emoji=#{emoji}])").attr("data-original-title")
$(that).siblings("button:has([data-emoji=#{emoji}])").attr("data-original-title").indexOf('me') > -1
showEmojiMenu: -> showEmojiMenu: ->
if $(".emoji-menu").length if $(".emoji-menu").length
if $(".emoji-menu").is ".is-visible" if $(".emoji-menu").is ".is-visible"
...@@ -34,7 +45,7 @@ class @AwardsHandler ...@@ -34,7 +45,7 @@ class @AwardsHandler
$("#emoji_search").focus() $("#emoji_search").focus()
else else
$('.js-add-award').addClass "is-loading" $('.js-add-award').addClass "is-loading"
$.get "/emojis", (response) => $.get @get_emojis_url, (response) =>
$('.js-add-award').removeClass "is-loading" $('.js-add-award').removeClass "is-loading"
$(".js-award-holder").append response $(".js-award-holder").append response
setTimeout => setTimeout =>
...@@ -105,7 +116,7 @@ class @AwardsHandler ...@@ -105,7 +116,7 @@ class @AwardsHandler
if origTitle if origTitle
authors = origTitle.split(', ') authors = origTitle.split(', ')
authors.push("me") authors.push("me")
award_block.attr("title", authors.join(", ")) award_block.attr("data-original-title", authors.join(", "))
@resetTooltip(award_block) @resetTooltip(award_block)
resetTooltip: (award) -> resetTooltip: (award) ->
...@@ -122,7 +133,7 @@ class @AwardsHandler ...@@ -122,7 +133,7 @@ class @AwardsHandler
nodes = [] nodes = []
nodes.push( nodes.push(
"<button class='btn award-control js-emoji-btn has-tooltip active' title='me'>", "<button class='btn award-control js-emoji-btn has-tooltip active' data-original-title='me'>",
"<div class='icon emoji-icon #{emojiCssClass}' data-emoji='#{emoji}'></div>", "<div class='icon emoji-icon #{emojiCssClass}' data-emoji='#{emoji}'></div>",
"<span class='award-control-text js-counter'>1</span>", "<span class='award-control-text js-counter'>1</span>",
"</button>" "</button>"
......
...@@ -35,4 +35,18 @@ $.fn.requiresInput = -> ...@@ -35,4 +35,18 @@ $.fn.requiresInput = ->
$form.on 'change input', fieldSelector, requireInput $form.on 'change input', fieldSelector, requireInput
$ -> $ ->
$('form.js-requires-input').requiresInput() $form = $('form.js-requires-input')
$form.requiresInput()
# Hide or Show the help block when creating a new project
# based on the option selected
hideOrShowHelpBlock = (form) ->
selected = $('.js-select-namespace option:selected')
if selected.length and selected.data('options-parent') is 'groups'
return form.find('.help-block').hide()
else if selected.length
form.find('.help-block').show()
hideOrShowHelpBlock($form)
$('.select2.js-select-namespace').change -> hideOrShowHelpBlock($form)
class @Compare
constructor: (@opts) ->
@source_loading = $ ".js-source-loading"
@target_loading = $ ".js-target-loading"
$('.js-compare-dropdown').each (i, dropdown) =>
$dropdown = $(dropdown)
$dropdown.glDropdown(
selectable: true
fieldName: $dropdown.data 'field-name'
filterable: true
id: (obj, $el) ->
$el.data 'id'
toggleLabel: (obj, $el) ->
$el.text().trim()
clicked: (e, el) =>
if $dropdown.is '.js-target-branch'
@getTargetHtml()
else if $dropdown.is '.js-source-branch'
@getSourceHtml()
else if $dropdown.is '.js-target-project'
@getTargetProject()
)
@initialState()
initialState: ->
@getSourceHtml()
@getTargetHtml()
getTargetProject: ->
$.ajax(
url: @opts.targetProjectUrl
data:
target_project_id: $("input[name='merge_request[target_project_id]']").val()
beforeSend: ->
$('.mr_target_commit').empty()
success: (html) ->
$('.js-target-branch-dropdown .dropdown-content').html html
)
getSourceHtml: ->
@sendAjax(@opts.sourceBranchUrl, @source_loading, '.mr_source_commit',
ref: $("input[name='merge_request[source_branch]']").val()
)
getTargetHtml: ->
@sendAjax(@opts.targetBranchUrl, @target_loading, '.mr_target_commit',
target_project_id: $("input[name='merge_request[target_project_id]']").val()
ref: $("input[name='merge_request[target_branch]']").val()
)
sendAjax: (url, loading, target, data) ->
$target = $(target)
$.ajax(
url: url
data: data
beforeSend: ->
loading.show()
$target.empty()
success: (html) ->
loading.hide()
$target.html html
$('.js-timeago', $target).timeago()
)
class GitLabDropdownFilter class GitLabDropdownFilter
BLUR_KEYCODES = [27, 40] BLUR_KEYCODES = [27, 40]
ARROW_KEY_CODES = [38, 40]
HAS_VALUE_CLASS = "has-value" HAS_VALUE_CLASS = "has-value"
constructor: (@input, @options) -> constructor: (@input, @options) ->
...@@ -22,19 +23,23 @@ class GitLabDropdownFilter ...@@ -22,19 +23,23 @@ class GitLabDropdownFilter
# Key events # Key events
timeout = "" timeout = ""
@input.on "keyup", (e) => @input.on "keyup", (e) =>
keyCode = e.which
return if ARROW_KEY_CODES.indexOf(keyCode) >= 0
if @input.val() isnt "" and !$inputContainer.hasClass HAS_VALUE_CLASS if @input.val() isnt "" and !$inputContainer.hasClass HAS_VALUE_CLASS
$inputContainer.addClass HAS_VALUE_CLASS $inputContainer.addClass HAS_VALUE_CLASS
else if @input.val() is "" and $inputContainer.hasClass HAS_VALUE_CLASS else if @input.val() is "" and $inputContainer.hasClass HAS_VALUE_CLASS
$inputContainer.removeClass HAS_VALUE_CLASS $inputContainer.removeClass HAS_VALUE_CLASS
if e.keyCode is 13 and @input.val() isnt "" if keyCode is 13 and @input.val() isnt ""
if @options.enterCallback if @options.enterCallback
@options.enterCallback() @options.enterCallback()
return return
clearTimeout timeout clearTimeout timeout
timeout = setTimeout => timeout = setTimeout =>
blur_field = @shouldBlur e.keyCode blur_field = @shouldBlur keyCode
search_text = @input.val() search_text = @input.val()
if blur_field and @filterInputBlur if blur_field and @filterInputBlur
...@@ -52,14 +57,30 @@ class GitLabDropdownFilter ...@@ -52,14 +57,30 @@ class GitLabDropdownFilter
filter: (search_text) -> filter: (search_text) ->
data = @options.data() data = @options.data()
results = data
if search_text isnt "" if data?
results = fuzzaldrinPlus.filter(data, search_text, results = data
key: @options.keys
) if search_text isnt ''
results = fuzzaldrinPlus.filter(data, search_text,
key: @options.keys
)
@options.callback results
else
elements = @options.elements()
if search_text
elements.each ->
$el = $(@)
matches = fuzzaldrinPlus.match($el.text().trim(), search_text)
@options.callback results if matches.length
$el.show()
else
$el.hide()
else
elements.show()
class GitLabDropdownRemote class GitLabDropdownRemote
constructor: (@dataEndpoint, @options) -> constructor: (@dataEndpoint, @options) ->
...@@ -96,6 +117,7 @@ class GitLabDropdown ...@@ -96,6 +117,7 @@ class GitLabDropdown
LOADING_CLASS = "is-loading" LOADING_CLASS = "is-loading"
PAGE_TWO_CLASS = "is-page-two" PAGE_TWO_CLASS = "is-page-two"
ACTIVE_CLASS = "is-active" ACTIVE_CLASS = "is-active"
currentIndex = -1
FILTER_INPUT = '.dropdown-input .dropdown-input-field' FILTER_INPUT = '.dropdown-input .dropdown-input-field'
...@@ -117,7 +139,7 @@ class GitLabDropdown ...@@ -117,7 +139,7 @@ class GitLabDropdown
if _.isString(@filterInput) if _.isString(@filterInput)
@filterInput = @getElement(@filterInput) @filterInput = @getElement(@filterInput)
search_fields = if @options.search then @options.search.fields else []; searchFields = if @options.search then @options.search.fields else [];
if @options.data if @options.data
# If data is an array # If data is an array
...@@ -141,15 +163,22 @@ class GitLabDropdown ...@@ -141,15 +163,22 @@ class GitLabDropdown
filterInputBlur: @filterInputBlur filterInputBlur: @filterInputBlur
remote: @options.filterRemote remote: @options.filterRemote
query: @options.data query: @options.data
keys: @options.search.fields keys: searchFields
elements: =>
selector = '.dropdown-content li:not(.divider)'
if @dropdown.find('.dropdown-toggle-page').length
selector = ".dropdown-page-one #{selector}"
return $(selector)
data: => data: =>
return @fullData return @fullData
callback: (data) => callback: (data) =>
currentIndex = -1
@parseData data @parseData data
@highlightRow 1
enterCallback: => enterCallback: =>
if @enterCallback if @enterCallback
@selectFirstRow() @selectRowAtIndex 0
# Event listeners # Event listeners
...@@ -171,10 +200,11 @@ class GitLabDropdown ...@@ -171,10 +200,11 @@ class GitLabDropdown
selector = ".dropdown-page-one .dropdown-content a" selector = ".dropdown-page-one .dropdown-content a"
@dropdown.on "click", selector, (e) -> @dropdown.on "click", selector, (e) ->
selected = self.rowClicked $(@) $el = $(@)
selected = self.rowClicked $el
if self.options.clicked if self.options.clicked
self.options.clicked(selected) self.options.clicked(selected, $el, e)
# Finds an element inside wrapper element # Finds an element inside wrapper element
getElement: (selector) -> getElement: (selector) ->
...@@ -218,6 +248,8 @@ class GitLabDropdown ...@@ -218,6 +248,8 @@ class GitLabDropdown
return true return true
opened: => opened: =>
@addArrowKeyEvent()
contentHtml = $('.dropdown-content', @dropdown).html() contentHtml = $('.dropdown-content', @dropdown).html()
if @remote && contentHtml is "" if @remote && contentHtml is ""
@remote.execute() @remote.execute()
...@@ -228,6 +260,7 @@ class GitLabDropdown ...@@ -228,6 +260,7 @@ class GitLabDropdown
@dropdown.trigger('shown.gl.dropdown') @dropdown.trigger('shown.gl.dropdown')
hidden: (e) => hidden: (e) =>
@removeArrayKeyEvent()
if @options.filterable if @options.filterable
@dropdown @dropdown
.find(".dropdown-input-field") .find(".dropdown-input-field")
...@@ -307,11 +340,11 @@ class GitLabDropdown ...@@ -307,11 +340,11 @@ class GitLabDropdown
if @highlight if @highlight
text = @highlightTextMatches(text, @filterInput.val()) text = @highlightTextMatches(text, @filterInput.val())
html = "<li>" html = "<li>
html += "<a href='#{url}' class='#{cssClass}'>" <a href='#{url}' class='#{cssClass}'>
html += text #{text}
html += "</a>" </a>
html += "</li>" </li>"
return html return html
...@@ -322,11 +355,11 @@ class GitLabDropdown ...@@ -322,11 +355,11 @@ class GitLabDropdown
).join('') ).join('')
noResults: -> noResults: ->
html = "<li>" html = "<li class='dropdown-menu-empty-link'>
html += "<a class='dropdown-menu-empty-link is-focused'>" <a href='#' class='is-focused'>
html += "No matching results." No matching results.
html += "</a>" </a>
html += "</li>" </li>"
highlightRow: (index) -> highlightRow: (index) ->
if @filterInput.val() isnt "" if @filterInput.val() isnt ""
...@@ -351,6 +384,8 @@ class GitLabDropdown ...@@ -351,6 +384,8 @@ class GitLabDropdown
# Toggle the dropdown label # Toggle the dropdown label
if @options.toggleLabel if @options.toggleLabel
$(@el).find(".dropdown-toggle-text").text @options.toggleLabel $(@el).find(".dropdown-toggle-text").text @options.toggleLabel
else
selectedObject
else else
if !value? if !value?
field.remove() field.remove()
...@@ -364,9 +399,9 @@ class GitLabDropdown ...@@ -364,9 +399,9 @@ class GitLabDropdown
# Toggle the dropdown label # Toggle the dropdown label
if @options.toggleLabel if @options.toggleLabel
$(@el).find(".dropdown-toggle-text").text @options.toggleLabel(selectedObject) $(@el).find(".dropdown-toggle-text").text @options.toggleLabel(selectedObject, el)
if value? if value?
if !field.length if !field.length and fieldName
# Create hidden input for form # Create hidden input for form
input = "<input type='hidden' name='#{fieldName}' value='#{value}' />" input = "<input type='hidden' name='#{fieldName}' value='#{value}' />"
if @options.inputId? if @options.inputId?
...@@ -378,16 +413,81 @@ class GitLabDropdown ...@@ -378,16 +413,81 @@ class GitLabDropdown
return selectedObject return selectedObject
selectFirstRow: -> selectRowAtIndex: (index) ->
selector = '.dropdown-content li:first-child a' selector = ".dropdown-content li:not(.divider):eq(#{index}) a"
if @dropdown.find(".dropdown-toggle-page").length if @dropdown.find(".dropdown-toggle-page").length
selector = ".dropdown-page-one .dropdown-content li:first-child a" selector = ".dropdown-page-one #{selector}"
# simulate a click on the first link # simulate a click on the first link
$(selector).trigger "click" $(selector, @dropdown).trigger "click"
addArrowKeyEvent: ->
ARROW_KEY_CODES = [38, 40]
$input = @dropdown.find(".dropdown-input-field")
selector = '.dropdown-content li:not(.divider)'
if @dropdown.find(".dropdown-toggle-page").length
selector = ".dropdown-page-one #{selector}"
$('body').on 'keydown', (e) =>
currentKeyCode = e.which
if ARROW_KEY_CODES.indexOf(currentKeyCode) >= 0
e.preventDefault()
e.stopImmediatePropagation()
PREV_INDEX = currentIndex
$listItems = $(selector, @dropdown)
# if @options.filterable
# $input.blur()
if currentKeyCode is 40
# Move down
currentIndex += 1 if currentIndex < ($listItems.length - 1)
else if currentKeyCode is 38
# Move up
currentIndex -= 1 if currentIndex > 0
@highlightRowAtIndex($listItems, currentIndex) if currentIndex isnt PREV_INDEX
return false
if currentKeyCode is 13
@selectRowAtIndex currentIndex
removeArrayKeyEvent: ->
$('body').off 'keydown'
highlightRowAtIndex: ($listItems, index) ->
# Remove the class for the previously focused row
$('.is-focused', @dropdown).removeClass 'is-focused'
# Update the class for the row at the specific index
$listItem = $listItems.eq(index)
$listItem.find('a:first-child').addClass "is-focused"
# Dropdown content scroll area
$dropdownContent = $listItem.closest('.dropdown-content')
dropdownScrollTop = $dropdownContent.scrollTop()
dropdownContentHeight = $dropdownContent.outerHeight()
dropdownContentTop = $dropdownContent.prop('offsetTop')
dropdownContentBottom = dropdownContentTop + dropdownContentHeight
# Get the offset bottom of the list item
listItemHeight = $listItem.outerHeight()
listItemTop = $listItem.prop('offsetTop')
listItemBottom = listItemTop + listItemHeight
if listItemBottom > dropdownContentBottom + dropdownScrollTop
# Scroll the dropdown content down
$dropdownContent.scrollTop(listItemBottom - dropdownContentBottom)
else if listItemTop < dropdownContentTop + dropdownScrollTop
# Scroll the dropdown content up
$dropdownContent.scrollTop(listItemTop - dropdownContentTop)
$.fn.glDropdown = (opts) -> $.fn.glDropdown = (opts) ->
return @.each -> return @.each ->
if (!$.data @, 'glDropdown') if (!$.data @, 'glDropdown')
$.data(@, 'glDropdown', new GitLabDropdown @, opts) $.data(@, 'glDropdown', new GitLabDropdown @, opts)
...@@ -6,25 +6,10 @@ class @Issue ...@@ -6,25 +6,10 @@ class @Issue
constructor: -> constructor: ->
# Prevent duplicate event bindings # Prevent duplicate event bindings
@disableTaskList() @disableTaskList()
@fixAffixScroll()
if $('a.btn-close').length if $('a.btn-close').length
@initTaskList() @initTaskList()
@initIssueBtnEventListeners() @initIssueBtnEventListeners()
fixAffixScroll: ->
fixAffix = ->
$discussion = $('.issuable-discussion')
$sidebar = $('.issuable-sidebar')
if $sidebar.hasClass('no-affix')
$sidebar.removeClass(['affix-top','affix'])
discussionHeight = $discussion.height()
sidebarHeight = $sidebar.height()
if sidebarHeight > discussionHeight
$discussion.height(sidebarHeight + 50)
$sidebar.addClass('no-affix')
$(window).on('resize', fixAffix)
fixAffix()
initTaskList: -> initTaskList: ->
$('.detail-page-description .js-task-list-container').taskList('enable') $('.detail-page-description .js-task-list-container').taskList('enable')
$(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList $(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList
...@@ -49,7 +34,7 @@ class @Issue ...@@ -49,7 +34,7 @@ class @Issue
issueStatus = if isClose then 'close' else 'open' issueStatus = if isClose then 'close' else 'open'
new Flash(issueFailMessage, 'alert') new Flash(issueFailMessage, 'alert')
success: (data, textStatus, jqXHR) -> success: (data, textStatus, jqXHR) ->
if data.saved if 'id' of data
$(document).trigger('issuable:change'); $(document).trigger('issuable:change');
if isClose if isClose
$('a.btn-close').addClass('hidden') $('a.btn-close').addClass('hidden')
......
...@@ -26,6 +26,20 @@ ...@@ -26,6 +26,20 @@
$(".selected_issue").bind "change", Issues.checkChanged $(".selected_issue").bind "change", Issues.checkChanged
# Update state filters if present in page
updateStateFilters: ->
stateFilters = $('.issues-state-filters')
newParams = {}
paramKeys = ['author_id', 'label_name', 'milestone_title', 'assignee_id', 'issue_search']
for paramKey in paramKeys
newParams[paramKey] = gl.utils.getUrlParameter(paramKey) or ''
if stateFilters.length
stateFilters.find('a').each ->
initialUrl = $(this).attr 'href'
$(this).attr 'href', gl.utils.mergeUrlParams(newParams, initialUrl)
# Make sure we trigger ajax request only after user stop typing # Make sure we trigger ajax request only after user stop typing
initSearch: -> initSearch: ->
@timer = null @timer = null
...@@ -54,6 +68,7 @@ ...@@ -54,6 +68,7 @@
# 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: issuesUrl}, document.title, issuesUrl history.replaceState {page: issuesUrl}, document.title, issuesUrl
Issues.reload() Issues.reload()
Issues.updateStateFilters()
dataType: "json" dataType: "json"
checkChanged: -> checkChanged: ->
......
((w) ->
w.gl ?= {}
w.gl.utils ?= {}
w.gl.utils.getUrlParameter = (sParam) ->
sPageURL = decodeURIComponent(window.location.search.substring(1))
sURLVariables = sPageURL.split('&')
sParameterName = undefined
i = 0
while i < sURLVariables.length
sParameterName = sURLVariables[i].split('=')
if sParameterName[0] is sParam
return if sParameterName[1] is undefined then true else sParameterName[1]
i++
# #
# @param {Object} params - url keys and value to merge
# @param {String} url
# #
w.gl.utils.mergeUrlParams = (params, url) ->
newUrl = decodeURIComponent(url)
for paramName, paramValue of params
pattern = new RegExp "\\b(#{paramName}=).*?(&|$)"
if url.search(pattern) >= 0
newUrl = newUrl.replace pattern, "$1#{paramValue}$2"
else
newUrl = "#{newUrl}#{(if newUrl.indexOf('?') > 0 then '&' else '?')}#{paramName}=#{paramValue}"
newUrl
) window
...@@ -15,8 +15,6 @@ class @MergeRequest ...@@ -15,8 +15,6 @@ class @MergeRequest
this.$('.show-all-commits').on 'click', => this.$('.show-all-commits').on 'click', =>
this.showAllCommits() this.showAllCommits()
@fixAffixScroll();
@initTabs() @initTabs()
# Prevent duplicate event bindings # Prevent duplicate event bindings
...@@ -30,20 +28,6 @@ class @MergeRequest ...@@ -30,20 +28,6 @@ class @MergeRequest
$: (selector) -> $: (selector) ->
this.$el.find(selector) this.$el.find(selector)
fixAffixScroll: ->
fixAffix = ->
$discussion = $('.issuable-discussion')
$sidebar = $('.issuable-sidebar')
if $sidebar.hasClass('no-affix')
$sidebar.removeClass(['affix-top','affix'])
discussionHeight = $discussion.height()
sidebarHeight = $sidebar.height()
if sidebarHeight > discussionHeight
$discussion.height(sidebarHeight + 50)
$sidebar.addClass('no-affix')
$(window).on('resize', fixAffix)
fixAffix()
initTabs: -> initTabs: ->
if @opts.action != 'new' if @opts.action != 'new'
# `MergeRequests#new` has no tab-persisting or lazy-loading behavior # `MergeRequests#new` has no tab-persisting or lazy-loading behavior
......
...@@ -73,7 +73,8 @@ class @MergeRequestTabs ...@@ -73,7 +73,8 @@ class @MergeRequestTabs
@expandView() @expandView()
else if action == 'diffs' else if action == 'diffs'
@loadDiff($target.attr('href')) @loadDiff($target.attr('href'))
@shrinkView() if bp? and bp.getBreakpointSize() isnt 'lg'
@shrinkView()
else if action == 'builds' else if action == 'builds'
@loadBuilds($target.attr('href')) @loadBuilds($target.attr('href'))
@expandView() @expandView()
......
...@@ -15,6 +15,8 @@ class @MergeRequestWidget ...@@ -15,6 +15,8 @@ class @MergeRequestWidget
@pollCIStatus() @pollCIStatus()
notifyPermissions() notifyPermissions()
setOpts: (@opts) ->
mergeInProgress: (deleteSourceBranch = false)-> mergeInProgress: (deleteSourceBranch = false)->
$.ajax $.ajax
type: 'GET' type: 'GET'
...@@ -48,7 +50,7 @@ class @MergeRequestWidget ...@@ -48,7 +50,7 @@ class @MergeRequestWidget
@getCIStatus(true) @getCIStatus(true)
@readyForCICheck = false @readyForCICheck = false
), 5000 ), 10000
getCIStatus: (showNotification) -> getCIStatus: (showNotification) ->
_this = @ _this = @
...@@ -61,6 +63,10 @@ class @MergeRequestWidget ...@@ -61,6 +63,10 @@ class @MergeRequestWidget
@firstCICheck = false @firstCICheck = false
@opts.ci_status = data.status @opts.ci_status = data.status
if @opts.ci_status is ''
@opts.ci_status = data.status
return
if data.status isnt @opts.ci_status if data.status isnt @opts.ci_status
@showCIStatus data.status @showCIStatus data.status
if data.coverage if data.coverage
......
...@@ -85,15 +85,21 @@ class @MilestoneSelect ...@@ -85,15 +85,21 @@ class @MilestoneSelect
# display:block overrides the hide-collapse rule # display:block overrides the hide-collapse rule
$value.removeAttr('style') $value.removeAttr('style')
clicked: (selected) -> clicked: (selected) ->
page = $('body').data 'page'
isIssueIndex = page is 'projects:issues:index'
isMRIndex = page is page is 'projects:merge_requests:index'
if $dropdown.hasClass 'js-filter-bulk-update' if $dropdown.hasClass 'js-filter-bulk-update'
return return
if $dropdown.hasClass('js-filter-submit') if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
if selected.name? if selected.name?
selectedMilestone = selected.name selectedMilestone = selected.name
else else
selectedMilestone = '' selectedMilestone = ''
Issues.filterResults $dropdown.closest('form') Issues.filterResults $dropdown.closest('form')
else if $dropdown.hasClass('js-filter-submit')
$dropdown.closest('form').submit()
else else
selected = $selectbox selected = $selectbox
.find('input[type="hidden"]') .find('input[type="hidden"]')
......
...@@ -251,13 +251,11 @@ class @Notes ...@@ -251,13 +251,11 @@ class @Notes
Sets some hidden fields in the form. Sets some hidden fields in the form.
### ###
setupMainTargetNoteForm: -> setupMainTargetNoteForm: ->
# find the form # find the form
form = $(".js-new-note-form") form = $(".js-new-note-form")
# insert the form after the button # Set a global clone of the form for later cloning
form.clone().replaceAll $(".js-main-target-form") @formClone = form.clone()
form = form.prev("form")
# show the form # show the form
@setupNoteForm(form) @setupNoteForm(form)
...@@ -266,9 +264,7 @@ class @Notes ...@@ -266,9 +264,7 @@ class @Notes
form.removeClass "js-new-note-form" form.removeClass "js-new-note-form"
form.addClass "js-main-target-form" form.addClass "js-main-target-form"
# remove unnecessary fields and buttons
form.find("#note_line_code").remove() form.find("#note_line_code").remove()
form.find(".js-close-discussion-note-form").remove()
### ###
General note form setup. General note form setup.
...@@ -297,7 +293,14 @@ class @Notes ...@@ -297,7 +293,14 @@ class @Notes
else else
previewButton.removeClass("turn-on").addClass "turn-off" previewButton.removeClass("turn-on").addClass "turn-off"
textarea.on 'focus', ->
$(this).closest('.md-area').addClass 'is-focused'
textarea.on 'blur', ->
$(this).closest('.md-area').removeClass 'is-focused'
autosize(textarea) autosize(textarea)
new Autosave textarea, [ new Autosave textarea, [
"Note" "Note"
form.find("#note_commit_id").val() form.find("#note_commit_id").val()
...@@ -307,7 +310,6 @@ class @Notes ...@@ -307,7 +310,6 @@ class @Notes
] ]
# remove notify commit author checkbox for non-commit notes # remove notify commit author checkbox for non-commit notes
form.find(".js-notify-commit-author").remove() if form.find("#note_noteable_type").val() isnt "Commit"
GitLab.GfmAutoComplete.setup() GitLab.GfmAutoComplete.setup()
new DropzoneInput(form) new DropzoneInput(form)
form.show() form.show()
...@@ -455,15 +457,15 @@ class @Notes ...@@ -455,15 +457,15 @@ class @Notes
Shows the note form below the notes. Shows the note form below the notes.
### ###
replyToDiscussionNote: (e) => replyToDiscussionNote: (e) =>
form = $(".js-new-note-form") form = @formClone.clone()
replyLink = $(e.target).closest(".js-discussion-reply-button") replyLink = $(e.target).closest(".js-discussion-reply-button")
replyLink.hide() replyLink.hide()
# insert the form after the button # insert the form after the button
form.clone().insertAfter replyLink replyLink.after form
# show the form # show the form
@setupDiscussionNoteForm(replyLink, replyLink.next("form")) @setupDiscussionNoteForm(replyLink, form)
### ###
Shows the diff or discussion form and does some setup on it. Shows the diff or discussion form and does some setup on it.
...@@ -488,7 +490,9 @@ class @Notes ...@@ -488,7 +490,9 @@ class @Notes
.text(form.find('.js-close-discussion-note-form').data('cancel-text')) .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
.removeClass('js-main-target-form')
.addClass("discussion-form js-discussion-note-form")
### ###
Called when clicking on the "add a comment" button on the side of a diff line. Called when clicking on the "add a comment" button on the side of a diff line.
...@@ -498,9 +502,8 @@ class @Notes ...@@ -498,9 +502,8 @@ class @Notes
### ###
addDiffNote: (e) => addDiffNote: (e) =>
e.preventDefault() e.preventDefault()
link = e.currentTarget $link = $(e.currentTarget)
form = $(".js-new-note-form") row = $link.closest("tr")
row = $(link).closest("tr")
nextRow = row.next() nextRow = row.next()
hasNotes = nextRow.is(".notes_holder") hasNotes = nextRow.is(".notes_holder")
addForm = false addForm = false
...@@ -509,7 +512,7 @@ class @Notes ...@@ -509,7 +512,7 @@ class @Notes
# In parallel view, look inside the correct left/right pane # In parallel view, look inside the correct left/right pane
if @isParallelView() if @isParallelView()
lineType = $(link).data("lineType") lineType = $link.data("lineType")
targetContent += "." + lineType targetContent += "." + lineType
rowCssToAdd = "<tr class=\"notes_holder js-temp-notes-holder\"><td class=\"notes_line\"></td><td class=\"notes_content parallel old\"></td><td class=\"notes_line\"></td><td class=\"notes_content parallel new\"></td></tr>" rowCssToAdd = "<tr class=\"notes_holder js-temp-notes-holder\"><td class=\"notes_line\"></td><td class=\"notes_content parallel old\"></td><td class=\"notes_line\"></td><td class=\"notes_content parallel new\"></td></tr>"
...@@ -531,11 +534,11 @@ class @Notes ...@@ -531,11 +534,11 @@ class @Notes
addForm = true addForm = true
if addForm if addForm
newForm = form.clone() newForm = @formClone.clone()
newForm.appendTo row.next().find(targetContent) newForm.appendTo row.next().find(targetContent)
# show the form # show the form
@setupDiscussionNoteForm $(link), newForm @setupDiscussionNoteForm $link, newForm
### ###
Called in response to "cancel" on a diff note form. Called in response to "cancel" on a diff note form.
...@@ -560,7 +563,6 @@ class @Notes ...@@ -560,7 +563,6 @@ class @Notes
cancelDiscussionForm: (e) => cancelDiscussionForm: (e) =>
e.preventDefault() e.preventDefault()
form = $(".js-new-note-form")
form = $(e.target).closest(".js-discussion-note-form") form = $(e.target).closest(".js-discussion-note-form")
@removeDiscussionNoteForm(form) @removeDiscussionNoteForm(form)
......
...@@ -62,6 +62,8 @@ class @SearchAutocomplete ...@@ -62,6 +62,8 @@ class @SearchAutocomplete
search: search:
fields: ['text'] fields: ['text']
data: @getData.bind(@) data: @getData.bind(@)
selectable: true
clicked: @onClick.bind(@)
getData: (term, callback) -> getData: (term, callback) ->
_this = @ _this = @
...@@ -102,6 +104,8 @@ class @SearchAutocomplete ...@@ -102,6 +104,8 @@ class @SearchAutocomplete
lastCategory = suggestion.category lastCategory = suggestion.category
data.push data.push
id: "#{suggestion.category.toLowerCase()}-#{suggestion.id}"
category: suggestion.category
text: suggestion.label text: suggestion.label
url: suggestion.url url: suggestion.url
...@@ -133,12 +137,19 @@ class @SearchAutocomplete ...@@ -133,12 +137,19 @@ class @SearchAutocomplete
} }
bindEvents: -> bindEvents: ->
$(document).on 'click', @onDocumentClick
@searchInput.on 'keydown', @onSearchInputKeyDown @searchInput.on 'keydown', @onSearchInputKeyDown
@searchInput.on 'keyup', @onSearchInputKeyUp @searchInput.on 'keyup', @onSearchInputKeyUp
@searchInput.on 'click', @onSearchInputClick @searchInput.on 'click', @onSearchInputClick
@searchInput.on 'focus', @onSearchInputFocus @searchInput.on 'focus', @onSearchInputFocus
@searchInput.on 'blur', @onSearchInputBlur @clearInput.on 'click', @onClearInputClick
@clearInput.on 'click', @onRemoveLocationClick
onDocumentClick: (e) =>
# If clicking outside the search box
# And search input is not focused
# And we are not clicking inside a suggestion
if not $.contains(@dropdown[0], e.target) and @isFocused and not $(e.target).parents('ul').length
@onSearchInputBlur()
enableAutocomplete: -> enableAutocomplete: ->
# No need to enable anything if user is not logged in # No need to enable anything if user is not logged in
...@@ -181,6 +192,8 @@ class @SearchAutocomplete ...@@ -181,6 +192,8 @@ class @SearchAutocomplete
# We should display the menu only when input is not empty # We should display the menu only when input is not empty
@enableAutocomplete() @enableAutocomplete()
@wrap.toggleClass 'has-value', !!e.target.value
# Avoid falsy value to be returned # Avoid falsy value to be returned
return return
...@@ -189,27 +202,20 @@ class @SearchAutocomplete ...@@ -189,27 +202,20 @@ class @SearchAutocomplete
e.stopImmediatePropagation() e.stopImmediatePropagation()
onSearchInputFocus: => onSearchInputFocus: =>
@isFocused = true
@wrap.addClass('search-active') @wrap.addClass('search-active')
onRemoveLocationClick: (e) => onClearInputClick: (e) =>
e.preventDefault() e.preventDefault()
@removeLocationBadge()
@searchInput.val('').focus() @searchInput.val('').focus()
@skipBlurEvent = true
onSearchInputBlur: (e) => onSearchInputBlur: (e) =>
@skipBlurEvent = false @isFocused = false
@wrap.removeClass('search-active')
# We should wait to make sure we are not clearing the input instead
setTimeout( =>
return if @skipBlurEvent
@wrap.removeClass('search-active') # If input is blank then restore state
if @searchInput.val() is ''
# If input is blank then restore state @restoreOriginalState()
if @searchInput.val() is ''
@restoreOriginalState()
, 150)
addLocationBadge: (item) -> addLocationBadge: (item) ->
category = if item.category? then "#{item.category}: " else '' category = if item.category? then "#{item.category}: " else ''
...@@ -268,3 +274,23 @@ class @SearchAutocomplete ...@@ -268,3 +274,23 @@ class @SearchAutocomplete
<li><a class='dropdown-menu-empty-link is-focused'>Loading...</a></li> <li><a class='dropdown-menu-empty-link is-focused'>Loading...</a></li>
</ul>" </ul>"
@dropdownContent.html(html) @dropdownContent.html(html)
onClick: (item, $el, e) ->
if location.pathname.indexOf(item.url) isnt -1
e.preventDefault()
if not @badgePresent
if item.category is 'Projects'
@projectInputEl.val(item.id)
@addLocationBadge(
value: 'This project'
)
if item.category is 'Groups'
@groupInputEl.val(item.id)
@addLocationBadge(
value: 'This group'
)
$el.removeClass('is-active')
@disableAutocomplete()
@searchInput.val('').focus()
...@@ -4,6 +4,7 @@ expanded = 'page-sidebar-expanded' ...@@ -4,6 +4,7 @@ expanded = 'page-sidebar-expanded'
toggleSidebar = -> 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")
$('.toggle-nav-collapse i').toggleClass("fa-angle-right fa-angle-left")
$.cookie("collapsed_nav", $('.page-with-sidebar').hasClass(collapsed), { path: '/' }) $.cookie("collapsed_nav", $('.page-with-sidebar').hasClass(collapsed), { path: '/' })
setTimeout ( -> setTimeout ( ->
......
...@@ -10,10 +10,10 @@ class @Subscription ...@@ -10,10 +10,10 @@ class @Subscription
btn = $(event.currentTarget) btn = $(event.currentTarget)
action = btn.find('span').text() action = btn.find('span').text()
current_status = @subscription_status.attr('data-status') current_status = @subscription_status.attr('data-status')
btn.prop('disabled', true) btn.addClass('disabled')
$.post @url, => $.post @url, =>
btn.prop('disabled', false) btn.removeClass('disabled')
status = if current_status == 'subscribed' then 'unsubscribed' else 'subscribed' status = if current_status == 'subscribed' then 'unsubscribed' else 'subscribed'
@subscription_status.attr('data-status', status) @subscription_status.attr('data-status', status)
action = if status == 'subscribed' then 'Unsubscribe' else 'Subscribe' action = if status == 'subscribed' then 'Unsubscribe' else 'Subscribe'
......
...@@ -57,5 +57,10 @@ class @Todos ...@@ -57,5 +57,10 @@ class @Todos
$('.todos-pending .badge, .todos-pending-count').text data.count $('.todos-pending .badge, .todos-pending-count').text data.count
$('.todos-done .badge').text data.done_count $('.todos-done .badge').text data.done_count
goToTodoUrl: -> goToTodoUrl: (e)->
Turbolinks.visit($(this).data('url')) todoLink = $(this).data('url')
if e.metaKey
e.preventDefault()
window.open(todoLink,'_blank')
else
Turbolinks.visit(todoLink)
...@@ -42,7 +42,7 @@ class @ZenMode ...@@ -42,7 +42,7 @@ class @ZenMode
$(e.currentTarget).trigger('zen_mode:leave') $(e.currentTarget).trigger('zen_mode:leave')
$(document).on 'zen_mode:enter', (e) => $(document).on 'zen_mode:enter', (e) =>
@enter(e.target.parentNode) @enter($(e.target).closest('.md-area').find('.zen-backdrop'))
$(document).on 'zen_mode:leave', (e) => $(document).on 'zen_mode:leave', (e) =>
@exit() @exit()
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
&:focus, &:focus,
&:active { &:active {
outline: none; outline: none;
background-color: $btn-active-gray;
@include box-shadow($gl-btn-active-background); @include box-shadow($gl-btn-active-background);
} }
} }
...@@ -27,7 +28,8 @@ ...@@ -27,7 +28,8 @@
color: $color; color: $color;
} }
&:active { &:active,
&.active {
@include box-shadow ($gl-btn-active-background); @include box-shadow ($gl-btn-active-background);
background-color: $dark; background-color: $dark;
...@@ -61,7 +63,7 @@ ...@@ -61,7 +63,7 @@
} }
@mixin btn-white { @mixin btn-white {
@include btn-color($white-light, $border-white-light, $white-normal, $border-white-normal, $white-dark, $border-white-dark, #313236); @include btn-color($white-light, $border-color, $white-normal, $border-white-normal, $white-dark, $border-white-dark, $btn-white-active);
} }
.btn { .btn {
...@@ -218,3 +220,26 @@ ...@@ -218,3 +220,26 @@
margin-right: 5px; margin-right: 5px;
} }
} }
.btn-text-field {
width: 100%;
text-align: left;
padding: 6px 16px;
border-color: $border-color;
color: $btn-placeholder-gray;
background-color: $background-color;
&:hover,
&:active,
&:focus {
cursor: text;
box-shadow: none;
border-color: $border-color;
color: $btn-placeholder-gray;
background-color: $background-color;
}
}
.btn-file-option {
background: linear-gradient(180deg, $white-light 25%, $gray-light 100%);
}
.calender-block {
@media (min-width: $screen-sm-min) and (max-width: $screen-lg-min) {
overflow-x: scroll;
}
}
.user-calendar-activities { .user-calendar-activities {
.calendar_onclick_hr { .calendar_onclick_hr {
padding: 0; padding: 0;
......
...@@ -125,13 +125,6 @@ p.time { ...@@ -125,13 +125,6 @@ p.time {
height: 150px; height: 150px;
} }
// Fixes alignment on notes.
.new_note {
label {
text-align: left;
}
}
// 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% }
......
...@@ -248,7 +248,7 @@ ...@@ -248,7 +248,7 @@
.dropdown-title { .dropdown-title {
position: relative; position: relative;
padding: 0 0 15px; padding: 0 25px 15px;
margin: 0 10px 10px; margin: 0 10px 10px;
font-weight: 600; font-weight: 600;
line-height: 1; line-height: 1;
...@@ -275,7 +275,7 @@ ...@@ -275,7 +275,7 @@
} }
.dropdown-menu-close { .dropdown-menu-close {
right: 7px; right: 5px;
width: 20px; width: 20px;
height: 20px; height: 20px;
top: -1px; top: -1px;
......
...@@ -15,11 +15,13 @@ ...@@ -15,11 +15,13 @@
.file-title { .file-title {
position: relative; position: relative;
background: $background-color; background-color: $background-color;
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
margin: 0; margin: 0;
text-align: left; text-align: left;
padding: 10px $gl-padding; padding: 10px $gl-padding;
word-wrap: break-word;
border-radius: 3px 3px 0 0;
.file-actions { .file-actions {
float: right; float: right;
...@@ -48,7 +50,7 @@ ...@@ -48,7 +50,7 @@
} }
} }
a { a:not(.btn) {
color: $gl-dark-link-color; color: $gl-dark-link-color;
} }
......
...@@ -33,15 +33,10 @@ ...@@ -33,15 +33,10 @@
background: $color; background: $color;
} }
.complex-sidebar .nav-primary {
border-right: 1px solid lighten($color, 3%);
}
.sidebar-wrapper { .sidebar-wrapper {
background: $color-darker; background: $color-darker;
.sidebar-user { .sidebar-user {
border-top: 1px solid lighten($color, 3%);
background: $color-darker; background: $color-darker;
color: $color-light; color: $color-light;
...@@ -67,6 +62,7 @@ ...@@ -67,6 +62,7 @@
.count { .count {
color: $color-light; color: $color-light;
background: $color-dark;
} }
} }
......
...@@ -123,11 +123,11 @@ header { ...@@ -123,11 +123,11 @@ header {
} }
@mixin collapsed-header { @mixin collapsed-header {
margin-left: 40px; margin-left: $sidebar_collapsed_width;
} }
.header-collapsed { .header-collapsed {
margin-left: 40px; margin-left: $sidebar_collapsed_width;
@media (min-width: $screen-md-min) { @media (min-width: $screen-md-min) {
@include collapsed-header; @include collapsed-header;
......
.div-dropzone-wrapper { .div-dropzone-wrapper {
.div-dropzone { .div-dropzone {
position: relative; position: relative;
padding: 0; margin-bottom: -5px;
border: 0;
margin-bottom: 5px;
.div-dropzone-focus { .div-dropzone-focus {
border-color: #66afe9 !important; border-color: #66afe9 !important;
...@@ -25,12 +23,10 @@ ...@@ -25,12 +23,10 @@
.div-dropzone-spinner { .div-dropzone-spinner {
position: absolute; position: absolute;
top: 100%; bottom: 10px;
left: 100%; right: 5px;
margin-top: -1.1em;
margin-left: -1.1em;
opacity: 0; opacity: 0;
font-size: 30px; font-size: 20px;
transition: opacity 200ms ease-in-out; transition: opacity 200ms ease-in-out;
} }
...@@ -65,17 +61,30 @@ ...@@ -65,17 +61,30 @@
position: relative; position: relative;
} }
.md-header {
.nav-links {
.active {
a {
border-bottom-color: #000;
}
}
a {
padding-top: 0;
line-height: 1;
}
}
}
.referenced-users { .referenced-users {
color: #4c4e54; color: #4c4e54;
padding-top: 10px; padding-top: 10px;
} }
.md-preview-holder { .md-preview-holder {
background: #fff; min-height: 167px;
border: 1px solid #ddd; padding: 10px 0;
min-height: 169px; overflow-x: auto;
padding: 5px;
box-shadow: none;
} }
.markdown-area { .markdown-area {
......
...@@ -56,6 +56,17 @@ ...@@ -56,6 +56,17 @@
} }
} }
.nav-search {
display: inline-block;
width: 50%;
padding: 11px 0;
/* Small devices (phones, tablets, 768px and lower) */
@media (max-width: $screen-sm-min) {
width: 100%;
}
}
.nav-links { .nav-links {
display: inline-block; display: inline-block;
width: 50%; width: 50%;
......
...@@ -144,7 +144,7 @@ ...@@ -144,7 +144,7 @@
} }
a { a {
padding: 7px 12px; padding: 7px 15px;
font-size: $gl-font-size; font-size: $gl-font-size;
line-height: 24px; line-height: 24px;
color: $gray; color: $gray;
...@@ -169,12 +169,10 @@ ...@@ -169,12 +169,10 @@
} }
.count { .count {
&:before { float: right;
content: '('; background: #eee;
} padding: 0 8px;
&:after { @include border-radius(6px);
content: ')';
}
} }
&.back-link i { &.back-link i {
...@@ -193,27 +191,6 @@ ...@@ -193,27 +191,6 @@
} }
} }
.expand-nav a {
color: $gl-icon-color;
width: 60px;
position: fixed;
top: 0;
left: 0;
font-size: 20px;
background: transparent;
height: 59px;
text-align: center;
line-height: 59px;
border-bottom: 1px solid #eee;
transition-duration: .3s;
outline: none;
z-index: 100;
&:hover {
text-decoration: none;
}
}
.collapse-nav a { .collapse-nav a {
width: $sidebar_width; width: $sidebar_width;
position: fixed; position: fixed;
...@@ -233,12 +210,55 @@ ...@@ -233,12 +210,55 @@
} }
.page-sidebar-collapsed { .page-sidebar-collapsed {
padding-left: $sidebar_collapsed_width;
.sidebar-wrapper { .sidebar-wrapper {
display: none; width: $sidebar_collapsed_width;
.header-logo {
width: $sidebar_collapsed_width;
a {
padding-left: ($sidebar_collapsed_width - 36) / 2;
.gitlab-text-container {
display: none;
}
}
}
.nav-sidebar {
width: $sidebar_collapsed_width;
li {
width: auto;
a {
span {
display: none;
}
}
}
}
.collapse-nav a {
width: $sidebar_collapsed_width;
}
.sidebar-user {
padding-left: ($sidebar_collapsed_width - 36) / 2;
width: $sidebar_collapsed_width;
.username {
display: none;
}
}
} }
} }
.page-sidebar-expanded { .page-sidebar-expanded {
padding-left: $sidebar_collapsed_width;
@media (min-width: $screen-md-min) { @media (min-width: $screen-md-min) {
padding-left: $sidebar_width; padding-left: $sidebar_width;
} }
...@@ -289,48 +309,3 @@ ...@@ -289,48 +309,3 @@
padding-right: $sidebar_collapsed_width; padding-right: $sidebar_collapsed_width;
} }
} }
.complex-sidebar {
display: inline-block;
.nav-primary {
width: 61px;
float: left;
height: 100vh;
.nav-sidebar {
width: 60px;
li a {
width: 60px;
span {
display: none;
}
}
}
}
.nav-secondary {
$nav-secondary-width: 168px;
float: left;
width: $nav-secondary-width;
.nav-sidebar {
width: $nav-secondary-width;
li {
width: $nav-secondary-width;
a {
width: $nav-secondary-width;
i {
display: none;
}
}
}
}
}
}
...@@ -14,10 +14,6 @@ ...@@ -14,10 +14,6 @@
background: $row-hover; background: $row-hover;
} }
&:last-child {
border-bottom: none;
}
.avatar { .avatar {
margin-right: 15px; margin-right: 15px;
} }
......
...@@ -138,6 +138,12 @@ ...@@ -138,6 +138,12 @@
} }
} }
a.no-attachment-icon {
&:before {
display: none;
}
}
/* Link to current header. */ /* Link to current header. */
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
position: relative; position: relative;
...@@ -244,7 +250,7 @@ a > code { ...@@ -244,7 +250,7 @@ a > code {
* Textareas intended for GFM * Textareas intended for GFM
* *
*/ */
textarea.js-gfm-input { .js-gfm-input {
font-family: $monospace_font; font-family: $monospace_font;
color: $gl-text-color; color: $gl-text-color;
} }
......
...@@ -10,10 +10,10 @@ $gutter_inner_width: 258px; ...@@ -10,10 +10,10 @@ $gutter_inner_width: 258px;
/* /*
* UI elements * UI elements
*/ */
$border-color: #efeff1; $border-color: #e5e5e5;
$focus-border-color: #3aabf0; $focus-border-color: #3aabf0;
$table-border-color: #eef0f2; $table-border-color: #eef0f2;
$background-color: #faf9f9; $background-color: #fafafa;
/* /*
* Text * Text
...@@ -81,7 +81,7 @@ $provider-btn-not-active-color: #4688f1; ...@@ -81,7 +81,7 @@ $provider-btn-not-active-color: #4688f1;
$white-light: #fff; $white-light: #fff;
$white-normal: #ededed; $white-normal: #ededed;
$white-dark: #ededed; $white-dark: #ececec;
$gray-light: #faf9f9; $gray-light: #faf9f9;
$gray-normal: #f5f5f5; $gray-normal: #f5f5f5;
...@@ -104,9 +104,11 @@ $orange-light: rgba(252, 109, 38, 0.80); ...@@ -104,9 +104,11 @@ $orange-light: rgba(252, 109, 38, 0.80);
$orange-normal: #e75e40; $orange-normal: #e75e40;
$orange-dark: #ce5237; $orange-dark: #ce5237;
$red-light: #f06559; $red-light: #e52c5a;
$red-normal: #e52c5a; $red-normal: #d22852;
$red-dark: #d22852; $red-dark: darken($red-normal, 5%);
$black-transparent: rgba(0, 0, 0, 0.3);
$border-white-light: #f1f2f4; $border-white-light: #f1f2f4;
$border-white-normal: #d6dae2; $border-white-normal: #d6dae2;
...@@ -128,9 +130,9 @@ $border-orange-light: #fc6d26; ...@@ -128,9 +130,9 @@ $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-light: #d22852;
$border-red-normal: #d22852; $border-red-normal: #ca264f;
$border-red-dark: #ca264f; $border-red-dark: darken($border-red-normal, 5%);
$help-well-bg: #fafafa; $help-well-bg: #fafafa;
$help-well-border: #e5e5e5; $help-well-border: #e5e5e5;
...@@ -150,15 +152,22 @@ $gl-success: $green-normal; ...@@ -150,15 +152,22 @@ $gl-success: $green-normal;
$gl-info: $blue-normal; $gl-info: $blue-normal;
$gl-warning: $orange-normal; $gl-warning: $orange-normal;
$gl-danger: $red-normal; $gl-danger: $red-normal;
$gl-btn-active-background: rgba(0, 0, 0, 0.12); $gl-btn-active-background: rgba(0, 0, 0, 0.16);
$gl-btn-active-gradient: inset 0 0 4px $gl-btn-active-background; $gl-btn-active-gradient: inset 0 2px 3px $gl-btn-active-background;
/* /*
* Commit Diff Colors * Commit Diff Colors
*/ */
$added: #63c363; $added: #63c363;
$deleted: #f77; $deleted: #f77;
$line-added: #ecfdf0;
$line-added-dark: #c7f0d2;
$line-removed: #fbe9eb;
$line-removed-dark: #fac5cd;
$line-number-old: #f9d7dc;
$line-number-new: #ddfbe6;
$match-line: #fafafa;
$table-border-gray: #f0f0f0;
/* /*
* Fonts * Fonts
*/ */
...@@ -191,6 +200,13 @@ $dropdown-toggle-hover-border-color: darken($dropdown-toggle-border-color, 15%); ...@@ -191,6 +200,13 @@ $dropdown-toggle-hover-border-color: darken($dropdown-toggle-border-color, 15%);
$dropdown-toggle-icon-color: #c4c4c4; $dropdown-toggle-icon-color: #c4c4c4;
$dropdown-toggle-hover-icon-color: $dropdown-toggle-hover-border-color; $dropdown-toggle-hover-icon-color: $dropdown-toggle-hover-border-color;
/*
* Buttons
*/
$btn-active-gray: #ececec;
$btn-placeholder-gray: #c7c7c7;
$btn-white-active: #848484;
/* /*
* Award emoji * Award emoji
*/ */
...@@ -201,14 +217,14 @@ $award-emoji-new-btn-icon-color: #dcdcdc; ...@@ -201,14 +217,14 @@ $award-emoji-new-btn-icon-color: #dcdcdc;
/* /*
* Search Box * Search Box
*/ */
$search-input-border-color: $dropdown-input-focus-border; $search-input-border-color: rgba(#4688f1, .8);
$search-input-focus-shadow-color: $dropdown-input-focus-shadow; $search-input-focus-shadow-color: $dropdown-input-focus-shadow;
$search-input-width: $dropdown-width; $search-input-width: 244px;
$location-badge-color: #aaa; $location-badge-color: #aaa;
$location-badge-bg: $gray-normal; $location-badge-bg: $gray-normal;
$location-badge-active-bg: #4f91f8;
$location-icon-color: #e7e9ed; $location-icon-color: #e7e9ed;
$location-active-color: $gl-text-color; $location-icon-active-color: #807e7e;
$location-active-bg: $search-input-border-color;
/* /*
* Notes * Notes
...@@ -217,3 +233,9 @@ $notes-light-color: #8e8e8e; ...@@ -217,3 +233,9 @@ $notes-light-color: #8e8e8e;
$notes-action-color: #c3c3c3; $notes-action-color: #c3c3c3;
$notes-role-color: #8e8e8e; $notes-role-color: #8e8e8e;
$notes-role-border-color: #e4e4e4; $notes-role-border-color: #e4e4e4;
$note-disabled-comment-color: #b2b2b2;
$note-form-border-color: #e5e5e5;
$note-toolbar-color: #959494;
$zen-control-hover-color: #111;
.zennable { .zen-backdrop {
a.js-zen-enter { &.fullscreen {
color: $gl-gray; background-color: white;
position: absolute; position: fixed;
top: 0; top: 0;
right: 4px; bottom: 0;
line-height: 56px; left: 0;
} right: 0;
z-index: 1031;
a.js-zen-leave { textarea {
display: none; border: none;
color: $gl-text-color; box-shadow: none;
position: absolute; border-radius: 0;
top: 10px; color: #000;
right: 10px; font-size: 20px;
padding: 5px; line-height: 26px;
font-size: 36px; padding: 30px;
display: block;
outline: none;
resize: none;
height: 100vh;
max-width: 900px;
margin: 0 auto;
}
&:hover { .zen-control-leave {
color: #111; display: block;
position: absolute;
top: 0;
} }
} }
}
.zen-backdrop { .zen-cotrol {
&.fullscreen { padding: 0;
background-color: white; color: #555;
position: fixed; background: none;
top: 0; border: 0;
bottom: 0; }
left: 0;
right: 0;
z-index: 1031;
textarea { .zen-control-full {
border: none; color: $note-toolbar-color;
box-shadow: none;
border-radius: 0;
color: #000;
font-size: 20px;
line-height: 26px;
padding: 30px;
display: block;
outline: none;
resize: none;
height: 100vh;
max-width: 900px;
margin: 0 auto;
}
a.js-zen-enter { &:hover {
display: none; color: $gl-link-color;
} text-decoration: none;
}
}
a.js-zen-leave { .zen-control-leave {
display: block; display: none;
position: absolute; color: $gl-text-color;
top: 0; position: absolute;
} right: 10px;
} padding: 5px;
font-size: 36px;
&:hover {
color: $zen-control-hover-color;
} }
} }
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
} }
.diff-line-num, .diff-line-num a { .diff-line-num, .diff-line-num a {
color: rgba(0, 0, 0, 0.3); color: $black-transparent;
} }
// Code itself // Code itself
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
} }
.line_content.match { .line_content.match {
color: rgba(0, 0, 0, 0.3); color: $black-transparent;
background: rgba(255, 255, 255, 0.4); background: rgba(255, 255, 255, 0.4);
} }
} }
......
...@@ -6,12 +6,12 @@ ...@@ -6,12 +6,12 @@
} }
.diff-line-num, .diff-line-num a { .diff-line-num, .diff-line-num a {
color: rgba(0, 0, 0, 0.3); color: $black-transparent;
} }
// Code itself // Code itself
pre.code, .diff-line-num { pre.code, .diff-line-num {
border-color: $border-color; border-color: $table-border-gray;
} }
&, pre.code, .line_holder .line_content { &, pre.code, .line_holder .line_content {
...@@ -23,36 +23,36 @@ ...@@ -23,36 +23,36 @@
.line_holder { .line_holder {
.diff-line-num { .diff-line-num {
&.old { &.old {
background: #fdd; background-color: $line-number-old;
border-color: #f1c0c0; border-color: $line-removed-dark;
} }
&.new { &.new {
background: #dbffdb; background-color: $line-number-new;
border-color: #c1e9c1; border-color: $line-added-dark;
} }
} }
.line_content { .line_content {
&.old { &.old {
background: #ffecec; background: $line-removed;
span.idiff { span.idiff {
background-color: #f8cbcb; background-color: $line-removed-dark;
} }
} }
&.new { &.new {
background: #eaffea; background-color: $line-added;
span.idiff { span.idiff {
background-color: #a6f3a6; background-color: $line-added-dark;
} }
} }
&.match { &.match {
color: rgba(0, 0, 0, 0.3); color: $black-transparent;
background: #fafafa; background: $match-line;
} }
} }
} }
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
margin: 0; margin: 0;
padding: 0; padding: 0;
margin-top: 10px; margin-top: 10px;
word-break: normal;
white-space: pre-wrap;
} }
.commit-info-row { .commit-info-row {
......
...@@ -47,6 +47,7 @@ li.commit { ...@@ -47,6 +47,7 @@ li.commit {
.commit_short_id { .commit_short_id {
min-width: 65px; min-width: 65px;
color: $gl-dark-link-color;
font-family: $monospace_font; font-family: $monospace_font;
} }
...@@ -88,6 +89,10 @@ li.commit { ...@@ -88,6 +89,10 @@ li.commit {
padding: 0; padding: 0;
margin: 0; margin: 0;
} }
a {
color: $gl-dark-link-color;
}
} }
.commit-row-info { .commit-row-info {
......
...@@ -33,8 +33,12 @@ ...@@ -33,8 +33,12 @@
.description { .description {
margin-top: 6px; margin-top: 6px;
p:last-child { p {
margin-bottom: 0; overflow-x: auto;
&:last-child {
margin-bottom: 0;
}
} }
} }
} }
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
.diff-file { .diff-file {
border: 1px solid $border-color; border: 1px solid $border-color;
margin-bottom: $gl-padding; margin-bottom: $gl-padding;
border-radius: 3px;
.diff-header { .diff-header {
position: relative; position: relative;
...@@ -10,6 +11,7 @@ ...@@ -10,6 +11,7 @@
padding: 10px 16px; padding: 10px 16px;
color: #555; color: #555;
z-index: 10; z-index: 10;
border-radius: 3px 3px 0 0;
.diff-title { .diff-title {
font-family: $monospace_font; font-family: $monospace_font;
...@@ -31,6 +33,7 @@ ...@@ -31,6 +33,7 @@
overflow-y: hidden; overflow-y: hidden;
background: #fff; background: #fff;
color: #333; color: #333;
border-radius: 0 0 3px 3px;
.unfold { .unfold {
cursor: pointer; cursor: pointer;
...@@ -59,9 +62,14 @@ ...@@ -59,9 +62,14 @@
border-collapse: separate; border-collapse: separate;
margin: 0; margin: 0;
padding: 0; padding: 0;
.line_holder td { .line_holder td {
line-height: $code_line_height; line-height: $code_line_height;
font-size: $code_font_size; font-size: $code_font_size;
span {
white-space: pre;
}
} }
} }
...@@ -104,6 +112,10 @@ ...@@ -104,6 +112,10 @@
display: table-cell; display: table-cell;
} }
} }
.text-file.diff-wrap-lines table .line_holder td span {
white-space: pre-wrap;
}
} }
.image { .image {
background: #ddd; background: #ddd;
...@@ -316,6 +328,16 @@ ...@@ -316,6 +328,16 @@
float: right; float: right;
} }
.diffs {
.content-block {
border-bottom: none;
}
}
.files-changed {
border-bottom: none;
}
// Mobile // Mobile
@media (max-width: 480px) { @media (max-width: 480px) {
.diff-title { .diff-title {
......
...@@ -59,6 +59,9 @@ ...@@ -59,6 +59,9 @@
position: relative; position: relative;
overflow-y: auto; overflow-y: auto;
padding: 15px; padding: 15px;
.form-actions {
margin: -$gl-padding+1;
}
} }
body.modal-open { body.modal-open {
......
...@@ -49,6 +49,15 @@ ...@@ -49,6 +49,15 @@
} }
.label-row { .label-row {
.label-name {
display: inline-block;
width: 200px;
@media (max-width: $screen-xs-min) {
display: block;
}
}
.label { .label {
padding: 9px; padding: 9px;
font-size: 14px; font-size: 14px;
...@@ -69,3 +78,52 @@ ...@@ -69,3 +78,52 @@
background-color: $gl-danger; background-color: $gl-danger;
color: $white-light; color: $white-light;
} }
.manage-labels-list {
.prepend-left-10 {
display: inline-block;
width: 40%;
vertical-align: middle;
@media (max-width: $screen-xs-min) {
display: block;
width: 100%;
margin-left: 0;
padding: 10px 0;
}
}
.pull-info-right {
float: right;
@media (max-width: $screen-xs-min) {
float: none;
}
.action-buttons {
border-color: transparent;
padding: 6px;
color: $gl-text-color;
&.subscribe-button {
padding-left: 0;
}
}
i {
color: $gl-text-color;
}
.append-right-20 {
a {
color: $gl-text-color;
}
@media (max-width: $screen-xs-min) {
display: block;
margin-bottom: 10px;
}
}
}
}
...@@ -123,6 +123,8 @@ ...@@ -123,6 +123,8 @@
.mr_source_commit, .mr_source_commit,
.mr_target_commit { .mr_target_commit {
margin-bottom: 0;
.commit { .commit {
margin: 0; margin: 0;
padding: 2px 0; padding: 2px 0;
...@@ -174,10 +176,6 @@ ...@@ -174,10 +176,6 @@
display: none; display: none;
} }
.merge-request-form .select2-container {
width: 250px !important;
}
#modal_merge_info .modal-dialog { #modal_merge_info .modal-dialog {
width: 600px; width: 600px;
...@@ -195,44 +193,81 @@ ...@@ -195,44 +193,81 @@
line-height: 31px; line-height: 31px;
} }
.disabled-comment-area { .builds {
padding: 16px 0; .table-holder {
overflow-x: scroll;
}
}
.disabled-profile { .panel-new-merge-request {
width: 40px; .panel-heading {
height: 40px; padding: 5px 10px;
background: $border-gray-dark; font-weight: 600;
border-radius: 20px; line-height: 25px;
display: inline-block;
margin-right: 10px;
} }
.disabled-comment { .panel-body {
background: $gray-light; padding: 10px 5px;
display: inline-block; }
vertical-align: top;
height: 200px;
border-radius: 4px;
border: 1px solid $border-gray-normal;
padding-top: 90px;
text-align: center;
right: 20px;
position: absolute;
left: 70px;
margin-bottom: 20px;
span { .panel-footer {
color: #b2b2b2; padding: 5px 10px;
}
a { .commit {
color: $md-link-color; .commit-row-title {
} margin-bottom: 4px;
}
.avatar {
width: 20px;
height: 20px;
margin-right: 5px;
}
.commit-row-info {
line-height: 20px;
} }
} }
.btn-clipboard {
margin-right: 5px;
padding: 0;
background: transparent;
}
.ci-status-link {
margin-right: 5px;
}
} }
.builds { .merge-request-select {
.table-holder { padding-left: 5px;
overflow-x: scroll; padding-right: 5px;
margin-bottom: 10px;
&:last-child {
margin-bottom: 0;
} }
@media (min-width: $screen-sm-min) {
float: left;
width: 50%;
margin-bottom: 0;
}
.dropdown-menu-toggle {
width: 100%;
}
.dropdown-menu {
left: 5px;
right: 5px;
width: auto;
}
}
.issuable-form-select-holder {
display: inline-block;
width: 250px;
} }
/** /**
* Note Form * Note Form
*/ */
.comment-btn { .comment-btn {
@extend .btn-create; @extend .btn-create;
} }
.reply-btn {
@extend .btn-primary;
margin: 10px $gl-padding;
}
.diff-file .diff-content { .diff-file .diff-content {
tr.line_holder:hover > td .line_note_link { tr.line_holder:hover > td .line_note_link {
opacity: 1.0; opacity: 1.0;
...@@ -17,16 +13,17 @@ ...@@ -17,16 +13,17 @@
} }
.diff-file, .diff-file,
.discussion { .discussion {
.new_note { .new-note {
margin: 0; margin: 0;
border: none; border: none;
} }
} }
.new_note {
.new-note {
display: none; display: none;
} }
.new_note, .note-edit-form { .new-note, .note-edit-form {
.note-form-actions { .note-form-actions {
margin-top: $gl-padding; margin-top: $gl-padding;
} }
...@@ -40,21 +37,18 @@ ...@@ -40,21 +37,18 @@
img { img {
max-width: 100%; max-width: 100%;
} }
}
.note_text { .note-textarea {
width: 100%; padding: 10px 0;
} font-family: $regular_font;
border: 0;
.comment-hints { &:focus {
margin-top: -12px; outline: 0;
} }
} }
/* loading indicator */
.notes-busy {
margin: 18px;
}
.note-image-attach { .note-image-attach {
@extend .col-md-4; @extend .col-md-4;
margin-left: 45px; margin-left: 45px;
...@@ -62,38 +56,29 @@ ...@@ -62,38 +56,29 @@
} }
.common-note-form { .common-note-form {
margin: 0; .md-area {
background: #fff; padding: $gl-padding-top $gl-padding;
padding: $gl-padding; border: 1px solid $note-form-border-color;
margin-left: -$gl-padding; border-radius: $border-radius-base;
margin-right: -$gl-padding;
margin-bottom: -$gl-padding; &.is-focused {
} border-color: $focus-border-color;
box-shadow: 0 0 2px rgba(#000, .2),
.note-form-actions { 0 0 4px rgba($focus-border-color, .4);
.note-form-option {
margin-top: 8px; .comment-toolbar,
margin-left: 30px; .nav-links {
@extend .pull-left; border-color: $focus-border-color;
} }
.js-notify-commit-author {
float: left;
}
.write-preview-btn {
// makes the "absolute" position for links relative to this
position: relative;
// preview/edit buttons
> a {
position: absolute;
right: 5px;
top: 8px;
} }
} }
} }
.discussion-form {
padding: $gl-padding-top $gl-padding;
background-color: #fff;
}
.note-edit-form { .note-edit-form {
display: none; display: none;
font-size: 15px; font-size: 15px;
...@@ -128,13 +113,12 @@ ...@@ -128,13 +113,12 @@
.discussion-body, .discussion-body,
.diff-file { .diff-file {
.notes .note { .notes .note {
border-color: #ddd;
padding: 10px 15px; padding: 10px 15px;
} }
.discussion-reply-holder { .discussion-reply-holder {
background: $background-color; background-color: $white-light;
border-top: 1px solid $border-color; padding: 10px 16px;
} }
} }
...@@ -152,11 +136,49 @@ ...@@ -152,11 +136,49 @@
} }
} }
.comment-hints { .comment-toolbar {
color: #999; padding-top: $gl-padding-top;
background: #fff; color: $note-toolbar-color;
padding: 7px; border-top: 1px solid $border-color;
margin-top: -7px; }
border: 1px solid $border-color;
font-size: 13px; .toolbar-button {
padding: 0;
background: none;
border: 0;
font-size: 14px;
line-height: 16px;
&:hover,
&:focus {
color: $gl-link-color;
outline: 0;
}
@media (min-width: $screen-md-min) {
float: left;
margin-right: $gl-padding;
&:last-child {
float: right;
margin-right: 0;
}
}
}
.toolbar-button-icon {
position: relative;
top: 1px;
margin-right: 3px;
color: inherit;
font-size: 16px;
}
.toolbar-text {
font-size: 14px;
line-height: 16px;
@media (min-width: $screen-md-min) {
float: left;
}
} }
...@@ -20,6 +20,12 @@ ul.notes { ...@@ -20,6 +20,12 @@ ul.notes {
.timeline-content { .timeline-content {
margin-left: 55px; margin-left: 55px;
&.timeline-content-form {
@media (max-width: $screen-sm-max) {
margin-left: 0;
}
}
} }
.note-created-ago, .note-updated-at { .note-created-ago, .note-updated-at {
...@@ -52,6 +58,7 @@ ul.notes { ...@@ -52,6 +58,7 @@ ul.notes {
.note { .note {
display: block; display: block;
position: relative; position: relative;
border-bottom: 1px solid $table-border-gray;
&.is-editting { &.is-editting {
.note-header, .note-header,
...@@ -76,7 +83,7 @@ ul.notes { ...@@ -76,7 +83,7 @@ ul.notes {
// On diffs code should wrap nicely and not overflow // On diffs code should wrap nicely and not overflow
pre { pre {
code { code {
white-space: pre-wrap; white-space: pre;
} }
} }
...@@ -111,9 +118,6 @@ ul.notes { ...@@ -111,9 +118,6 @@ ul.notes {
padding-bottom: 3px; padding-bottom: 3px;
} }
&:last-child {
border-bottom: 1px solid $border-color;
}
} }
} }
...@@ -131,14 +135,14 @@ ul.notes { ...@@ -131,14 +135,14 @@ ul.notes {
font-family: $regular_font; font-family: $regular_font;
td { td {
border: 1px solid #ddd; border: 1px solid $table-border-gray;
border-left: none; border-left: none;
&.notes_line { &.notes_line {
vertical-align: middle; vertical-align: middle;
text-align: center; text-align: center;
padding: 10px 0; padding: 10px 0;
background: #fff; background: $background-color;
color: $text-color; color: $text-color;
} }
&.notes_line2 { &.notes_line2 {
...@@ -149,7 +153,7 @@ ul.notes { ...@@ -149,7 +153,7 @@ ul.notes {
&.notes_content { &.notes_content {
background-color: #fff; background-color: #fff;
border-width: 1px 0; border-width: 1px 0;
padding-top: 0; padding: 0;
vertical-align: top; vertical-align: top;
&.parallel { &.parallel {
border-width: 1px; border-width: 1px;
...@@ -169,9 +173,6 @@ ul.notes { ...@@ -169,9 +173,6 @@ ul.notes {
} }
} }
.author_link {
font-weight: 600;
}
} }
.note-headline-light, .note-headline-light,
...@@ -197,14 +198,26 @@ ul.notes { ...@@ -197,14 +198,26 @@ ul.notes {
line-height: 24px; line-height: 24px;
.fa { .fa {
color: $notes-action-color;
position: relative; position: relative;
top: 1px; top: 1px;
font-size: 17px; font-size: 17px;
} }
.fa-trash-o { &.js-note-delete {
top: 0; i {
font-size: 16px; &:hover {
color: $gl-text-red;
}
}
}
&.js-note-edit {
i {
&:hover {
color: $gl-link-color;
}
}
} }
} }
...@@ -281,3 +294,21 @@ ul.notes { ...@@ -281,3 +294,21 @@ ul.notes {
} }
} }
} }
.disabled-comment {
margin-left: -$gl-padding-top;
margin-right: -$gl-padding-top;
background-color: $gray-light;
border-radius: $border-radius-base;
border: 1px solid $border-gray-normal;
color: $note-disabled-comment-color;
line-height: 200px;
.disabled-comment-text {
line-height: normal;
}
a {
color: $gl-link-color;
}
}
...@@ -315,7 +315,7 @@ pre.light-well { ...@@ -315,7 +315,7 @@ pre.light-well {
} }
.git-empty { .git-empty {
margin: 0 7px; margin: 0 7px 7px;
h5 { h5 {
color: #5c5d5e; color: #5c5d5e;
...@@ -401,7 +401,7 @@ pre.light-well { ...@@ -401,7 +401,7 @@ pre.light-well {
} }
.commit_short_id { .commit_short_id {
margin-right: 5px; margin: 0 5px;
color: $gl-link-color; color: $gl-link-color;
font-weight: 600; font-weight: 600;
} }
......
...@@ -135,25 +135,25 @@ ...@@ -135,25 +135,25 @@
.location-badge { .location-badge {
@include transition(all .15s); @include transition(all .15s);
background-color: $location-active-bg; background-color: $location-badge-active-bg;
color: $white-light; color: $white-light;
} }
.search-input-wrap { .search-input-wrap {
i { i {
color: $location-active-color; color: $location-icon-active-color;
} }
} }
}
&.has-location-badge { &.has-value {
.search-icon { .search-icon {
display: none; display: none;
} }
.clear-icon { .clear-icon {
cursor: pointer; cursor: pointer;
display: block; display: block;
}
} }
} }
......
.container-fluid .content { .container-fluid {
.ci-status { .ci-status {
padding: 2px 7px; padding: 2px 7px;
margin-right: 5px; margin-right: 5px;
......
...@@ -5,7 +5,7 @@ class Admin::ProjectsController < Admin::ApplicationController ...@@ -5,7 +5,7 @@ class Admin::ProjectsController < Admin::ApplicationController
def index def index
@projects = Project.all @projects = Project.all
@projects = @projects.in_namespace(params[:namespace_id]) if params[:namespace_id].present? @projects = @projects.in_namespace(params[:namespace_id]) if params[:namespace_id].present?
@projects = @projects.where("visibility_level IN (?)", params[:visibility_levels]) if params[:visibility_levels].present? @projects = @projects.where("projects.visibility_level IN (?)", params[:visibility_levels]) if params[:visibility_levels].present?
@projects = @projects.with_push if params[:with_push].present? @projects = @projects.with_push if params[:with_push].present?
@projects = @projects.abandoned if params[:abandoned].present? @projects = @projects.abandoned if params[:abandoned].present?
@projects = @projects.where(last_repository_check_failed: true) if params[:last_repository_check_failed].present? @projects = @projects.where(last_repository_check_failed: true) if params[:last_repository_check_failed].present?
......
...@@ -47,6 +47,16 @@ class ApplicationController < ActionController::Base ...@@ -47,6 +47,16 @@ class ApplicationController < ActionController::Base
email: current_user.email, email: current_user.email,
username: current_user.username, username: current_user.username,
) )
Raven.tags_context(program: sentry_program_context)
end
end
def sentry_program_context
if Sidekiq.server?
'sidekiq'
else
'rails'
end end
end end
......
...@@ -18,14 +18,14 @@ class Groups::MilestonesController < Groups::ApplicationController ...@@ -18,14 +18,14 @@ class Groups::MilestonesController < Groups::ApplicationController
end end
def create def create
project_ids = params[:milestone][:project_ids] project_ids = params[:milestone][:project_ids].reject(&:blank?)
title = milestone_params[:title] title = milestone_params[:title]
@projects.where(id: project_ids).each do |project| if create_milestones(project_ids)
Milestones::CreateService.new(project, current_user, milestone_params).execute redirect_to milestone_path(title)
else
render_new_with_error(project_ids.empty?)
end end
redirect_to milestone_path(title)
end end
def show def show
...@@ -41,6 +41,27 @@ class Groups::MilestonesController < Groups::ApplicationController ...@@ -41,6 +41,27 @@ class Groups::MilestonesController < Groups::ApplicationController
private private
def create_milestones(project_ids)
return false unless project_ids.present?
ActiveRecord::Base.transaction do
@projects.where(id: project_ids).each do |project|
Milestones::CreateService.new(project, current_user, milestone_params).execute
end
end
true
rescue ActiveRecord::ActiveRecordError => e
flash.now[:alert] = "An error occurred while creating the milestone: #{e.message}"
false
end
def render_new_with_error(empty_project_ids)
@milestone = Milestone.new(milestone_params)
@milestone.errors.add(:project_id, "Please select at least one project.") if empty_project_ids
render :new
end
def authorize_admin_milestones! def authorize_admin_milestones!
return render_404 unless can?(current_user, :admin_milestones, group) return render_404 unless can?(current_user, :admin_milestones, group)
end end
......
...@@ -55,7 +55,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController ...@@ -55,7 +55,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
end end
else else
saml_user = Gitlab::Saml::User.new(oauth) saml_user = Gitlab::Saml::User.new(oauth)
saml_user.save saml_user.save if saml_user.changed?
@user = saml_user.gl_user @user = saml_user.gl_user
continue_login_process continue_login_process
......
...@@ -68,7 +68,9 @@ class Projects::ApplicationController < ApplicationController ...@@ -68,7 +68,9 @@ class Projects::ApplicationController < ApplicationController
end end
def require_non_empty_project def require_non_empty_project
redirect_to namespace_project_path(@project.namespace, @project) if @project.empty_repo? # Be sure to return status code 303 to avoid a double DELETE:
# http://api.rubyonrails.org/classes/ActionController/Redirecting.html
redirect_to namespace_project_path(@project.namespace, @project), status: 303 if @project.empty_repo?
end end
def require_branch_head def require_branch_head
......
class Projects::BadgesController < Projects::ApplicationController class Projects::BadgesController < Projects::ApplicationController
before_action :no_cache_headers layout 'project_settings'
before_action :authorize_admin_project!, only: [:index]
before_action :no_cache_headers, except: [:index]
def index
@ref = params[:ref] || @project.default_branch || 'master'
@build_badge = Gitlab::Badge::Build.new(@project, @ref)
end
def build def build
badge = Gitlab::Badge::Build.new(project, params[:ref]) badge = Gitlab::Badge::Build.new(project, params[:ref])
......
...@@ -48,7 +48,7 @@ class Projects::BranchesController < Projects::ApplicationController ...@@ -48,7 +48,7 @@ class Projects::BranchesController < Projects::ApplicationController
respond_to do |format| respond_to do |format|
format.html do format.html do
redirect_to namespace_project_branches_path(@project.namespace, redirect_to namespace_project_branches_path(@project.namespace,
@project) @project), status: 303
end end
format.js { render status: status[:return_code] } format.js { render status: status[:return_code] }
end end
......
...@@ -207,20 +207,20 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -207,20 +207,20 @@ class Projects::MergeRequestsController < Projects::ApplicationController
#This is always source #This is always source
@source_project = @merge_request.nil? ? @project : @merge_request.source_project @source_project = @merge_request.nil? ? @project : @merge_request.source_project
@commit = @repository.commit(params[:ref]) if params[:ref].present? @commit = @repository.commit(params[:ref]) if params[:ref].present?
render layout: false
end end
def branch_to def branch_to
@target_project = selected_target_project @target_project = selected_target_project
@commit = @target_project.commit(params[:ref]) if params[:ref].present? @commit = @target_project.commit(params[:ref]) if params[:ref].present?
render layout: false
end end
def update_branches def update_branches
@target_project = selected_target_project @target_project = selected_target_project
@target_branches = @target_project.repository.branch_names @target_branches = @target_project.repository.branch_names
respond_to do |format| render layout: false
format.js
end
end end
def ci_status def ci_status
......
...@@ -39,8 +39,7 @@ class Projects::NotesController < Projects::ApplicationController ...@@ -39,8 +39,7 @@ class Projects::NotesController < Projects::ApplicationController
def destroy def destroy
if note.editable? if note.editable?
note.destroy Notes::DeleteService.new(project, current_user).execute(note)
note.reset_events_cache
end end
respond_to do |format| respond_to do |format|
......
...@@ -94,9 +94,14 @@ class Projects::ProjectMembersController < Projects::ApplicationController ...@@ -94,9 +94,14 @@ class Projects::ProjectMembersController < Projects::ApplicationController
end end
def apply_import def apply_import
giver = Project.find(params[:source_project_id]) source_project = Project.find(params[:source_project_id])
status = @project.team.import(giver, current_user)
notice = status ? "Successfully imported" : "Import failed" if can?(current_user, :read_project_member, source_project)
status = @project.team.import(source_project, current_user)
notice = status ? "Successfully imported" : "Import failed"
else
return render_404
end
redirect_to(namespace_project_project_members_path(project.namespace, project), redirect_to(namespace_project_project_members_path(project.namespace, project),
notice: notice) notice: notice)
......
...@@ -24,6 +24,8 @@ class Projects::RefsController < Projects::ApplicationController ...@@ -24,6 +24,8 @@ class Projects::RefsController < Projects::ApplicationController
namespace_project_find_file_path(@project.namespace, @project, @id) namespace_project_find_file_path(@project.namespace, @project, @id)
when "graphs_commits" when "graphs_commits"
commits_namespace_project_graph_path(@project.namespace, @project, @id) commits_namespace_project_graph_path(@project.namespace, @project, @id)
when "badges"
namespace_project_badges_path(@project.namespace, @project, ref: @id)
else else
namespace_project_commits_path(@project.namespace, @project, @id) namespace_project_commits_path(@project.namespace, @project, @id)
end end
......
...@@ -88,6 +88,20 @@ class Projects::WikisController < Projects::ApplicationController ...@@ -88,6 +88,20 @@ class Projects::WikisController < Projects::ApplicationController
) )
end end
def markdown_preview
text = params[:text]
ext = Gitlab::ReferenceExtractor.new(@project, current_user, current_user)
ext.analyze(text)
render json: {
body: view_context.markdown(text, pipeline: :wiki, project_wiki: @project_wiki),
references: {
users: ext.users.map(&:username)
}
}
end
def git_access def git_access
end end
......
...@@ -40,6 +40,9 @@ class ProjectsController < Projects::ApplicationController ...@@ -40,6 +40,9 @@ class ProjectsController < Projects::ApplicationController
def update def update
status = ::Projects::UpdateService.new(@project, current_user, project_params).execute status = ::Projects::UpdateService.new(@project, current_user, project_params).execute
# Refresh the repo in case anything changed
@repository = project.repository
respond_to do |format| respond_to do |format|
if status if status
flash[:notice] = "Project '#{@project.name}' was successfully updated." flash[:notice] = "Project '#{@project.name}' was successfully updated."
...@@ -71,7 +74,7 @@ class ProjectsController < Projects::ApplicationController ...@@ -71,7 +74,7 @@ class ProjectsController < Projects::ApplicationController
def remove_fork def remove_fork
return access_denied! unless can?(current_user, :remove_fork_project, @project) return access_denied! unless can?(current_user, :remove_fork_project, @project)
if @project.unlink_fork if ::Projects::UnlinkForkService.new(@project, current_user).execute
flash[:notice] = 'The fork relationship has been removed.' flash[:notice] = 'The fork relationship has been removed.'
end end
end end
......
...@@ -5,7 +5,8 @@ class SessionsController < Devise::SessionsController ...@@ -5,7 +5,8 @@ class SessionsController < Devise::SessionsController
skip_before_action :check_2fa_requirement, only: [:destroy] skip_before_action :check_2fa_requirement, only: [:destroy]
prepend_before_action :check_initial_setup, only: [:new] prepend_before_action :check_initial_setup, only: [:new]
prepend_before_action :authenticate_with_two_factor, only: [:create] prepend_before_action :authenticate_with_two_factor,
if: :two_factor_enabled?, only: [:create]
prepend_before_action :store_redirect_path, only: [:new] prepend_before_action :store_redirect_path, only: [:new]
before_action :auto_sign_in_with_provider, only: [:new] before_action :auto_sign_in_with_provider, only: [:new]
...@@ -56,10 +57,10 @@ class SessionsController < Devise::SessionsController ...@@ -56,10 +57,10 @@ class SessionsController < Devise::SessionsController
end end
def find_user def find_user
if user_params[:login] if session[:otp_user_id]
User.by_login(user_params[:login])
elsif user_params[:otp_attempt] && session[:otp_user_id]
User.find(session[:otp_user_id]) User.find(session[:otp_user_id])
elsif user_params[:login]
User.by_login(user_params[:login])
end end
end end
...@@ -83,11 +84,13 @@ class SessionsController < Devise::SessionsController ...@@ -83,11 +84,13 @@ class SessionsController < Devise::SessionsController
end end
end end
def two_factor_enabled?
find_user.try(:two_factor_enabled?)
end
def authenticate_with_two_factor def authenticate_with_two_factor
user = self.resource = find_user user = self.resource = find_user
return unless user && user.two_factor_enabled?
if user_params[:otp_attempt].present? && session[:otp_user_id] if user_params[:otp_attempt].present? && session[:otp_user_id]
if valid_otp_attempt?(user) if valid_otp_attempt?(user)
# Remove any lingering user data from login # Remove any lingering user data from login
......
...@@ -27,9 +27,9 @@ module BlobHelper ...@@ -27,9 +27,9 @@ module BlobHelper
link_opts) link_opts)
if !on_top_of_branch?(project, ref) if !on_top_of_branch?(project, ref)
button_tag "Edit", class: "btn btn-default disabled has-tooltip", title: "You can only edit files when you are on a branch", data: { container: 'body' } button_tag "Edit", class: "btn disabled has-tooltip btn-file-option", title: "You can only edit files when you are on a branch", data: { container: 'body' }
elsif can_edit_blob?(blob, project, ref) elsif can_edit_blob?(blob, project, ref)
link_to "Edit", edit_path, class: 'btn' link_to "Edit", edit_path, class: 'btn btn-file-option'
elsif can?(current_user, :fork_project, project) elsif can?(current_user, :fork_project, project)
continue_params = { continue_params = {
to: edit_path, to: edit_path,
...@@ -38,7 +38,7 @@ module BlobHelper ...@@ -38,7 +38,7 @@ module BlobHelper
} }
fork_path = namespace_project_forks_path(project.namespace, project, namespace_key: current_user.namespace.id, continue: continue_params) fork_path = namespace_project_forks_path(project.namespace, project, namespace_key: current_user.namespace.id, continue: continue_params)
link_to "Edit", fork_path, class: 'btn', method: :post link_to "Edit", fork_path, class: 'btn btn-file-option', method: :post
end end
end end
......
...@@ -28,7 +28,7 @@ module CommitsHelper ...@@ -28,7 +28,7 @@ module CommitsHelper
def commit_to_html(commit, project, inline = true) def commit_to_html(commit, project, inline = true)
template = inline ? "inline_commit" : "commit" template = inline ? "inline_commit" : "commit"
escape_javascript(render "projects/commits/#{template}", commit: commit, project: project) unless commit.nil? render "projects/commits/#{template}", commit: commit, project: project unless commit.nil?
end end
# Breadcrumb links for a Project and, if applicable, a tree path # Breadcrumb links for a Project and, if applicable, a tree path
...@@ -117,7 +117,7 @@ module CommitsHelper ...@@ -117,7 +117,7 @@ module CommitsHelper
end end
end end
link_to( link_to(
"Browse Files »", "Browse Files",
namespace_project_tree_path(project.namespace, project, commit), namespace_project_tree_path(project.namespace, project, commit),
class: "pull-right" class: "pull-right"
) )
...@@ -197,7 +197,7 @@ module CommitsHelper ...@@ -197,7 +197,7 @@ module CommitsHelper
link_to( link_to(
namespace_project_blob_path(project.namespace, project, namespace_project_blob_path(project.namespace, project,
tree_join(commit_sha, diff.new_path)), tree_join(commit_sha, diff.new_path)),
class: 'btn view-file js-view-file' class: 'btn view-file js-view-file btn-file-option'
) do ) do
raw('View file @') + content_tag(:span, commit_sha[0..6], raw('View file @') + content_tag(:span, commit_sha[0..6],
class: 'commit-short-id') class: 'commit-short-id')
......
...@@ -216,7 +216,7 @@ module EventsHelper ...@@ -216,7 +216,7 @@ module EventsHelper
end end
def event_row_class(event) def event_row_class(event)
if event.body? || event.created_project? if event.body?
"event-block" "event-block"
else else
"event-inline" "event-inline"
......
module FormHelper
def form_errors(model)
return unless model.errors.any?
pluralized = 'error'.pluralize(model.errors.count)
headline = "The form contains the following #{pluralized}:"
content_tag(:div, class: 'alert alert-danger', id: 'error_explanation') do
content_tag(:h4, headline) <<
content_tag(:ul) do
model.errors.full_messages.
map { |msg| content_tag(:li, msg) }.
join.
html_safe
end
end
end
end
...@@ -116,29 +116,6 @@ module GitlabMarkdownHelper ...@@ -116,29 +116,6 @@ module GitlabMarkdownHelper
end end
end end
MARKDOWN_TIPS = [
"End a line with two or more spaces for a line-break, or soft-return",
"Inline code can be denoted by `surrounding it with backticks`",
"Blocks of code can be denoted by three backticks ``` or four leading spaces",
"Emoji can be added by :emoji_name:, for example :thumbsup:",
"Notify other participants using @user_name",
"Notify a specific group using @group_name",
"Notify the entire team using @all",
"Reference an issue using a hash, for example issue #123",
"Reference a merge request using an exclamation point, for example MR !123",
"Italicize words or phrases using *asterisks* or _underscores_",
"Bold words or phrases using **double asterisks** or __double underscores__",
"Strikethrough words or phrases using ~~two tildes~~",
"Make a bulleted list using + pluses, - minuses, or * asterisks",
"Denote blockquotes using > at the beginning of a line",
"Make a horizontal line using three or more hyphens ---, asterisks ***, or underscores ___"
].freeze
# Returns a random markdown tip for use as a textarea placeholder
def random_markdown_tip
MARKDOWN_TIPS.sample
end
private private
# Return +text+, truncated to +max_chars+ characters, excluding any HTML # Return +text+, truncated to +max_chars+ characters, excluding any HTML
......
...@@ -52,6 +52,7 @@ module IssuesHelper ...@@ -52,6 +52,7 @@ module IssuesHelper
def milestone_options(object) def milestone_options(object)
milestones = object.project.milestones.active.reorder(due_date: :asc, title: :asc).to_a milestones = object.project.milestones.active.reorder(due_date: :asc, title: :asc).to_a
milestones.unshift(object.milestone) if object.milestone.present? && object.milestone.closed?
milestones.unshift(Milestone::None) milestones.unshift(Milestone::None)
options_from_collection_for_select(milestones, 'id', 'title', object.milestone_id) options_from_collection_for_select(milestones, 'id', 'title', object.milestone_id)
...@@ -115,17 +116,32 @@ module IssuesHelper ...@@ -115,17 +116,32 @@ module IssuesHelper
icon('eye-slash') if issue.confidential? icon('eye-slash') if issue.confidential?
end end
def emoji_icon(name, unicode = nil, aliases = []) def emoji_icon(name, unicode = nil, aliases = [], sprite: true)
unicode ||= Emoji.emoji_filename(name) rescue "" unicode ||= Emoji.emoji_filename(name) rescue ""
content_tag :div, "", data = {
class: "icon emoji-icon emoji-#{unicode}", aliases: aliases.join(" "),
title: name, emoji: name,
data: { unicode_name: unicode
aliases: aliases.join(' '), }
emoji: name,
unicode_name: unicode if sprite
} # Emoji icons for the emoji menu, these use a spritesheet.
content_tag :div, "",
class: "icon emoji-icon emoji-#{unicode}",
title: name,
data: data
else
# Emoji icons displayed separately, used for the awards already given
# to an issue or merge request.
content_tag :img, "",
class: "icon emoji",
title: name,
height: "20px",
width: "20px",
src: url_to_image("#{unicode}.png"),
data: data
end
end end
def emoji_author_list(notes, current_user) def emoji_author_list(notes, current_user)
......
...@@ -3,8 +3,16 @@ module NamespacesHelper ...@@ -3,8 +3,16 @@ module NamespacesHelper
groups = current_user.owned_groups + current_user.masters_groups groups = current_user.owned_groups + current_user.masters_groups
users = [current_user.namespace] users = [current_user.namespace]
group_opts = ["Groups", groups.sort_by(&:human_name).map {|g| [display_path ? g.path : g.human_name, g.id]} ] data_attr_group = { 'data-options-parent' => 'groups' }
users_opts = [ "Users", users.sort_by(&:human_name).map {|u| [display_path ? u.path : u.human_name, u.id]} ] data_attr_users = { 'data-options-parent' => 'users' }
group_opts = [
"Groups", groups.sort_by(&:human_name).map { |g| [display_path ? g.path : g.human_name, g.id, data_attr_group] }
]
users_opts = [
"Users", users.sort_by(&:human_name).map { |u| [display_path ? u.path : u.human_name, u.id, data_attr_users] }
]
options = [] options = []
options << group_opts options << group_opts
......
...@@ -69,10 +69,7 @@ module NotesHelper ...@@ -69,10 +69,7 @@ module NotesHelper
line_type: line_type line_type: line_type
} }
button_tag class: 'btn btn-nr reply-btn js-discussion-reply-button', button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button',
data: data, title: 'Add a reply' do data: data, title: 'Add a reply'
link_text = icon('comment')
link_text << ' Reply'
end
end end
end end
...@@ -135,6 +135,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -135,6 +135,7 @@ class MergeRequest < ActiveRecord::Base
scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) } scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) }
scope :by_milestone, ->(milestone) { where(milestone_id: milestone) } scope :by_milestone, ->(milestone) { where(milestone_id: milestone) }
scope :of_projects, ->(ids) { where(target_project_id: ids) } scope :of_projects, ->(ids) { where(target_project_id: ids) }
scope :from_project, ->(project) { where(source_project_id: project.id) }
scope :merged, -> { with_state(:merged) } scope :merged, -> { with_state(:merged) }
scope :closed_and_merged, -> { with_states(:closed, :merged) } scope :closed_and_merged, -> { with_states(:closed, :merged) }
......
...@@ -931,16 +931,6 @@ class Project < ActiveRecord::Base ...@@ -931,16 +931,6 @@ class Project < ActiveRecord::Base
self.builds_enabled = true self.builds_enabled = true
end end
def unlink_fork
if forked?
forked_from_project.lfs_objects.find_each do |lfs_object|
lfs_object.projects << self
end
forked_project_link.destroy
end
end
def any_runners?(&block) def any_runners?(&block)
if runners.active.any?(&block) if runners.active.any?(&block)
return true return true
......
...@@ -50,12 +50,15 @@ class BuildsEmailService < Service ...@@ -50,12 +50,15 @@ class BuildsEmailService < Service
def execute(push_data) def execute(push_data)
return unless supported_events.include?(push_data[:object_kind]) return unless supported_events.include?(push_data[:object_kind])
return unless should_build_be_notified?(push_data)
if should_build_be_notified?(push_data) recipients = all_recipients(push_data)
if recipients.any?
BuildEmailWorker.perform_async( BuildEmailWorker.perform_async(
push_data[:build_id], push_data[:build_id],
all_recipients(push_data), recipients,
push_data, push_data
) )
end end
end end
...@@ -84,7 +87,7 @@ class BuildsEmailService < Service ...@@ -84,7 +87,7 @@ class BuildsEmailService < Service
end end
def all_recipients(data) def all_recipients(data)
all_recipients = recipients.split(',') all_recipients = recipients.split(',').compact.reject(&:blank?)
if add_pusher? && data[:user][:email] if add_pusher? && data[:user][:email]
all_recipients << "#{data[:user][:email]}" all_recipients << "#{data[:user][:email]}"
......
...@@ -331,6 +331,8 @@ class Repository ...@@ -331,6 +331,8 @@ class Repository
# Runs code after a repository has been created. # Runs code after a repository has been created.
def after_create def after_create
expire_exists_cache expire_exists_cache
expire_root_ref_cache
expire_emptiness_caches
end end
# Runs code just before a repository is deleted. # Runs code just before a repository is deleted.
...@@ -364,6 +366,11 @@ class Repository ...@@ -364,6 +366,11 @@ class Repository
expire_tag_count_cache expire_tag_count_cache
end end
def before_import
expire_emptiness_caches
expire_exists_cache
end
# Runs code after a repository has been forked/imported. # Runs code after a repository has been forked/imported.
def after_import def after_import
expire_emptiness_caches expire_emptiness_caches
...@@ -889,9 +896,9 @@ class Repository ...@@ -889,9 +896,9 @@ class Repository
end end
def main_language def main_language
unless empty? return if empty? || rugged.head_unborn?
Linguist::Repository.new(rugged, rugged.head.target_id).language
end Linguist::Repository.new(rugged, rugged.head.target_id).language
end end
def avatar def avatar
......
...@@ -43,23 +43,27 @@ class GitPushService < BaseService ...@@ -43,23 +43,27 @@ class GitPushService < BaseService
@push_commits = @project.repository.commits_between(params[:oldrev], params[:newrev]) @push_commits = @project.repository.commits_between(params[:oldrev], params[:newrev])
process_commit_messages process_commit_messages
end end
# Checks if the main language has changed in the project and if so
# it updates it accordingly
update_main_language
# Update merge requests that may be affected by this push. A new branch # Update merge requests that may be affected by this push. A new branch
# could cause the last commit of a merge request to change. # could cause the last commit of a merge request to change.
update_merge_requests update_merge_requests
# Checks if the main language has changed in the project and if so
# it updates it accordingly
update_main_language
perform_housekeeping perform_housekeeping
end end
def update_main_language def update_main_language
current_language = @project.repository.main_language # Performance can be bad so for now only check main_language once
# See https://gitlab.com/gitlab-org/gitlab-ce/issues/14937
return if @project.main_language.present?
unless current_language == @project.main_language return unless is_default_branch?
return @project.update_attributes(main_language: current_language) return unless push_to_new_branch? || push_to_existing_branch?
end
current_language = @project.repository.main_language
@project.update_attributes(main_language: current_language)
true true
end end
......
...@@ -3,7 +3,7 @@ module Milestones ...@@ -3,7 +3,7 @@ module Milestones
def execute def execute
milestone = project.milestones.new(params) milestone = project.milestones.new(params)
if milestone.save if milestone.save!
event_service.open_milestone(milestone, current_user) event_service.open_milestone(milestone, current_user)
end end
......
module Notes
class DeleteService < BaseService
def execute(note)
note.destroy
note.reset_events_cache
end
end
end
...@@ -46,6 +46,8 @@ module Projects ...@@ -46,6 +46,8 @@ module Projects
def import_data def import_data
return unless has_importer? return unless has_importer?
project.repository.before_import
unless importer.execute unless importer.execute
raise Error, 'The remote data could not be imported.' raise Error, 'The remote data could not be imported.'
end end
......
module Projects
class UnlinkForkService < BaseService
def execute
return unless @project.forked?
@project.forked_from_project.lfs_objects.find_each do |lfs_object|
lfs_object.projects << @project
end
merge_requests = @project.forked_from_project.merge_requests.opened.from_project(@project)
merge_requests.each do |mr|
MergeRequests::CloseService.new(@project, @current_user).execute(mr)
end
@project.forked_project_link.destroy
end
end
end
...@@ -3,11 +3,9 @@ ...@@ -3,11 +3,9 @@
%p Please use this form to report users who create spam issues, comments or behave inappropriately. %p Please use this form to report users who create spam issues, comments or behave inappropriately.
%hr %hr
= form_for @abuse_report, html: { class: 'form-horizontal js-quick-submit js-requires-input'} do |f| = form_for @abuse_report, html: { class: 'form-horizontal js-quick-submit js-requires-input'} do |f|
= form_errors(@abuse_report)
= f.hidden_field :user_id = f.hidden_field :user_id
- if @abuse_report.errors.any?
.alert.alert-danger
- @abuse_report.errors.full_messages.each do |msg|
%p= msg
.form-group .form-group
= f.label :user_id, class: 'control-label' = f.label :user_id, class: 'control-label'
.col-sm-10 .col-sm-10
......
= form_for @appearance, url: admin_appearances_path, html: { class: 'form-horizontal'} do |f| = form_for @appearance, url: admin_appearances_path, html: { class: 'form-horizontal'} do |f|
- if @appearance.errors.any? = form_errors(@appearance)
.alert.alert-danger
- @appearance.errors.full_messages.each do |msg|
%p= msg
%fieldset.sign-in %fieldset.sign-in
%legend %legend
......
= form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f| = form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f|
- if @application_setting.errors.any? = form_errors(@application_setting)
#error_explanation
.alert.alert-danger
- @application_setting.errors.full_messages.each do |msg|
%p= msg
%fieldset %fieldset
%legend Visibility and Access Controls %legend Visibility and Access Controls
......
= form_for [:admin, @application], url: @url, html: {class: 'form-horizontal', role: 'form'} do |f| = form_for [:admin, @application], url: @url, html: {class: 'form-horizontal', role: 'form'} do |f|
- if application.errors.any? = form_errors(application)
.alert.alert-danger
%button{ type: "button", class: "close", "data-dismiss" => "alert"} &times;
- application.errors.full_messages.each do |msg|
%p= msg
= content_tag :div, class: 'form-group' do = content_tag :div, class: 'form-group' do
= f.label :name, class: 'col-sm-2 control-label' = f.label :name, class: 'col-sm-2 control-label'
.col-sm-10 .col-sm-10
......
...@@ -4,10 +4,8 @@ ...@@ -4,10 +4,8 @@
= render_broadcast_message(@broadcast_message.message.presence || "Your message here") = render_broadcast_message(@broadcast_message.message.presence || "Your message here")
= form_for [:admin, @broadcast_message], html: { class: 'broadcast-message-form form-horizontal js-quick-submit js-requires-input'} do |f| = form_for [:admin, @broadcast_message], html: { class: 'broadcast-message-form form-horizontal js-quick-submit js-requires-input'} do |f|
-if @broadcast_message.errors.any? = form_errors(@broadcast_message)
.alert.alert-danger
- @broadcast_message.errors.full_messages.each do |msg|
%p= msg
.form-group .form-group
= f.label :message, class: 'control-label' = f.label :message, class: 'control-label'
.col-sm-10 .col-sm-10
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
%td %td
- if project - if project
= link_to project.name_with_namespace, admin_namespace_project_path(project.namespace, project), class: "monospace" = link_to project.name_with_namespace, admin_namespace_project_path(project.namespace, project)
%td %td
= link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "monospace" = link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "monospace"
......
.admin-dashboard .admin-dashboard.prepend-top-default
.row .row
.col-md-4 .col-md-4
%h4 Statistics %h4 Statistics
......
- page_title "Deploy Keys" - page_title "Deploy Keys"
.panel.panel-default .panel.panel-default.prepend-top-default
.panel-heading .panel-heading
Public deploy keys (#{@deploy_keys.count}) Public deploy keys (#{@deploy_keys.count})
.controls .controls
......
...@@ -4,11 +4,7 @@ ...@@ -4,11 +4,7 @@
%div %div
= form_for [:admin, @deploy_key], html: { class: 'deploy-key-form form-horizontal' } do |f| = form_for [:admin, @deploy_key], html: { class: 'deploy-key-form form-horizontal' } do |f|
-if @deploy_key.errors.any? = form_errors(@deploy_key)
.alert.alert-danger
%ul
- @deploy_key.errors.full_messages.each do |msg|
%li= msg
.form-group .form-group
= f.label :title, class: "control-label" = f.label :title, class: "control-label"
......
= form_for [:admin, @group], html: { class: "form-horizontal" } do |f| = form_for [:admin, @group], html: { class: "form-horizontal" } do |f|
- if @group.errors.any? = form_errors(@group)
.alert.alert-danger
%span= @group.errors.full_messages.first
= render 'shared/group_form', f: f = render 'shared/group_form', f: f
.form-group.group-description-holder .form-group.group-description-holder
......
- css_class = '' unless local_assigns[:css_class]
- css_class += ' no-description' if group.description.blank?
%li.group-row{ class: css_class }
.controls.hidden-xs
= link_to 'Edit', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: 'btn btn-grouped btn-sm'
= link_to 'Destroy', [:admin, group], data: {confirm: "REMOVE #{group.name}? Are you sure?"}, method: :delete, class: 'btn btn-grouped btn-sm btn-remove'
.stats
%span
= icon('bookmark')
= number_with_delimiter(group.projects.count)
%span
= icon('users')
= number_with_delimiter(group.users.count)
%span.visibility-icon.has-tooltip{data: { container: 'body', placement: 'left' }, title: visibility_icon_description(group)}
= visibility_level_icon(group.visibility_level, fw: false)
= image_tag group_icon(group), class: 'avatar s40 hidden-xs'
.title
= link_to [:admin, group], class: 'group-name' do
= group.name
- if group.description.present?
.description
= markdown(group.description, pipeline: :description)
- page_title "Groups" - page_title "Groups"
%h3.page-title %h3.page-title
Groups (#{number_with_delimiter(@groups.total_count)}) Groups (#{number_with_delimiter(@groups.total_count)})
= link_to 'New Group', new_admin_group_path, class: "btn btn-new pull-right"
%p.light %p.light
Group allows you to keep projects organized. Group allows you to keep projects organized.
Use groups for uniting related projects. Use groups for uniting related projects.
%hr .top-area
= form_tag admin_groups_path, method: :get, class: 'form-inline' do .nav-search
= hidden_field_tag :sort, @sort = form_tag admin_groups_path, method: :get, class: 'form-inline' do
.form-group = hidden_field_tag :sort, @sort
= text_field_tag :name, params[:name], class: "form-control" = text_field_tag :name, params[:name], class: "form-control"
= button_tag "Search", class: "btn submit btn-primary" = button_tag "Search", class: "btn submit btn-primary"
.pull-right .nav-controls
.dropdown.inline .dropdown.inline
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
%span.light %span.light
...@@ -33,34 +32,10 @@ ...@@ -33,34 +32,10 @@
= sort_title_recently_updated = sort_title_recently_updated
= link_to admin_groups_path(sort: sort_value_oldest_updated) do = link_to admin_groups_path(sort: sort_value_oldest_updated) do
= sort_title_oldest_updated = sort_title_oldest_updated
= link_to 'New Group', new_admin_group_path, class: "btn btn-new"
%hr %ul.content-list
%ul.bordered-list
- @groups.each do |group| - @groups.each do |group|
%li = render 'group', group: group
.clearfix
.pull-right.prepend-top-10
= link_to 'Edit', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn btn-sm"
= link_to 'Destroy', [:admin, group], data: {confirm: "REMOVE #{group.name}? Are you sure?"}, method: :delete, class: "btn btn-sm btn-remove"
%h4
= link_to [:admin, group] do
%span{ class: visibility_level_color(group.visibility_level) }
= visibility_level_icon(group.visibility_level)
%i.fa.fa-folder
= group.name
&rarr;
%span.monospace
%strong #{group.path}/
.clearfix
%p
= truncate group.description, length: 150
.clearfix
%p.light
#{pluralize(group.members.size, 'member')}, #{pluralize(group.projects.count, 'project')}
= paginate @groups, theme: "gitlab" = paginate @groups, theme: "gitlab"
...@@ -10,10 +10,8 @@ ...@@ -10,10 +10,8 @@
= form_for @hook, as: :hook, url: admin_hooks_path, html: { class: 'form-horizontal' } do |f| = form_for @hook, as: :hook, url: admin_hooks_path, html: { class: 'form-horizontal' } do |f|
-if @hook.errors.any? = form_errors(@hook)
.alert.alert-danger
- @hook.errors.full_messages.each do |msg|
%p= msg
.form-group .form-group
= f.label :url, "URL:", class: 'control-label' = f.label :url, "URL:", class: 'control-label'
.col-sm-10 .col-sm-10
......
= form_for [:admin, @user, @identity], html: { class: 'form-horizontal fieldset-form' } do |f| = form_for [:admin, @user, @identity], html: { class: 'form-horizontal fieldset-form' } do |f|
- if @identity.errors.any? = form_errors(@identity)
#error_explanation
.alert.alert-danger
- @identity.errors.full_messages.each do |msg|
%p= msg
.form-group .form-group
= f.label :provider, class: 'control-label' = f.label :provider, class: 'control-label'
......
= form_for [:admin, @label], html: { class: 'form-horizontal label-form js-requires-input' } do |f| = form_for [:admin, @label], html: { class: 'form-horizontal label-form js-requires-input' } do |f|
-if @label.errors.any? = form_errors(@label)
.row
.col-sm-offset-2.col-sm-10
.alert.alert-danger
- @label.errors.full_messages.each do |msg|
%span= msg
%br
.form-group .form-group
= f.label :title, class: 'control-label' = f.label :title, class: 'control-label'
......
- page_title "Labels" - page_title "Labels"
= link_to new_admin_label_path, class: "pull-right btn btn-nr btn-new" do
New label %div
%h3.page-title = link_to new_admin_label_path, class: "pull-right btn btn-nr btn-new" do
Labels New label
%h3.page-title
Labels
%hr %hr
.labels .labels
...@@ -13,4 +15,4 @@ ...@@ -13,4 +15,4 @@
- else - else
.light-well .light-well
.nothing-here-block There are no labels yet .nothing-here-block There are no labels yet
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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