Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into #15643
# Conflicts: # app/assets/stylesheets/pages/issuable.scss
This commit is contained in:
commit
aa2a7dad59
103
.rubocop.yml
103
.rubocop.yml
|
|
@ -21,6 +21,7 @@ AllCops:
|
|||
- 'lib/email_validator.rb'
|
||||
- 'lib/gitlab/upgrader.rb'
|
||||
- 'lib/gitlab/seeder.rb'
|
||||
- 'generator_templates/**/*'
|
||||
|
||||
|
||||
##################### Style ##################################
|
||||
|
|
@ -151,7 +152,7 @@ Style/ConstantName:
|
|||
|
||||
# Use def with parentheses when there are arguments.
|
||||
Style/DefWithParentheses:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Checks for use of deprecated Hash methods.
|
||||
Style/DeprecatedHashMethods:
|
||||
|
|
@ -276,7 +277,7 @@ Style/IdenticalConditionalBranches:
|
|||
Enabled: false
|
||||
|
||||
# Checks the indentation of the first line of the right-hand-side of a
|
||||
# multi-line assignment.
|
||||
# multi-line assignment.
|
||||
Style/IndentAssignment:
|
||||
Enabled: false
|
||||
|
||||
|
|
@ -298,7 +299,7 @@ Style/IndentHash:
|
|||
|
||||
# Use Kernel#loop for infinite loops.
|
||||
Style/InfiniteLoop:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Use the new lambda literal syntax for single-line blocks.
|
||||
Style/Lambda:
|
||||
|
|
@ -332,6 +333,12 @@ Style/MethodName:
|
|||
Style/ModuleFunction:
|
||||
Enabled: false
|
||||
|
||||
# Checks that the closing brace in an array literal is either on the same line
|
||||
# as the last array element, or a new line.
|
||||
Style/MultilineArrayBraceLayout:
|
||||
Enabled: false
|
||||
EnforcedStyle: symmetrical
|
||||
|
||||
# Avoid multi-line chains of blocks.
|
||||
Style/MultilineBlockChain:
|
||||
Enabled: false
|
||||
|
|
@ -340,10 +347,22 @@ Style/MultilineBlockChain:
|
|||
Style/MultilineBlockLayout:
|
||||
Enabled: true
|
||||
|
||||
# Checks that the closing brace in a hash literal is either on the same line as
|
||||
# the last hash element, or a new line.
|
||||
Style/MultilineHashBraceLayout:
|
||||
Enabled: false
|
||||
EnforcedStyle: symmetrical
|
||||
|
||||
# Do not use then for multi-line if/unless.
|
||||
Style/MultilineIfThen:
|
||||
Enabled: false
|
||||
|
||||
# Checks that the closing brace in a method call is either on the same line as
|
||||
# the last method argument, or a new line.
|
||||
Style/MultilineMethodCallBraceLayout:
|
||||
Enabled: false
|
||||
EnforcedStyle: symmetrical
|
||||
|
||||
# Checks indentation of method calls with the dot operator that span more than
|
||||
# one line.
|
||||
Style/MultilineMethodCallIndentation:
|
||||
|
|
@ -524,14 +543,13 @@ Style/SpaceAfterSemicolon:
|
|||
Style/SpaceAroundEqualsInParameterDefault:
|
||||
Enabled: false
|
||||
|
||||
# TODO: Enable SpaceAroundKeyword Cop.
|
||||
# Use a space around keywords if appropriate.
|
||||
Style/SpaceAroundKeyword:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Use a single space around operators.
|
||||
Style/SpaceAroundOperators:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Checks that the left block brace has or doesn't have space before it.
|
||||
Style/SpaceBeforeBlockBraces:
|
||||
|
|
@ -754,23 +772,23 @@ Lint/BlockAlignment:
|
|||
# Default values in optional keyword arguments and optional ordinal arguments
|
||||
# should not refer back to the name of the argument.
|
||||
Lint/CircularArgumentReference:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Checks for condition placed in a confusing position relative to the keyword.
|
||||
Lint/ConditionPosition:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Check for debugger calls.
|
||||
Lint/Debugger:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Align ends corresponding to defs correctly.
|
||||
Lint/DefEndAlignment:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Check for deprecated class method calls.
|
||||
Lint/DeprecatedClassMethods:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Check for duplicate method definitions.
|
||||
Lint/DuplicateMethods:
|
||||
|
|
@ -782,15 +800,15 @@ Lint/DuplicatedKey:
|
|||
|
||||
# Check for immutable argument given to each_with_object.
|
||||
Lint/EachWithObjectArgument:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Check for odd code arrangement in an else block.
|
||||
Lint/ElseLayout:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Checks for empty ensure block.
|
||||
Lint/EmptyEnsure:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Checks for empty string interpolation.
|
||||
Lint/EmptyInterpolation:
|
||||
|
|
@ -798,37 +816,36 @@ Lint/EmptyInterpolation:
|
|||
|
||||
# Align ends correctly.
|
||||
Lint/EndAlignment:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# END blocks should not be placed inside method definitions.
|
||||
Lint/EndInMethod:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Do not use return in an ensure block.
|
||||
Lint/EnsureReturn:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# The use of eval represents a serious security risk.
|
||||
Lint/Eval:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Catches floating-point literals too large or small for Ruby to represent.
|
||||
Lint/FloatOutOfRange:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# The number of parameters to format/sprint must match the fields.
|
||||
Lint/FormatParameterMismatch:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Don't suppress exception.
|
||||
Lint/HandleExceptions:
|
||||
Enabled: false
|
||||
|
||||
# TODO: Enable ImplicitStringConcatenation Cop.
|
||||
# Checks for adjacent string literals on the same line, which could better be
|
||||
# represented as a single string literal.
|
||||
Lint/ImplicitStringConcatenation:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# TODO: Enable IneffectiveAccessModifier Cop.
|
||||
# Checks for attempts to use `private` or `protected` to set the visibility
|
||||
|
|
@ -839,7 +856,7 @@ Lint/IneffectiveAccessModifier:
|
|||
# Checks for invalid character literals with a non-escaped whitespace
|
||||
# character.
|
||||
Lint/InvalidCharacterLiteral:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Checks of literals used in conditions.
|
||||
Lint/LiteralInCondition:
|
||||
|
|
@ -847,7 +864,7 @@ Lint/LiteralInCondition:
|
|||
|
||||
# Checks for literals used in interpolation.
|
||||
Lint/LiteralInInterpolation:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Use Kernel#loop with break rather than begin/end/until or begin/end/while
|
||||
# for post-loop tests.
|
||||
|
|
@ -856,11 +873,11 @@ Lint/Loop:
|
|||
|
||||
# Do not use nested method definitions.
|
||||
Lint/NestedMethodDefinition:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Do not omit the accumulator when calling `next` in a `reduce`/`inject` block.
|
||||
Lint/NextWithoutAccumulator:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Checks for method calls with a space before the opening parenthesis.
|
||||
Lint/ParenthesesAsGroupedExpression:
|
||||
|
|
@ -869,11 +886,11 @@ Lint/ParenthesesAsGroupedExpression:
|
|||
# Checks for `rand(1)` calls. Such calls always return `0` and most likely
|
||||
# a mistake.
|
||||
Lint/RandOne:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Use parentheses in the method call to avoid confusion about precedence.
|
||||
Lint/RequireParentheses:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Avoid rescuing the Exception class.
|
||||
Lint/RescueException:
|
||||
|
|
@ -908,7 +925,7 @@ Lint/UnusedMethodArgument:
|
|||
|
||||
# Unreachable code.
|
||||
Lint/UnreachableCode:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Checks for useless access modifiers.
|
||||
Lint/UselessAccessModifier:
|
||||
|
|
@ -920,19 +937,19 @@ Lint/UselessAssignment:
|
|||
|
||||
# Checks for comparison of something with itself.
|
||||
Lint/UselessComparison:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Checks for useless `else` in `begin..end` without `rescue`.
|
||||
Lint/UselessElseWithoutRescue:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Checks for useless setter call to a local variable.
|
||||
Lint/UselessSetterCall:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Possible use of operator/literal/variable in void context.
|
||||
Lint/Void:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
|
||||
##################### Performance ############################
|
||||
|
|
@ -941,11 +958,10 @@ Lint/Void:
|
|||
Performance/Casecmp:
|
||||
Enabled: true
|
||||
|
||||
# TODO: Enable DoubleStartEndWith Cop.
|
||||
# Use `str.{start,end}_with?(x, ..., y, ...)` instead of
|
||||
# `str.{start,end}_with?(x, ...) || str.{start,end}_with?(y, ...)`.
|
||||
Performance/DoubleStartEndWith:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# TODO: Enable EndWith Cop.
|
||||
# Use `end_with?` instead of a regex match anchored to the end of a string.
|
||||
|
|
@ -956,10 +972,9 @@ Performance/EndWith:
|
|||
Performance/LstripRstrip:
|
||||
Enabled: true
|
||||
|
||||
# TODO: Enable RangeInclude Cop.
|
||||
# Use `Range#cover?` instead of `Range#include?`.
|
||||
Performance/RangeInclude:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# TODO: Enable RedundantBlockCall Cop.
|
||||
# Use `yield` instead of `block.call`.
|
||||
|
|
@ -979,16 +994,14 @@ Performance/RedundantMerge:
|
|||
MaxKeyValuePairs: 2
|
||||
Enabled: false
|
||||
|
||||
# TODO: Enable RedundantSortBy Cop.
|
||||
# Use `sort` instead of `sort_by { |x| x }`.
|
||||
Performance/RedundantSortBy:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# TODO: Enable StartWith Cop.
|
||||
# Use `start_with?` instead of a regex match anchored to the beginning of a
|
||||
# string.
|
||||
Performance/StartWith:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Use `tr` instead of `gsub` when you are replacing the same number of
|
||||
# characters. Use `delete` instead of `gsub` when you are deleting
|
||||
|
|
@ -1024,11 +1037,11 @@ Rails/Delegate:
|
|||
|
||||
# Prefer `find_by` over `where.first`.
|
||||
Rails/FindBy:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Prefer `all.find_each` over `all.find`.
|
||||
Rails/FindEach:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Prefer has_many :through to has_and_belongs_to_many.
|
||||
Rails/HasAndBelongsToMany:
|
||||
|
|
@ -1040,7 +1053,7 @@ Rails/Output:
|
|||
|
||||
# Checks for incorrect grammar when using methods like `3.day.ago`.
|
||||
Rails/PluralizationGrammar:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Checks for `read_attribute(:attr)` and `write_attribute(:attr, val)`.
|
||||
Rails/ReadWriteAttribute:
|
||||
|
|
@ -1048,7 +1061,7 @@ Rails/ReadWriteAttribute:
|
|||
|
||||
# Checks the arguments of ActiveRecord scopes.
|
||||
Rails/ScopeArgs:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Checks the correct usage of time zone aware methods.
|
||||
# http://danilenko.org/2012/7/6/rails_timezones
|
||||
|
|
|
|||
83
CHANGELOG
83
CHANGELOG
|
|
@ -1,57 +1,115 @@
|
|||
Please view this file on the master branch, on stable branches it's out of date.
|
||||
|
||||
v 8.8.0 (unreleased)
|
||||
v 8.8.2 (unreleased)
|
||||
- Fix Error 500 when accessing application settings due to nil disabled OAuth sign-in sources
|
||||
- Fix Error 500 in CI charts by gracefully handling commits with no durations
|
||||
|
||||
v 8.8.1
|
||||
- Add documentation for the "Health Check" feature
|
||||
- Allow anonymous users to access a public project's pipelines
|
||||
- Fix MySQL compatibility in zero downtime migrations helpers
|
||||
- Fix the CI login to Container Registry (the gitlab-ci-token user)
|
||||
|
||||
v 8.8.0
|
||||
- Implement GFM references for milestones (Alejandro Rodríguez)
|
||||
- Snippets tab under user profile. !4001 (Long Nguyen)
|
||||
- Fix error when using link to uploads in global snippets
|
||||
- Fix Error 500 when attempting to retrieve project license when HEAD points to non-existent ref
|
||||
- Assign labels and milestone to target project when moving issue. !3934 (Long Nguyen)
|
||||
- Use a case-insensitive comparison in sanitizing URI schemes
|
||||
- Toggle sign-up confirmation emails in application settings
|
||||
- Make it possible to prevent tagged runner from picking untagged jobs
|
||||
- Added `InlineDiffFilter` to the markdown parser. (Adam Butler)
|
||||
- Added inline diff styling for `change_title` system notes. (Adam Butler)
|
||||
- Project#open_branches has been cleaned up and no longer loads entire records into memory.
|
||||
- Escape HTML in commit titles in system note messages
|
||||
- Fix scope used when accessing container registry
|
||||
- Fix creation of Ci::Commit object which can lead to pending, failed in some scenarios
|
||||
- Improve multiple branch push performance by memoizing permission checking
|
||||
- Log to application.log when an admin starts and stops impersonating a user
|
||||
- Changing the confidentiality of an issue now creates a new system note (Alex Moore-Niemi)
|
||||
- Updated gitlab_git to 10.1.0
|
||||
- GitAccess#protected_tag? no longer loads all tags just to check if a single one exists
|
||||
- Reduce delay in destroying a project from 1-minute to immediately
|
||||
- Make build status canceled if any of the jobs was canceled and none failed
|
||||
- Upgrade Sidekiq to 4.1.2
|
||||
- Added /health_check endpoint for checking service status
|
||||
- Make 'upcoming' filter for milestones work better across projects
|
||||
- Sanitize repo paths in new project error message
|
||||
- Bump mail_room to 0.7.0 to fix stuck IDLE connections
|
||||
- Remove future dates from contribution calendar graph.
|
||||
- Support e-mail notifications for comments on project snippets
|
||||
- Fix API leak of notes of unauthorized issues, snippets and merge requests
|
||||
- Use ActionDispatch Remote IP for Akismet checking
|
||||
- Fix error when visiting commit builds page before build was updated
|
||||
- Add 'l' shortcut to open Label dropdown on issuables and 'i' to create new issue on a project
|
||||
- Update SVG sanitizer to conform to SVG 1.1
|
||||
- Speed up push emails with multiple recipients by only generating the email once
|
||||
- Updated search UI
|
||||
- Added authentication service for Container Registry
|
||||
- Display informative message when new milestone is created
|
||||
- Sanitize milestones and labels titles
|
||||
- Support multi-line tag messages. !3833 (Calin Seciu)
|
||||
- Force users to reset their password after an admin changes it
|
||||
- Allow "NEWS" and "CHANGES" as alternative names for CHANGELOG. !3768 (Connor Shea)
|
||||
- Added button to toggle whitespaces changes on diff view
|
||||
- Backport GitHub Enterprise import support from EE
|
||||
- Create tags using Rugged for performance reasons. !3745
|
||||
- Allow guests to set notification level in projects
|
||||
- API: Expose Issue#user_notes_count. !3126 (Anton Popov)
|
||||
- Don't show forks button when user can't view forks
|
||||
- Fix atom feed links and rendering
|
||||
- Files over 5MB can only be viewed in their raw form, files over 1MB without highlighting !3718
|
||||
- Add support for supressing text diffs using .gitattributes on the default branch (Matt Oakes)
|
||||
- Add eager load paths to help prevent dependency load issues in Sidekiq workers. !3724
|
||||
- Added multiple colors for labels in dropdowns when dups happen.
|
||||
- Show commits in the same order as `git log`
|
||||
- Improve description for the Two-factor Authentication sign-in screen. (Connor Shea)
|
||||
- API support for the 'since' and 'until' operators on commit requests (Paco Guzman)
|
||||
- Fix Gravatar hint in user profile when Gravatar is disabled. !3988 (Artem Sidorenko)
|
||||
- Expire repository exists? and has_visible_content? caches after a push if necessary
|
||||
- Fix unintentional filtering bug in issues sorted by milestone due (Takuya Noguchi)
|
||||
- Fix unintentional filtering bug in Issue/MR sorted by milestone due (Takuya Noguchi)
|
||||
- Fix adding a todo for private group members (Ahmad Sherif)
|
||||
- Bump ace-rails-ap gem version from 2.0.1 to 4.0.2 which upgrades Ace Editor from 1.1.2 to 1.2.3
|
||||
- Total method execution timings are no longer tracked
|
||||
- Allow Admins to remove the Login with buttons for OAuth services and still be able to import !4034. (Andrei Gliga)
|
||||
- Add API endpoints for un/subscribing from/to a label. !4051 (Ahmad Sherif)
|
||||
- Hide left sidebar on phone screens to give more space for content
|
||||
- Redesign navigation for profile and group pages
|
||||
- Add counter metrics for rails cache
|
||||
- Import pull requests from GitHub where the source or target branches were removed
|
||||
- All Grape API helpers are now instrumented
|
||||
- Improve Issue formatting for the Slack Service (Jeroen van Baarsen)
|
||||
- Fixed advice on invalid permissions on upload path !2948 (Ludovic Perrine)
|
||||
- Allows MR authors to have the source branch removed when merging the MR. !2801 (Jeroen Jacobs)
|
||||
- When creating a .gitignore file a dropdown with templates will be provided
|
||||
|
||||
v 8.7.6
|
||||
- Fix links on wiki pages for relative url setups. !4131 (Artem Sidorenko)
|
||||
- Fix import from GitLab.com to a private instance failure. !4181
|
||||
- Fix external imports not finding the import data. !4106
|
||||
|
||||
v 8.7.5
|
||||
- Fix relative links in wiki pages. !4050
|
||||
- Fix always showing build notification message when switching between merge requests !4086
|
||||
- Fix an issue when filtering merge requests with more than one label. !3886
|
||||
- Fix short note for the default scope on build page (Takuya Noguchi)
|
||||
|
||||
v 8.7.4
|
||||
- Fix always showing build notification message when switching between merge requests
|
||||
- Links for Redmine issue references are generated correctly again (Benedikt Huss)
|
||||
- Fix an issue when filtering merge requests with more than one label. !3886
|
||||
- Links for Redmine issue references are generated correctly again !4048 (Benedikt Huss)
|
||||
- Fix setting trusted proxies !3970
|
||||
- Fix BitBucket importer bug when throwing exceptions !3941
|
||||
- Use sign out path only if not empty !3989
|
||||
- Running rake gitlab:db:drop_tables now drops tables with cascade !4020
|
||||
- Running rake gitlab:db:drop_tables uses "IF EXISTS" as a precaution !4100
|
||||
- Use a case-insensitive comparison in sanitizing URI schemes
|
||||
|
||||
v 8.7.3
|
||||
- Emails, Gitlab::Email::Message, Gitlab::Diff, and Premailer::Adapter::Nokogiri are now instrumented
|
||||
- Merge request widget displays TeamCity build state and code coverage correctly again.
|
||||
- Fix the line code when importing PR review comments from GitHub. !4010
|
||||
- Wikis are now initialized on legacy projects when checking repositories
|
||||
- Remove animate.css in favor of a smaller subset of animations. !3937 (Connor Shea)
|
||||
|
||||
v 8.7.2
|
||||
- The "New Branch" button is now loaded asynchronously
|
||||
|
|
@ -860,7 +918,7 @@ v 8.1.3
|
|||
- Use issue editor as cross reference comment author when issue is edited with a new mention
|
||||
- Add Facebook authentication
|
||||
|
||||
v 8.1.2
|
||||
v 8.1.1
|
||||
- Fix cloning Wiki repositories via HTTP (Stan Hu)
|
||||
- Add migration to remove satellites directory
|
||||
- Fix specific runners visibility
|
||||
|
|
@ -1485,20 +1543,17 @@ v 7.10.0
|
|||
- Fix stuck Merge Request merging events from old installations (Ben Bodenmiller)
|
||||
- Fix merge request comments on files with multiple commits
|
||||
- Fix Resource Owner Password Authentication Flow
|
||||
|
||||
v 7.9.4
|
||||
- Security: Fix project import URL regex to prevent arbitary local repos from being imported
|
||||
- Fixed issue where only 25 commits would load in file listings
|
||||
- Fix LDAP identities after config update
|
||||
|
||||
v 7.9.3
|
||||
- Contains no changes
|
||||
- Add icons to Add dropdown items.
|
||||
- Allow admin to create public deploy keys that are accessible to any project.
|
||||
- Warn when gitlab-shell version doesn't match requirement.
|
||||
- Skip email confirmation when set by admin or via LDAP.
|
||||
- Only allow users to reference groups, projects, issues, MRs, commits they have access to.
|
||||
|
||||
v 7.9.4
|
||||
- Security: Fix project import URL regex to prevent arbitary local repos from being imported
|
||||
- Fixed issue where only 25 commits would load in file listings
|
||||
- Fix LDAP identities after config update
|
||||
|
||||
v 7.9.3
|
||||
- Contains no changes
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
0.7.1
|
||||
0.7.3
|
||||
|
|
|
|||
12
Gemfile
12
Gemfile
|
|
@ -36,6 +36,7 @@ gem 'omniauth-shibboleth', '~> 1.2.0'
|
|||
gem 'omniauth-twitter', '~> 1.2.0'
|
||||
gem 'omniauth_crowd', '~> 2.2.0'
|
||||
gem 'rack-oauth2', '~> 1.2.1'
|
||||
gem 'jwt'
|
||||
|
||||
# Spam and anti-bot protection
|
||||
gem 'recaptcha', require: 'recaptcha/rails'
|
||||
|
|
@ -224,6 +225,7 @@ gem 'request_store', '~> 1.3.0'
|
|||
gem 'select2-rails', '~> 3.5.9'
|
||||
gem 'virtus', '~> 1.0.1'
|
||||
gem 'net-ssh', '~> 3.0.1'
|
||||
gem 'base32', '~> 0.3.0'
|
||||
|
||||
# Sentry integration
|
||||
gem 'sentry-raven', '~> 0.15'
|
||||
|
|
@ -291,9 +293,9 @@ group :development, :test do
|
|||
gem 'spring-commands-spinach', '~> 1.1.0'
|
||||
gem 'spring-commands-teaspoon', '~> 0.0.2'
|
||||
|
||||
gem 'rubocop', '~> 0.38.0', require: false
|
||||
gem 'rubocop', '~> 0.40.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.11.0', require: false
|
||||
gem 'flog', require: false
|
||||
gem 'flay', require: false
|
||||
|
|
@ -323,8 +325,7 @@ gem "mail_room", "~> 0.7"
|
|||
gem 'email_reply_parser', '~> 0.5.8'
|
||||
|
||||
## CI
|
||||
gem 'activerecord-deprecated_finders', '~> 1.0.3'
|
||||
gem 'activerecord-session_store', '~> 0.1.0'
|
||||
gem 'activerecord-session_store', '~> 1.0.0'
|
||||
gem "nested_form", '~> 0.3.2'
|
||||
|
||||
# OAuth
|
||||
|
|
@ -332,3 +333,6 @@ gem 'oauth2', '~> 1.0.0'
|
|||
|
||||
# Soft deletion
|
||||
gem "paranoia", "~> 2.0"
|
||||
|
||||
# Health check
|
||||
gem 'health_check', '~> 1.5.1'
|
||||
|
|
|
|||
34
Gemfile.lock
34
Gemfile.lock
|
|
@ -33,11 +33,12 @@ GEM
|
|||
activemodel (= 4.2.6)
|
||||
activesupport (= 4.2.6)
|
||||
arel (~> 6.0)
|
||||
activerecord-deprecated_finders (1.0.4)
|
||||
activerecord-session_store (0.1.2)
|
||||
actionpack (>= 4.0.0, < 5)
|
||||
activerecord (>= 4.0.0, < 5)
|
||||
railties (>= 4.0.0, < 5)
|
||||
activerecord-session_store (1.0.0)
|
||||
actionpack (>= 4.0, < 5.1)
|
||||
activerecord (>= 4.0, < 5.1)
|
||||
multi_json (~> 1.11, >= 1.11.2)
|
||||
rack (>= 1.5.2, < 3)
|
||||
railties (>= 4.0, < 5.1)
|
||||
activesupport (4.2.6)
|
||||
i18n (~> 0.7)
|
||||
json (~> 1.7, >= 1.7.7)
|
||||
|
|
@ -71,6 +72,7 @@ GEM
|
|||
ice_nine (~> 0.11.0)
|
||||
thread_safe (~> 0.3, >= 0.3.1)
|
||||
babosa (1.0.2)
|
||||
base32 (0.3.2)
|
||||
bcrypt (3.1.10)
|
||||
benchmark-ips (2.3.0)
|
||||
better_errors (1.0.1)
|
||||
|
|
@ -402,6 +404,8 @@ GEM
|
|||
html2haml (>= 1.0.1)
|
||||
railties (>= 4.0.1)
|
||||
hashie (3.4.3)
|
||||
health_check (1.5.1)
|
||||
rails (>= 2.3.0)
|
||||
highline (1.7.8)
|
||||
hipchat (1.5.2)
|
||||
httparty
|
||||
|
|
@ -547,7 +551,7 @@ GEM
|
|||
orm_adapter (0.5.0)
|
||||
paranoia (2.1.4)
|
||||
activerecord (~> 4.0)
|
||||
parser (2.3.0.6)
|
||||
parser (2.3.1.0)
|
||||
ast (~> 2.2)
|
||||
pg (0.18.4)
|
||||
poltergeist (1.9.0)
|
||||
|
|
@ -682,15 +686,15 @@ GEM
|
|||
rspec-retry (0.4.5)
|
||||
rspec-core
|
||||
rspec-support (3.4.1)
|
||||
rubocop (0.38.0)
|
||||
parser (>= 2.3.0.6, < 3.0)
|
||||
rubocop (0.40.0)
|
||||
parser (>= 2.3.1.0, < 3.0)
|
||||
powerpack (~> 0.1)
|
||||
rainbow (>= 1.99.1, < 3.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (~> 1.0, >= 1.0.1)
|
||||
ruby-fogbugz (0.2.1)
|
||||
crack (~> 0.4)
|
||||
ruby-progressbar (1.7.5)
|
||||
ruby-progressbar (1.8.1)
|
||||
ruby-saml (1.1.2)
|
||||
nokogiri (>= 1.5.10)
|
||||
uuid (~> 2.3)
|
||||
|
|
@ -837,7 +841,7 @@ GEM
|
|||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.2)
|
||||
unicode-display_width (1.0.2)
|
||||
unicode-display_width (1.0.5)
|
||||
unicorn (4.9.0)
|
||||
kgio (~> 2.6)
|
||||
rack
|
||||
|
|
@ -881,8 +885,7 @@ PLATFORMS
|
|||
DEPENDENCIES
|
||||
RedCloth (~> 4.2.9)
|
||||
ace-rails-ap (~> 4.0.2)
|
||||
activerecord-deprecated_finders (~> 1.0.3)
|
||||
activerecord-session_store (~> 0.1.0)
|
||||
activerecord-session_store (~> 1.0.0)
|
||||
acts-as-taggable-on (~> 3.4)
|
||||
addressable (~> 2.3.8)
|
||||
after_commit_queue
|
||||
|
|
@ -893,6 +896,7 @@ DEPENDENCIES
|
|||
attr_encrypted (~> 1.3.4)
|
||||
awesome_print (~> 1.2.0)
|
||||
babosa (~> 1.0.2)
|
||||
base32 (~> 0.3.0)
|
||||
benchmark-ips
|
||||
better_errors (~> 1.0.1)
|
||||
binding_of_caller (~> 0.7.2)
|
||||
|
|
@ -945,6 +949,7 @@ DEPENDENCIES
|
|||
grape (~> 0.13.0)
|
||||
grape-entity (~> 0.4.2)
|
||||
haml-rails (~> 0.9.0)
|
||||
health_check (~> 1.5.1)
|
||||
hipchat (~> 1.5.0)
|
||||
html-pipeline (~> 1.11.0)
|
||||
httparty (~> 0.13.3)
|
||||
|
|
@ -953,6 +958,7 @@ DEPENDENCIES
|
|||
jquery-rails (~> 4.1.0)
|
||||
jquery-turbolinks (~> 2.1.0)
|
||||
jquery-ui-rails (~> 5.0.0)
|
||||
jwt
|
||||
kaminari (~> 0.16.3)
|
||||
letter_opener_web (~> 1.3.0)
|
||||
licensee (~> 8.0.0)
|
||||
|
|
@ -1009,7 +1015,7 @@ DEPENDENCIES
|
|||
rqrcode-rails3 (~> 0.1.7)
|
||||
rspec-rails (~> 3.4.0)
|
||||
rspec-retry
|
||||
rubocop (~> 0.38.0)
|
||||
rubocop (~> 0.40.0)
|
||||
ruby-fogbugz (~> 0.2.1)
|
||||
sanitize (~> 2.0)
|
||||
sass-rails (~> 5.0.0)
|
||||
|
|
@ -1054,4 +1060,4 @@ DEPENDENCIES
|
|||
wikicloth (= 0.8.1)
|
||||
|
||||
BUNDLED WITH
|
||||
1.12.3
|
||||
1.12.4
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 6.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 74 KiB |
|
|
@ -1,14 +1,15 @@
|
|||
@Api =
|
||||
groups_path: "/api/:version/groups.json"
|
||||
group_path: "/api/:version/groups/:id.json"
|
||||
namespaces_path: "/api/:version/namespaces.json"
|
||||
group_projects_path: "/api/:version/groups/:id/projects.json"
|
||||
projects_path: "/api/:version/projects.json"
|
||||
labels_path: "/api/:version/projects/:id/labels"
|
||||
license_path: "/api/:version/licenses/:key"
|
||||
groupsPath: "/api/:version/groups.json"
|
||||
groupPath: "/api/:version/groups/:id.json"
|
||||
namespacesPath: "/api/:version/namespaces.json"
|
||||
groupProjectsPath: "/api/:version/groups/:id/projects.json"
|
||||
projectsPath: "/api/:version/projects.json"
|
||||
labelsPath: "/api/:version/projects/:id/labels"
|
||||
licensePath: "/api/:version/licenses/:key"
|
||||
gitignorePath: "/api/:version/gitignores/:key"
|
||||
|
||||
group: (group_id, callback) ->
|
||||
url = Api.buildUrl(Api.group_path)
|
||||
url = Api.buildUrl(Api.groupPath)
|
||||
url = url.replace(':id', group_id)
|
||||
|
||||
$.ajax(
|
||||
|
|
@ -22,7 +23,7 @@
|
|||
# Return groups list. Filtered by query
|
||||
# Only active groups retrieved
|
||||
groups: (query, skip_ldap, callback) ->
|
||||
url = Api.buildUrl(Api.groups_path)
|
||||
url = Api.buildUrl(Api.groupsPath)
|
||||
|
||||
$.ajax(
|
||||
url: url
|
||||
|
|
@ -36,7 +37,7 @@
|
|||
|
||||
# Return namespaces list. Filtered by query
|
||||
namespaces: (query, callback) ->
|
||||
url = Api.buildUrl(Api.namespaces_path)
|
||||
url = Api.buildUrl(Api.namespacesPath)
|
||||
|
||||
$.ajax(
|
||||
url: url
|
||||
|
|
@ -50,7 +51,7 @@
|
|||
|
||||
# Return projects list. Filtered by query
|
||||
projects: (query, order, callback) ->
|
||||
url = Api.buildUrl(Api.projects_path)
|
||||
url = Api.buildUrl(Api.projectsPath)
|
||||
|
||||
$.ajax(
|
||||
url: url
|
||||
|
|
@ -64,7 +65,7 @@
|
|||
callback(projects)
|
||||
|
||||
newLabel: (project_id, data, callback) ->
|
||||
url = Api.buildUrl(Api.labels_path)
|
||||
url = Api.buildUrl(Api.labelsPath)
|
||||
url = url.replace(':id', project_id)
|
||||
|
||||
data.private_token = gon.api_token
|
||||
|
|
@ -80,7 +81,7 @@
|
|||
|
||||
# Return group projects list. Filtered by query
|
||||
groupProjects: (group_id, query, callback) ->
|
||||
url = Api.buildUrl(Api.group_projects_path)
|
||||
url = Api.buildUrl(Api.groupProjectsPath)
|
||||
url = url.replace(':id', group_id)
|
||||
|
||||
$.ajax(
|
||||
|
|
@ -95,7 +96,7 @@
|
|||
|
||||
# Return text for a specific license
|
||||
licenseText: (key, data, callback) ->
|
||||
url = Api.buildUrl(Api.license_path).replace(':key', key)
|
||||
url = Api.buildUrl(Api.licensePath).replace(':key', key)
|
||||
|
||||
$.ajax(
|
||||
url: url
|
||||
|
|
@ -103,6 +104,12 @@
|
|||
).done (license) ->
|
||||
callback(license)
|
||||
|
||||
gitignoreText: (key, callback) ->
|
||||
url = Api.buildUrl(Api.gitignorePath).replace(':key', key)
|
||||
|
||||
$.get url, (gitignore) ->
|
||||
callback(gitignore)
|
||||
|
||||
buildUrl: (url) ->
|
||||
url = gon.relative_url_root + url if gon.relative_url_root?
|
||||
return url.replace(':version', gon.api_version)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
class @BlobGitignoreSelector
|
||||
constructor: (opts) ->
|
||||
{
|
||||
@dropdown
|
||||
@editor
|
||||
@$wrapper = @dropdown.closest('.gitignore-selector')
|
||||
@$filenameInput = $('#file_name')
|
||||
@data = @dropdown.data('filenames')
|
||||
} = opts
|
||||
|
||||
@dropdown.glDropdown(
|
||||
data: @data,
|
||||
filterable: true,
|
||||
selectable: true,
|
||||
search:
|
||||
fields: ['name']
|
||||
clicked: @onClick
|
||||
text: (gitignore) ->
|
||||
gitignore.name
|
||||
)
|
||||
|
||||
@toggleGitignoreSelector()
|
||||
@bindEvents()
|
||||
|
||||
bindEvents: ->
|
||||
@$filenameInput
|
||||
.on 'keyup blur', (e) =>
|
||||
@toggleGitignoreSelector()
|
||||
|
||||
toggleGitignoreSelector: ->
|
||||
filename = @$filenameInput.val() or $('.editor-file-name').text().trim()
|
||||
@$wrapper.toggleClass 'hidden', filename isnt '.gitignore'
|
||||
|
||||
onClick: (item, el, e) =>
|
||||
e.preventDefault()
|
||||
@requestIgnoreFile(item.name)
|
||||
|
||||
requestIgnoreFile: (name) ->
|
||||
Api.gitignoreText name, @requestIgnoreFileSuccess.bind(@)
|
||||
|
||||
requestIgnoreFileSuccess: (gitignore) ->
|
||||
@editor.setValue(gitignore.content, 1)
|
||||
@editor.focus()
|
||||
|
||||
class @BlobGitignoreSelectors
|
||||
constructor: (opts) ->
|
||||
{
|
||||
@$dropdowns = $('.js-gitignore-selector')
|
||||
@editor
|
||||
} = opts
|
||||
|
||||
@$dropdowns.each (i, dropdown) =>
|
||||
$dropdown = $(dropdown)
|
||||
|
||||
new BlobGitignoreSelector(
|
||||
dropdown: $dropdown,
|
||||
editor: @editor
|
||||
)
|
||||
|
|
@ -13,6 +13,7 @@ class @EditBlob
|
|||
|
||||
@initModePanesAndLinks()
|
||||
new BlobLicenseSelector(@editor)
|
||||
new BlobGitignoreSelectors(editor: @editor)
|
||||
|
||||
initModePanesAndLinks: ->
|
||||
@$editModePanes = $(".js-edit-mode-pane")
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
class CiBuild
|
||||
@interval: null
|
||||
@state: null
|
||||
|
||||
constructor: (build_url, build_status) ->
|
||||
constructor: (build_url, build_status, build_state) ->
|
||||
clearInterval(CiBuild.interval)
|
||||
|
||||
@state = build_state
|
||||
|
||||
@initScrollButtonAffix()
|
||||
|
||||
if build_status == "running" || build_status == "pending"
|
||||
|
|
@ -26,14 +29,18 @@ class CiBuild
|
|||
CiBuild.interval = setInterval =>
|
||||
if window.location.href.split("#").first() is build_url
|
||||
$.ajax
|
||||
url: build_url
|
||||
url: build_url + "/trace.json?state=" + encodeURIComponent(@state)
|
||||
dataType: "json"
|
||||
success: (build) =>
|
||||
if build.status == "running"
|
||||
$('#build-trace code').html build.trace_html
|
||||
$('#build-trace code').append '<i class="fa fa-refresh fa-spin"/>'
|
||||
success: (log) =>
|
||||
@state = log.state
|
||||
if log.status is "running"
|
||||
if log.append
|
||||
$('.fa-refresh').before log.html
|
||||
else
|
||||
$('#build-trace code').html log.html
|
||||
$('#build-trace code').append '<i class="fa fa-refresh fa-spin"/>'
|
||||
@checkAutoscroll()
|
||||
else if build.status != build_status
|
||||
else if log.status isnt build_status
|
||||
Turbolinks.visit build_url
|
||||
, 4000
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ class @DueDateSelect
|
|||
$block = $dropdown.closest('.block')
|
||||
$selectbox = $dropdown.closest('.selectbox')
|
||||
$value = $block.find('.value')
|
||||
$valueContent = $block.find('.value-content')
|
||||
$sidebarValue = $('.js-due-date-sidebar-value', $block)
|
||||
|
||||
fieldName = $dropdown.data('field-name')
|
||||
|
|
@ -23,11 +24,15 @@ class @DueDateSelect
|
|||
$value.removeAttr('style')
|
||||
)
|
||||
|
||||
addDueDate = ->
|
||||
addDueDate = (isDropdown) ->
|
||||
# Create the post date
|
||||
value = $("input[name='#{fieldName}']").val()
|
||||
date = new Date value.replace(new RegExp('-', 'g'), ',')
|
||||
mediumDate = $.datepicker.formatDate 'M d, yy', date
|
||||
|
||||
if value isnt ''
|
||||
date = new Date value.replace(new RegExp('-', 'g'), ',')
|
||||
mediumDate = $.datepicker.formatDate 'M d, yy', date
|
||||
else
|
||||
mediumDate = 'None'
|
||||
|
||||
data = {}
|
||||
data[abilityName] = {}
|
||||
|
|
@ -39,23 +44,35 @@ class @DueDateSelect
|
|||
data: data
|
||||
beforeSend: ->
|
||||
$loading.fadeIn()
|
||||
$dropdown.trigger('loading.gl.dropdown')
|
||||
$selectbox.hide()
|
||||
if isDropdown
|
||||
$dropdown.trigger('loading.gl.dropdown')
|
||||
$selectbox.hide()
|
||||
$value.removeAttr('style')
|
||||
|
||||
$value.html(mediumDate)
|
||||
$valueContent.html(mediumDate)
|
||||
$sidebarValue.html(mediumDate)
|
||||
|
||||
if value isnt ''
|
||||
$('.js-remove-due-date-holder').removeClass 'hidden'
|
||||
else
|
||||
$('.js-remove-due-date-holder').addClass 'hidden'
|
||||
).done (data) ->
|
||||
$dropdown.trigger('loaded.gl.dropdown')
|
||||
$dropdown.dropdown('toggle')
|
||||
if isDropdown
|
||||
$dropdown.trigger('loaded.gl.dropdown')
|
||||
$dropdown.dropdown('toggle')
|
||||
$loading.fadeOut()
|
||||
|
||||
$block.on 'click', '.js-remove-due-date', (e) ->
|
||||
e.preventDefault()
|
||||
$("input[name='#{fieldName}']").val ''
|
||||
addDueDate(false)
|
||||
|
||||
$datePicker.datepicker(
|
||||
dateFormat: 'yy-mm-dd',
|
||||
defaultDate: $("input[name='#{fieldName}']").val()
|
||||
altField: "input[name='#{fieldName}']"
|
||||
onSelect: ->
|
||||
addDueDate()
|
||||
addDueDate(true)
|
||||
)
|
||||
|
||||
$(document)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ GitLab.GfmAutoComplete =
|
|||
Issues:
|
||||
template: '<li><small>${id}</small> ${title}</li>'
|
||||
|
||||
# Milestones
|
||||
Milestones:
|
||||
template: '<li>${title}</li>'
|
||||
|
||||
# Add GFM auto-completion to all input fields, that accept GFM input.
|
||||
setup: (wrap) ->
|
||||
@input = $('.js-gfm-input')
|
||||
|
|
@ -81,6 +85,19 @@ GitLab.GfmAutoComplete =
|
|||
title: sanitize(i.title)
|
||||
search: "#{i.iid} #{i.title}"
|
||||
|
||||
@input.atwho
|
||||
at: '%'
|
||||
alias: 'milestones'
|
||||
searchKey: 'search'
|
||||
displayTpl: @Milestones.template
|
||||
insertTpl: '${atwho-at}"${title}"'
|
||||
callbacks:
|
||||
beforeSave: (milestones) ->
|
||||
$.map milestones, (m) ->
|
||||
id: m.iid
|
||||
title: sanitize(m.title)
|
||||
search: "#{m.title}"
|
||||
|
||||
@input.atwho
|
||||
at: '!'
|
||||
alias: 'mergerequests'
|
||||
|
|
@ -105,6 +122,8 @@ GitLab.GfmAutoComplete =
|
|||
@input.atwho 'load', '@', data.members
|
||||
# load issues
|
||||
@input.atwho 'load', 'issues', data.issues
|
||||
# load milestones
|
||||
@input.atwho 'load', 'milestones', data.milestones
|
||||
# load merge requests
|
||||
@input.atwho 'load', 'mergerequests', data.mergerequests
|
||||
# load emojis
|
||||
|
|
|
|||
|
|
@ -60,9 +60,36 @@ class GitLabDropdownFilter
|
|||
results = data
|
||||
|
||||
if search_text isnt ''
|
||||
results = fuzzaldrinPlus.filter(data, search_text,
|
||||
key: @options.keys
|
||||
)
|
||||
# When data is an array of objects therefore [object Array] e.g.
|
||||
# [
|
||||
# { prop: 'foo' },
|
||||
# { prop: 'baz' }
|
||||
# ]
|
||||
if _.isArray(data)
|
||||
results = fuzzaldrinPlus.filter(data, search_text,
|
||||
key: @options.keys
|
||||
)
|
||||
else
|
||||
# If data is grouped therefore an [object Object]. e.g.
|
||||
# {
|
||||
# groupName1: [
|
||||
# { prop: 'foo' },
|
||||
# { prop: 'baz' }
|
||||
# ],
|
||||
# groupName2: [
|
||||
# { prop: 'abc' },
|
||||
# { prop: 'def' }
|
||||
# ]
|
||||
# }
|
||||
if gl.utils.isObject data
|
||||
results = {}
|
||||
for key, group of data
|
||||
tmp = fuzzaldrinPlus.filter(group, search_text,
|
||||
key: @options.keys
|
||||
)
|
||||
|
||||
if tmp.length
|
||||
results[key] = tmp.map (item) -> item
|
||||
|
||||
@options.callback results
|
||||
else
|
||||
|
|
@ -141,8 +168,9 @@ class GitLabDropdown
|
|||
searchFields = if @options.search then @options.search.fields else [];
|
||||
|
||||
if @options.data
|
||||
# If data is an array
|
||||
if _.isArray @options.data
|
||||
# If we provided data
|
||||
# data could be an array of objects or a group of arrays
|
||||
if _.isObject(@options.data) and not _.isFunction(@options.data)
|
||||
@fullData = @options.data
|
||||
@parseData @options.data
|
||||
else
|
||||
|
|
@ -230,19 +258,33 @@ class GitLabDropdown
|
|||
parseData: (data) ->
|
||||
@renderedData = data
|
||||
|
||||
# Render each row
|
||||
html = $.map data, (obj) =>
|
||||
return @renderItem(obj)
|
||||
|
||||
if @options.filterable and data.length is 0
|
||||
# render no matching results
|
||||
html = [@noResults()]
|
||||
else
|
||||
# Handle array groups
|
||||
if gl.utils.isObject data
|
||||
html = []
|
||||
for name, groupData of data
|
||||
# Add header for each group
|
||||
html.push(@renderItem(header: name, name))
|
||||
|
||||
@renderData(groupData, name)
|
||||
.map (item) ->
|
||||
html.push item
|
||||
else
|
||||
# Render each row
|
||||
html = @renderData(data)
|
||||
|
||||
# Render the full menu
|
||||
full_html = @renderMenu(html.join(""))
|
||||
|
||||
@appendMenu(full_html)
|
||||
|
||||
renderData: (data, group = false) ->
|
||||
data.map (obj, index) =>
|
||||
return @renderItem(obj, group, index)
|
||||
|
||||
shouldPropagate: (e) =>
|
||||
if @options.multiSelect
|
||||
$target = $(e.target)
|
||||
|
|
@ -299,11 +341,10 @@ class GitLabDropdown
|
|||
selector = '.dropdown-content'
|
||||
if @dropdown.find(".dropdown-toggle-page").length
|
||||
selector = ".dropdown-page-one .dropdown-content"
|
||||
|
||||
$(selector, @dropdown).html html
|
||||
|
||||
# Render the row
|
||||
renderItem: (data) ->
|
||||
renderItem: (data, group = false, index = false) ->
|
||||
html = ""
|
||||
|
||||
# Divider
|
||||
|
|
@ -346,8 +387,13 @@ class GitLabDropdown
|
|||
if @highlight
|
||||
text = @highlightTextMatches(text, @filterInput.val())
|
||||
|
||||
if group
|
||||
groupAttrs = "data-group='#{group}' data-index='#{index}'"
|
||||
else
|
||||
groupAttrs = ''
|
||||
|
||||
html = "<li>
|
||||
<a href='#{url}' class='#{cssClass}'>
|
||||
<a href='#{url}' #{groupAttrs} class='#{cssClass}'>
|
||||
#{text}
|
||||
</a>
|
||||
</li>"
|
||||
|
|
@ -377,9 +423,15 @@ class GitLabDropdown
|
|||
|
||||
rowClicked: (el) ->
|
||||
fieldName = @options.fieldName
|
||||
selectedIndex = el.parent().index()
|
||||
if @renderedData
|
||||
selectedObject = @renderedData[selectedIndex]
|
||||
groupName = el.data('group')
|
||||
if groupName
|
||||
selectedIndex = el.data('index')
|
||||
selectedObject = @renderedData[groupName][selectedIndex]
|
||||
else
|
||||
selectedIndex = el.closest('li').index()
|
||||
selectedObject = @renderedData[selectedIndex]
|
||||
|
||||
value = if @options.id then @options.id(selectedObject, el) else selectedObject.id
|
||||
field = @dropdown.parent().find("input[name='#{fieldName}'][value='#{value}']")
|
||||
if el.hasClass(ACTIVE_CLASS)
|
||||
|
|
@ -460,7 +512,7 @@ class GitLabDropdown
|
|||
return false
|
||||
|
||||
if currentKeyCode is 13
|
||||
@selectRowAtIndex currentIndex
|
||||
@selectRowAtIndex if currentIndex < 0 then 0 else currentIndex
|
||||
|
||||
removeArrayKeyEvent: ->
|
||||
$('body').off 'keydown'
|
||||
|
|
|
|||
|
|
@ -20,6 +20,15 @@ class @IssuableForm
|
|||
|
||||
@initWip()
|
||||
|
||||
$issuableDueDate = $('#issuable-due-date')
|
||||
|
||||
if $issuableDueDate.length
|
||||
$('.datepicker').datepicker(
|
||||
dateFormat: 'yy-mm-dd',
|
||||
onSelect: (dateText, inst) ->
|
||||
$issuableDueDate.val dateText
|
||||
).datepicker 'setDate', $.datepicker.parseDate('yy-mm-dd', $issuableDueDate.val())
|
||||
|
||||
initAutosave: ->
|
||||
new Autosave @titleField, [
|
||||
document.location.pathname,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
((w) ->
|
||||
|
||||
w.gl ?= {}
|
||||
w.gl.utils ?= {}
|
||||
|
||||
w.gl.utils.isObject = (obj) ->
|
||||
obj? and (obj.constructor is Object)
|
||||
|
||||
) window
|
||||
|
|
@ -113,7 +113,7 @@ class @MergeRequestWidget
|
|||
switch state
|
||||
when "failed", "canceled", "not_found"
|
||||
@setMergeButtonClass('btn-danger')
|
||||
when "running", "pending"
|
||||
when "running"
|
||||
@setMergeButtonClass('btn-warning')
|
||||
when "success"
|
||||
@setMergeButtonClass('btn-create')
|
||||
|
|
@ -126,6 +126,6 @@ class @MergeRequestWidget
|
|||
$('.ci_widget:visible .ci-coverage').text(text)
|
||||
|
||||
setMergeButtonClass: (css_class) ->
|
||||
$('.accept_merge_request')
|
||||
$('.js-merge-button')
|
||||
.removeClass('btn-danger btn-warning btn-create')
|
||||
.addClass(css_class)
|
||||
|
|
|
|||
|
|
@ -285,6 +285,7 @@ class @Notes
|
|||
form.addClass "js-main-target-form"
|
||||
|
||||
form.find("#note_line_code").remove()
|
||||
form.find("#note_type").remove()
|
||||
|
||||
###
|
||||
General note form setup.
|
||||
|
|
@ -472,6 +473,7 @@ class @Notes
|
|||
setupDiscussionNoteForm: (dataHolder, form) =>
|
||||
# setup note target
|
||||
form.attr 'id', "new-discussion-note-form-#{dataHolder.data("discussionId")}"
|
||||
form.find("#note_type").val dataHolder.data("noteType")
|
||||
form.find("#line_type").val dataHolder.data("lineType")
|
||||
form.find("#note_commit_id").val dataHolder.data("commitId")
|
||||
form.find("#note_line_code").val dataHolder.data("lineCode")
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@
|
|||
# Personal projects
|
||||
# </a>
|
||||
# </li>
|
||||
# <li class="snippets-tab">
|
||||
# <a data-action="snippets" data-target="#snippets" data-toggle="tab" href="/u/username/snippets">
|
||||
# </a>
|
||||
# </li>
|
||||
# </ul>
|
||||
#
|
||||
# <div class="tab-content">
|
||||
|
|
@ -41,6 +45,9 @@
|
|||
# <div class="tab-pane" id="projects">
|
||||
# Projects content
|
||||
# </div>
|
||||
# <div class="tab-pane" id="snippets">
|
||||
# Snippets content
|
||||
# </div>
|
||||
# </div>
|
||||
#
|
||||
# <div class="loading-status">
|
||||
|
|
@ -100,7 +107,7 @@ class @UserTabs
|
|||
if action is 'activity'
|
||||
@loadActivities(source)
|
||||
|
||||
if action in ['groups', 'contributed', 'projects']
|
||||
if action in ['groups', 'contributed', 'projects', 'snippets']
|
||||
@loadTab(source, action)
|
||||
|
||||
loadTab: (source, action) ->
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
*= require dropzone/basic
|
||||
*= require cal-heatmap
|
||||
*= require cropper.css
|
||||
*= require animate
|
||||
*/
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
@import 'framework/tw_bootstrap';
|
||||
@import "framework/layout";
|
||||
|
||||
@import "framework/animations.scss";
|
||||
@import "framework/avatar.scss";
|
||||
@import "framework/blocks.scss";
|
||||
@import "framework/buttons.scss";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
// This file is based off animate.css 3.5.1, available here:
|
||||
// https://github.com/daneden/animate.css/blob/3.5.1/animate.css
|
||||
//
|
||||
// animate.css - http://daneden.me/animate
|
||||
// Version - 3.5.1
|
||||
// Licensed under the MIT license - http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Copyright (c) 2016 Daniel Eden
|
||||
|
||||
.animated {
|
||||
-webkit-animation-duration: 1s;
|
||||
animation-duration: 1s;
|
||||
-webkit-animation-fill-mode: both;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
.animated.infinite {
|
||||
-webkit-animation-iteration-count: infinite;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.animated.hinge {
|
||||
-webkit-animation-duration: 2s;
|
||||
animation-duration: 2s;
|
||||
}
|
||||
|
||||
.animated.flipOutX,
|
||||
.animated.flipOutY,
|
||||
.animated.bounceIn,
|
||||
.animated.bounceOut {
|
||||
-webkit-animation-duration: .75s;
|
||||
animation-duration: .75s;
|
||||
}
|
||||
|
||||
@-webkit-keyframes pulse {
|
||||
from {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
|
||||
50% {
|
||||
-webkit-transform: scale3d(1.05, 1.05, 1.05);
|
||||
transform: scale3d(1.05, 1.05, 1.05);
|
||||
}
|
||||
|
||||
to {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
from {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
|
||||
50% {
|
||||
-webkit-transform: scale3d(1.05, 1.05, 1.05);
|
||||
transform: scale3d(1.05, 1.05, 1.05);
|
||||
}
|
||||
|
||||
to {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
.pulse {
|
||||
-webkit-animation-name: pulse;
|
||||
animation-name: pulse;
|
||||
}
|
||||
|
|
@ -289,7 +289,7 @@ table {
|
|||
text-shadow: none;
|
||||
|
||||
@media (min-width: $screen-sm-min) {
|
||||
margin-top: 11px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,22 +36,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.filename {
|
||||
&.old {
|
||||
display: inline-block;
|
||||
span.idiff {
|
||||
background-color: #f8cbcb;
|
||||
}
|
||||
}
|
||||
|
||||
&.new {
|
||||
display: inline-block;
|
||||
span.idiff {
|
||||
background-color: #a6f3a6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a:not(.btn) {
|
||||
color: $gl-dark-link-color;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,10 +28,6 @@ input[type='text'].danger {
|
|||
}
|
||||
|
||||
label {
|
||||
&.control-label {
|
||||
@extend .col-sm-2;
|
||||
}
|
||||
|
||||
&.inline-label {
|
||||
margin: 0;
|
||||
}
|
||||
|
|
@ -41,6 +37,10 @@ label {
|
|||
}
|
||||
}
|
||||
|
||||
.control-label {
|
||||
@extend .col-sm-2;
|
||||
}
|
||||
|
||||
.inline-input-group {
|
||||
width: 250px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@
|
|||
@mixin gitlab-theme($color-light, $color, $color-darker, $color-dark) {
|
||||
.page-with-sidebar {
|
||||
.header-logo {
|
||||
background-color: $color;
|
||||
border-color: $color;
|
||||
background: $color-darker;
|
||||
|
||||
a {
|
||||
color: $color-light;
|
||||
|
|
@ -21,7 +20,7 @@
|
|||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $color-darker;
|
||||
background-color: $color-dark;
|
||||
a {
|
||||
color: #fff;
|
||||
|
||||
|
|
@ -91,8 +90,8 @@
|
|||
}
|
||||
|
||||
$theme-blue: #2980b9;
|
||||
$theme-charcoal: #333c47;
|
||||
$theme-graphite: #888;
|
||||
$theme-charcoal: #3d454d;
|
||||
$theme-graphite: #666;
|
||||
$theme-gray: #373737;
|
||||
$theme-green: #019875;
|
||||
$theme-violet: #548;
|
||||
|
|
@ -103,11 +102,11 @@ body {
|
|||
}
|
||||
|
||||
&.ui_charcoal {
|
||||
@include gitlab-theme(#c5d0de, $theme-charcoal, #2b333d, #24272d);
|
||||
@include gitlab-theme(#d6d7d9, #485157, $theme-charcoal, #353b41);
|
||||
}
|
||||
|
||||
&.ui_graphite {
|
||||
@include gitlab-theme(#ccc, $theme-graphite, #777, #666);
|
||||
@include gitlab-theme(#ccc, #777, $theme-graphite, #555);
|
||||
}
|
||||
|
||||
&.ui_gray {
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@ header {
|
|||
transition-duration: .3s;
|
||||
|
||||
&.navbar-empty {
|
||||
height: 58px;
|
||||
height: $header-height;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid $btn-gray-hover;
|
||||
|
||||
.center-logo {
|
||||
margin: 11px 0;
|
||||
margin: 8px 0;
|
||||
text-align: center;
|
||||
|
||||
#tanuki-logo, img {
|
||||
|
|
|
|||
|
|
@ -209,6 +209,15 @@
|
|||
float: right;
|
||||
padding: 7px 0 0;
|
||||
|
||||
@media (max-width: $screen-xs-min) {
|
||||
float: none;
|
||||
padding: 0 9px;
|
||||
|
||||
.dropdown-new {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
i {
|
||||
color: $layout-link-gray;
|
||||
}
|
||||
|
|
@ -225,6 +234,10 @@
|
|||
|
||||
.dropdown {
|
||||
margin-left: 7px;
|
||||
|
||||
@media (max-width: $screen-xs-min) {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -260,4 +273,10 @@
|
|||
|
||||
.page-with-layout-nav {
|
||||
margin-top: 50px;
|
||||
|
||||
&.controls-dropdown-visible {
|
||||
@media (max-width: $screen-xs-min) {
|
||||
margin-top: 96px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@
|
|||
}
|
||||
|
||||
.nav-sidebar li a {
|
||||
width: 230px;
|
||||
width: $sidebar_width;
|
||||
|
||||
&.back-link {
|
||||
i {
|
||||
|
|
|
|||
|
|
@ -269,3 +269,11 @@ h1, h2, h3, h4 {
|
|||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.idiff.deletion {
|
||||
background: $line-removed-dark;
|
||||
}
|
||||
|
||||
.idiff.addition {
|
||||
background: $line-added-dark;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
* Layout
|
||||
*/
|
||||
$sidebar_collapsed_width: 62px;
|
||||
$sidebar_width: 230px;
|
||||
$sidebar_width: 220px;
|
||||
$gutter_collapsed_width: 62px;
|
||||
$gutter_width: 290px;
|
||||
$gutter_inner_width: 258px;
|
||||
|
|
@ -12,7 +12,7 @@ $gutter_inner_width: 258px;
|
|||
*/
|
||||
$border-color: #e5e5e5;
|
||||
$focus-border-color: #3aabf0;
|
||||
$table-border-color: #ececec;
|
||||
$table-border-color: #f0f0f0;
|
||||
$background-color: #fafafa;
|
||||
|
||||
/*
|
||||
|
|
@ -178,6 +178,7 @@ $table-border-gray: #f0f0f0;
|
|||
$line-target-blue: #eaf3fc;
|
||||
$line-select-yellow: #fcf8e7;
|
||||
$line-select-yellow-dark: #f0e2bd;
|
||||
|
||||
/*
|
||||
* Fonts
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.zen-cotrol {
|
||||
.zen-control {
|
||||
padding: 0;
|
||||
color: #555;
|
||||
background: none;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
@import "framework/variables";
|
||||
|
||||
table.code {
|
||||
width: 100%;
|
||||
font-family: monospace;
|
||||
border: none;
|
||||
border-collapse: separate;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-premailer-cellpadding: 0;
|
||||
-premailer-cellspacing: 0;
|
||||
-premailer-width: 100%;
|
||||
|
||||
td {
|
||||
line-height: $code_line_height;
|
||||
font-family: monospace;
|
||||
font-size: $code_font_size;
|
||||
}
|
||||
|
||||
td.diff-line-num {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: $background-color;
|
||||
color: rgba(0, 0, 0, 0.3);
|
||||
padding: 0 5px;
|
||||
border-right: 1px solid $border-color;
|
||||
text-align: right;
|
||||
min-width: 35px;
|
||||
max-width: 50px;
|
||||
width: 35px;
|
||||
}
|
||||
|
||||
td.line_content {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 0 0.5em;
|
||||
border: none;
|
||||
white-space: pre;
|
||||
}
|
||||
}
|
||||
|
||||
@import "highlight/white";
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
.file-title {
|
||||
@extend .monospace;
|
||||
|
||||
line-height: 42px;
|
||||
line-height: 35px;
|
||||
padding-top: 7px;
|
||||
padding-bottom: 7px;
|
||||
|
||||
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
.editor-file-name {
|
||||
@extend .monospace;
|
||||
|
||||
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
|
@ -59,7 +59,22 @@
|
|||
}
|
||||
|
||||
.encoding-selector,
|
||||
.license-selector {
|
||||
.license-selector,
|
||||
.gitignore-selector {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
font-family: $regular_font;
|
||||
}
|
||||
|
||||
.gitignore-selector {
|
||||
|
||||
.dropdown {
|
||||
line-height: 21px;
|
||||
}
|
||||
|
||||
.dropdown-menu-toggle {
|
||||
vertical-align: top;
|
||||
width: 220px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@
|
|||
|
||||
.right-sidebar {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
top: $header-height;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
|
|
@ -150,6 +150,10 @@
|
|||
font-weight: 600;
|
||||
}
|
||||
|
||||
.light {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.sidebar-collapsed-icon {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -226,8 +226,7 @@ ul.notes {
|
|||
}
|
||||
}
|
||||
|
||||
.note-action-button,
|
||||
.discussion-action-button {
|
||||
.note-action-button {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
line-height: 24px;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
.pipeline-stage {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
}
|
||||
.no-ssh-key-message, .project-limit-message {
|
||||
background-color: #f28d35;
|
||||
margin-bottom: 16px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.new_project,
|
||||
.edit_project {
|
||||
|
|
@ -149,6 +149,10 @@
|
|||
white-space: nowrap;
|
||||
margin: 0 11px 0 4px;
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #fff;
|
||||
}
|
||||
|
|
@ -161,7 +165,7 @@
|
|||
display: inline-table;
|
||||
margin-right: 12px;
|
||||
|
||||
a {
|
||||
> a {
|
||||
margin: -1px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@ class Admin::AbuseReportsController < Admin::ApplicationController
|
|||
abuse_report.remove_user(deleted_by: current_user) if params[:remove_user]
|
||||
abuse_report.destroy
|
||||
|
||||
render nothing: true
|
||||
head :ok
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -19,6 +19,12 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
|
|||
redirect_to admin_runners_path
|
||||
end
|
||||
|
||||
def reset_health_check_token
|
||||
@application_setting.reset_health_check_access_token!
|
||||
flash[:notice] = 'New health check access token has been generated!'
|
||||
redirect_to :back
|
||||
end
|
||||
|
||||
def clear_repository_check_states
|
||||
RepositoryCheck::ClearWorker.perform_async
|
||||
|
||||
|
|
@ -53,6 +59,12 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
enabled_oauth_sign_in_sources = params[:application_setting].delete(:enabled_oauth_sign_in_sources)
|
||||
|
||||
params[:application_setting][:disabled_oauth_sign_in_sources] =
|
||||
AuthHelper.button_based_providers.map(&:to_s) -
|
||||
Array(enabled_oauth_sign_in_sources)
|
||||
|
||||
params.require(:application_setting).permit(
|
||||
:default_projects_limit,
|
||||
:default_branch_protection,
|
||||
|
|
@ -94,8 +106,10 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
|
|||
:email_author_in_body,
|
||||
:repository_checks_enabled,
|
||||
:metrics_packet_size,
|
||||
:send_user_confirmation_email,
|
||||
restricted_visibility_levels: [],
|
||||
import_sources: []
|
||||
import_sources: [],
|
||||
disabled_oauth_sign_in_sources: []
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.html { redirect_back_or_default(default: { action: 'index' }) }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
class Admin::HealthCheckController < Admin::ApplicationController
|
||||
def show
|
||||
@errors = HealthCheck::Utils.process_checks('standard')
|
||||
end
|
||||
end
|
||||
|
|
@ -6,7 +6,7 @@ class Admin::KeysController < Admin::ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -9,23 +9,18 @@ class Admin::RunnersController < Admin::ApplicationController
|
|||
end
|
||||
|
||||
def show
|
||||
@builds = @runner.builds.order('id DESC').first(30)
|
||||
@projects =
|
||||
if params[:search].present?
|
||||
::Project.search(params[:search])
|
||||
else
|
||||
Project.all
|
||||
end
|
||||
@projects = @projects.where.not(id: @runner.projects.select(:id)) if @runner.projects.any?
|
||||
@projects = @projects.page(params[:page]).per(30)
|
||||
assign_builds_and_projects
|
||||
end
|
||||
|
||||
def update
|
||||
@runner.update_attributes(runner_params)
|
||||
|
||||
respond_to do |format|
|
||||
format.js
|
||||
format.html { redirect_to admin_runner_path(@runner) }
|
||||
if @runner.update_attributes(runner_params)
|
||||
respond_to do |format|
|
||||
format.js
|
||||
format.html { redirect_to admin_runner_path(@runner) }
|
||||
end
|
||||
else
|
||||
assign_builds_and_projects
|
||||
render 'show'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -58,6 +53,18 @@ class Admin::RunnersController < Admin::ApplicationController
|
|||
end
|
||||
|
||||
def runner_params
|
||||
params.require(:runner).permit(:token, :description, :tag_list, :active)
|
||||
params.require(:runner).permit(Ci::Runner::FORM_EDITABLE)
|
||||
end
|
||||
|
||||
def assign_builds_and_projects
|
||||
@builds = runner.builds.order('id DESC').first(30)
|
||||
@projects =
|
||||
if params[:search].present?
|
||||
::Project.search(params[:search])
|
||||
else
|
||||
Project.all
|
||||
end
|
||||
@projects = @projects.where.not(id: runner.projects.select(:id)) if runner.projects.any?
|
||||
@projects = @projects.page(params[:page]).per(30)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class Admin::SpamLogsController < Admin::ApplicationController
|
|||
redirect_to admin_spam_logs_path, notice: "User #{spam_log.user.username} was successfully removed."
|
||||
else
|
||||
spam_log.destroy
|
||||
render nothing: true
|
||||
head :ok
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ class Admin::UsersController < Admin::ApplicationController
|
|||
user_params_with_pass.merge!(
|
||||
password: params[:user][:password],
|
||||
password_confirmation: params[:user][:password_confirmation],
|
||||
password_expires_at: Time.now
|
||||
)
|
||||
end
|
||||
|
||||
|
|
@ -153,7 +154,7 @@ class Admin::UsersController < Admin::ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.html { redirect_back_or_admin_user(notice: "Successfully removed email.") }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
def check_password_expiration
|
||||
if current_user && current_user.password_expires_at && current_user.password_expires_at < Time.now && !current_user.ldap_user?
|
||||
if current_user && current_user.password_expires_at && current_user.password_expires_at < Time.now && !current_user.ldap_user?
|
||||
redirect_to new_profile_password_path and return
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ module CreatesCommit
|
|||
# Merge request from fork to this project
|
||||
@mr_source_project = @tree_edit_project
|
||||
@mr_target_project = @project
|
||||
@mr_target_branch ||= @ref
|
||||
@mr_target_branch ||= @ref
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ module ToggleSubscriptionAction
|
|||
|
||||
subscribable_resource.toggle_subscription(current_user)
|
||||
|
||||
render nothing: true
|
||||
head :ok
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
|
|||
end
|
||||
|
||||
def starred
|
||||
@projects = current_user.starred_projects.sorted_by_activity
|
||||
@projects = current_user.viewable_starred_projects.sorted_by_activity
|
||||
@projects = filter_projects(@projects)
|
||||
@projects = @projects.includes(:namespace, :forked_from_project, :tags)
|
||||
@projects = @projects.sort(@sort = params[:sort])
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to dashboard_todos_path, notice: todo_notice }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
format.json do
|
||||
render json: { count: @todos.size, done_count: current_user.todos.done.count }
|
||||
end
|
||||
|
|
@ -24,7 +24,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to dashboard_todos_path, notice: 'All todos were marked as done.' }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
format.json do
|
||||
find_todos
|
||||
render json: { count: @todos.size, done_count: current_user.todos.done.count }
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class DashboardController < Dashboard::ApplicationController
|
|||
def load_events
|
||||
projects =
|
||||
if params[:filter] == "starred"
|
||||
current_user.starred_projects
|
||||
current_user.viewable_starred_projects
|
||||
else
|
||||
current_user.authorized_projects
|
||||
end
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to group_group_members_path(@group), notice: 'User was successfully removed from group.' }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
class HealthCheckController < HealthCheck::HealthCheckController
|
||||
before_action :validate_health_check_access!
|
||||
|
||||
private
|
||||
|
||||
def validate_health_check_access!
|
||||
render_404 unless token_valid?
|
||||
end
|
||||
|
||||
def token_valid?
|
||||
token = params[:token].presence || request.headers['TOKEN']
|
||||
token.present? &&
|
||||
ActiveSupport::SecurityUtils.variable_size_secure_compare(
|
||||
token,
|
||||
current_application_settings.health_check_access_token
|
||||
)
|
||||
end
|
||||
|
||||
def render_404
|
||||
render file: Rails.root.join('public', '404'), layout: false, status: '404'
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
class JwtController < ApplicationController
|
||||
skip_before_action :authenticate_user!
|
||||
skip_before_action :verify_authenticity_token
|
||||
before_action :authenticate_project_or_user
|
||||
|
||||
SERVICES = {
|
||||
Auth::ContainerRegistryAuthenticationService::AUDIENCE => Auth::ContainerRegistryAuthenticationService,
|
||||
}
|
||||
|
||||
def auth
|
||||
service = SERVICES[params[:service]]
|
||||
return head :not_found unless service
|
||||
|
||||
result = service.new(@project, @user, auth_params).execute
|
||||
|
||||
render json: result, status: result[:http_status]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def authenticate_project_or_user
|
||||
authenticate_with_http_basic do |login, password|
|
||||
# if it's possible we first try to authenticate project with login and password
|
||||
@project = authenticate_project(login, password)
|
||||
return if @project
|
||||
|
||||
@user = authenticate_user(login, password)
|
||||
return if @user
|
||||
|
||||
render_403
|
||||
end
|
||||
end
|
||||
|
||||
def auth_params
|
||||
params.permit(:service, :scope, :offline_token, :account, :client_id)
|
||||
end
|
||||
|
||||
def authenticate_project(login, password)
|
||||
if login == 'gitlab-ci-token'
|
||||
Project.find_by(builds_enabled: true, runners_token: password)
|
||||
end
|
||||
end
|
||||
|
||||
def authenticate_user(login, password)
|
||||
# TODO: this is a copy and paste from grack_auth,
|
||||
# it should be refactored in the future
|
||||
|
||||
user = Gitlab::Auth.new.find(login, password)
|
||||
|
||||
# If the user authenticated successfully, we reset the auth failure count
|
||||
# from Rack::Attack for that IP. A client may attempt to authenticate
|
||||
# with a username and blank password first, and only after it receives
|
||||
# a 401 error does it present a password. Resetting the count prevents
|
||||
# false positives from occurring.
|
||||
#
|
||||
# Otherwise, we let Rack::Attack know there was a failed authentication
|
||||
# attempt from this IP. This information is stored in the Rails cache
|
||||
# (Redis) and will be used by the Rack::Attack middleware to decide
|
||||
# whether to block requests from this IP.
|
||||
config = Gitlab.config.rack_attack.git_basic_auth
|
||||
|
||||
if config.enabled
|
||||
if user
|
||||
# A successful login will reset the auth failure count from this IP
|
||||
Rack::Attack::Allow2Ban.reset(request.ip, config)
|
||||
else
|
||||
banned = Rack::Attack::Allow2Ban.filter(request.ip, config) do
|
||||
# Unless the IP is whitelisted, return true so that Allow2Ban
|
||||
# increments the counter (stored in Rails.cache) for the IP
|
||||
if config.ip_whitelist.include?(request.ip)
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
if banned
|
||||
Rails.logger.info "IP #{request.ip} failed to login " \
|
||||
"as #{login} but has been temporarily banned from Git auth"
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
user
|
||||
end
|
||||
end
|
||||
|
|
@ -24,7 +24,7 @@ class Profiles::EmailsController < Profiles::ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to profile_emails_url }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class Profiles::KeysController < Profiles::ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to profile_keys_url }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,14 @@ class Projects::BuildsController < Projects::ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def trace
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
render json: @build.trace_with_state(params[:state]).merge!(id: @build.id, status: @build.status)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def retry
|
||||
unless @build.retryable?
|
||||
return render_404
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@ class Projects::CommitController < Projects::ApplicationController
|
|||
def show
|
||||
apply_diff_view_cookie!
|
||||
|
||||
@line_notes = commit.notes.inline
|
||||
@grouped_diff_notes = commit.notes.grouped_diff_notes
|
||||
|
||||
@note = @project.build_commit_note(commit)
|
||||
@notes = commit.notes.not_inline.fresh
|
||||
@notes = commit.notes.non_diff_notes.fresh
|
||||
@noteable = @commit
|
||||
@comments_allowed = @reply_allowed = true
|
||||
@comments_target = {
|
||||
@comments_target = {
|
||||
noteable_type: 'Commit',
|
||||
commit_id: @commit.id
|
||||
}
|
||||
|
|
@ -67,10 +67,10 @@ class Projects::CommitController < Projects::ApplicationController
|
|||
create_commit(Commits::RevertService, success_notice: "The #{@commit.change_type_title} has been successfully reverted.",
|
||||
success_path: successful_change_path, failure_path: failed_change_path)
|
||||
end
|
||||
|
||||
|
||||
def cherry_pick
|
||||
assign_change_commit_vars(@commit.cherry_pick_branch_name)
|
||||
|
||||
|
||||
return render_404 if @target_branch.blank?
|
||||
|
||||
create_commit(Commits::CherryPickService, success_notice: "The #{@commit.change_type_title} has been successfully cherry-picked.",
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ class Projects::CompareController < Projects::ApplicationController
|
|||
@base_commit = @project.merge_base_commit(@base_ref, @head_ref)
|
||||
@diffs = compare.diffs(diff_options)
|
||||
@diff_refs = [@base_commit, @commit]
|
||||
@line_notes = []
|
||||
@diff_notes_disabled = true
|
||||
@grouped_diff_notes = {}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
class Projects::ContainerRegistryController < Projects::ApplicationController
|
||||
before_action :verify_registry_enabled
|
||||
before_action :authorize_read_container_image!
|
||||
before_action :authorize_update_container_image!, only: [:destroy]
|
||||
layout 'project'
|
||||
|
||||
def index
|
||||
@tags = container_registry_repository.tags
|
||||
end
|
||||
|
||||
def destroy
|
||||
url = namespace_project_container_registry_index_path(project.namespace, project)
|
||||
|
||||
if tag.delete
|
||||
redirect_to url
|
||||
else
|
||||
redirect_to url, alert: 'Failed to remove tag'
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def verify_registry_enabled
|
||||
render_404 unless Gitlab.config.registry.enabled
|
||||
end
|
||||
|
||||
def container_registry_repository
|
||||
@container_registry_repository ||= project.container_registry_repository
|
||||
end
|
||||
|
||||
def tag
|
||||
@tag ||= container_registry_repository.tag(params[:id])
|
||||
end
|
||||
end
|
||||
|
|
@ -27,8 +27,10 @@ class Projects::HooksController < Projects::ApplicationController
|
|||
if !@project.empty_repo?
|
||||
status, message = TestHookService.new.execute(hook, current_user)
|
||||
|
||||
if status
|
||||
flash[:notice] = 'Hook successfully executed.'
|
||||
if status && status >= 200 && status < 400
|
||||
flash[:notice] = "Hook executed successfully: HTTP #{status}"
|
||||
elsif status
|
||||
flash[:alert] = "Hook executed successfully but returned HTTP #{status} #{message}"
|
||||
else
|
||||
flash[:alert] = "Hook execution failed: #{message}"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ class Projects::ImportsController < Projects::ApplicationController
|
|||
@project.import_retry
|
||||
else
|
||||
@project.import_start
|
||||
@project.add_import_job
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -73,12 +73,12 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
# but we need it for the "View file @ ..." link by deleted files
|
||||
@base_commit ||= @merge_request.first_commit.parent || @merge_request.first_commit
|
||||
|
||||
@comments_allowed = @reply_allowed = true
|
||||
@comments_target = {
|
||||
noteable_type: 'MergeRequest',
|
||||
noteable_id: @merge_request.id
|
||||
}
|
||||
@line_notes = @merge_request.notes.where("line_code is not null")
|
||||
|
||||
@grouped_diff_notes = @merge_request.notes.grouped_diff_notes
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
|
|
@ -117,6 +117,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
@commit = @merge_request.last_commit
|
||||
@base_commit = @merge_request.diff_base_commit
|
||||
@diffs = @merge_request.compare.diffs(diff_options) if @merge_request.compare
|
||||
@diff_notes_disabled = true
|
||||
|
||||
@ci_commit = @merge_request.ci_commit
|
||||
@statuses = @ci_commit.statuses if @ci_commit
|
||||
|
|
@ -300,7 +301,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
# Build a note object for comment form
|
||||
@note = @project.notes.new(noteable: @merge_request)
|
||||
@notes = @merge_request.mr_and_commit_notes.nonawards.inc_author.fresh
|
||||
@discussions = Note.discussions_from_notes(@notes)
|
||||
@discussions = @notes.discussions
|
||||
@noteable = @merge_request
|
||||
|
||||
# Get commits from repository
|
||||
|
|
@ -333,7 +334,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
params.require(:merge_request).permit(
|
||||
:title, :assignee_id, :source_project_id, :source_branch,
|
||||
:target_project_id, :target_branch, :milestone_id,
|
||||
:state_event, :description, :task_num, label_ids: []
|
||||
:state_event, :description, :task_num, :force_remove_source_branch,
|
||||
label_ids: []
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ class Projects::MilestonesController < Projects::ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to namespace_project_milestones_path }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class Projects::NotesController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ class Projects::NotesController < Projects::ApplicationController
|
|||
note.update_attribute(:attachment, nil)
|
||||
|
||||
respond_to do |format|
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ class Projects::NotesController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def note_to_discussion_html(note)
|
||||
return unless note.for_diff_line?
|
||||
return unless note.diff_note?
|
||||
|
||||
if params[:view] == 'parallel'
|
||||
template = "projects/notes/_diff_notes_with_reply_parallel"
|
||||
|
|
@ -120,7 +120,7 @@ class Projects::NotesController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def note_to_discussion_with_diff_html(note)
|
||||
return unless note.for_diff_line?
|
||||
return unless note.diff_note?
|
||||
|
||||
render_to_string(
|
||||
"projects/notes/_discussion",
|
||||
|
|
@ -158,7 +158,7 @@ class Projects::NotesController < Projects::ApplicationController
|
|||
def note_params
|
||||
params.require(:note).permit(
|
||||
:note, :noteable, :noteable_id, :noteable_type, :project_id,
|
||||
:attachment, :line_code, :commit_id
|
||||
:attachment, :line_code, :commit_id, :type
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
class Projects::PipelinesController < Projects::ApplicationController
|
||||
before_action :pipeline, except: [:index, :new, :create]
|
||||
before_action :commit, only: [:show]
|
||||
before_action :authorize_read_pipeline!
|
||||
before_action :authorize_create_pipeline!, only: [:new, :create]
|
||||
before_action :authorize_update_pipeline!, only: [:retry, :cancel]
|
||||
|
||||
def index
|
||||
@scope = params[:scope]
|
||||
all_pipelines = project.ci_commits
|
||||
@pipelines_count = all_pipelines.count
|
||||
@running_or_pending_count = all_pipelines.running_or_pending.count
|
||||
@pipelines = PipelinesFinder.new(project).execute(all_pipelines, @scope)
|
||||
@pipelines = @pipelines.order(id: :desc).page(params[:page]).per(30)
|
||||
end
|
||||
|
||||
def new
|
||||
@pipeline = project.ci_commits.new(ref: @project.default_branch)
|
||||
end
|
||||
|
||||
def create
|
||||
@pipeline = Ci::CreatePipelineService.new(project, current_user, create_params).execute
|
||||
unless @pipeline.persisted?
|
||||
render 'new'
|
||||
return
|
||||
end
|
||||
|
||||
redirect_to namespace_project_pipeline_path(project.namespace, project, @pipeline)
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def retry
|
||||
pipeline.retry_failed
|
||||
|
||||
redirect_back_or_default default: namespace_project_pipelines_path(project.namespace, project)
|
||||
end
|
||||
|
||||
def cancel
|
||||
pipeline.cancel_running
|
||||
|
||||
redirect_back_or_default default: namespace_project_pipelines_path(project.namespace, project)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_params
|
||||
params.require(:pipeline).permit(:ref)
|
||||
end
|
||||
|
||||
def pipeline
|
||||
@pipeline ||= project.ci_commits.find_by!(id: params[:id])
|
||||
end
|
||||
|
||||
def commit
|
||||
@commit ||= @pipeline.commit_data
|
||||
end
|
||||
end
|
||||
|
|
@ -55,7 +55,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
|
|||
format.html do
|
||||
redirect_to namespace_project_project_members_path(@project.namespace, @project)
|
||||
end
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to dashboard_projects_path, notice: "You left the project." }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
else
|
||||
if current_user == @project.owner
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to namespace_project_protected_branches_path }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class Projects::RunnersController < Projects::ApplicationController
|
|||
if @runner.update_attributes(runner_params)
|
||||
redirect_to runner_path(@runner), notice: 'Runner was successfully updated.'
|
||||
else
|
||||
redirect_to runner_path(@runner), alert: 'Runner was not updated.'
|
||||
render 'edit'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -64,6 +64,6 @@ class Projects::RunnersController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def runner_params
|
||||
params.require(:runner).permit(:description, :tag_list, :active)
|
||||
params.require(:runner).permit(Ci::Runner::FORM_EDITABLE)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,20 +3,44 @@ class Projects::VariablesController < Projects::ApplicationController
|
|||
|
||||
layout 'project_settings'
|
||||
|
||||
def index
|
||||
@variable = Ci::Variable.new
|
||||
end
|
||||
|
||||
def show
|
||||
@variable = @project.variables.find(params[:id])
|
||||
end
|
||||
|
||||
def update
|
||||
if project.update_attributes(project_params)
|
||||
@variable = @project.variables.find(params[:id])
|
||||
|
||||
if @variable.update_attributes(project_params)
|
||||
redirect_to namespace_project_variables_path(project.namespace, project), notice: 'Variable was successfully updated.'
|
||||
else
|
||||
render action: "show"
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
@variable = Ci::Variable.new(project_params)
|
||||
|
||||
if @variable.valid? && @project.variables << @variable
|
||||
redirect_to namespace_project_variables_path(project.namespace, project), notice: 'Variables were successfully updated.'
|
||||
else
|
||||
render action: 'show'
|
||||
render action: "index"
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@key = @project.variables.find(params[:id])
|
||||
@key.destroy
|
||||
|
||||
redirect_to namespace_project_variables_path(project.namespace, project), notice: 'Variable was successfully removed.'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def project_params
|
||||
params.require(:project).permit({ variables_attributes: [:id, :key, :value, :_destroy] })
|
||||
params.require(:variable).permit([:id, :key, :value, :_destroy])
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -101,13 +101,7 @@ class ProjectsController < Projects::ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
if current_user
|
||||
@membership = @project.team.find_member(current_user.id)
|
||||
|
||||
if @membership
|
||||
@notification_setting = current_user.notification_settings_for(@project)
|
||||
end
|
||||
end
|
||||
@notification_setting = current_user.notification_settings_for(@project) if current_user
|
||||
|
||||
if @project.repository_exists?
|
||||
if @project.empty_repo?
|
||||
|
|
@ -147,6 +141,7 @@ class ProjectsController < Projects::ApplicationController
|
|||
@suggestions = {
|
||||
emojis: AwardEmoji.urls,
|
||||
issues: autocomplete.issues,
|
||||
milestones: autocomplete.milestones,
|
||||
mergerequests: autocomplete.merge_requests,
|
||||
members: participants
|
||||
}
|
||||
|
|
@ -235,7 +230,8 @@ class ProjectsController < Projects::ApplicationController
|
|||
def project_params
|
||||
params.require(:project).permit(
|
||||
:name, :path, :description, :issues_tracker, :tag_list, :runners_token,
|
||||
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, :default_branch,
|
||||
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :container_registry_enabled,
|
||||
:issues_tracker_id, :default_branch,
|
||||
:wiki_enabled, :visibility_level, :import_url, :last_activity_at, :namespace_id, :avatar,
|
||||
:builds_enabled, :build_allow_git_fetch, :build_timeout_in_minutes, :build_coverage_regex,
|
||||
:public_builds,
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ class RegistrationsController < Devise::RegistrationsController
|
|||
super
|
||||
end
|
||||
|
||||
def after_sign_up_path_for(_resource)
|
||||
users_almost_there_path
|
||||
def after_sign_up_path_for(user)
|
||||
user.confirmed? ? dashboard_projects_path : users_almost_there_path
|
||||
end
|
||||
|
||||
def after_inactive_sign_up_path_for(_resource)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ class SnippetsController < ApplicationController
|
|||
# Allow destroy snippet
|
||||
before_action :authorize_admin_snippet!, only: [:destroy]
|
||||
|
||||
skip_before_action :authenticate_user!, only: [:index, :user_index, :show, :raw]
|
||||
skip_before_action :authenticate_user!, only: [:index, :show, :raw]
|
||||
|
||||
layout 'snippets'
|
||||
respond_to :html
|
||||
|
|
|
|||
|
|
@ -58,6 +58,19 @@ class UsersController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def snippets
|
||||
load_snippets
|
||||
|
||||
respond_to do |format|
|
||||
format.html { render 'show' }
|
||||
format.json do
|
||||
render json: {
|
||||
html: view_to_html_string("snippets/_snippets", collection: @snippets)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def calendar
|
||||
calendar = contributions_calendar
|
||||
@timestamps = calendar.timestamps
|
||||
|
|
@ -116,6 +129,15 @@ class UsersController < ApplicationController
|
|||
@groups = JoinedGroupsFinder.new(user).execute(current_user)
|
||||
end
|
||||
|
||||
def load_snippets
|
||||
@snippets = SnippetsFinder.new.execute(
|
||||
current_user,
|
||||
filter: :by_user,
|
||||
user: user,
|
||||
scope: params[:scope]
|
||||
).page(params[:page])
|
||||
end
|
||||
|
||||
def projects_for_current_user
|
||||
ProjectsFinder.new.execute(current_user)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -252,8 +252,8 @@ class IssuableFinder
|
|||
if filter_by_no_milestone?
|
||||
items = items.where(milestone_id: [-1, nil])
|
||||
elsif filter_by_upcoming_milestone?
|
||||
upcoming = Milestone.where(project_id: projects).upcoming
|
||||
items = items.joins(:milestone).where(milestones: { title: upcoming.try(:title) })
|
||||
upcoming_ids = Milestone.upcoming_ids_by_projects(projects)
|
||||
items = items.joins(:milestone).where(milestone_id: upcoming_ids)
|
||||
else
|
||||
items = items.joins(:milestone).where(milestones: { title: params[:milestone_title] })
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ class NotesFinder
|
|||
notes =
|
||||
case target_type
|
||||
when "commit"
|
||||
project.notes.for_commit_id(target_id).not_inline
|
||||
project.notes.for_commit_id(target_id).non_diff_notes
|
||||
when "issue"
|
||||
project.issues.find(target_id).notes.nonawards.inc_author
|
||||
when "merge_request"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
class PipelinesFinder
|
||||
attr_reader :project
|
||||
|
||||
def initialize(project)
|
||||
@project = project
|
||||
end
|
||||
|
||||
def execute(pipelines, scope)
|
||||
case scope
|
||||
when 'running'
|
||||
pipelines.running_or_pending
|
||||
when 'branches'
|
||||
from_ids(pipelines, ids_for_ref(pipelines, branches))
|
||||
when 'tags'
|
||||
from_ids(pipelines, ids_for_ref(pipelines, tags))
|
||||
else
|
||||
pipelines
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ids_for_ref(pipelines, refs)
|
||||
pipelines.where(ref: refs).group(:ref).select('max(id)')
|
||||
end
|
||||
|
||||
def from_ids(pipelines, ids)
|
||||
pipelines.unscoped.where(id: ids)
|
||||
end
|
||||
|
||||
def branches
|
||||
project.repository.branches.map(&:name)
|
||||
end
|
||||
|
||||
def tags
|
||||
project.repository.tags.map(&:name)
|
||||
end
|
||||
end
|
||||
|
|
@ -36,7 +36,7 @@ class TodosFinder
|
|||
private
|
||||
|
||||
def action_id?
|
||||
action_id.present? && [Todo::ASSIGNED, Todo::MENTIONED].include?(action_id.to_i)
|
||||
action_id.present? && [Todo::ASSIGNED, Todo::MENTIONED, Todo::BUILD_FAILED].include?(action_id.to_i)
|
||||
end
|
||||
|
||||
def action_id
|
||||
|
|
|
|||
|
|
@ -110,8 +110,7 @@ module ApplicationHelper
|
|||
]
|
||||
|
||||
# If reference is commit id - we should add it to branch/tag selectbox
|
||||
if(@ref && !options.flatten.include?(@ref) &&
|
||||
@ref =~ /\A[0-9a-zA-Z]{6,52}\z/)
|
||||
if @ref && !options.flatten.include?(@ref) && @ref =~ /\A[0-9a-zA-Z]{6,52}\z/
|
||||
options << ['Commit', [@ref]]
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -60,4 +60,18 @@ module ApplicationSettingsHelper
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
def oauth_providers_checkboxes
|
||||
button_based_providers.map do |source|
|
||||
disabled = current_application_settings.disabled_oauth_sign_in_sources.include?(source.to_s)
|
||||
css_class = 'btn'
|
||||
css_class << ' active' unless disabled
|
||||
checkbox_name = 'application_setting[enabled_oauth_sign_in_sources][]'
|
||||
|
||||
label_tag(checkbox_name, class: css_class) do
|
||||
check_box_tag(checkbox_name, source, !disabled,
|
||||
autocomplete: 'off') + Gitlab::OAuth::Provider.label_for(source)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -38,6 +38,16 @@ module AuthHelper
|
|||
auth_providers.reject { |provider| form_based_provider?(provider) }
|
||||
end
|
||||
|
||||
def enabled_button_based_providers
|
||||
disabled_providers = current_application_settings.disabled_oauth_sign_in_sources || []
|
||||
|
||||
button_based_providers.map(&:to_s) - disabled_providers
|
||||
end
|
||||
|
||||
def button_based_providers_enabled?
|
||||
enabled_button_based_providers.any?
|
||||
end
|
||||
|
||||
def provider_image_tag(provider, size = 64)
|
||||
label = label_for_provider(provider)
|
||||
|
||||
|
|
|
|||
|
|
@ -184,4 +184,14 @@ module BlobHelper
|
|||
Other: licenses.reject(&:featured).map { |license| [license.name, license.key] }
|
||||
}
|
||||
end
|
||||
|
||||
def gitignore_names
|
||||
return @gitignore_names if defined?(@gitignore_names)
|
||||
|
||||
@gitignore_names = {
|
||||
Global: Gitlab::Gitignore.global.map { |gitignore| { name: gitignore.name } },
|
||||
# Note that the key here doesn't cover it really
|
||||
Languages: Gitlab::Gitignore.languages_frameworks.map{ |gitignore| { name: gitignore.name } }
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -38,19 +38,30 @@ module CiStatusHelper
|
|||
icon(icon_name + ' fw')
|
||||
end
|
||||
|
||||
def render_ci_status(ci_commit, tooltip_placement: 'auto left')
|
||||
# TODO: split this method into
|
||||
# - render_commit_status
|
||||
# - render_pipeline_status
|
||||
link_to ci_icon_for_status(ci_commit.status),
|
||||
ci_status_path(ci_commit),
|
||||
class: "ci-status-link ci-status-icon-#{ci_commit.status.dasherize}",
|
||||
title: "Build #{ci_label_for_status(ci_commit.status)}",
|
||||
data: { toggle: 'tooltip', placement: tooltip_placement }
|
||||
def render_commit_status(commit, tooltip_placement: 'auto left')
|
||||
project = commit.project
|
||||
path = builds_namespace_project_commit_path(project.namespace, project, commit)
|
||||
render_status_with_link('commit', commit.status, path, tooltip_placement)
|
||||
end
|
||||
|
||||
def render_pipeline_status(pipeline, tooltip_placement: 'auto left')
|
||||
project = pipeline.project
|
||||
path = namespace_project_pipeline_path(project.namespace, project, pipeline)
|
||||
render_status_with_link('pipeline', pipeline.status, path, tooltip_placement)
|
||||
end
|
||||
|
||||
def no_runners_for_project?(project)
|
||||
project.runners.blank? &&
|
||||
Ci::Runner.shared.blank?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def render_status_with_link(type, status, path, tooltip_placement)
|
||||
link_to ci_icon_for_status(status),
|
||||
path,
|
||||
class: "ci-status-link ci-status-icon-#{status.dasherize}",
|
||||
title: "#{type.titleize}: #{ci_label_for_status(status)}",
|
||||
data: { toggle: 'tooltip', placement: tooltip_placement }
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ module DiffHelper
|
|||
def mark_inline_diffs(old_line, new_line)
|
||||
old_diffs, new_diffs = Gitlab::Diff::InlineDiff.new(old_line, new_line).inline_diffs
|
||||
|
||||
marked_old_line = Gitlab::Diff::InlineDiffMarker.new(old_line).mark(old_diffs)
|
||||
marked_new_line = Gitlab::Diff::InlineDiffMarker.new(new_line).mark(new_diffs)
|
||||
marked_old_line = Gitlab::Diff::InlineDiffMarker.new(old_line).mark(old_diffs, mode: :deletion)
|
||||
marked_new_line = Gitlab::Diff::InlineDiffMarker.new(new_line).mark(new_diffs, mode: :addition)
|
||||
|
||||
[marked_old_line, marked_new_line]
|
||||
end
|
||||
|
|
@ -55,22 +55,18 @@ module DiffHelper
|
|||
end
|
||||
end
|
||||
|
||||
def line_comments
|
||||
@line_comments ||= @line_notes.select(&:active?).sort_by(&:created_at).group_by(&:line_code)
|
||||
end
|
||||
def organize_comments(left, right)
|
||||
notes_left = notes_right = nil
|
||||
|
||||
def organize_comments(type_left, type_right, line_code_left, line_code_right)
|
||||
comments_left = comments_right = nil
|
||||
|
||||
unless type_left.nil? && type_right == 'new'
|
||||
comments_left = line_comments[line_code_left]
|
||||
unless left[:type].nil? && right[:type] == 'new'
|
||||
notes_left = @grouped_diff_notes[left[:line_code]]
|
||||
end
|
||||
|
||||
unless type_left.nil? && type_right.nil?
|
||||
comments_right = line_comments[line_code_right]
|
||||
unless left[:type].nil? && right[:type].nil?
|
||||
notes_right = @grouped_diff_notes[right[:line_code]]
|
||||
end
|
||||
|
||||
[comments_left, comments_right]
|
||||
[notes_left, notes_right]
|
||||
end
|
||||
|
||||
def inline_diff_btn
|
||||
|
|
@ -96,8 +92,8 @@ module DiffHelper
|
|||
].join(' ').html_safe
|
||||
end
|
||||
|
||||
def commit_for_diff(diff)
|
||||
if diff.deleted_file
|
||||
def commit_for_diff(diff_file)
|
||||
if diff_file.deleted_file
|
||||
@base_commit || @commit.parent || @commit
|
||||
else
|
||||
@commit
|
||||
|
|
|
|||
|
|
@ -32,12 +32,6 @@ module EmailsHelper
|
|||
nil
|
||||
end
|
||||
|
||||
def color_email_diff(diffcontent)
|
||||
formatter = Rouge::Formatters::HTML.new(css_class: 'highlight', inline_theme: 'github')
|
||||
lexer = Rouge::Lexers::Diff
|
||||
raw formatter.format(lexer.lex(diffcontent))
|
||||
end
|
||||
|
||||
def password_reset_token_valid_time
|
||||
valid_hours = Devise.reset_password_within / 60 / 60
|
||||
if valid_hours >= 24
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ module EventsHelper
|
|||
author = event.author
|
||||
|
||||
if author
|
||||
link_to author.name, user_path(author.username), title: h(author.name)
|
||||
link_to author.name, user_path(author.username), title: author.name
|
||||
else
|
||||
event.author_name
|
||||
end
|
||||
|
|
@ -39,15 +39,6 @@ module EventsHelper
|
|||
end
|
||||
end
|
||||
|
||||
def icon_for_event
|
||||
{
|
||||
EventFilter.push => 'upload',
|
||||
EventFilter.merged => 'check-square-o',
|
||||
EventFilter.comments => 'comments',
|
||||
EventFilter.team => 'user',
|
||||
}
|
||||
end
|
||||
|
||||
def event_preposition(event)
|
||||
if event.push? || event.commented? || event.target
|
||||
"at"
|
||||
|
|
@ -66,11 +57,7 @@ module EventsHelper
|
|||
words << event.ref_name
|
||||
words << "at"
|
||||
elsif event.commented?
|
||||
if event.note_commit?
|
||||
words << event.note_short_commit_id
|
||||
else
|
||||
words << "##{truncate event.note_target_iid}"
|
||||
end
|
||||
words << event.note_target_reference
|
||||
words << "at"
|
||||
elsif event.milestone?
|
||||
words << "##{event.target_iid}" if event.target_iid
|
||||
|
|
@ -93,21 +80,12 @@ module EventsHelper
|
|||
elsif event.merge_request?
|
||||
namespace_project_merge_request_url(event.project.namespace,
|
||||
event.project, event.merge_request)
|
||||
elsif event.note? && event.note_commit?
|
||||
elsif event.note? && event.commit_note?
|
||||
namespace_project_commit_url(event.project.namespace, event.project,
|
||||
event.note_target)
|
||||
elsif event.note?
|
||||
if event.note_target
|
||||
if event.note_commit?
|
||||
namespace_project_commit_path(event.project.namespace, event.project,
|
||||
event.note_commit_id,
|
||||
anchor: dom_id(event.target))
|
||||
elsif event.note_project_snippet?
|
||||
namespace_project_snippet_path(event.project.namespace,
|
||||
event.project, event.note_target)
|
||||
else
|
||||
event_note_target_path(event)
|
||||
end
|
||||
event_note_target_path(event)
|
||||
end
|
||||
elsif event.push?
|
||||
push_event_feed_url(event)
|
||||
|
|
@ -143,42 +121,30 @@ module EventsHelper
|
|||
end
|
||||
|
||||
def event_note_target_path(event)
|
||||
if event.note? && event.note_commit?
|
||||
namespace_project_commit_path(event.project.namespace, event.project,
|
||||
event.note_target)
|
||||
if event.note? && event.commit_note?
|
||||
namespace_project_commit_path(event.project.namespace,
|
||||
event.project,
|
||||
event.note_target,
|
||||
anchor: dom_id(event.target))
|
||||
elsif event.project_snippet_note?
|
||||
namespace_project_snippet_path(event.project.namespace,
|
||||
event.project,
|
||||
event.note_target,
|
||||
anchor: dom_id(event.target))
|
||||
else
|
||||
polymorphic_path([event.project.namespace.becomes(Namespace),
|
||||
event.project, event.note_target],
|
||||
anchor: dom_id(event.target))
|
||||
anchor: dom_id(event.target))
|
||||
end
|
||||
end
|
||||
|
||||
def event_note_title_html(event)
|
||||
if event.note_target
|
||||
if event.note_commit?
|
||||
link_to(
|
||||
namespace_project_commit_path(event.project.namespace, event.project,
|
||||
event.note_commit_id,
|
||||
anchor: dom_id(event.target), title: h(event.target_title)),
|
||||
class: "commit_short_id"
|
||||
) do
|
||||
"#{event.note_target_type} #{event.note_short_commit_id}"
|
||||
end
|
||||
elsif event.note_project_snippet?
|
||||
link_to(namespace_project_snippet_path(event.project.namespace,
|
||||
event.project,
|
||||
event.note_target), title: h(event.project.name)) do
|
||||
"#{event.note_target_type} #{truncate event.note_target.to_reference}"
|
||||
end
|
||||
else
|
||||
link_to event_note_target_path(event) do
|
||||
"#{event.note_target_type} #{truncate event.note_target.to_reference}"
|
||||
end
|
||||
link_to(event_note_target_path(event), title: event.target_title, class: 'has-tooltip') do
|
||||
"#{event.note_target_type} #{event.note_target_reference}"
|
||||
end
|
||||
else
|
||||
content_tag :strong do
|
||||
"(deleted)"
|
||||
end
|
||||
content_tag(:strong, '(deleted)')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ module GitlabMarkdownHelper
|
|||
def link_to_gfm(body, url, html_options = {})
|
||||
return "" if body.blank?
|
||||
|
||||
escaped_body = if body =~ /\A\<img/
|
||||
escaped_body = if body.start_with?('<img')
|
||||
body
|
||||
else
|
||||
escape_once(body)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,10 @@ module GitlabRoutingHelper
|
|||
namespace_project_builds_path(project.namespace, project, *args)
|
||||
end
|
||||
|
||||
def project_container_registry_path(project, *args)
|
||||
namespace_project_container_registry_index_path(project.namespace, project, *args)
|
||||
end
|
||||
|
||||
def activity_project_path(project, *args)
|
||||
activity_namespace_project_path(project.namespace, project, *args)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -43,4 +43,12 @@ module NavHelper
|
|||
class_name += " with-horizontal-nav" if defined?(nav) && nav
|
||||
class_name
|
||||
end
|
||||
|
||||
def layout_nav_class
|
||||
"page-with-layout-nav" if defined?(nav) && nav
|
||||
end
|
||||
|
||||
def layout_dropdown_class
|
||||
"controls-dropdown-visible" if current_user
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
module NotesHelper
|
||||
# Helps to distinguish e.g. commit notes in mr notes list
|
||||
def note_for_main_target?(note)
|
||||
(@noteable.class.name == note.noteable_type && !note.for_diff_line?)
|
||||
@noteable.class.name == note.noteable_type && !note.diff_note?
|
||||
end
|
||||
|
||||
def note_target_fields(note)
|
||||
|
|
@ -15,16 +15,6 @@ module NotesHelper
|
|||
note.editable? && can?(current_user, :admin_note, note)
|
||||
end
|
||||
|
||||
def link_to_commit_diff_line_note(note)
|
||||
if note.for_commit_diff_line?
|
||||
link_to(
|
||||
"#{note.diff_file_name}:L#{note.diff_new_line}",
|
||||
namespace_project_commit_path(@project.namespace, @project,
|
||||
note.noteable, anchor: note.line_code)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def noteable_json(noteable)
|
||||
{
|
||||
id: noteable.id,
|
||||
|
|
@ -35,7 +25,7 @@ module NotesHelper
|
|||
end
|
||||
|
||||
def link_to_new_diff_note(line_code, line_type = nil)
|
||||
discussion_id = Note.build_discussion_id(
|
||||
discussion_id = LegacyDiffNote.build_discussion_id(
|
||||
@comments_target[:noteable_type],
|
||||
@comments_target[:noteable_id] || @comments_target[:commit_id],
|
||||
line_code
|
||||
|
|
@ -45,9 +35,10 @@ module NotesHelper
|
|||
noteable_type: @comments_target[:noteable_type],
|
||||
noteable_id: @comments_target[:noteable_id],
|
||||
commit_id: @comments_target[:commit_id],
|
||||
line_type: line_type,
|
||||
line_code: line_code,
|
||||
discussion_id: discussion_id,
|
||||
line_type: line_type
|
||||
note_type: LegacyDiffNote.name,
|
||||
discussion_id: discussion_id
|
||||
}
|
||||
|
||||
button_tag(class: 'btn add-diff-note js-add-diff-note-button',
|
||||
|
|
@ -57,18 +48,24 @@ module NotesHelper
|
|||
end
|
||||
end
|
||||
|
||||
def link_to_reply_diff(note, line_type = nil)
|
||||
def link_to_reply_discussion(note, line_type = nil)
|
||||
return unless current_user
|
||||
|
||||
data = {
|
||||
noteable_type: note.noteable_type,
|
||||
noteable_id: note.noteable_id,
|
||||
commit_id: note.commit_id,
|
||||
line_code: note.line_code,
|
||||
discussion_id: note.discussion_id,
|
||||
line_type: line_type
|
||||
}
|
||||
|
||||
if note.diff_note?
|
||||
data.merge!(
|
||||
line_code: note.line_code,
|
||||
note_type: LegacyDiffNote.name
|
||||
)
|
||||
end
|
||||
|
||||
button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button',
|
||||
data: data, title: 'Add a reply'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -124,11 +124,7 @@ module ProjectsHelper
|
|||
end
|
||||
|
||||
def license_short_name(project)
|
||||
no_license_key = project.repository.license_key.nil? ||
|
||||
# Back-compat if cache contains 'no-license', can be removed in a few weeks
|
||||
project.repository.license_key == 'no-license'
|
||||
|
||||
return 'LICENSE' if no_license_key
|
||||
return 'LICENSE' if project.repository.license_key.nil?
|
||||
|
||||
license = Licensee::License.new(project.repository.license_key)
|
||||
|
||||
|
|
@ -138,20 +134,28 @@ module ProjectsHelper
|
|||
private
|
||||
|
||||
def get_project_nav_tabs(project, current_user)
|
||||
nav_tabs = [:home, :forks]
|
||||
nav_tabs = [:home]
|
||||
|
||||
if !project.empty_repo? && can?(current_user, :download_code, project)
|
||||
nav_tabs << [:files, :commits, :network, :graphs]
|
||||
nav_tabs << [:files, :commits, :network, :graphs, :forks]
|
||||
end
|
||||
|
||||
if project.repo_exists? && can?(current_user, :read_merge_request, project)
|
||||
nav_tabs << :merge_requests
|
||||
end
|
||||
|
||||
if can?(current_user, :read_pipeline, project)
|
||||
nav_tabs << :pipelines
|
||||
end
|
||||
|
||||
if can?(current_user, :read_build, project)
|
||||
nav_tabs << :builds
|
||||
end
|
||||
|
||||
if Gitlab.config.registry.enabled && can?(current_user, :read_container_image, project)
|
||||
nav_tabs << :container_registry
|
||||
end
|
||||
|
||||
if can?(current_user, :admin_project, project)
|
||||
nav_tabs << :settings
|
||||
end
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ module SearchHelper
|
|||
# Autocomplete results for the current project, if it's defined
|
||||
def project_autocomplete
|
||||
if @project && @project.repository.exists? && @project.repository.root_ref
|
||||
ref = @ref || @project.repository.root_ref
|
||||
ref = @ref || @project.repository.root_ref
|
||||
|
||||
[
|
||||
{ category: "Current Project", label: "Files", url: namespace_project_tree_path(@project.namespace, @project, ref) },
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ module SelectsHelper
|
|||
first_user: first_user,
|
||||
current_user: opts[:current_user] || false,
|
||||
"push-code-to-protected-branches" => opts[:push_code_to_protected_branches],
|
||||
author_id: opts[:author_id] || ''
|
||||
author_id: opts[:author_id] || ''
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ module TabHelper
|
|||
end
|
||||
|
||||
def profile_tab_class
|
||||
if controller.controller_path =~ /\Aprofiles/
|
||||
if controller.controller_path.start_with?('profiles')
|
||||
return 'active'
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ module TodosHelper
|
|||
case todo.action
|
||||
when Todo::ASSIGNED then 'assigned you'
|
||||
when Todo::MENTIONED then 'mentioned you on'
|
||||
when Todo::BUILD_FAILED then 'The build failed for your'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -28,8 +29,11 @@ module TodosHelper
|
|||
namespace_project_commit_path(todo.project.namespace.becomes(Namespace), todo.project,
|
||||
todo.target, anchor: anchor)
|
||||
else
|
||||
polymorphic_path([todo.project.namespace.becomes(Namespace),
|
||||
todo.project, todo.target], anchor: anchor)
|
||||
path = [todo.project.namespace.becomes(Namespace), todo.project, todo.target]
|
||||
|
||||
path.unshift(:builds) if todo.build_failed?
|
||||
|
||||
polymorphic_path(path, anchor: anchor)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue