Merge branch 'master' into diverging-branch-graphs
This commit is contained in:
commit
932a7fd96f
|
@ -43,3 +43,4 @@ rails_best_practices_output.html
|
|||
tmp/
|
||||
vendor/bundle/*
|
||||
builds/*
|
||||
shared/*
|
||||
|
|
|
@ -80,7 +80,6 @@ flog:
|
|||
tags:
|
||||
- ruby
|
||||
- mysql
|
||||
allow_failure: true
|
||||
|
||||
flay:
|
||||
script:
|
||||
|
@ -88,4 +87,12 @@ flay:
|
|||
tags:
|
||||
- ruby
|
||||
- mysql
|
||||
|
||||
bundler:audit:
|
||||
script:
|
||||
- "bundle exec bundle-audit update"
|
||||
- "bundle exec bundle-audit check"
|
||||
tags:
|
||||
- ruby
|
||||
- mysql
|
||||
allow_failure: true
|
||||
|
|
|
@ -888,7 +888,7 @@ Lint/RequireParentheses:
|
|||
Lint/RescueException:
|
||||
Description: 'Avoid rescuing the Exception class.'
|
||||
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-blind-rescues'
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
Lint/ShadowingOuterLocalVariable:
|
||||
Description: >-
|
||||
|
|
|
@ -1 +1 @@
|
|||
2.1.6
|
||||
2.1.7
|
||||
|
|
50
CHANGELOG
50
CHANGELOG
|
@ -1,12 +1,41 @@
|
|||
Please view this file on the master branch, on stable branches it's out of date.
|
||||
|
||||
v 8.2.0 (unreleased)
|
||||
- Remove CSS property preventing hard tabs from rendering in Chromium 45 (Stan Hu)
|
||||
v 8.3.0 (unreleased)
|
||||
- Fix: Assignee selector is empty when 'Unassigned' is selected (Jose Corcuera)
|
||||
- Fix 500 error when update group member permission
|
||||
- Trim leading and trailing whitespace of milestone and issueable titles (Jose Corcuera)
|
||||
- Add ignore whitespace change option to commit view
|
||||
- Fire update hook from GitLab
|
||||
- Don't show project fork event as "imported"
|
||||
|
||||
v 8.2.2
|
||||
- Fix 404 in redirection after removing a project (Stan Hu)
|
||||
- Ensure cached application settings are refreshed at startup (Stan Hu)
|
||||
- Fix Error 500 when viewing user's personal projects from admin page (Stan Hu)
|
||||
- Fix: Raw private snippets access workflow
|
||||
- Prevent "413 Request entity too large" errors when pushing large files with LFS
|
||||
- Fix invalid links within projects dashboard header
|
||||
|
||||
v 8.2.1
|
||||
- Forcefully update builds that didn't want to update with state machine
|
||||
- Fix: saving GitLabCiService as Admin Template
|
||||
|
||||
v 8.2.0
|
||||
- Improved performance of finding projects and groups in various places
|
||||
- Improved performance of rendering user profile pages and Atom feeds
|
||||
- Expose build artifacts path as config option
|
||||
- Fix grouping of contributors by email in graph.
|
||||
- Improved performance of finding issues with/without labels
|
||||
- Fix Drone CI service template not saving properly (Stan Hu)
|
||||
- Fix avatars not showing in Atom feeds and project issues when Gravatar disabled (Stan Hu)
|
||||
- Added a GitLab specific profiling tool called "Sherlock" (see GitLab CE merge request #1749)
|
||||
- Upgrade gitlab_git to 7.2.20 and rugged to 0.23.3 (Stan Hu)
|
||||
- Improved performance of finding users by one of their Email addresses
|
||||
- Add allow_failure field to commit status API (Stan Hu)
|
||||
- Commits without .gitlab-ci.yml are marked as skipped
|
||||
- Save detailed error when YAML syntax is invalid
|
||||
- Since GitLab CI is enabled by default, remove enabling it by pushing .gitlab-ci.yml
|
||||
- Added build artifacts
|
||||
- Improved performance of replacing references in comments
|
||||
- Show last project commit to default branch on project home page
|
||||
- Highlight comment based on anchor in URL
|
||||
|
@ -20,21 +49,37 @@ v 8.2.0 (unreleased)
|
|||
- Send build name and stage in CI notification e-mail
|
||||
- Extend yml syntax for only and except to support specifying repository path
|
||||
- Enable shared runners to all new projects
|
||||
- Bump GitLab-Workhorse to 0.4.1
|
||||
- Allow to define cache in `.gitlab-ci.yml`
|
||||
- Fix: 500 error returned if destroy request without HTTP referer (Kazuki Shimizu)
|
||||
- Remove deprecated CI events from project settings page
|
||||
- Use issue editor as cross reference comment author when issue is edited with a new mention.
|
||||
- Add graphs of commits ahead and behind default branch (Jeff Stubler)
|
||||
- Improve personal snippet access workflow (Douglas Alexandre)
|
||||
- [API] Add ability to fetch the commit ID of the last commit that actually touched a file
|
||||
- Fix omniauth documentation setting for omnibus configuration (Jon Cairns)
|
||||
- Add "New file" link to dropdown on project page
|
||||
- Include commit logs in project search
|
||||
- Add "added", "modified" and "removed" properties to commit object in webhook
|
||||
- Rename "Back to" links to "Go to" because its not always a case it point to place user come from
|
||||
- Allow groups to appear in the search results if the group owner allows it
|
||||
- Add email notification to former assignee upon unassignment (Adam Lieskovský)
|
||||
- New design for project graphs page
|
||||
- Remove deprecated dumped yaml file generated from previous job definitions
|
||||
- Fix incoming email config defaults
|
||||
- Show specific runners from projects where user is master or owner
|
||||
- MR target branch is now visible on a list view when it is different from project's default one
|
||||
- Improve Continuous Integration graphs page
|
||||
- Make color of "Accept Merge Request" button consistent with current build status
|
||||
- Add ignore white space option in merge request diff and commit and compare view
|
||||
- Ability to add release notes (markdown text and attachments) to git tags (aka Releases)
|
||||
- Relative links from a repositories README.md now link to the default branch
|
||||
- Fix trailing whitespace issue in merge request/issue title
|
||||
- Fix bug when milestone/label filter was empty for dashboard issues page
|
||||
- Add ability to create milestone in group projects from single form
|
||||
- Add option to create merge request when editing/creating a file (Dirceu Tiegs)
|
||||
- Prevent the last owner of a group from being able to delete themselves by 'adding' themselves as a master (James Lopez)
|
||||
- Add Award Emoji to issue and merge request pages
|
||||
|
||||
v 8.1.4
|
||||
- Fix bug where manually merged branches in a MR would end up with an empty diff (Stan Hu)
|
||||
|
@ -104,7 +149,6 @@ v 8.1.0
|
|||
- Show CI status on Your projects page and Starred projects page
|
||||
- Remove "Continuous Integration" page from dashboard
|
||||
- Add notes and SSL verification entries to hook APIs (Ben Boeckel)
|
||||
- Added build artifacts
|
||||
- Fix grammar in admin area "labels" .nothing-here-block when no labels exist.
|
||||
- Move CI runners page to project settings area
|
||||
- Move CI variables page to project settings area
|
||||
|
|
|
@ -10,7 +10,7 @@ By submitting code as an individual you agree to the [individual contributor lic
|
|||
|
||||
## Security vulnerability disclosure
|
||||
|
||||
Please report suspected security vulnerabilities in private to support@gitlab.com, also see the [disclosure section on the GitLab.com website](http://about.gitlab.com/disclosure/). Please do NOT create publicly viewable issues for suspected security vulnerabilities.
|
||||
Please report suspected security vulnerabilities in private to support@gitlab.com, also see the [disclosure section on the GitLab.com website](https://about.gitlab.com/disclosure/). Please do NOT create publicly viewable issues for suspected security vulnerabilities.
|
||||
|
||||
## Closing policy for issues and merge requests
|
||||
|
||||
|
@ -23,10 +23,20 @@ Issues and merge requests should be in English and contain appropriate language
|
|||
## Helping others
|
||||
|
||||
Please help other GitLab users when you can.
|
||||
The channnels people will reach out on can be found on the [getting help page](https://about.gitlab.com/getting-help/).
|
||||
Sign up for the mailinglist, answer GitLab questions on StackOverflow or respond in the irc channel.
|
||||
The channels people will reach out on can be found on the [getting help page](https://about.gitlab.com/getting-help/).
|
||||
Sign up for the mailinglist, answer GitLab questions on StackOverflow or respond in the IRC channel.
|
||||
You can also sign up on [CodeTriage](http://www.codetriage.com/gitlabhq/gitlabhq) to help with one issue every day.
|
||||
|
||||
## I want to contribute!
|
||||
|
||||
If you want to contribute to GitLab, but are not sure where to start,
|
||||
look for [issues](https://gitlab.com/gitlab-org/gitlab-ce/issues?milestone_id=&scope=all&sort=created_desc&state=opened&utf8=%E2%9C%93&assignee_id=&author_id=&milestone_title=&label_name=up-for-grabs)
|
||||
with the label `up-for-grabs`.
|
||||
These issues will be of reasonable size and challenge, for anyone to start
|
||||
contributing to GitLab.
|
||||
|
||||
This was inspired by [an article by Kent C. Dodds](https://medium.com/@kentcdodds/first-timers-only-78281ea47455#.i2f363mx4).
|
||||
|
||||
## Issue tracker
|
||||
|
||||
To get support for your particular problem please use the [getting help channels](https://about.gitlab.com/getting-help/).
|
||||
|
@ -35,7 +45,7 @@ The [GitLab CE issue tracker on GitLab.com](https://gitlab.com/gitlab-org/gitlab
|
|||
|
||||
Do not use the issue tracker for feature requests. We have a specific [feature request forum](http://feedback.gitlab.com) for this purpose. Please keep feature requests as small and simple as possible, complex ones might be edited to make them small and simple.
|
||||
|
||||
Please send a merge request with a tested solution or a merge request with a failing test instead of opening an issue if you can. If you're unsure where to post, post to the [mailing list](https://groups.google.com/forum/#!forum/gitlabhq) or [Stack Overflow](http://stackoverflow.com/questions/tagged/gitlab) first. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there.
|
||||
Please send a merge request with a tested solution or a merge request with a failing test instead of opening an issue if you can. If you're unsure where to post, post to the [mailing list](https://groups.google.com/forum/#!forum/gitlabhq) or [Stack Overflow](https://stackoverflow.com/questions/tagged/gitlab) first. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there.
|
||||
|
||||
### Issue tracker guidelines
|
||||
|
||||
|
@ -47,10 +57,10 @@ Please send a merge request with a tested solution or a merge request with a fai
|
|||
1. **Observed behavior**
|
||||
1. **Relevant logs and/or screenshots:** Please use code blocks (\`\`\`) to format console output, logs, and code as it's very hard to read otherwise.
|
||||
1. **Output of checks**
|
||||
* Results of GitLab [Application Check](doc/install/installation.md#check-application-status) (`sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true`); we will only investigate if the tests are passing
|
||||
* Results of GitLab [Application Check](doc/install/installation.md#check-application-status) (For installations with omnibus-gitlab package: `sudo gitlab-rake gitlab:check SANITIZE=true`); For installations from source: `sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true`); we will only investigate if the tests are passing
|
||||
* Version of GitLab you are running; we will only investigate issues in the latest stable and development releases as per the [maintenance policy](MAINTENANCE.md)
|
||||
* Add the last commit SHA-1 of the GitLab version you used to replicate the issue (obtainable from the help page)
|
||||
* Describe your setup (use relevant parts from `sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`)
|
||||
* Describe your setup (use relevant parts from the env info: For installations with omnibus-gitlab package: `sudo gitlab-rake gitlab:env:info`; For installations from source: `sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`)
|
||||
1. **Possible fixes**: If you can, link to the line of code that might be responsible for the problem
|
||||
|
||||
## Merge requests
|
||||
|
@ -59,7 +69,7 @@ We welcome merge requests with fixes and improvements to GitLab code, tests, and
|
|||
|
||||
Merge requests can be filed either at [gitlab.com](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests) or [github.com](https://github.com/gitlabhq/gitlabhq/pulls).
|
||||
|
||||
If you are new to GitLab development (or web development in general), search for the label `easyfix` ([gitlab.com](https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=easyfix), [github](https://github.com/gitlabhq/gitlabhq/labels/easyfix)). Those are issues easy to fix, marked by the GitLab core-team. If you are unsure how to proceed but want to help, mention one of the core-team members to give you a hint.
|
||||
If you are new to GitLab development (or web development in general), search for the label `easyfix` ([GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=easyfix), [GitHub](https://github.com/gitlabhq/gitlabhq/labels/easyfix)). Those are issues easy to fix, marked by the GitLab core-team. If you are unsure how to proceed but want to help, mention one of the core-team members to give you a hint.
|
||||
|
||||
To start with GitLab download the [GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit) and see [Development section](doc/development/README.md) in the help file.
|
||||
|
||||
|
@ -72,7 +82,7 @@ If you can, please submit a merge request with the fix or improvements including
|
|||
1. Write [tests](https://gitlab.com/gitlab-org/gitlab-development-kit#running-the-tests) and code
|
||||
1. Add your changes to the [CHANGELOG](CHANGELOG)
|
||||
1. If you are changing the README, some documentation or other things which have no effect on the tests, add `[ci skip]` somewhere in the commit message
|
||||
1. If you have multiple commits please combine them into one commit by [squashing them](http://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
|
||||
1. If you have multiple commits please combine them into one commit by [squashing them](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
|
||||
1. Push the commit to your fork
|
||||
1. Submit a merge request (MR) to the master branch
|
||||
1. The MR title should describe the change you want to make
|
||||
|
@ -99,7 +109,7 @@ If you contribute to GitLab please know that changes involve more than just code
|
|||
We have the following [definition of done](http://guide.agilealliance.org/guide/definition-of-done.html).
|
||||
Please ensure you support the feature you contribute through all of these steps.
|
||||
|
||||
1. Description explaning the relevancy (see following item)
|
||||
1. Description explaining the relevancy (see following item)
|
||||
1. Working and clean code that is commented where needed
|
||||
1. Unit and integration tests that pass on the CI server
|
||||
1. Documented in the /doc directory
|
||||
|
@ -163,7 +173,7 @@ If you add a dependency in GitLab (such as an operating system package) please c
|
|||
1. [Markdown](http://www.cirosantilli.com/markdown-styleguide)
|
||||
1. [Database Migrations](doc/development/migration_style_guide.md)
|
||||
1. [Documentation styleguide](doc_styleguide.md)
|
||||
1. Interface text should be written subjectively instead of objectively. It should be the gitlab core team addressing a person. It should be written in present time and never use past tense (has been/was). For example instead of "prohibited this user from being saved due to the following errors:" the text should be "sorry, we could not create your account because:". Also these [excellent writing guidelines](https://github.com/NARKOZ/guides#writing).
|
||||
1. Interface text should be written subjectively instead of objectively. It should be the GitLab core team addressing a person. It should be written in present time and never use past tense (has been/was). For example instead of "prohibited this user from being saved due to the following errors:" the text should be "sorry, we could not create your account because:". Also these [excellent writing guidelines](https://github.com/NARKOZ/guides#writing).
|
||||
|
||||
This is also the style used by linting tools such as [RuboCop](https://github.com/bbatsov/rubocop), [PullReview](https://www.pullreview.com/) and [Hound CI](https://houndci.com).
|
||||
|
||||
|
@ -181,4 +191,4 @@ This code of conduct applies both within project spaces and in public spaces whe
|
|||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior can be reported by emailing contact@gitlab.com
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.1.0, available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/)
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.1.0, available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/)
|
||||
|
|
|
@ -1 +1 @@
|
|||
2.6.6
|
||||
2.6.8
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.3.1
|
||||
0.4.2
|
||||
|
|
29
Gemfile
29
Gemfile
|
@ -1,6 +1,10 @@
|
|||
source "https://rubygems.org"
|
||||
|
||||
gem 'rails', '4.1.12'
|
||||
gem 'rails', '4.2.4'
|
||||
gem 'rails-deprecated_sanitizer', '~> 1.0.3'
|
||||
|
||||
# Responders respond_to and respond_with
|
||||
gem 'responders', '~> 2.0'
|
||||
|
||||
# Specify a sprockets version due to security issue
|
||||
# See https://groups.google.com/forum/#!topic/rubyonrails-security/doAVp0YaTqY
|
||||
|
@ -16,7 +20,7 @@ gem "pg", '~> 0.18.2', group: :postgres
|
|||
# Authentication libraries
|
||||
gem 'devise', '~> 3.5.2'
|
||||
gem 'devise-async', '~> 0.9.0'
|
||||
gem 'doorkeeper', '~> 2.1.3'
|
||||
gem 'doorkeeper', '~> 2.2.0'
|
||||
gem 'omniauth', '~> 1.2.2'
|
||||
gem 'omniauth-bitbucket', '~> 0.0.2'
|
||||
gem 'omniauth-facebook', '~> 3.0.0'
|
||||
|
@ -28,7 +32,7 @@ gem 'omniauth-saml', '~> 1.4.0'
|
|||
gem 'omniauth-shibboleth', '~> 1.2.0'
|
||||
gem 'omniauth-twitter', '~> 1.2.0'
|
||||
gem 'omniauth_crowd'
|
||||
gem 'rack-oauth2', '~> 1.0.5'
|
||||
gem 'rack-oauth2', '~> 1.2.1'
|
||||
|
||||
# Two-factor authentication
|
||||
gem 'devise-two-factor', '~> 2.0.0'
|
||||
|
@ -62,9 +66,6 @@ gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
|
|||
# based on human-friendly examples
|
||||
gem "stamp", '~> 0.6.0'
|
||||
|
||||
# Enumeration fields
|
||||
gem 'enumerize', '~> 0.7.0'
|
||||
|
||||
# Pagination
|
||||
gem "kaminari", "~> 0.16.3"
|
||||
|
||||
|
@ -95,9 +96,10 @@ gem 'redcarpet', '~> 3.3.3'
|
|||
gem 'RedCloth', '~> 4.2.9'
|
||||
gem 'rdoc', '~>3.6'
|
||||
gem 'org-ruby', '~> 0.9.12'
|
||||
gem 'creole', '~>0.3.6'
|
||||
gem 'creole', '~> 0.5.0'
|
||||
gem 'wikicloth', '0.8.1'
|
||||
gem 'asciidoctor', '~> 1.5.2'
|
||||
gem 'net-ssh', '~> 3.0.1'
|
||||
|
||||
# Diffs
|
||||
gem 'diffy', '~> 3.0.3'
|
||||
|
@ -125,8 +127,7 @@ gem 'sidetiq', '~> 0.6.3'
|
|||
gem "httparty", '~> 0.13.3'
|
||||
|
||||
# Colored output to console
|
||||
gem "colored", '~> 1.2'
|
||||
gem "colorize", '~> 0.5.8'
|
||||
gem "colorize", '~> 0.7.0'
|
||||
|
||||
# GitLab settings
|
||||
gem 'settingslogic', '~> 2.0.9'
|
||||
|
@ -154,7 +155,7 @@ gem "gemnasium-gitlab-service", "~> 0.2"
|
|||
gem "slack-notifier", "~> 1.2.0"
|
||||
|
||||
# Asana integration
|
||||
gem 'asana', '~> 0.0.6'
|
||||
gem 'asana', '~> 0.4.0'
|
||||
|
||||
# FogBugz integration
|
||||
gem 'ruby-fogbugz', '~> 0.2.1'
|
||||
|
@ -187,13 +188,13 @@ gem "sass-rails", '~> 4.0.5'
|
|||
gem "coffee-rails", '~> 4.1.0'
|
||||
gem "uglifier", '~> 2.7.2'
|
||||
gem 'turbolinks', '~> 2.5.0'
|
||||
gem 'jquery-turbolinks', '~> 2.0.1'
|
||||
gem 'jquery-turbolinks', '~> 2.1.0'
|
||||
|
||||
gem 'addressable', '~> 2.3.8'
|
||||
gem 'bootstrap-sass', '~> 3.0'
|
||||
gem 'font-awesome-rails', '~> 4.2'
|
||||
gem 'gitlab_emoji', '~> 0.1'
|
||||
gem 'gon', '~> 5.0.0'
|
||||
gem 'gon', '~> 6.0.1'
|
||||
gem 'jquery-atwho-rails', '~> 1.3.2'
|
||||
gem 'jquery-rails', '~> 3.1.3'
|
||||
gem 'jquery-scrollto-rails', '~> 1.4.3'
|
||||
|
@ -214,6 +215,7 @@ group :development do
|
|||
gem 'rerun', '~> 0.10.0'
|
||||
gem 'bullet', require: false
|
||||
gem 'rblineprof', platform: :mri, require: false
|
||||
gem 'web-console', '~> 2.0'
|
||||
|
||||
# Better errors handler
|
||||
gem 'better_errors', '~> 1.0.1'
|
||||
|
@ -261,6 +263,7 @@ group :development, :test do
|
|||
gem 'simplecov', '~> 0.10.0', require: false
|
||||
gem 'flog', require: false
|
||||
gem 'flay', require: false
|
||||
gem 'bundler-audit', require: false
|
||||
|
||||
gem 'benchmark-ips', require: false
|
||||
end
|
||||
|
@ -269,7 +272,7 @@ group :test do
|
|||
gem 'shoulda-matchers', '~> 2.8.0', require: false
|
||||
gem 'email_spec', '~> 1.6.0'
|
||||
gem 'webmock', '~> 1.21.0'
|
||||
gem 'test_after_commit', '~> 0.2.2'
|
||||
gem 'test_after_commit', '~> 0.4.2'
|
||||
gem 'sham_rack'
|
||||
end
|
||||
|
||||
|
|
285
Gemfile.lock
285
Gemfile.lock
|
@ -1,63 +1,71 @@
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (2.3.1)
|
||||
CFPropertyList (2.3.2)
|
||||
RedCloth (4.2.9)
|
||||
ace-rails-ap (2.0.1)
|
||||
actionmailer (4.1.12)
|
||||
actionpack (= 4.1.12)
|
||||
actionview (= 4.1.12)
|
||||
actionmailer (4.2.4)
|
||||
actionpack (= 4.2.4)
|
||||
actionview (= 4.2.4)
|
||||
activejob (= 4.2.4)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
actionpack (4.1.12)
|
||||
actionview (= 4.1.12)
|
||||
activesupport (= 4.1.12)
|
||||
rack (~> 1.5.2)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||
actionpack (4.2.4)
|
||||
actionview (= 4.2.4)
|
||||
activesupport (= 4.2.4)
|
||||
rack (~> 1.6)
|
||||
rack-test (~> 0.6.2)
|
||||
actionview (4.1.12)
|
||||
activesupport (= 4.1.12)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||
actionview (4.2.4)
|
||||
activesupport (= 4.2.4)
|
||||
builder (~> 3.1)
|
||||
erubis (~> 2.7.0)
|
||||
activemodel (4.1.12)
|
||||
activesupport (= 4.1.12)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||
activejob (4.2.4)
|
||||
activesupport (= 4.2.4)
|
||||
globalid (>= 0.3.0)
|
||||
activemodel (4.2.4)
|
||||
activesupport (= 4.2.4)
|
||||
builder (~> 3.1)
|
||||
activerecord (4.1.12)
|
||||
activemodel (= 4.1.12)
|
||||
activesupport (= 4.1.12)
|
||||
arel (~> 5.0.0)
|
||||
activerecord (4.2.4)
|
||||
activemodel (= 4.2.4)
|
||||
activesupport (= 4.2.4)
|
||||
arel (~> 6.0)
|
||||
activerecord-deprecated_finders (1.0.4)
|
||||
activerecord-session_store (0.1.1)
|
||||
activerecord-session_store (0.1.2)
|
||||
actionpack (>= 4.0.0, < 5)
|
||||
activerecord (>= 4.0.0, < 5)
|
||||
railties (>= 4.0.0, < 5)
|
||||
activeresource (4.0.0)
|
||||
activemodel (~> 4.0)
|
||||
activesupport (~> 4.0)
|
||||
rails-observers (~> 0.1.1)
|
||||
activesupport (4.1.12)
|
||||
i18n (~> 0.6, >= 0.6.9)
|
||||
activesupport (4.2.4)
|
||||
i18n (~> 0.7)
|
||||
json (~> 1.7, >= 1.7.7)
|
||||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.1)
|
||||
thread_safe (~> 0.3, >= 0.3.4)
|
||||
tzinfo (~> 1.1)
|
||||
acts-as-taggable-on (3.5.0)
|
||||
activerecord (>= 3.2, < 5)
|
||||
addressable (2.3.8)
|
||||
after_commit_queue (1.1.0)
|
||||
rails (>= 3.0)
|
||||
after_commit_queue (1.3.0)
|
||||
activerecord (>= 3.0)
|
||||
annotate (2.6.10)
|
||||
activerecord (>= 3.2, <= 4.3)
|
||||
rake (~> 10.4)
|
||||
arel (5.0.1.20140414130214)
|
||||
asana (0.0.6)
|
||||
activeresource (>= 3.2.3)
|
||||
asciidoctor (1.5.2)
|
||||
arel (6.0.3)
|
||||
asana (0.4.0)
|
||||
faraday (~> 0.9)
|
||||
faraday_middleware (~> 0.9)
|
||||
faraday_middleware-multi_json (~> 0.0)
|
||||
oauth2 (~> 1.0)
|
||||
asciidoctor (1.5.3)
|
||||
ast (2.1.0)
|
||||
astrolabe (1.3.1)
|
||||
parser (~> 2.2)
|
||||
attr_encrypted (1.3.4)
|
||||
encryptor (>= 1.3.0)
|
||||
attr_required (1.0.0)
|
||||
autoprefixer-rails (5.2.1.2)
|
||||
autoprefixer-rails (6.1.1)
|
||||
execjs
|
||||
json
|
||||
awesome_print (1.2.0)
|
||||
|
@ -85,12 +93,15 @@ GEM
|
|||
ruby_parser (~> 3.5.0)
|
||||
sass (~> 3.0)
|
||||
terminal-table (~> 1.4)
|
||||
browser (1.0.0)
|
||||
browser (1.0.1)
|
||||
builder (3.2.2)
|
||||
bullet (4.14.9)
|
||||
bullet (4.14.10)
|
||||
activesupport (>= 3.0.0)
|
||||
uniform_notifier (~> 1.9.0)
|
||||
byebug (6.0.2)
|
||||
bundler-audit (0.4.0)
|
||||
bundler (~> 1.2)
|
||||
thor (~> 0.18)
|
||||
byebug (8.2.0)
|
||||
cal-heatmap-rails (0.0.1)
|
||||
capybara (2.4.4)
|
||||
mime-types (>= 1.16)
|
||||
|
@ -108,7 +119,7 @@ GEM
|
|||
celluloid (0.16.0)
|
||||
timers (~> 4.0.0)
|
||||
charlock_holmes (0.7.3)
|
||||
chunky_png (1.3.4)
|
||||
chunky_png (1.3.5)
|
||||
cliver (0.3.2)
|
||||
coderay (1.1.0)
|
||||
coercible (1.0.0)
|
||||
|
@ -119,19 +130,19 @@ GEM
|
|||
coffee-script (2.4.1)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.9.1.1)
|
||||
colored (1.2)
|
||||
colorize (0.5.8)
|
||||
coffee-script-source (1.10.0)
|
||||
colorize (0.7.7)
|
||||
connection_pool (2.2.0)
|
||||
coveralls (0.8.2)
|
||||
coveralls (0.8.9)
|
||||
json (~> 1.8)
|
||||
rest-client (>= 1.6.8, < 2)
|
||||
simplecov (~> 0.10.0)
|
||||
term-ansicolor (~> 1.3)
|
||||
thor (~> 0.19.1)
|
||||
tins (~> 1.6.0)
|
||||
crack (0.4.2)
|
||||
safe_yaml (~> 1.0.0)
|
||||
creole (0.3.8)
|
||||
creole (0.5.0)
|
||||
d3_rails (3.5.6)
|
||||
railties (>= 3.1.0)
|
||||
daemons (1.2.3)
|
||||
|
@ -151,7 +162,7 @@ GEM
|
|||
warden (~> 1.2.3)
|
||||
devise-async (0.9.0)
|
||||
devise (~> 3.2)
|
||||
devise-two-factor (2.0.0)
|
||||
devise-two-factor (2.0.1)
|
||||
activesupport
|
||||
attr_encrypted (~> 1.3.2)
|
||||
devise (~> 3.5.0)
|
||||
|
@ -160,19 +171,17 @@ GEM
|
|||
diff-lcs (1.2.5)
|
||||
diffy (3.0.7)
|
||||
docile (1.1.5)
|
||||
domain_name (0.5.24)
|
||||
domain_name (0.5.25)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
doorkeeper (2.1.4)
|
||||
doorkeeper (2.2.2)
|
||||
railties (>= 3.2)
|
||||
dropzonejs-rails (0.7.1)
|
||||
dropzonejs-rails (0.7.2)
|
||||
rails (> 3.1)
|
||||
email_reply_parser (0.5.8)
|
||||
email_spec (1.6.0)
|
||||
launchy (~> 2.1)
|
||||
mail (~> 2.2)
|
||||
encryptor (1.3.0)
|
||||
enumerize (0.7.0)
|
||||
activesupport (>= 3.2)
|
||||
equalizer (0.0.11)
|
||||
erubis (2.7.0)
|
||||
escape_utils (1.1.0)
|
||||
|
@ -189,6 +198,9 @@ GEM
|
|||
multipart-post (>= 1.2, < 3)
|
||||
faraday_middleware (0.10.0)
|
||||
faraday (>= 0.7.4, < 0.10)
|
||||
faraday_middleware-multi_json (0.0.6)
|
||||
faraday_middleware
|
||||
multi_json
|
||||
fastercsv (1.5.5)
|
||||
ffaker (2.0.0)
|
||||
ffi (1.9.10)
|
||||
|
@ -200,7 +212,7 @@ GEM
|
|||
flog (4.3.2)
|
||||
ruby_parser (~> 3.1, > 3.1.0)
|
||||
sexp_processor (~> 4.4)
|
||||
flowdock (0.7.0)
|
||||
flowdock (0.7.1)
|
||||
httparty (~> 0.7)
|
||||
multi_json
|
||||
fog (1.25.0)
|
||||
|
@ -222,13 +234,10 @@ GEM
|
|||
fog-core (~> 1.22)
|
||||
fog-json
|
||||
inflecto (~> 0.0.2)
|
||||
fog-core (1.32.1)
|
||||
fog-core (1.35.0)
|
||||
builder
|
||||
excon (~> 0.45)
|
||||
formatador (~> 0.2)
|
||||
mime-types
|
||||
net-scp (~> 1.1)
|
||||
net-ssh (>= 2.1.3)
|
||||
fog-json (1.0.2)
|
||||
fog-core (~> 1.0)
|
||||
multi_json (~> 1.10)
|
||||
|
@ -240,10 +249,10 @@ GEM
|
|||
fog-core (>= 1.21.0)
|
||||
fog-json
|
||||
fog-xml (>= 0.0.1)
|
||||
fog-sakuracloud (1.0.1)
|
||||
fog-sakuracloud (1.4.0)
|
||||
fog-core
|
||||
fog-json
|
||||
fog-softlayer (0.4.7)
|
||||
fog-softlayer (1.0.2)
|
||||
fog-core
|
||||
fog-json
|
||||
fog-terremark (0.1.0)
|
||||
|
@ -258,7 +267,7 @@ GEM
|
|||
fog-xml (0.1.2)
|
||||
fog-core
|
||||
nokogiri (~> 1.5, >= 1.5.11)
|
||||
font-awesome-rails (4.4.0.0)
|
||||
font-awesome-rails (4.5.0.0)
|
||||
railties (>= 3.2, < 5.0)
|
||||
foreman (0.78.0)
|
||||
thor (~> 0.19.1)
|
||||
|
@ -268,11 +277,11 @@ GEM
|
|||
ruby-progressbar (~> 1.4)
|
||||
gemnasium-gitlab-service (0.2.6)
|
||||
rugged (~> 0.21)
|
||||
gemojione (2.0.1)
|
||||
gemojione (2.1.0)
|
||||
json
|
||||
get_process_mem (0.2.0)
|
||||
gherkin-ruby (0.3.2)
|
||||
github-linguist (4.7.0)
|
||||
github-linguist (4.7.2)
|
||||
charlock_holmes (~> 0.7.3)
|
||||
escape_utils (~> 1.1.0)
|
||||
mime-types (>= 1.19)
|
||||
|
@ -287,8 +296,8 @@ GEM
|
|||
diff-lcs (~> 1.1)
|
||||
mime-types (~> 1.15)
|
||||
posix-spawn (~> 0.3)
|
||||
gitlab_emoji (0.1.1)
|
||||
gemojione (~> 2.0)
|
||||
gitlab_emoji (0.2.0)
|
||||
gemojione (~> 2.1)
|
||||
gitlab_git (7.2.20)
|
||||
activesupport (~> 4.0)
|
||||
charlock_holmes (~> 0.7.3)
|
||||
|
@ -300,6 +309,8 @@ GEM
|
|||
omniauth (~> 1.0)
|
||||
pyu-ruby-sasl (~> 0.0.3.1)
|
||||
rubyntlm (~> 0.3)
|
||||
globalid (0.3.6)
|
||||
activesupport (>= 4.1.0)
|
||||
gollum-grit_adapter (1.0.0)
|
||||
gitlab-grit (~> 2.7, >= 2.7.1)
|
||||
gollum-lib (4.0.3)
|
||||
|
@ -309,9 +320,11 @@ GEM
|
|||
rouge (~> 1.10.1)
|
||||
sanitize (~> 2.1.0)
|
||||
stringex (~> 2.5.1)
|
||||
gon (5.0.4)
|
||||
actionpack (>= 2.3.0)
|
||||
gon (6.0.1)
|
||||
actionpack (>= 3.0)
|
||||
json
|
||||
multi_json
|
||||
request_store (>= 1.0)
|
||||
grape (0.13.0)
|
||||
activesupport
|
||||
builder
|
||||
|
@ -333,7 +346,7 @@ GEM
|
|||
haml (>= 4.0.6, < 5.0)
|
||||
html2haml (>= 1.0.1)
|
||||
railties (>= 4.0.1)
|
||||
hashie (3.4.2)
|
||||
hashie (3.4.3)
|
||||
highline (1.6.21)
|
||||
hike (1.2.3)
|
||||
hipchat (1.5.2)
|
||||
|
@ -351,40 +364,42 @@ GEM
|
|||
http-cookie (1.0.2)
|
||||
domain_name (~> 0.5)
|
||||
http_parser.rb (0.5.3)
|
||||
httparty (0.13.5)
|
||||
httparty (0.13.7)
|
||||
json (~> 1.8)
|
||||
multi_xml (>= 0.5.2)
|
||||
httpclient (2.6.0.1)
|
||||
httpclient (2.7.0.1)
|
||||
i18n (0.7.0)
|
||||
ice_cube (0.11.1)
|
||||
ice_nine (0.11.1)
|
||||
inflecto (0.0.2)
|
||||
ipaddress (0.8.0)
|
||||
jquery-atwho-rails (1.3.2)
|
||||
jquery-rails (3.1.3)
|
||||
jquery-rails (3.1.4)
|
||||
railties (>= 3.0, < 5.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
jquery-scrollto-rails (1.4.3)
|
||||
railties (> 3.1, < 5.0)
|
||||
jquery-turbolinks (2.0.2)
|
||||
jquery-turbolinks (2.1.0)
|
||||
railties (>= 3.1.0)
|
||||
turbolinks
|
||||
jquery-ui-rails (4.2.1)
|
||||
railties (>= 3.2.16)
|
||||
json (1.8.3)
|
||||
jwt (1.5.1)
|
||||
jwt (1.5.2)
|
||||
kaminari (0.16.3)
|
||||
actionpack (>= 3.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
kgio (2.9.3)
|
||||
kgio (2.10.0)
|
||||
launchy (2.4.3)
|
||||
addressable (~> 2.3)
|
||||
letter_opener (1.1.2)
|
||||
launchy (~> 2.2)
|
||||
listen (2.10.1)
|
||||
celluloid (~> 0.16.0)
|
||||
listen (2.9.0)
|
||||
celluloid (>= 0.15.2)
|
||||
rb-fsevent (>= 0.9.3)
|
||||
rb-inotify (>= 0.9)
|
||||
loofah (2.0.3)
|
||||
nokogiri (>= 1.5.9)
|
||||
macaddr (1.7.1)
|
||||
systemu (~> 2.6.2)
|
||||
mail (2.6.3)
|
||||
|
@ -401,16 +416,14 @@ GEM
|
|||
multipart-post (2.0.0)
|
||||
mysql2 (0.3.20)
|
||||
nested_form (0.3.2)
|
||||
net-ldap (0.11)
|
||||
net-scp (1.2.1)
|
||||
net-ssh (>= 2.6.5)
|
||||
net-ssh (2.9.2)
|
||||
netrc (0.10.3)
|
||||
net-ldap (0.12.1)
|
||||
net-ssh (3.0.1)
|
||||
netrc (0.11.0)
|
||||
newrelic-grape (2.0.0)
|
||||
grape
|
||||
newrelic_rpm
|
||||
newrelic_rpm (3.9.4.245)
|
||||
nokogiri (1.6.6.2)
|
||||
nokogiri (1.6.6.4)
|
||||
mini_portile (~> 0.6.0)
|
||||
nprogress-rails (0.1.6.7)
|
||||
oauth (0.4.7)
|
||||
|
@ -434,12 +447,15 @@ GEM
|
|||
omniauth-github (1.1.2)
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth2 (~> 1.1)
|
||||
omniauth-gitlab (1.0.0)
|
||||
omniauth-gitlab (1.0.1)
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth2 (~> 1.0)
|
||||
omniauth-google-oauth2 (0.2.6)
|
||||
omniauth (> 1.0)
|
||||
omniauth-oauth2 (~> 1.1)
|
||||
omniauth-google-oauth2 (0.2.10)
|
||||
addressable (~> 2.3)
|
||||
jwt (~> 1.0)
|
||||
multi_json (~> 1.3)
|
||||
omniauth (>= 1.1.1)
|
||||
omniauth-oauth2 (~> 1.3.1)
|
||||
omniauth-kerberos (0.3.0)
|
||||
omniauth-multipassword
|
||||
timfel-krb5-auth (~> 0.8)
|
||||
|
@ -463,18 +479,18 @@ GEM
|
|||
activesupport
|
||||
nokogiri (>= 1.4.4)
|
||||
omniauth (~> 1.0)
|
||||
opennebula (4.12.1)
|
||||
opennebula (4.14.2)
|
||||
json
|
||||
nokogiri
|
||||
rbvmomi
|
||||
org-ruby (0.9.12)
|
||||
rubypants (~> 0.2)
|
||||
orm_adapter (0.5.0)
|
||||
paranoia (2.1.3)
|
||||
paranoia (2.1.4)
|
||||
activerecord (~> 4.0)
|
||||
parser (2.2.2.6)
|
||||
parser (2.2.3.0)
|
||||
ast (>= 1.1, < 3.0)
|
||||
pg (0.18.2)
|
||||
pg (0.18.4)
|
||||
poltergeist (1.6.0)
|
||||
capybara (~> 2.1)
|
||||
cliver (~> 0.3.1)
|
||||
|
@ -482,7 +498,7 @@ GEM
|
|||
websocket-driver (>= 0.2.0)
|
||||
posix-spawn (0.3.11)
|
||||
powerpack (0.0.9)
|
||||
pry (0.10.1)
|
||||
pry (0.10.3)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.8.1)
|
||||
slop (~> 3.4)
|
||||
|
@ -491,7 +507,7 @@ GEM
|
|||
pyu-ruby-sasl (0.0.3.3)
|
||||
quiet_assets (1.0.3)
|
||||
railties (>= 3.1, < 5.0)
|
||||
rack (1.5.5)
|
||||
rack (1.6.4)
|
||||
rack-accept (0.4.5)
|
||||
rack (>= 0.4)
|
||||
rack-attack (4.3.0)
|
||||
|
@ -499,7 +515,7 @@ GEM
|
|||
rack-cors (0.4.0)
|
||||
rack-mount (0.8.3)
|
||||
rack (>= 1.0.0)
|
||||
rack-oauth2 (1.0.10)
|
||||
rack-oauth2 (1.2.1)
|
||||
activesupport (>= 2.3)
|
||||
attr_required (>= 0.0.5)
|
||||
httpclient (>= 2.4)
|
||||
|
@ -509,28 +525,35 @@ GEM
|
|||
rack
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
rails (4.1.12)
|
||||
actionmailer (= 4.1.12)
|
||||
actionpack (= 4.1.12)
|
||||
actionview (= 4.1.12)
|
||||
activemodel (= 4.1.12)
|
||||
activerecord (= 4.1.12)
|
||||
activesupport (= 4.1.12)
|
||||
rails (4.2.4)
|
||||
actionmailer (= 4.2.4)
|
||||
actionpack (= 4.2.4)
|
||||
actionview (= 4.2.4)
|
||||
activejob (= 4.2.4)
|
||||
activemodel (= 4.2.4)
|
||||
activerecord (= 4.2.4)
|
||||
activesupport (= 4.2.4)
|
||||
bundler (>= 1.3.0, < 2.0)
|
||||
railties (= 4.1.12)
|
||||
sprockets-rails (~> 2.0)
|
||||
rails-observers (0.1.2)
|
||||
activemodel (~> 4.0)
|
||||
railties (4.1.12)
|
||||
actionpack (= 4.1.12)
|
||||
activesupport (= 4.1.12)
|
||||
railties (= 4.2.4)
|
||||
sprockets-rails
|
||||
rails-deprecated_sanitizer (1.0.3)
|
||||
activesupport (>= 4.2.0.alpha)
|
||||
rails-dom-testing (1.0.7)
|
||||
activesupport (>= 4.2.0.beta, < 5.0)
|
||||
nokogiri (~> 1.6.0)
|
||||
rails-deprecated_sanitizer (>= 1.0.1)
|
||||
rails-html-sanitizer (1.0.2)
|
||||
loofah (~> 2.0)
|
||||
railties (4.2.4)
|
||||
actionpack (= 4.2.4)
|
||||
activesupport (= 4.2.4)
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
rainbow (2.0.0)
|
||||
raindrops (0.15.0)
|
||||
rake (10.4.2)
|
||||
raphael-rails (2.1.2)
|
||||
rb-fsevent (0.9.5)
|
||||
rb-fsevent (0.9.6)
|
||||
rb-inotify (0.9.5)
|
||||
ffi (>= 0.5.0)
|
||||
rblineprof (0.3.6)
|
||||
|
@ -542,13 +565,13 @@ GEM
|
|||
rdoc (3.12.2)
|
||||
json (~> 1.4)
|
||||
redcarpet (3.3.3)
|
||||
redis (3.2.1)
|
||||
redis-actionpack (4.0.0)
|
||||
redis (3.2.2)
|
||||
redis-actionpack (4.0.1)
|
||||
actionpack (~> 4)
|
||||
redis-rack (~> 1.5.0)
|
||||
redis-store (~> 1.1.0)
|
||||
redis-activesupport (4.1.1)
|
||||
activesupport (~> 4)
|
||||
redis-activesupport (4.1.5)
|
||||
activesupport (>= 3, < 5)
|
||||
redis-store (~> 1.1.0)
|
||||
redis-namespace (1.5.2)
|
||||
redis (~> 3.0, >= 3.0.4)
|
||||
|
@ -559,13 +582,13 @@ GEM
|
|||
redis-actionpack (~> 4)
|
||||
redis-activesupport (~> 4)
|
||||
redis-store (~> 1.1.0)
|
||||
redis-store (1.1.6)
|
||||
redis-store (1.1.7)
|
||||
redis (>= 2.2)
|
||||
request_store (1.2.0)
|
||||
request_store (1.2.1)
|
||||
rerun (0.10.0)
|
||||
listen (~> 2.7, >= 2.7.3)
|
||||
responders (1.1.2)
|
||||
railties (>= 3.2, < 4.2)
|
||||
responders (2.1.0)
|
||||
railties (>= 4.2.0, < 5)
|
||||
rest-client (1.8.0)
|
||||
http-cookie (>= 1.0.2, < 2.0)
|
||||
mime-types (>= 1.16, < 3.0)
|
||||
|
@ -687,7 +710,7 @@ GEM
|
|||
multi_json (~> 1.0)
|
||||
rack (~> 1.0)
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
sprockets-rails (2.3.2)
|
||||
sprockets-rails (2.3.3)
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
sprockets (>= 2.8, < 4.0)
|
||||
|
@ -710,11 +733,11 @@ GEM
|
|||
term-ansicolor (1.3.2)
|
||||
tins (~> 1.0)
|
||||
terminal-table (1.5.2)
|
||||
test_after_commit (0.2.7)
|
||||
test_after_commit (0.4.2)
|
||||
activerecord (>= 3.2)
|
||||
thin (1.6.3)
|
||||
thin (1.6.4)
|
||||
daemons (~> 1.0, >= 1.0.9)
|
||||
eventmachine (~> 1.0)
|
||||
eventmachine (~> 1.0, >= 1.0.4)
|
||||
rack (~> 1.0)
|
||||
thor (0.19.1)
|
||||
thread_safe (0.3.5)
|
||||
|
@ -752,9 +775,9 @@ GEM
|
|||
kgio (~> 2.6)
|
||||
rack
|
||||
raindrops (~> 0.7)
|
||||
unicorn-worker-killer (0.4.3)
|
||||
unicorn-worker-killer (0.4.4)
|
||||
get_process_mem (~> 0)
|
||||
unicorn (~> 4)
|
||||
unicorn (>= 4, < 6)
|
||||
uniform_notifier (1.9.0)
|
||||
uuid (2.3.8)
|
||||
macaddr (~> 1.0)
|
||||
|
@ -766,10 +789,15 @@ GEM
|
|||
equalizer (~> 0.0, >= 0.0.9)
|
||||
warden (1.2.3)
|
||||
rack (>= 1.0)
|
||||
web-console (2.2.1)
|
||||
activemodel (>= 4.0)
|
||||
binding_of_caller (>= 0.7.2)
|
||||
railties (>= 4.0)
|
||||
sprockets-rails (>= 2.0, < 4.0)
|
||||
webmock (1.21.0)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
websocket-driver (0.6.2)
|
||||
websocket-driver (0.6.3)
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.2)
|
||||
wikicloth (0.8.1)
|
||||
|
@ -791,7 +819,7 @@ DEPENDENCIES
|
|||
addressable (~> 2.3.8)
|
||||
after_commit_queue
|
||||
annotate (~> 2.6.0)
|
||||
asana (~> 0.0.6)
|
||||
asana (~> 0.4.0)
|
||||
asciidoctor (~> 1.5.2)
|
||||
attr_encrypted (~> 1.3.4)
|
||||
awesome_print (~> 1.2.0)
|
||||
|
@ -802,6 +830,7 @@ DEPENDENCIES
|
|||
brakeman (= 3.0.1)
|
||||
browser (~> 1.0.0)
|
||||
bullet
|
||||
bundler-audit
|
||||
byebug
|
||||
cal-heatmap-rails (~> 0.0.1)
|
||||
capybara (~> 2.4.0)
|
||||
|
@ -809,10 +838,9 @@ DEPENDENCIES
|
|||
carrierwave (~> 0.9.0)
|
||||
charlock_holmes (~> 0.7.3)
|
||||
coffee-rails (~> 4.1.0)
|
||||
colored (~> 1.2)
|
||||
colorize (~> 0.5.8)
|
||||
colorize (~> 0.7.0)
|
||||
coveralls (~> 0.8.2)
|
||||
creole (~> 0.3.6)
|
||||
creole (~> 0.5.0)
|
||||
d3_rails (~> 3.5.5)
|
||||
database_cleaner (~> 1.4.0)
|
||||
default_value_for (~> 3.0.0)
|
||||
|
@ -820,11 +848,10 @@ DEPENDENCIES
|
|||
devise-async (~> 0.9.0)
|
||||
devise-two-factor (~> 2.0.0)
|
||||
diffy (~> 3.0.3)
|
||||
doorkeeper (~> 2.1.3)
|
||||
doorkeeper (~> 2.2.0)
|
||||
dropzonejs-rails (~> 0.7.1)
|
||||
email_reply_parser (~> 0.5.8)
|
||||
email_spec (~> 1.6.0)
|
||||
enumerize (~> 0.7.0)
|
||||
factory_girl_rails (~> 4.3.0)
|
||||
ffaker (~> 2.0.0)
|
||||
flay
|
||||
|
@ -842,7 +869,7 @@ DEPENDENCIES
|
|||
gitlab_meta (= 7.0)
|
||||
gitlab_omniauth-ldap (~> 1.2.1)
|
||||
gollum-lib (~> 4.0.2)
|
||||
gon (~> 5.0.0)
|
||||
gon (~> 6.0.1)
|
||||
grape (~> 0.13.0)
|
||||
grape-entity (~> 0.4.2)
|
||||
haml-rails (~> 0.9.0)
|
||||
|
@ -852,7 +879,7 @@ DEPENDENCIES
|
|||
jquery-atwho-rails (~> 1.3.2)
|
||||
jquery-rails (~> 3.1.3)
|
||||
jquery-scrollto-rails (~> 1.4.3)
|
||||
jquery-turbolinks (~> 2.0.1)
|
||||
jquery-turbolinks (~> 2.1.0)
|
||||
jquery-ui-rails (~> 4.2.1)
|
||||
kaminari (~> 0.16.3)
|
||||
letter_opener (~> 1.1.2)
|
||||
|
@ -861,6 +888,7 @@ DEPENDENCIES
|
|||
mousetrap-rails (~> 1.4.6)
|
||||
mysql2 (~> 0.3.16)
|
||||
nested_form (~> 0.3.2)
|
||||
net-ssh (~> 3.0.1)
|
||||
newrelic-grape
|
||||
newrelic_rpm (~> 3.9.4.245)
|
||||
nprogress-rails (~> 0.1.6.7)
|
||||
|
@ -885,8 +913,9 @@ DEPENDENCIES
|
|||
quiet_assets (~> 1.0.2)
|
||||
rack-attack (~> 4.3.0)
|
||||
rack-cors (~> 0.4.0)
|
||||
rack-oauth2 (~> 1.0.5)
|
||||
rails (= 4.1.12)
|
||||
rack-oauth2 (~> 1.2.1)
|
||||
rails (= 4.2.4)
|
||||
rails-deprecated_sanitizer (~> 1.0.3)
|
||||
raphael-rails (~> 2.1.2)
|
||||
rblineprof
|
||||
rdoc (~> 3.6)
|
||||
|
@ -894,6 +923,7 @@ DEPENDENCIES
|
|||
redis-rails (~> 4.0.0)
|
||||
request_store (~> 1.2.0)
|
||||
rerun (~> 0.10.0)
|
||||
responders (~> 2.0)
|
||||
rqrcode-rails3 (~> 0.1.7)
|
||||
rspec-rails (~> 3.3.0)
|
||||
rubocop (~> 0.28.0)
|
||||
|
@ -923,7 +953,7 @@ DEPENDENCIES
|
|||
task_list (~> 1.0.2)
|
||||
teaspoon (~> 1.0.0)
|
||||
teaspoon-jasmine (~> 2.2.0)
|
||||
test_after_commit (~> 0.2.2)
|
||||
test_after_commit (~> 0.4.2)
|
||||
thin (~> 1.6.1)
|
||||
tinder (~> 1.10.0)
|
||||
turbolinks (~> 2.5.0)
|
||||
|
@ -934,6 +964,7 @@ DEPENDENCIES
|
|||
unicorn-worker-killer (~> 0.4.2)
|
||||
version_sorter (~> 2.0.0)
|
||||
virtus (~> 1.0.1)
|
||||
web-console (~> 2.0)
|
||||
webmock (~> 1.21.0)
|
||||
wikicloth (= 0.8.1)
|
||||
|
||||
|
|
10
PROCESS.md
10
PROCESS.md
|
@ -34,13 +34,19 @@ The most important thing is making sure valid issues receive feedback from the d
|
|||
|
||||
## Workflow labels
|
||||
|
||||
Workflow labels are purposely not very detailed since that would be hard to keep updated as you would need to re-evaluate them after every comment. We optionally use functional labels on demand when want to group related issues to get an overview (for example all issues related to RVM, to tackle them in one go) and to add details to the issue.
|
||||
Workflow labels are purposely not very detailed since that would be hard to keep updated as you would need to re-evaluate them after every comment. We optionally use functional labels on demand when want to group related issues to get an overview (for example all issues related to RVM, to tackle them in one go) and to add details to the issue.
|
||||
|
||||
- *Awaiting feedback*: Feedback pending from the reporter
|
||||
- *Awaiting confirmation of fix*: The issue should already be solved in **master** (generally you can avoid this workflow item and just close the issue right away)
|
||||
- *Attached MR*: There is a MR attached and the discussion should happen there
|
||||
- We need to let issues stay in sync with the MR's. We can do this with a "Closing #XXXX" or "Fixes #XXXX" comment in the MR. We can't close the issue when there is a merge request because sometimes a MR is not good and we just close the MR, then the issue must stay.
|
||||
- *Awaiting developer action/feedback*: Issue needs to be fixed or clarified by a developer
|
||||
- *Developer*: needs help from a developer
|
||||
- *UX* needs needs help from a UX designer
|
||||
- *Frontend* needs help from a Front-end engineer
|
||||
- *Graphics* needs help from a Graphics designer
|
||||
- *up-for-grabs* is an issue suitable for first-time contributors, of reasonable difficulty and size. Not exclusive with other labels.
|
||||
|
||||
Example workflow: when a UX designer provided a design but it needs frontend work they remove the UX label and add the frontend label.
|
||||
|
||||
## Functional labels
|
||||
|
||||
|
|
6
Procfile
6
Procfile
|
@ -1,3 +1,7 @@
|
|||
# For DEVELOPMENT only. Production uses Runit in
|
||||
# https://gitlab.com/gitlab-org/omnibus-gitlab or the init scripts in
|
||||
# lib/support/init.d, which call scripts in bin/ .
|
||||
#
|
||||
web: bundle exec unicorn_rails -p ${PORT:="3000"} -E ${RAILS_ENV:="development"} -c ${UNICORN_CONFIG:="config/unicorn.rb"}
|
||||
worker: bundle exec sidekiq -q post_receive -q mailer -q archive_repo -q system_hook -q project_web_hook -q gitlab_shell -q incoming_email -q runner -q common -q default
|
||||
worker: bundle exec sidekiq -q post_receive -q mailer -q archive_repo -q system_hook -q project_web_hook -q gitlab_shell -q incoming_email -q runner -q common -q mailers -q default
|
||||
# mail_room: bundle exec mail_room -q -c config/mail_room.yml
|
||||
|
|
|
@ -27,8 +27,6 @@ There are two editions of GitLab:
|
|||
- GitLab Community Edition (CE) is available freely under the MIT Expat license.
|
||||
- GitLab Enterprise Edition (EE) includes [extra features](https://about.gitlab.com/features/#compare) that are more useful for organizations with more than 100 users. To use EE and get official support please [become a subscriber](https://about.gitlab.com/pricing/).
|
||||
|
||||
Included with the GitLab Omnibus Packages is [GitLab CI](https://about.gitlab.com/gitlab-ci/) that can easily build, test and deploy code.
|
||||
|
||||
## Website
|
||||
|
||||
On [about.gitlab.com](https://about.gitlab.com/) you can find more information about:
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 726 B After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,91 @@
|
|||
class @AwardsHandler
|
||||
constructor: (@post_emoji_url, @noteable_type, @noteable_id) ->
|
||||
|
||||
addAward: (emoji) ->
|
||||
@postEmoji emoji, =>
|
||||
@addAwardToEmojiBar(emoji)
|
||||
|
||||
addAwardToEmojiBar: (emoji, custom_path = '') ->
|
||||
if @exist(emoji)
|
||||
if @isActive(emoji)
|
||||
@decrementCounter(emoji)
|
||||
else
|
||||
counter = @findEmojiIcon(emoji).siblings(".counter")
|
||||
counter.text(parseInt(counter.text()) + 1)
|
||||
counter.parent().addClass("active")
|
||||
@addMeToAuthorList(emoji)
|
||||
else
|
||||
@createEmoji(emoji, custom_path)
|
||||
|
||||
exist: (emoji) ->
|
||||
@findEmojiIcon(emoji).length > 0
|
||||
|
||||
isActive: (emoji) ->
|
||||
@findEmojiIcon(emoji).parent().hasClass("active")
|
||||
|
||||
decrementCounter: (emoji) ->
|
||||
counter = @findEmojiIcon(emoji).siblings(".counter")
|
||||
|
||||
if parseInt(counter.text()) > 1
|
||||
counter.text(parseInt(counter.text()) - 1)
|
||||
counter.parent().removeClass("active")
|
||||
@removeMeFromAuthorList(emoji)
|
||||
else
|
||||
award = counter.parent()
|
||||
award.tooltip("destroy")
|
||||
award.remove()
|
||||
|
||||
removeMeFromAuthorList: (emoji) ->
|
||||
award_block = @findEmojiIcon(emoji).parent()
|
||||
authors = award_block.attr("data-original-title").split(", ")
|
||||
authors = _.without(authors, "me").join(", ")
|
||||
award_block.attr("title", authors)
|
||||
@resetTooltip(award_block)
|
||||
|
||||
addMeToAuthorList: (emoji) ->
|
||||
award_block = @findEmojiIcon(emoji).parent()
|
||||
authors = award_block.attr("data-original-title").split(", ")
|
||||
authors.push("me")
|
||||
award_block.attr("title", authors.join(", "))
|
||||
@resetTooltip(award_block)
|
||||
|
||||
resetTooltip: (award) ->
|
||||
award.tooltip("destroy")
|
||||
|
||||
# "destroy" call is asynchronous, this is why we need to set timeout.
|
||||
setTimeout (->
|
||||
award.tooltip()
|
||||
), 200
|
||||
|
||||
|
||||
createEmoji: (emoji, custom_path) ->
|
||||
nodes = []
|
||||
nodes.push("<div class='award active' title='me'>")
|
||||
nodes.push("<div class='icon' data-emoji='" + emoji + "'>")
|
||||
nodes.push(@getImage(emoji, custom_path))
|
||||
nodes.push("</div>")
|
||||
nodes.push("<div class='counter'>1")
|
||||
nodes.push("</div></div>")
|
||||
|
||||
$(".awards-controls").before(nodes.join("\n"))
|
||||
|
||||
$(".award").tooltip()
|
||||
|
||||
getImage: (emoji, custom_path) ->
|
||||
if custom_path
|
||||
$("<img>").attr({src: custom_path, width: 20, height: 20}).wrap("<div>").parent().html()
|
||||
else
|
||||
$("li[data-emoji='" + emoji + "']").html()
|
||||
|
||||
|
||||
postEmoji: (emoji, callback) ->
|
||||
$.post @post_emoji_url, { note: {
|
||||
note: ":" + emoji + ":"
|
||||
noteable_type: @noteable_type
|
||||
noteable_id: @noteable_id
|
||||
}},(data) ->
|
||||
if data.ok
|
||||
callback.call()
|
||||
|
||||
findEmojiIcon: (emoji) ->
|
||||
$(".icon[data-emoji='" + emoji + "']")
|
|
@ -23,18 +23,6 @@ class @BlobFileDropzone
|
|||
init: ->
|
||||
this.on 'addedfile', (file) ->
|
||||
$('.dropzone-alerts').html('').hide()
|
||||
commit_message = form.find('#commit_message')[0]
|
||||
|
||||
if /^Upload/.test(commit_message.placeholder)
|
||||
commit_message.placeholder = 'Upload ' + file.name
|
||||
|
||||
return
|
||||
|
||||
this.on 'removedfile', (file) ->
|
||||
commit_message = form.find('#commit_message')[0]
|
||||
|
||||
if /^Upload/.test(commit_message.placeholder)
|
||||
commit_message.placeholder = 'Upload new file'
|
||||
|
||||
return
|
||||
|
||||
|
@ -47,8 +35,9 @@ class @BlobFileDropzone
|
|||
return
|
||||
|
||||
this.on 'sending', (file, xhr, formData) ->
|
||||
formData.append('new_branch', form.find('#new_branch').val())
|
||||
formData.append('commit_message', form.find('#commit_message').val())
|
||||
formData.append('new_branch', form.find('.js-new-branch').val())
|
||||
formData.append('create_merge_request', form.find('.js-create-merge-request').val())
|
||||
formData.append('commit_message', form.find('.js-commit-message').val())
|
||||
return
|
||||
|
||||
# Override behavior of adding error underneath preview
|
||||
|
|
|
@ -1,21 +1,37 @@
|
|||
#= require clipboard
|
||||
|
||||
genericSuccess = (e) ->
|
||||
showTooltip(e.trigger, 'Copied!')
|
||||
|
||||
# Clear the selection and blur the trigger so it loses its border
|
||||
e.clearSelection()
|
||||
$(e.trigger).blur()
|
||||
|
||||
# Safari doesn't support `execCommand`, so instead we inform the user to
|
||||
# copy manually.
|
||||
#
|
||||
# See http://clipboardjs.com/#browser-support
|
||||
genericError = (e) ->
|
||||
if /Mac/i.test(navigator.userAgent)
|
||||
key = '⌘' # Command
|
||||
else
|
||||
key = 'Ctrl'
|
||||
|
||||
showTooltip(e.trigger, "Press #{key}-C to copy")
|
||||
|
||||
showTooltip = (target, title) ->
|
||||
$(target).
|
||||
tooltip(
|
||||
container: 'body'
|
||||
html: 'true'
|
||||
placement: 'auto bottom'
|
||||
title: title
|
||||
trigger: 'manual'
|
||||
).
|
||||
tooltip('show').
|
||||
one('mouseleave', -> $(this).tooltip('hide'))
|
||||
|
||||
$ ->
|
||||
clipboard = new Clipboard '.js-clipboard-trigger',
|
||||
text: (trigger) ->
|
||||
$target = $(trigger.nextElementSibling || trigger.previousElementSibling)
|
||||
$target.data('clipboard-text') || $target.text().trim()
|
||||
|
||||
clipboard.on 'success', (e) ->
|
||||
$(e.trigger).
|
||||
tooltip(trigger: 'manual', placement: 'auto bottom', title: 'Copied!').
|
||||
tooltip('show')
|
||||
|
||||
# Clear the selection and blur the trigger so it loses its border
|
||||
e.clearSelection()
|
||||
$(e.trigger).blur()
|
||||
|
||||
# Manually hide the tooltip after 1 second
|
||||
setTimeout(->
|
||||
$(e.trigger).tooltip('hide')
|
||||
, 1000)
|
||||
clipboard = new Clipboard '[data-clipboard-target], [data-clipboard-text]'
|
||||
clipboard.on 'success', genericSuccess
|
||||
clipboard.on 'error', genericError
|
||||
|
|
|
@ -28,6 +28,8 @@ class Dispatcher
|
|||
when 'projects:milestones:new', 'projects:milestones:edit'
|
||||
new ZenMode()
|
||||
new DropzoneInput($('.milestone-form'))
|
||||
when 'groups:milestones:new'
|
||||
new ZenMode()
|
||||
when 'projects:compare:show'
|
||||
new Diff()
|
||||
when 'projects:issues:new','projects:issues:edit'
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#= require markdown_preview
|
||||
|
||||
class @DropzoneInput
|
||||
constructor: (form) ->
|
||||
Dropzone.autoDiscover = false
|
||||
|
@ -11,17 +13,14 @@ class @DropzoneInput
|
|||
uploadProgress = $("<div class=\"div-dropzone-progress\"></div>")
|
||||
btnAlert = "<button type=\"button\"" + alertAttr + ">×</button>"
|
||||
project_uploads_path = window.project_uploads_path or null
|
||||
markdown_preview_path = window.markdown_preview_path or null
|
||||
max_file_size = gon.max_file_size or 10
|
||||
|
||||
form_textarea = $(form).find("textarea.markdown-area")
|
||||
form_textarea.wrap "<div class=\"div-dropzone\"></div>"
|
||||
form_textarea.on 'paste', (event) =>
|
||||
handlePaste(event)
|
||||
form_textarea.on "input", ->
|
||||
hideReferencedUsers()
|
||||
form_textarea.on "blur", ->
|
||||
renderMarkdown()
|
||||
|
||||
$(form).setupMarkdownPreview()
|
||||
|
||||
form_dropzone = $(form).find('.div-dropzone')
|
||||
form_dropzone.parent().addClass "div-dropzone-wrapper"
|
||||
|
@ -34,42 +33,6 @@ class @DropzoneInput
|
|||
"opacity": 0
|
||||
"display": "none"
|
||||
|
||||
# Preview button
|
||||
$(document).off "click", ".js-md-preview-button"
|
||||
$(document).on "click", ".js-md-preview-button", (e) ->
|
||||
###
|
||||
Shows the Markdown preview.
|
||||
|
||||
Lets the server render GFM into Html and displays it.
|
||||
###
|
||||
e.preventDefault()
|
||||
form = $(this).closest("form")
|
||||
# toggle tabs
|
||||
form.find(".js-md-write-button").parent().removeClass "active"
|
||||
form.find(".js-md-preview-button").parent().addClass "active"
|
||||
|
||||
# toggle content
|
||||
form.find(".md-write-holder").hide()
|
||||
form.find(".md-preview-holder").show()
|
||||
|
||||
renderMarkdown()
|
||||
|
||||
# Write button
|
||||
$(document).off "click", ".js-md-write-button"
|
||||
$(document).on "click", ".js-md-write-button", (e) ->
|
||||
###
|
||||
Shows the Markdown textarea.
|
||||
###
|
||||
e.preventDefault()
|
||||
form = $(this).closest("form")
|
||||
# toggle tabs
|
||||
form.find(".js-md-write-button").parent().addClass "active"
|
||||
form.find(".js-md-preview-button").parent().removeClass "active"
|
||||
|
||||
# toggle content
|
||||
form.find(".md-write-holder").show()
|
||||
form.find(".md-preview-holder").hide()
|
||||
|
||||
dropzone = form_dropzone.dropzone(
|
||||
url: project_uploads_path
|
||||
dictDefaultMessage: ""
|
||||
|
@ -136,41 +99,6 @@ class @DropzoneInput
|
|||
|
||||
child = $(dropzone[0]).children("textarea")
|
||||
|
||||
hideReferencedUsers = ->
|
||||
referencedUsers = form.find(".referenced-users")
|
||||
referencedUsers.hide()
|
||||
|
||||
renderReferencedUsers = (users) ->
|
||||
referencedUsers = form.find(".referenced-users")
|
||||
|
||||
if referencedUsers.length
|
||||
if users.length >= 10
|
||||
referencedUsers.show()
|
||||
referencedUsers.find(".js-referenced-users-count").text users.length
|
||||
else
|
||||
referencedUsers.hide()
|
||||
|
||||
renderMarkdown = ->
|
||||
preview = form.find(".js-md-preview")
|
||||
mdText = form.find(".markdown-area").val()
|
||||
if mdText.trim().length is 0
|
||||
preview.text "Nothing to preview."
|
||||
hideReferencedUsers()
|
||||
else
|
||||
preview.text "Loading..."
|
||||
$.ajax(
|
||||
type: "POST",
|
||||
url: markdown_preview_path,
|
||||
data: {
|
||||
text: mdText
|
||||
},
|
||||
dataType: "json"
|
||||
).success (data) ->
|
||||
preview.html data.body
|
||||
preview.syntaxHighlight()
|
||||
|
||||
renderReferencedUsers data.references.users
|
||||
|
||||
formatLink = (link) ->
|
||||
text = "[#{link.alt}](#{link.url})"
|
||||
text = "!#{text}" if link.is_image
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
$('#filter_issue_search').val($('#issue_search').val())
|
||||
|
||||
initSelects: ->
|
||||
$("select#update_status").select2(width: 'resolve', dropdownAutoWidth: true)
|
||||
$("select#update_state_event").select2(width: 'resolve', dropdownAutoWidth: true)
|
||||
$("select#update_assignee_id").select2(width: 'resolve', dropdownAutoWidth: true)
|
||||
$("select#update_milestone_id").select2(width: 'resolve', dropdownAutoWidth: true)
|
||||
$("select#label_name").select2(width: 'resolve', dropdownAutoWidth: true)
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
# MarkdownPreview
|
||||
#
|
||||
# Handles toggling the "Write" and "Preview" tab clicks, rendering the preview,
|
||||
# and showing a warning when more than `x` users are referenced.
|
||||
#
|
||||
class @MarkdownPreview
|
||||
# Minimum number of users referenced before triggering a warning
|
||||
referenceThreshold: 10
|
||||
|
||||
showPreview: (form) ->
|
||||
preview = form.find('.js-md-preview')
|
||||
mdText = form.find('textarea.markdown-area').val()
|
||||
|
||||
if mdText.trim().length == 0
|
||||
preview.text('Nothing to preview.')
|
||||
@hideReferencedUsers(form)
|
||||
else
|
||||
preview.text('Loading...')
|
||||
@renderMarkdown mdText, (response) =>
|
||||
preview.html(response.body)
|
||||
preview.syntaxHighlight()
|
||||
@renderReferencedUsers(response.references.users, form)
|
||||
|
||||
renderMarkdown: (text, success) ->
|
||||
return unless window.markdown_preview_path
|
||||
|
||||
$.ajax
|
||||
type: 'POST'
|
||||
url: window.markdown_preview_path
|
||||
data: { text: text }
|
||||
dataType: 'json'
|
||||
success: success
|
||||
|
||||
hideReferencedUsers: (form) ->
|
||||
referencedUsers = form.find('.referenced-users')
|
||||
referencedUsers.hide()
|
||||
|
||||
renderReferencedUsers: (users, form) ->
|
||||
referencedUsers = form.find('.referenced-users')
|
||||
|
||||
if referencedUsers.length
|
||||
if users.length >= @referenceThreshold
|
||||
referencedUsers.show()
|
||||
referencedUsers.find('.js-referenced-users-count').text(users.length)
|
||||
else
|
||||
referencedUsers.hide()
|
||||
|
||||
markdownPreview = new MarkdownPreview()
|
||||
|
||||
previewButtonSelector = '.js-md-preview-button'
|
||||
writeButtonSelector = '.js-md-write-button'
|
||||
|
||||
$.fn.setupMarkdownPreview = ->
|
||||
$form = $(this)
|
||||
|
||||
form_textarea = $form.find('textarea.markdown-area')
|
||||
|
||||
form_textarea.on 'input', -> markdownPreview.hideReferencedUsers($form)
|
||||
form_textarea.on 'blur', -> markdownPreview.showPreview($form)
|
||||
|
||||
$(document).on 'click', previewButtonSelector, (e) ->
|
||||
e.preventDefault()
|
||||
|
||||
$form = $(this).closest('form')
|
||||
|
||||
# toggle tabs
|
||||
$form.find(writeButtonSelector).parent().removeClass('active')
|
||||
$form.find(previewButtonSelector).parent().addClass('active')
|
||||
|
||||
# toggle content
|
||||
$form.find('.md-write-holder').hide()
|
||||
$form.find('.md-preview-holder').show()
|
||||
|
||||
markdownPreview.showPreview($form)
|
||||
|
||||
$(document).on 'click', writeButtonSelector, (e) ->
|
||||
e.preventDefault()
|
||||
|
||||
$form = $(this).closest('form')
|
||||
|
||||
# toggle tabs
|
||||
$form.find(writeButtonSelector).parent().addClass('active')
|
||||
$form.find(previewButtonSelector).parent().removeClass('active')
|
||||
|
||||
# toggle content
|
||||
$form.find('.md-write-holder').show()
|
||||
$form.find('.md-preview-holder').hide()
|
|
@ -0,0 +1,21 @@
|
|||
class @NewCommitForm
|
||||
constructor: (form) ->
|
||||
@newBranch = form.find('.js-new-branch')
|
||||
@originalBranch = form.find('.js-original-branch')
|
||||
@createMergeRequest = form.find('.js-create-merge-request')
|
||||
@createMergeRequestFormGroup = form.find('.js-create-merge-request-form-group')
|
||||
|
||||
@renderDestination()
|
||||
@newBranch.keyup @renderDestination
|
||||
|
||||
renderDestination: =>
|
||||
different = @newBranch.val() != @originalBranch.val()
|
||||
|
||||
if different
|
||||
@createMergeRequestFormGroup.show()
|
||||
@createMergeRequest.prop('checked', true) unless @wasDifferent
|
||||
else
|
||||
@createMergeRequestFormGroup.hide()
|
||||
@createMergeRequest.prop('checked', false)
|
||||
|
||||
@wasDifferent = different
|
|
@ -113,13 +113,16 @@ class @Notes
|
|||
renderNote: (note) ->
|
||||
# render note if it not present in loaded list
|
||||
# or skip if rendered
|
||||
if @isNewNote(note)
|
||||
if @isNewNote(note) && !note.award
|
||||
@note_ids.push(note.id)
|
||||
$('ul.main-notes-list').
|
||||
append(note.html).
|
||||
syntaxHighlight()
|
||||
@initTaskList()
|
||||
|
||||
if note.award
|
||||
awards_handler.addAwardToEmojiBar(note.note, note.emoji_path)
|
||||
|
||||
###
|
||||
Check if note does not exists on page
|
||||
###
|
||||
|
@ -255,7 +258,6 @@ class @Notes
|
|||
###
|
||||
addNote: (xhr, note, status) =>
|
||||
@renderNote(note)
|
||||
@updateVotes()
|
||||
|
||||
###
|
||||
Called in response to the new note form being submitted
|
||||
|
@ -473,9 +475,6 @@ class @Notes
|
|||
form = $(e.target).closest(".js-discussion-note-form")
|
||||
@removeDiscussionNoteForm(form)
|
||||
|
||||
updateVotes: ->
|
||||
true
|
||||
|
||||
###
|
||||
Called after an attachment file has been selected.
|
||||
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
class @Project
|
||||
constructor: ->
|
||||
# Git clone panel switcher
|
||||
cloneHolder = $('.git-clone-holder')
|
||||
if cloneHolder.length
|
||||
$('a, button', cloneHolder).click ->
|
||||
$('a, button', cloneHolder).removeClass 'active'
|
||||
$(@).addClass 'active'
|
||||
$('#project_clone', cloneHolder).val $(@).data 'clone'
|
||||
$(".clone").text("").append $(@).data 'clone'
|
||||
# Git protocol switcher
|
||||
$('.js-protocol-switch').click ->
|
||||
return if $(@).hasClass('active')
|
||||
|
||||
# Toggle 'active' for both buttons
|
||||
$('.js-protocol-switch').toggleClass('active')
|
||||
|
||||
url = $(@).data('clone')
|
||||
|
||||
# Update the input field
|
||||
$('#project_clone').val(url)
|
||||
|
||||
# Update the command line instructions
|
||||
$('.clone').text(url)
|
||||
|
||||
# Ref switcher
|
||||
$('.project-refs-select').on 'change', ->
|
||||
|
@ -39,4 +45,4 @@ class @Project
|
|||
when 4 then label = ' On Mention '
|
||||
$('#notifications-button').empty().append("<i class='fa fa-bell'></i>" + label + "<i class='fa fa-angle-down'></i>")
|
||||
$(@).parents('ul').find('li.active').removeClass 'active'
|
||||
$(@).parent().addClass 'active'
|
||||
$(@).parent().addClass 'active'
|
||||
|
|
|
@ -6,7 +6,7 @@ window.ContributorsStatGraphUtil =
|
|||
for entry in log
|
||||
@add_date(entry.date, total) unless total[entry.date]?
|
||||
|
||||
data = by_author[entry.author_name] #|| by_email[entry.author_email]
|
||||
data = by_author[entry.author_name] || by_email[entry.author_email]
|
||||
data ?= @add_author(entry, by_author, by_email)
|
||||
|
||||
@add_date(entry.date, data) unless data[entry.date]
|
||||
|
@ -95,5 +95,4 @@ window.ContributorsStatGraphUtil =
|
|||
if date_range is null || date_range[0] <= new Date(date) <= date_range[1]
|
||||
true
|
||||
else
|
||||
false
|
||||
|
||||
false
|
|
@ -32,17 +32,15 @@ class @UsersSelect
|
|||
if showNullUser
|
||||
nullUser = {
|
||||
name: 'Unassigned',
|
||||
avatar: null,
|
||||
username: 'none',
|
||||
id: 0
|
||||
}
|
||||
data.results.unshift(nullUser)
|
||||
|
||||
if showAnyUser
|
||||
name = showAnyUser
|
||||
name = 'Any User' if name == true
|
||||
anyUser = {
|
||||
name: 'Any',
|
||||
avatar: null,
|
||||
username: 'none',
|
||||
name: name,
|
||||
id: null
|
||||
}
|
||||
data.results.unshift(anyUser)
|
||||
|
@ -50,7 +48,6 @@ class @UsersSelect
|
|||
if showEmailUser && data.results.length == 0 && query.term.match(/^[^@]+@[^@]+$/)
|
||||
emailUser = {
|
||||
name: "Invite \"#{query.term}\"",
|
||||
avatar: null,
|
||||
username: query.term,
|
||||
id: query.term
|
||||
}
|
||||
|
@ -58,11 +55,8 @@ class @UsersSelect
|
|||
|
||||
query.callback(data)
|
||||
|
||||
initSelection: (element, callback) =>
|
||||
id = $(element).val()
|
||||
if id != "" && id != "0"
|
||||
@user(id, callback)
|
||||
|
||||
initSelection: (args...) =>
|
||||
@initSelection(args...)
|
||||
formatResult: (args...) =>
|
||||
@formatResult(args...)
|
||||
formatSelection: (args...) =>
|
||||
|
@ -71,16 +65,24 @@ class @UsersSelect
|
|||
escapeMarkup: (m) -> # we do not want to escape markup since we are displaying html in results
|
||||
m
|
||||
|
||||
initSelection: (element, callback) ->
|
||||
id = $(element).val()
|
||||
if id == "0"
|
||||
nullUser = { name: 'Unassigned' }
|
||||
callback(nullUser)
|
||||
else if id != ""
|
||||
@user(id, callback)
|
||||
|
||||
formatResult: (user) ->
|
||||
if user.avatar_url
|
||||
avatar = user.avatar_url
|
||||
else
|
||||
avatar = gon.default_avatar_url
|
||||
|
||||
"<div class='user-result'>
|
||||
"<div class='user-result #{'no-username' unless user.username}'>
|
||||
<div class='user-image'><img class='avatar s24' src='#{avatar}'></div>
|
||||
<div class='user-name'>#{user.name}</div>
|
||||
<div class='user-username'>#{user.username}</div>
|
||||
<div class='user-username'>#{user.username || ""}</div>
|
||||
</div>"
|
||||
|
||||
formatSelection: (user) ->
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
@import "framework/fonts";
|
||||
@import "framework/variables";
|
||||
@import "framework/mixins";
|
||||
@import "framework/layout";
|
||||
@import 'framework/tw_bootstrap_variables';
|
||||
@import 'framework/tw_bootstrap';
|
||||
@import "framework/layout";
|
||||
|
||||
@import "framework/avatar.scss";
|
||||
@import "framework/blocks.scss";
|
||||
|
@ -25,6 +25,7 @@
|
|||
@import "framework/markdown_area.scss";
|
||||
@import "framework/mobile.scss";
|
||||
@import "framework/pagination.scss";
|
||||
@import "framework/panels.scss";
|
||||
@import "framework/selects.scss";
|
||||
@import "framework/sidebar.scss";
|
||||
@import "framework/tables.scss";
|
||||
|
|
|
@ -68,6 +68,10 @@
|
|||
.oneline {
|
||||
line-height: 42px;
|
||||
}
|
||||
|
||||
> p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.cover-block {
|
||||
|
@ -112,5 +116,14 @@
|
|||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
|
||||
&.left {
|
||||
left: 10px;
|
||||
right: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.block-connector {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
/** COMMON CLASSES **/
|
||||
.prepend-top-10 { margin-top:10px }
|
||||
.prepend-top-default { margin-top: $gl-padding; }
|
||||
.prepend-top-default { margin-top: $gl-padding !important; }
|
||||
.prepend-top-20 { margin-top:20px }
|
||||
.prepend-left-10 { margin-left:10px }
|
||||
.prepend-left-20 { margin-left:20px }
|
||||
|
@ -52,6 +52,10 @@ pre {
|
|||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: $gl-padding 0;
|
||||
}
|
||||
|
||||
.dropdown-menu > li > a {
|
||||
text-shadow: none;
|
||||
}
|
||||
|
@ -64,7 +68,7 @@ pre {
|
|||
.dropdown-menu > li > a:hover,
|
||||
.dropdown-menu > li > a:focus {
|
||||
background: $gl-primary;
|
||||
color: #FFF
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
.str-truncated {
|
||||
|
@ -328,15 +332,15 @@ table {
|
|||
}
|
||||
}
|
||||
|
||||
.well {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.search_box {
|
||||
@extend .well;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.task-status {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
#nprogress .spinner {
|
||||
top: 15px !important;
|
||||
right: 10px !important;
|
||||
|
@ -429,3 +433,7 @@ table {
|
|||
.space-right {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.alert, .progress {
|
||||
margin-bottom: $gl-padding;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
border: none;
|
||||
border-top: 1px solid #E7E9EE;
|
||||
border-bottom: 1px solid #E7E9EE;
|
||||
margin-bottom: 1em;
|
||||
|
||||
&.readme-holder {
|
||||
border-bottom: 0;
|
||||
|
@ -25,7 +24,7 @@
|
|||
text-shadow: 0 1px 1px #fff;
|
||||
margin: 0;
|
||||
text-align: left;
|
||||
padding: 10px 15px;
|
||||
padding: 10px $gl-padding;
|
||||
|
||||
.file-actions {
|
||||
float: right;
|
||||
|
@ -171,4 +170,3 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,9 +22,10 @@ input[type='text'].danger {
|
|||
}
|
||||
|
||||
.form-actions {
|
||||
padding: 17px 20px 18px;
|
||||
margin-top: 18px;
|
||||
margin-bottom: 18px;
|
||||
margin: -$gl-padding;
|
||||
margin-top: 0;
|
||||
margin-bottom: -$gl-padding;
|
||||
padding: $gl-padding;
|
||||
background-color: $background-color;
|
||||
border-top: 1px solid $border-color;
|
||||
}
|
||||
|
@ -73,6 +74,8 @@ label {
|
|||
|
||||
.form-control {
|
||||
@include box-shadow(none);
|
||||
height: 42px;
|
||||
padding: 8px $gl-padding;
|
||||
}
|
||||
|
||||
.wiki-content {
|
||||
|
@ -88,7 +91,19 @@ label {
|
|||
}
|
||||
|
||||
.input-group {
|
||||
.select2-container {
|
||||
display: table-cell;
|
||||
width: 200px !important;
|
||||
}
|
||||
.input-group-addon {
|
||||
background-color: #f7f8fa;
|
||||
}
|
||||
.input-group-addon:not(:first-child):not(:last-child) {
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.help-block {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
|
|
@ -118,6 +118,10 @@ header {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.impersonation i {
|
||||
color: $red-normal;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin collapsed-header {
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
.issue-box {
|
||||
@include border-radius(2px);
|
||||
|
||||
display: inline-block;
|
||||
padding: 10px $gl-padding;
|
||||
display: block;
|
||||
float: left;
|
||||
padding: 0 $gl-padding;
|
||||
font-weight: normal;
|
||||
margin-right: 10px;
|
||||
font-size: $gl-font-size;
|
||||
|
|
|
@ -2,10 +2,10 @@ html {
|
|||
overflow-y: scroll;
|
||||
|
||||
&.touch .tooltip { display: none !important; }
|
||||
}
|
||||
|
||||
body {
|
||||
padding-top: $header-height;
|
||||
}
|
||||
body {
|
||||
background-color: #EAEBEC !important;
|
||||
}
|
||||
|
||||
.container {
|
||||
|
@ -18,6 +18,7 @@ html {
|
|||
}
|
||||
|
||||
.navless-container {
|
||||
padding-top: $header-height;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
|
|
|
@ -127,3 +127,8 @@ ul.content-list {
|
|||
}
|
||||
}
|
||||
|
||||
.panel > .content-list {
|
||||
li {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,3 +32,7 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.panel > .gl-pagination {
|
||||
margin: 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
.panel {
|
||||
margin-bottom: $gl-padding;
|
||||
|
||||
.panel-heading {
|
||||
padding: 10px $gl-padding;
|
||||
}
|
||||
.panel-body {
|
||||
padding: $gl-padding;
|
||||
|
||||
.form-actions {
|
||||
margin: -$gl-padding;
|
||||
margin-top: $gl-padding;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,6 +15,16 @@
|
|||
border-left: none;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.select2-chosen {
|
||||
color: $gl-text-color;
|
||||
}
|
||||
|
||||
&.select2-default {
|
||||
.select2-chosen {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +33,7 @@
|
|||
border: 1px solid #e7e9ed;
|
||||
}
|
||||
|
||||
|
||||
.select2-drop {
|
||||
@include box-shadow(rgba(76, 86, 103, 0.247059) 0px 0px 1px 0px, rgba(31, 37, 50, 0.317647) 0px 2px 18px 0px);
|
||||
@include border-radius (0px);
|
||||
|
@ -123,10 +134,16 @@
|
|||
}
|
||||
|
||||
.user-result {
|
||||
min-height: 24px;
|
||||
|
||||
.user-image {
|
||||
float: left;
|
||||
}
|
||||
.user-name {
|
||||
|
||||
&.no-username {
|
||||
.user-name {
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
.page-with-sidebar {
|
||||
padding-top: $header-height;
|
||||
|
||||
.sidebar-wrapper {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
@ -18,15 +20,12 @@
|
|||
}
|
||||
|
||||
.content-wrapper {
|
||||
min-height: 100vh;
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
background: #EAEBEC;
|
||||
|
||||
.container-fluid {
|
||||
background: #FFF;
|
||||
padding: $gl-padding;
|
||||
min-height: 90vh;
|
||||
|
||||
&.container-blank {
|
||||
background: none;
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
table {
|
||||
&.table {
|
||||
margin-bottom: $gl-padding;
|
||||
|
||||
.dropdown-menu a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
|
|
@ -172,7 +172,7 @@
|
|||
}
|
||||
|
||||
.panel-body {
|
||||
form {
|
||||
form, pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
@ -190,6 +190,10 @@
|
|||
.btn {
|
||||
min-width: 124px;
|
||||
}
|
||||
|
||||
.btn-clipboard {
|
||||
min-width: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
&.panel-small {
|
||||
|
|
|
@ -181,6 +181,10 @@ body {
|
|||
line-height: 1.3;
|
||||
font-size: 1.25em;
|
||||
font-weight: 600;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.page-title-empty {
|
||||
|
@ -256,3 +260,9 @@ textarea.js-gfm-input {
|
|||
.strikethrough {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
small {
|
||||
color: $gl-gray;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
.autoscroll-container {
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
@ -34,7 +34,7 @@
|
|||
|
||||
a {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
display: block;
|
||||
}
|
||||
|
||||
.commit-title{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.commit-author, .commit-committer{
|
||||
display: block;
|
||||
color: #999;
|
||||
|
@ -41,6 +37,8 @@
|
|||
.commit-box {
|
||||
.commit-title {
|
||||
margin: 0;
|
||||
font-size: 23px;
|
||||
color: #313236;
|
||||
}
|
||||
|
||||
.commit-description {
|
||||
|
@ -56,6 +54,7 @@
|
|||
|
||||
li {
|
||||
padding: 3px 0px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
.new-file {
|
||||
|
@ -107,16 +106,3 @@
|
|||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
||||
.commit-ci-menu {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
margin-top: 5px;
|
||||
height: 56px;
|
||||
margin: -16px;
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
|
|
@ -19,48 +19,38 @@
|
|||
color: #B94A48;
|
||||
}
|
||||
}
|
||||
.commit-button-annotation {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
padding: 2px;
|
||||
|
||||
> * {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.message {
|
||||
display: inline-block;
|
||||
margin: 5px 8px 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.file-title {
|
||||
@extend .monospace;
|
||||
|
||||
line-height: 42px;
|
||||
padding-top: 7px;
|
||||
padding-bottom: 7px;
|
||||
}
|
||||
|
||||
.editor-ref {
|
||||
background: $background-color;
|
||||
padding: 11px 15px;
|
||||
padding-right: $gl-padding;
|
||||
border-right: 1px solid $border-color;
|
||||
display: inline-block;
|
||||
margin: -5px -5px;
|
||||
display: block;
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.editor-file-name {
|
||||
.new-file-name {
|
||||
display: inline-block;
|
||||
width: 450px;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
margin-top: -3px;
|
||||
}
|
||||
@extend .monospace;
|
||||
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
margin: -$gl-padding;
|
||||
margin-top: 0;
|
||||
padding: $gl-padding
|
||||
.new-file-name {
|
||||
display: inline-block;
|
||||
width: 450px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.select2 {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
.new-group-member-holder {
|
||||
margin-top: 50px;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.member-search-form {
|
||||
float: left;
|
||||
}
|
||||
|
@ -15,4 +10,4 @@
|
|||
.form-control {
|
||||
height: 42px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,11 +51,12 @@
|
|||
|
||||
.issuable-details {
|
||||
.page-title {
|
||||
margin-top: -15px;
|
||||
padding: 10px 0;
|
||||
margin-top: -$gl-padding;
|
||||
padding: 7px 0;
|
||||
margin-bottom: 0;
|
||||
color: #5c5d5e;
|
||||
font-size: 16px;
|
||||
line-height: 42px;
|
||||
|
||||
.author {
|
||||
color: #5c5d5e;
|
||||
|
@ -101,3 +102,72 @@
|
|||
background-color: $background-color;
|
||||
}
|
||||
}
|
||||
|
||||
.awards {
|
||||
@include clearfix;
|
||||
line-height: 34px;
|
||||
margin: 2px 0;
|
||||
|
||||
.award {
|
||||
@include border-radius(5px);
|
||||
|
||||
border: 1px solid;
|
||||
padding: 0px 10px;
|
||||
float: left;
|
||||
margin: 0 5px;
|
||||
border-color: $border-color;
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
border-color: $border-gray-light;
|
||||
background-color: $gray-light;
|
||||
|
||||
.counter {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.counter {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
.awards-controls {
|
||||
margin-left: 10px;
|
||||
float: left;
|
||||
|
||||
.add-award {
|
||||
font-size: 24px;
|
||||
color: $gl-gray;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
|
||||
&:hover,
|
||||
&:link {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.awards-menu {
|
||||
padding: $gl-padding;
|
||||
min-width: 214px;
|
||||
|
||||
> li {
|
||||
cursor: pointer;
|
||||
margin: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.awards-menu{
|
||||
li {
|
||||
float: left;
|
||||
margin: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
/* Login Page */
|
||||
.login-page {
|
||||
background-color: white;
|
||||
|
||||
.container {
|
||||
max-width: 960px;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
*/
|
||||
.mr-state-widget {
|
||||
background: #F7F8FA;
|
||||
margin-bottom: 20px;
|
||||
color: $gl-gray;
|
||||
border: 1px solid #dce0e6;
|
||||
@include border-radius(2px);
|
||||
|
@ -87,7 +86,7 @@
|
|||
.mr-widget-body,
|
||||
.ci_widget,
|
||||
.mr-widget-footer {
|
||||
padding: 15px;
|
||||
padding: $gl-padding;
|
||||
}
|
||||
|
||||
.normal {
|
||||
|
@ -116,26 +115,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
.merge-request .merge-request-tabs {
|
||||
@include nav-menu;
|
||||
margin: -$gl-padding;
|
||||
padding: $gl-padding;
|
||||
text-align: center;
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
|
||||
// Mobile
|
||||
@media (max-width: 480px) {
|
||||
.merge-request .merge-request-tabs {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
a {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.merge-request-details {
|
||||
margin-bottom: $gl-padding;
|
||||
}
|
||||
|
||||
.mr_source_commit,
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
}
|
||||
.reply-btn {
|
||||
@extend .btn-primary;
|
||||
margin: 10px $gl-padding;
|
||||
}
|
||||
.diff-file .diff-content {
|
||||
tr.line_holder:hover {
|
||||
|
@ -38,9 +39,8 @@
|
|||
}
|
||||
|
||||
.new_note, .edit_note {
|
||||
.buttons {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 3px;
|
||||
.note-form-actions {
|
||||
margin-top: $gl-padding;
|
||||
}
|
||||
|
||||
.note-preview-holder {
|
||||
|
@ -79,8 +79,8 @@
|
|||
padding: $gl-padding;
|
||||
margin-left: -$gl-padding;
|
||||
margin-right: -$gl-padding;
|
||||
border-right: 1px solid #ECEEF1;
|
||||
border-top: 1px solid #ECEEF1;
|
||||
border-right: 1px solid $border-color;
|
||||
border-top: 1px solid $border-color;
|
||||
margin-bottom: -$gl-padding;
|
||||
}
|
||||
|
||||
|
@ -150,7 +150,6 @@
|
|||
|
||||
.discussion-reply-holder {
|
||||
background: $background-color;
|
||||
padding: 10px 15px;
|
||||
border-top: 1px solid $border-color;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,10 +18,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.project-edit-content {
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
.project-name-holder {
|
||||
.help-inline {
|
||||
vertical-align: top;
|
||||
|
@ -30,12 +26,6 @@
|
|||
}
|
||||
|
||||
.project-home-panel {
|
||||
text-align: center;
|
||||
background: #f7f8fa;
|
||||
margin: -$gl-padding;
|
||||
padding: $gl-padding;
|
||||
padding: 44px 0 17px 0;
|
||||
|
||||
.project-identicon-holder {
|
||||
margin-bottom: 16px;
|
||||
|
||||
|
@ -90,7 +80,12 @@
|
|||
}
|
||||
|
||||
.visibility-level-label {
|
||||
@extend .btn;
|
||||
@extend .btn-gray;
|
||||
|
||||
color: $gray;
|
||||
cursor: default;
|
||||
|
||||
i {
|
||||
color: inherit;
|
||||
}
|
||||
|
@ -100,7 +95,6 @@
|
|||
display: inline-table;
|
||||
position: relative;
|
||||
top: 17px;
|
||||
margin-bottom: 44px;
|
||||
}
|
||||
|
||||
.project-repo-buttons {
|
||||
|
@ -178,6 +172,11 @@
|
|||
&:active {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&.btn-clipboard {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.active {
|
||||
|
@ -366,7 +365,7 @@ table.table.protected-branches-list tr.no-border {
|
|||
|
||||
.project-stats {
|
||||
text-align: center;
|
||||
margin-top: 15px;
|
||||
margin-top: $gl-padding;
|
||||
margin-bottom: 0;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 4px;
|
||||
|
@ -552,4 +551,4 @@ pre.light-well {
|
|||
z-index: 100;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,56 +27,22 @@
|
|||
}
|
||||
|
||||
.snippet-holder {
|
||||
.snippet-details {
|
||||
.page-title {
|
||||
margin-top: -15px;
|
||||
padding: 10px 0;
|
||||
margin-bottom: 0;
|
||||
color: #5c5d5e;
|
||||
font-size: 16px;
|
||||
|
||||
.author {
|
||||
color: #5c5d5e;
|
||||
}
|
||||
|
||||
.snippet-id {
|
||||
color: #5c5d5e;
|
||||
}
|
||||
}
|
||||
|
||||
.snippet-title {
|
||||
margin: 0;
|
||||
font-size: 23px;
|
||||
color: #313236;
|
||||
}
|
||||
|
||||
@media (max-width: $screen-md-max) {
|
||||
.new-snippet-link {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $screen-sm-max) {
|
||||
.creator,
|
||||
.page-title .btn-close {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
margin-bottom: -$gl-padding;
|
||||
|
||||
.file-holder {
|
||||
border-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.snippet-box {
|
||||
@include border-radius(2px);
|
||||
|
||||
display: inline-block;
|
||||
padding: 10px $gl-padding;
|
||||
display: block;
|
||||
float: left;
|
||||
padding: 0 $gl-padding;
|
||||
font-weight: normal;
|
||||
margin-right: 10px;
|
||||
font-size: $gl-font-size;
|
||||
border: 1px solid;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
|
|
@ -4,3 +4,8 @@
|
|||
margin-right: auto;
|
||||
padding-right: 7px;
|
||||
}
|
||||
|
||||
.wiki-last-edit-by {
|
||||
font-size: 80%;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ class AbuseReportsController < ApplicationController
|
|||
|
||||
if @abuse_report.save
|
||||
if current_application_settings.admin_notification_email.present?
|
||||
AbuseReportMailer.delay.notify(@abuse_report.id)
|
||||
AbuseReportMailer.notify(@abuse_report.id).deliver_later
|
||||
end
|
||||
|
||||
message = "Thank you for your report. A GitLab administrator will look into it shortly."
|
||||
|
|
|
@ -8,4 +8,10 @@ class Admin::ApplicationController < ApplicationController
|
|||
def authenticate_admin!
|
||||
return render_404 unless current_user.is_admin?
|
||||
end
|
||||
|
||||
def authorize_impersonator!
|
||||
if session[:impersonator_id]
|
||||
User.find_by!(username: session[:impersonator_id]).admin?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
class Admin::ImpersonationController < Admin::ApplicationController
|
||||
skip_before_action :authenticate_admin!, only: :destroy
|
||||
|
||||
before_action :user
|
||||
before_action :authorize_impersonator!
|
||||
|
||||
def create
|
||||
if @user.blocked?
|
||||
flash[:alert] = "You cannot impersonate a blocked user"
|
||||
|
||||
redirect_to admin_user_path(@user)
|
||||
else
|
||||
session[:impersonator_id] = current_user.username
|
||||
session[:impersonator_return_to] = admin_user_path(@user)
|
||||
|
||||
warden.set_user(user, scope: 'user')
|
||||
|
||||
flash[:alert] = "You are impersonating #{user.username}."
|
||||
|
||||
redirect_to root_path
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
redirect = session[:impersonator_return_to]
|
||||
|
||||
warden.set_user(user, scope: 'user')
|
||||
|
||||
session[:impersonator_return_to] = nil
|
||||
session[:impersonator_id] = nil
|
||||
|
||||
redirect_to redirect || root_path
|
||||
end
|
||||
|
||||
def user
|
||||
@user ||= User.find_by!(username: params[:id] || session[:impersonator_id])
|
||||
end
|
||||
end
|
|
@ -63,12 +63,6 @@ class Admin::UsersController < Admin::ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def login_as
|
||||
sign_in(user)
|
||||
flash[:alert] = "Logged in as #{user.username}"
|
||||
redirect_to root_path
|
||||
end
|
||||
|
||||
def disable_two_factor
|
||||
user.disable_two_factor!
|
||||
redirect_to admin_user_path(user),
|
||||
|
|
|
@ -1,41 +1,15 @@
|
|||
class AutocompleteController < ApplicationController
|
||||
skip_before_action :authenticate_user!, only: [:users]
|
||||
before_action :find_users, only: [:users]
|
||||
|
||||
def users
|
||||
begin
|
||||
@users =
|
||||
if params[:project_id].present?
|
||||
project = Project.find(params[:project_id])
|
||||
|
||||
if can?(current_user, :read_project, project)
|
||||
project.team.users
|
||||
end
|
||||
elsif params[:group_id]
|
||||
group = Group.find(params[:group_id])
|
||||
|
||||
if can?(current_user, :read_group, group)
|
||||
group.users
|
||||
end
|
||||
elsif current_user
|
||||
User.all
|
||||
end
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
if current_user
|
||||
return render json: {}, status: 404
|
||||
end
|
||||
end
|
||||
|
||||
if @users.nil? && current_user.nil?
|
||||
authenticate_user!
|
||||
end
|
||||
|
||||
@users ||= User.none
|
||||
@users = @users.search(params[:search]) if params[:search].present?
|
||||
@users = @users.active
|
||||
@users = @users.reorder(:name)
|
||||
@users = @users.page(params[:page]).per(PER_PAGE)
|
||||
|
||||
unless params[:search].present?
|
||||
if params[:search].blank?
|
||||
# Include current user if available to filter by "Me"
|
||||
if params[:current_user] && current_user
|
||||
@users = [*@users, current_user].uniq
|
||||
|
@ -49,4 +23,25 @@ class AutocompleteController < ApplicationController
|
|||
@user = User.find(params[:id])
|
||||
render json: @user, only: [:name, :username, :id], methods: [:avatar_url]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_users
|
||||
@users =
|
||||
if params[:project_id].present?
|
||||
project = Project.find(params[:project_id])
|
||||
return render_404 unless can?(current_user, :read_project, project)
|
||||
|
||||
project.team.users
|
||||
elsif params[:group_id].present?
|
||||
group = Group.find(params[:group_id])
|
||||
return render_404 unless can?(current_user, :read_group, group)
|
||||
|
||||
group.users
|
||||
elsif current_user
|
||||
User.all
|
||||
else
|
||||
User.none
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,10 +15,10 @@ module Ci
|
|||
@builds = @config_processor.builds
|
||||
@status = true
|
||||
end
|
||||
rescue Ci::GitlabCiYamlProcessor::ValidationError => e
|
||||
rescue Ci::GitlabCiYamlProcessor::ValidationError, Psych::SyntaxError => e
|
||||
@error = e.message
|
||||
@status = false
|
||||
rescue Exception
|
||||
rescue
|
||||
@error = "Undefined error"
|
||||
@status = false
|
||||
end
|
||||
|
|
|
@ -26,10 +26,6 @@ module Ci
|
|||
redirect_to namespace_project_runners_path(project.gl_project.namespace, project.gl_project)
|
||||
end
|
||||
|
||||
def dumped_yaml
|
||||
send_data @project.generated_yaml_config, filename: '.gitlab-ci.yml'
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def project
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
module CreatesMergeRequestForCommit
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def new_merge_request_path
|
||||
if @project.forked?
|
||||
target_project = @project.forked_from_project || @project
|
||||
target_branch = target_project.repository.root_ref
|
||||
else
|
||||
target_project = @project
|
||||
target_branch = @ref
|
||||
end
|
||||
|
||||
new_namespace_project_merge_request_path(
|
||||
@project.namespace,
|
||||
@project,
|
||||
merge_request: {
|
||||
source_project_id: @project.id,
|
||||
target_project_id: target_project.id,
|
||||
source_branch: @new_branch,
|
||||
target_branch: target_branch
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
def create_merge_request?
|
||||
params[:create_merge_request] && @new_branch != @ref
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
module GlobalMilestones
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def milestones
|
||||
@milestones = MilestonesFinder.new.execute(@projects, params)
|
||||
@milestones = GlobalMilestone.build_collection(@milestones)
|
||||
@milestones = Kaminari.paginate_array(@milestones).page(params[:page]).per(ApplicationController::PER_PAGE)
|
||||
end
|
||||
|
||||
def milestone
|
||||
milestones = Milestone.of_projects(@projects).where(title: params[:title])
|
||||
|
||||
if milestones.present?
|
||||
@milestone = GlobalMilestone.new(params[:title], milestones)
|
||||
else
|
||||
render_404
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
module IssuesAction
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def issues
|
||||
@issues = get_issues_collection
|
||||
@issues = @issues.page(params[:page]).per(ApplicationController::PER_PAGE)
|
||||
@issues = @issues.preload(:author, :project)
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.atom { render layout: false }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
module MergeRequestsAction
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def merge_requests
|
||||
@merge_requests = get_merge_requests_collection
|
||||
@merge_requests = @merge_requests.page(params[:page]).per(ApplicationController::PER_PAGE)
|
||||
@merge_requests = @merge_requests.preload(:author, :target_project)
|
||||
end
|
||||
end
|
|
@ -1,34 +1,19 @@
|
|||
class Dashboard::MilestonesController < Dashboard::ApplicationController
|
||||
before_action :load_projects
|
||||
include GlobalMilestones
|
||||
|
||||
before_action :projects
|
||||
before_action :milestones, only: [:index]
|
||||
before_action :milestone, only: [:show]
|
||||
|
||||
def index
|
||||
project_milestones = case params[:state]
|
||||
when 'all'; state
|
||||
when 'closed'; state('closed')
|
||||
else state('active')
|
||||
end
|
||||
@dashboard_milestones = Milestones::GroupService.new(project_milestones).execute
|
||||
@dashboard_milestones = Kaminari.paginate_array(@dashboard_milestones).page(params[:page]).per(PER_PAGE)
|
||||
end
|
||||
|
||||
def show
|
||||
project_milestones = Milestone.where(project_id: @projects).order("due_date ASC")
|
||||
@dashboard_milestone = Milestones::GroupService.new(project_milestones).milestone(title)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_projects
|
||||
@projects = current_user.authorized_projects.sorted_by_activity.non_archived
|
||||
end
|
||||
|
||||
def title
|
||||
params[:title]
|
||||
end
|
||||
|
||||
def state(state = nil)
|
||||
conditions = { project_id: @projects }
|
||||
conditions.reverse_merge!(state: state) if state
|
||||
Milestone.where(conditions).order("title ASC")
|
||||
def projects
|
||||
@projects ||= current_user.authorized_projects.sorted_by_activity.non_archived
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,25 +1,12 @@
|
|||
class DashboardController < Dashboard::ApplicationController
|
||||
include IssuesAction
|
||||
include MergeRequestsAction
|
||||
|
||||
before_action :event_filter, only: :activity
|
||||
before_action :projects, only: [:issues, :merge_requests]
|
||||
|
||||
respond_to :html
|
||||
|
||||
def merge_requests
|
||||
@merge_requests = get_merge_requests_collection
|
||||
@merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE)
|
||||
@merge_requests = @merge_requests.preload(:author, :target_project)
|
||||
end
|
||||
|
||||
def issues
|
||||
@issues = get_issues_collection
|
||||
@issues = @issues.page(params[:page]).per(PER_PAGE)
|
||||
@issues = @issues.preload(:author, :project)
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.atom { render layout: false }
|
||||
end
|
||||
end
|
||||
|
||||
def activity
|
||||
@last_push = current_user.recent_push
|
||||
|
||||
|
@ -47,4 +34,8 @@ class DashboardController < Dashboard::ApplicationController
|
|||
@events = @event_filter.apply_filter(@events).with_associations
|
||||
@events = @events.limit(20).offset(params[:offset] || 0)
|
||||
end
|
||||
|
||||
def projects
|
||||
@projects ||= current_user.authorized_projects.sorted_by_activity.non_archived
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
class Groups::ApplicationController < ApplicationController
|
||||
layout 'group'
|
||||
before_action :group
|
||||
|
||||
private
|
||||
|
||||
|
||||
def group
|
||||
@group ||= Group.find_by(path: params[:group_id])
|
||||
end
|
||||
|
||||
def authorize_read_group!
|
||||
unless @group and can?(current_user, :read_group, @group)
|
||||
if current_user.nil?
|
||||
|
@ -12,13 +17,13 @@ class Groups::ApplicationController < ApplicationController
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def authorize_admin_group!
|
||||
unless can?(current_user, :admin_group, group)
|
||||
return render_404
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def authorize_admin_group_member!
|
||||
unless can?(current_user, :admin_group_member, group)
|
||||
return render_403
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
class Groups::AvatarsController < ApplicationController
|
||||
class Groups::AvatarsController < Groups::ApplicationController
|
||||
def destroy
|
||||
@group = Group.find_by(path: params[:group_id])
|
||||
@group.remove_avatar!
|
||||
|
||||
@group.save
|
||||
|
||||
redirect_to edit_group_path(@group)
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
class Groups::GroupMembersController < Groups::ApplicationController
|
||||
skip_before_action :authenticate_user!, only: [:index]
|
||||
before_action :group
|
||||
|
||||
# Authorize
|
||||
before_action :authorize_read_group!
|
||||
before_action :authorize_admin_group!, except: [:index, :leave]
|
||||
before_action :authorize_admin_group_member!, only: [:create, :resend_invite]
|
||||
before_action :authorize_admin_group_member!, except: [:index, :leave]
|
||||
|
||||
def index
|
||||
@project = @group.projects.find(params[:project_id]) if params[:project_id]
|
||||
|
@ -18,7 +16,8 @@ class Groups::GroupMembersController < Groups::ApplicationController
|
|||
end
|
||||
|
||||
@members = @members.order('access_level DESC').page(params[:page]).per(50)
|
||||
@group_member = GroupMember.new
|
||||
|
||||
@group_member = @group.group_members.new
|
||||
end
|
||||
|
||||
def create
|
||||
|
@ -28,24 +27,23 @@ class Groups::GroupMembersController < Groups::ApplicationController
|
|||
end
|
||||
|
||||
def update
|
||||
@member = @group.group_members.find(params[:id])
|
||||
@group_member = @group.group_members.find(params[:id])
|
||||
|
||||
return render_403 unless can?(current_user, :update_group_member, @member)
|
||||
return render_403 unless can?(current_user, :update_group_member, @group_member)
|
||||
|
||||
@member.update_attributes(member_params)
|
||||
@group_member.update_attributes(member_params)
|
||||
end
|
||||
|
||||
def destroy
|
||||
@group_member = @group.group_members.find(params[:id])
|
||||
|
||||
if can?(current_user, :destroy_group_member, @group_member) # May fail if last owner.
|
||||
@group_member.destroy
|
||||
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 }
|
||||
end
|
||||
else
|
||||
return render_403
|
||||
return render_403 unless can?(current_user, :destroy_group_member, @group_member)
|
||||
|
||||
@group_member.destroy
|
||||
|
||||
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 }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -64,10 +62,11 @@ class Groups::GroupMembersController < Groups::ApplicationController
|
|||
end
|
||||
|
||||
def leave
|
||||
@group_member = @group.group_members.where(user_id: current_user.id).first
|
||||
@group_member = @group.group_members.find_by(user_id: current_user)
|
||||
|
||||
if can?(current_user, :destroy_group_member, @group_member)
|
||||
@group_member.destroy
|
||||
|
||||
redirect_to(dashboard_groups_path, notice: "You left #{group.name} group.")
|
||||
else
|
||||
if @group.last_owner?(current_user)
|
||||
|
@ -80,10 +79,6 @@ class Groups::GroupMembersController < Groups::ApplicationController
|
|||
|
||||
protected
|
||||
|
||||
def group
|
||||
@group ||= Group.find_by(path: params[:group_id])
|
||||
end
|
||||
|
||||
def member_params
|
||||
params.require(:group_member).permit(:access_level, :user_id)
|
||||
end
|
||||
|
|
|
@ -1,54 +1,55 @@
|
|||
class Groups::MilestonesController < Groups::ApplicationController
|
||||
before_action :authorize_group_milestone!, only: :update
|
||||
include GlobalMilestones
|
||||
|
||||
before_action :projects
|
||||
before_action :milestones, only: [:index]
|
||||
before_action :milestone, only: [:show, :update]
|
||||
before_action :authorize_group_milestone!, only: [:create, :update]
|
||||
|
||||
def index
|
||||
project_milestones = case params[:state]
|
||||
when 'all'; state
|
||||
when 'closed'; state('closed')
|
||||
else state('active')
|
||||
end
|
||||
@group_milestones = Milestones::GroupService.new(project_milestones).execute
|
||||
@group_milestones = Kaminari.paginate_array(@group_milestones).page(params[:page]).per(PER_PAGE)
|
||||
end
|
||||
|
||||
def new
|
||||
@milestone = Milestone.new
|
||||
end
|
||||
|
||||
def create
|
||||
project_ids = params[:milestone][:project_ids]
|
||||
title = milestone_params[:title]
|
||||
|
||||
@group.projects.where(id: project_ids).each do |project|
|
||||
Milestones::CreateService.new(project, current_user, milestone_params).execute
|
||||
end
|
||||
|
||||
redirect_to milestone_path(title)
|
||||
end
|
||||
|
||||
def show
|
||||
project_milestones = Milestone.where(project_id: group.projects).order("due_date ASC")
|
||||
@group_milestone = Milestones::GroupService.new(project_milestones).milestone(title)
|
||||
end
|
||||
|
||||
def update
|
||||
project_milestones = Milestone.where(project_id: group.projects).order("due_date ASC")
|
||||
@group_milestones = Milestones::GroupService.new(project_milestones).milestone(title)
|
||||
|
||||
@group_milestones.milestones.each do |milestone|
|
||||
Milestones::UpdateService.new(milestone.project, current_user, params[:milestone]).execute(milestone)
|
||||
@milestone.milestones.each do |milestone|
|
||||
Milestones::UpdateService.new(milestone.project, current_user, milestone_params).execute(milestone)
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.js
|
||||
format.html do
|
||||
redirect_to group_milestones_path(group)
|
||||
end
|
||||
end
|
||||
redirect_back_or_default(default: milestone_path(@milestone.title))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def group
|
||||
@group ||= Group.find_by(path: params[:group_id])
|
||||
end
|
||||
|
||||
def title
|
||||
params[:title]
|
||||
end
|
||||
|
||||
def state(state = nil)
|
||||
conditions = { project_id: group.projects }
|
||||
conditions.reverse_merge!(state: state) if state
|
||||
Milestone.where(conditions).order("title ASC")
|
||||
end
|
||||
|
||||
def authorize_group_milestone!
|
||||
return render_404 unless can?(current_user, :admin_group, group)
|
||||
return render_404 unless can?(current_user, :admin_milestones, group)
|
||||
end
|
||||
|
||||
def milestone_params
|
||||
params.require(:milestone).permit(:title, :description, :due_date, :state_event)
|
||||
end
|
||||
|
||||
def milestone_path(title)
|
||||
group_milestone_path(@group, title.parameterize, title: title)
|
||||
end
|
||||
|
||||
def projects
|
||||
@projects ||= @group.projects
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
class GroupsController < Groups::ApplicationController
|
||||
include IssuesAction
|
||||
include MergeRequestsAction
|
||||
|
||||
skip_before_action :authenticate_user!, only: [:show, :issues, :merge_requests]
|
||||
respond_to :html
|
||||
before_action :group, except: [:new, :create]
|
||||
|
@ -53,23 +56,6 @@ class GroupsController < Groups::ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def merge_requests
|
||||
@merge_requests = get_merge_requests_collection
|
||||
@merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE)
|
||||
@merge_requests = @merge_requests.preload(:author, :target_project)
|
||||
end
|
||||
|
||||
def issues
|
||||
@issues = get_issues_collection
|
||||
@issues = @issues.page(params[:page]).per(PER_PAGE)
|
||||
@issues = @issues.preload(:author, :project)
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.atom { render layout: false }
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ class Projects::ApplicationController < ApplicationController
|
|||
private
|
||||
|
||||
def ci_enabled
|
||||
return render_404 unless @project.gitlab_ci?
|
||||
return render_404 unless @project.builds_enabled?
|
||||
end
|
||||
|
||||
def ci_project
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# Controller for viewing a file's blame
|
||||
class Projects::BlobController < Projects::ApplicationController
|
||||
include ExtractsPath
|
||||
include CreatesMergeRequestForCommit
|
||||
include ActionView::Helpers::SanitizeHelper
|
||||
|
||||
# Raised when given an invalid file path
|
||||
|
@ -22,21 +23,9 @@ class Projects::BlobController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def create
|
||||
result = Files::CreateService.new(@project, current_user, @commit_params).execute
|
||||
|
||||
if result[:status] == :success
|
||||
flash[:notice] = "The changes have been successfully committed"
|
||||
respond_to do |format|
|
||||
format.html { redirect_to namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @file_path)) }
|
||||
format.json { render json: { message: "success", filePath: namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @file_path)) } }
|
||||
end
|
||||
else
|
||||
flash[:alert] = result[:message]
|
||||
respond_to do |format|
|
||||
format.html { render :new }
|
||||
format.json { render json: { message: "failed", filePath: namespace_project_blob_path(@project.namespace, @project, @id) } }
|
||||
end
|
||||
end
|
||||
create_commit(Files::CreateService, success_path: after_create_path,
|
||||
failure_view: :new,
|
||||
failure_path: namespace_project_new_blob_path(@project.namespace, @project, @ref))
|
||||
end
|
||||
|
||||
def show
|
||||
|
@ -47,21 +36,9 @@ class Projects::BlobController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def update
|
||||
result = Files::UpdateService.new(@project, current_user, @commit_params).execute
|
||||
|
||||
if result[:status] == :success
|
||||
flash[:notice] = "Your changes have been successfully committed"
|
||||
respond_to do |format|
|
||||
format.html { redirect_to after_edit_path }
|
||||
format.json { render json: { message: "success", filePath: after_edit_path } }
|
||||
end
|
||||
else
|
||||
flash[:alert] = result[:message]
|
||||
respond_to do |format|
|
||||
format.html { render :edit }
|
||||
format.json { render json: { message: "failed", filePath: namespace_project_new_blob_path(@project.namespace, @project, @id) } }
|
||||
end
|
||||
end
|
||||
create_commit(Files::UpdateService, success_path: after_edit_path,
|
||||
failure_view: :edit,
|
||||
failure_path: namespace_project_blob_path(@project.namespace, @project, @id))
|
||||
end
|
||||
|
||||
def preview
|
||||
|
@ -77,7 +54,7 @@ class Projects::BlobController < Projects::ApplicationController
|
|||
|
||||
if result[:status] == :success
|
||||
flash[:notice] = "Your changes have been successfully committed"
|
||||
redirect_to namespace_project_tree_path(@project.namespace, @project, @target_branch)
|
||||
redirect_to after_destroy_path
|
||||
else
|
||||
flash[:alert] = result[:message]
|
||||
render :show
|
||||
|
@ -131,15 +108,51 @@ class Projects::BlobController < Projects::ApplicationController
|
|||
render_404
|
||||
end
|
||||
|
||||
def create_commit(service, success_path:, failure_view:, failure_path:)
|
||||
result = service.new(@project, current_user, @commit_params).execute
|
||||
|
||||
if result[:status] == :success
|
||||
flash[:notice] = "Your changes have been successfully committed"
|
||||
respond_to do |format|
|
||||
format.html { redirect_to success_path }
|
||||
format.json { render json: { message: "success", filePath: success_path } }
|
||||
end
|
||||
else
|
||||
flash[:alert] = result[:message]
|
||||
respond_to do |format|
|
||||
format.html { render failure_view }
|
||||
format.json { render json: { message: "failed", filePath: failure_path } }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def after_create_path
|
||||
@after_create_path ||=
|
||||
if create_merge_request?
|
||||
new_merge_request_path
|
||||
else
|
||||
namespace_project_blob_path(@project.namespace, @project, File.join(@new_branch, @file_path))
|
||||
end
|
||||
end
|
||||
|
||||
def after_edit_path
|
||||
@after_edit_path ||=
|
||||
if from_merge_request
|
||||
if create_merge_request?
|
||||
new_merge_request_path
|
||||
elsif from_merge_request && @new_branch == @ref
|
||||
diffs_namespace_project_merge_request_path(from_merge_request.target_project.namespace, from_merge_request.target_project, from_merge_request) +
|
||||
"#file-path-#{hexdigest(@path)}"
|
||||
elsif @target_branch.present?
|
||||
namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @path))
|
||||
else
|
||||
namespace_project_blob_path(@project.namespace, @project, @id)
|
||||
namespace_project_blob_path(@project.namespace, @project, File.join(@new_branch, @path))
|
||||
end
|
||||
end
|
||||
|
||||
def after_destroy_path
|
||||
@after_destroy_path ||=
|
||||
if create_merge_request?
|
||||
new_merge_request_path
|
||||
else
|
||||
namespace_project_tree_path(@project.namespace, @project, @new_branch)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -154,7 +167,7 @@ class Projects::BlobController < Projects::ApplicationController
|
|||
|
||||
def editor_variables
|
||||
@current_branch = @ref
|
||||
@target_branch = params[:new_branch].present? ? sanitized_new_branch_name : @ref
|
||||
@new_branch = params[:new_branch].present? ? sanitized_new_branch_name : @ref
|
||||
|
||||
@file_path =
|
||||
if action_name.to_s == 'create'
|
||||
|
@ -174,7 +187,7 @@ class Projects::BlobController < Projects::ApplicationController
|
|||
@commit_params = {
|
||||
file_path: @file_path,
|
||||
current_branch: @current_branch,
|
||||
target_branch: @target_branch,
|
||||
target_branch: @new_branch,
|
||||
commit_message: params[:commit_message],
|
||||
file_content: params[:content],
|
||||
file_content_encoding: params[:encoding]
|
||||
|
|
|
@ -3,7 +3,7 @@ class Projects::BranchesController < Projects::ApplicationController
|
|||
# Authorize
|
||||
before_action :require_non_empty_project
|
||||
before_action :authorize_download_code!
|
||||
before_action :authorize_push_code!, only: [:create, :destroy]
|
||||
before_action :authorize_push_code!, only: [:new, :create, :destroy]
|
||||
|
||||
def index
|
||||
@sort = params[:sort] || 'name'
|
||||
|
|
|
@ -67,7 +67,12 @@ class Projects::CommitController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def define_show_vars
|
||||
@diffs = commit.diffs
|
||||
if params[:w].to_i == 1
|
||||
@diffs = commit.diffs({ ignore_whitespace_change: true })
|
||||
else
|
||||
@diffs = commit.diffs
|
||||
end
|
||||
|
||||
@notes_count = commit.notes.count
|
||||
|
||||
@builds = ci_commit.builds if ci_commit
|
||||
|
|
|
@ -12,15 +12,16 @@ class Projects::CompareController < Projects::ApplicationController
|
|||
def show
|
||||
base_ref = Addressable::URI.unescape(params[:from])
|
||||
@ref = head_ref = Addressable::URI.unescape(params[:to])
|
||||
diff_options = { ignore_whitespace_change: true } if params[:w] == '1'
|
||||
|
||||
compare_result = CompareService.new.
|
||||
execute(@project, head_ref, @project, base_ref)
|
||||
execute(@project, head_ref, @project, base_ref, diff_options)
|
||||
|
||||
if compare_result
|
||||
@commits = Commit.decorate(compare_result.commits, @project)
|
||||
@diffs = compare_result.diffs
|
||||
@commit = @commits.last
|
||||
@first_commit = @commits.first
|
||||
@commit = @project.commit(head_ref)
|
||||
@first_commit = @project.commit(base_ref)
|
||||
@line_notes = []
|
||||
end
|
||||
end
|
||||
|
|
|
@ -28,8 +28,8 @@ class Projects::ImportsController < Projects::ApplicationController
|
|||
if @project.import_finished?
|
||||
redirect_to(project_path(@project)) and return
|
||||
else
|
||||
redirect_to new_namespace_project_import_path(@project.namespace,
|
||||
@project) && return
|
||||
redirect_to(new_namespace_project_import_path(@project.namespace,
|
||||
@project)) and return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -60,7 +60,7 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
def show
|
||||
@participants = @issue.participants(current_user)
|
||||
@note = @project.notes.new(noteable: @issue)
|
||||
@notes = @issue.notes.with_associations.fresh
|
||||
@notes = @issue.notes.nonawards.with_associations.fresh
|
||||
@noteable = @issue
|
||||
|
||||
respond_with(@issue)
|
||||
|
|
|
@ -254,7 +254,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.inc_author.fresh
|
||||
@notes = @merge_request.mr_and_commit_notes.nonawards.inc_author.fresh
|
||||
@discussions = Note.discussions_from_notes(@notes)
|
||||
@noteable = @merge_request
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ class Projects::NotesController < Projects::ApplicationController
|
|||
before_action :authorize_read_note!
|
||||
before_action :authorize_create_note!, only: [:create]
|
||||
before_action :authorize_admin_note!, only: [:update, :destroy]
|
||||
before_action :find_current_user_notes, except: [:destroy, :delete_attachment]
|
||||
before_action :find_current_user_notes, except: [:destroy, :delete_attachment, :award_toggle]
|
||||
|
||||
def index
|
||||
current_fetched_at = Time.now.to_i
|
||||
|
@ -58,6 +58,30 @@ class Projects::NotesController < Projects::ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def award_toggle
|
||||
noteable = if note_params[:noteable_type] == "issue"
|
||||
project.issues.find(note_params[:noteable_id])
|
||||
else
|
||||
project.merge_requests.find(note_params[:noteable_id])
|
||||
end
|
||||
|
||||
data = {
|
||||
author: current_user,
|
||||
is_award: true,
|
||||
note: note_params[:note].gsub(":", '')
|
||||
}
|
||||
|
||||
note = noteable.notes.find_by(data)
|
||||
|
||||
if note
|
||||
note.destroy
|
||||
else
|
||||
Notes::CreateService.new(project, current_user, note_params).execute
|
||||
end
|
||||
|
||||
render json: { ok: true }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def note
|
||||
|
@ -111,6 +135,9 @@ class Projects::NotesController < Projects::ApplicationController
|
|||
id: note.id,
|
||||
discussion_id: note.discussion_id,
|
||||
html: note_to_html(note),
|
||||
award: note.is_award,
|
||||
emoji_path: note.is_award ? view_context.image_url(::AwardEmoji.path_to_emoji_image(note.note)) : "",
|
||||
note: note.note,
|
||||
discussion_html: note_to_discussion_html(note),
|
||||
discussion_with_diff_html: note_to_discussion_with_diff_html(note)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class Projects::ProjectMembersController < Projects::ApplicationController
|
||||
# Authorize
|
||||
before_action :authorize_admin_project!, except: :leave
|
||||
before_action :authorize_admin_project_member!, except: :leave
|
||||
|
||||
def index
|
||||
@project_members = @project.project_members
|
||||
|
@ -29,10 +29,6 @@ class Projects::ProjectMembersController < Projects::ApplicationController
|
|||
@project_member = @project.project_members.new
|
||||
end
|
||||
|
||||
def new
|
||||
@project_member = @project.project_members.new
|
||||
end
|
||||
|
||||
def create
|
||||
@project.team.add_users(params[:user_ids].split(','), params[:access_level], current_user)
|
||||
|
||||
|
@ -41,11 +37,17 @@ class Projects::ProjectMembersController < Projects::ApplicationController
|
|||
|
||||
def update
|
||||
@project_member = @project.project_members.find(params[:id])
|
||||
|
||||
return render_403 unless can?(current_user, :update_project_member, @project_member)
|
||||
|
||||
@project_member.update_attributes(member_params)
|
||||
end
|
||||
|
||||
def destroy
|
||||
@project_member = @project.project_members.find(params[:id])
|
||||
|
||||
return render_403 unless can?(current_user, :destroy_project_member, @project_member)
|
||||
|
||||
@project_member.destroy
|
||||
|
||||
respond_to do |format|
|
||||
|
@ -71,16 +73,22 @@ class Projects::ProjectMembersController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def leave
|
||||
if @project.namespace == current_user.namespace
|
||||
message = 'You can not leave your own project. Transfer or delete the project.'
|
||||
return redirect_back_or_default(default: { action: 'index' }, options: { alert: message })
|
||||
end
|
||||
@project_member = @project.project_members.find_by(user_id: current_user)
|
||||
|
||||
@project.project_members.find_by(user_id: current_user).destroy
|
||||
if can?(current_user, :destroy_project_member, @project_member)
|
||||
@project_member.destroy
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to dashboard_projects_path }
|
||||
format.js { render nothing: true }
|
||||
respond_to do |format|
|
||||
format.html { redirect_to dashboard_projects_path, notice: "You left the project." }
|
||||
format.js { render nothing: true }
|
||||
end
|
||||
else
|
||||
if current_user == @project.owner
|
||||
message = 'You can not leave your own project. Transfer or delete the project.'
|
||||
redirect_back_or_default(default: { action: 'index' }, options: { alert: message })
|
||||
else
|
||||
render_403
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ class Projects::TagsController < Projects::ApplicationController
|
|||
# Authorize
|
||||
before_action :require_non_empty_project
|
||||
before_action :authorize_download_code!
|
||||
before_action :authorize_push_code!, only: [:create]
|
||||
before_action :authorize_push_code!, only: [:new, :create]
|
||||
before_action :authorize_admin_project!, only: [:destroy]
|
||||
|
||||
def index
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# Controller for viewing a repository's file structure
|
||||
class Projects::TreeController < Projects::ApplicationController
|
||||
include ExtractsPath
|
||||
include CreatesMergeRequestForCommit
|
||||
include ActionView::Helpers::SanitizeHelper
|
||||
|
||||
before_action :require_non_empty_project, except: [:new, :create]
|
||||
|
@ -43,7 +44,7 @@ class Projects::TreeController < Projects::ApplicationController
|
|||
if result && result[:status] == :success
|
||||
flash[:notice] = "The directory has been successfully created"
|
||||
respond_to do |format|
|
||||
format.html { redirect_to namespace_project_blob_path(@project.namespace, @project, File.join(@new_branch, @dir_name)) }
|
||||
format.html { redirect_to after_create_dir_path }
|
||||
end
|
||||
else
|
||||
flash[:alert] = message
|
||||
|
@ -53,6 +54,8 @@ class Projects::TreeController < Projects::ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def assign_dir_vars
|
||||
@new_branch = params[:new_branch].present? ? sanitize(strip_tags(params[:new_branch])) : @ref
|
||||
@dir_name = File.join(@path, params[:dir_name])
|
||||
|
@ -63,4 +66,12 @@ class Projects::TreeController < Projects::ApplicationController
|
|||
commit_message: params[:commit_message],
|
||||
}
|
||||
end
|
||||
|
||||
def after_create_dir_path
|
||||
if create_merge_request?
|
||||
new_merge_request_path
|
||||
else
|
||||
namespace_project_blob_path(@project.namespace, @project, File.join(@new_branch, @dir_name))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -72,8 +72,7 @@ class ProjectsController < ApplicationController
|
|||
def remove_fork
|
||||
return access_denied! unless can?(current_user, :remove_fork_project, @project)
|
||||
|
||||
if @project.forked?
|
||||
@project.forked_project_link.destroy
|
||||
if @project.unlink_fork
|
||||
flash[:notice] = 'The fork relationship has been removed.'
|
||||
end
|
||||
end
|
||||
|
@ -124,7 +123,7 @@ class ProjectsController < ApplicationController
|
|||
::Projects::DestroyService.new(@project, current_user, {}).execute
|
||||
flash[:alert] = "Project '#{@project.name}' was deleted."
|
||||
|
||||
redirect_back_or_default(default: dashboard_projects_path, options: {})
|
||||
redirect_to dashboard_projects_path
|
||||
rescue Projects::DestroyService::DestroyError => ex
|
||||
redirect_to edit_project_path(@project), alert: ex.message
|
||||
end
|
||||
|
@ -213,7 +212,8 @@ class ProjectsController < ApplicationController
|
|||
params.require(:project).permit(
|
||||
:name, :path, :description, :issues_tracker, :tag_list,
|
||||
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, :default_branch,
|
||||
:wiki_enabled, :visibility_level, :import_url, :last_activity_at, :namespace_id, :avatar
|
||||
:wiki_enabled, :visibility_level, :import_url, :last_activity_at, :namespace_id, :avatar,
|
||||
:builds_enabled
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -242,7 +242,7 @@ class ProjectsController < ApplicationController
|
|||
project.repository_exists? && !project.empty_repo?
|
||||
end
|
||||
|
||||
# Override get_id from ExtractsPath, which returns the branch and file path
|
||||
# Override get_id from ExtractsPath, which returns the branch and file path
|
||||
# for the blob/tree, which in this case is just the root of the default branch.
|
||||
def get_id
|
||||
project.repository.root_ref
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
class SnippetsController < ApplicationController
|
||||
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw]
|
||||
|
||||
# Allow read snippet
|
||||
before_action :authorize_read_snippet!, only: [:show, :raw]
|
||||
|
||||
# Allow modify snippet
|
||||
before_action :authorize_update_snippet!, only: [:edit, :update]
|
||||
|
||||
|
@ -79,10 +82,14 @@ class SnippetsController < ApplicationController
|
|||
[Snippet::PUBLIC, Snippet::INTERNAL]).
|
||||
find(params[:id])
|
||||
else
|
||||
PersonalSnippet.are_public.find(params[:id])
|
||||
PersonalSnippet.find(params[:id])
|
||||
end
|
||||
end
|
||||
|
||||
def authorize_read_snippet!
|
||||
authenticate_user! unless can?(current_user, :read_personal_snippet, @snippet)
|
||||
end
|
||||
|
||||
def authorize_update_snippet!
|
||||
return render_404 unless can?(current_user, :update_personal_snippet, @snippet)
|
||||
end
|
||||
|
|
|
@ -3,14 +3,11 @@ class UsersController < ApplicationController
|
|||
before_action :set_user
|
||||
|
||||
def show
|
||||
@contributed_projects = contributed_projects.joined(@user).
|
||||
reject(&:forked?)
|
||||
@contributed_projects = contributed_projects.joined(@user).reject(&:forked?)
|
||||
|
||||
@projects = @user.personal_projects.
|
||||
where(id: authorized_projects_ids).includes(:namespace)
|
||||
@projects = PersonalProjectsFinder.new(@user).execute(current_user)
|
||||
|
||||
# Collect only groups common for both users
|
||||
@groups = @user.groups & GroupsFinder.new.execute(current_user)
|
||||
@groups = JoinedGroupsFinder.new(@user).execute(current_user)
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
|
@ -53,16 +50,8 @@ class UsersController < ApplicationController
|
|||
@user = User.find_by_username!(params[:username])
|
||||
end
|
||||
|
||||
def authorized_projects_ids
|
||||
# Projects user can view
|
||||
@authorized_projects_ids ||=
|
||||
ProjectsFinder.new.execute(current_user).pluck(:id)
|
||||
end
|
||||
|
||||
def contributed_projects
|
||||
@contributed_projects = Project.
|
||||
where(id: authorized_projects_ids & @user.contributed_projects_ids).
|
||||
includes(:namespace)
|
||||
ContributedProjectsFinder.new(@user).execute(current_user)
|
||||
end
|
||||
|
||||
def contributions_calendar
|
||||
|
@ -73,9 +62,13 @@ class UsersController < ApplicationController
|
|||
def load_events
|
||||
# Get user activity feed for projects common for both users
|
||||
@events = @user.recent_events.
|
||||
where(project_id: authorized_projects_ids).
|
||||
with_associations
|
||||
merge(projects_for_current_user).
|
||||
references(:project).
|
||||
with_associations.
|
||||
limit_recent(20, params[:offset])
|
||||
end
|
||||
|
||||
@events = @events.limit(20).offset(params[:offset] || 0)
|
||||
def projects_for_current_user
|
||||
ProjectsFinder.new.execute(current_user)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
class ContributedProjectsFinder
|
||||
def initialize(user)
|
||||
@user = user
|
||||
end
|
||||
|
||||
# Finds the projects "@user" contributed to, limited to either public projects
|
||||
# or projects visible to the given user.
|
||||
#
|
||||
# current_user - When given the list of the projects is limited to those only
|
||||
# visible by this user.
|
||||
#
|
||||
# Returns an ActiveRecord::Relation.
|
||||
def execute(current_user = nil)
|
||||
if current_user
|
||||
relation = projects_visible_to_user(current_user)
|
||||
else
|
||||
relation = public_projects
|
||||
end
|
||||
|
||||
relation.includes(:namespace).order_id_desc
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def projects_visible_to_user(current_user)
|
||||
authorized = @user.contributed_projects.visible_to_user(current_user)
|
||||
|
||||
union = Gitlab::SQL::Union.
|
||||
new([authorized.select(:id), public_projects.select(:id)])
|
||||
|
||||
Project.where("projects.id IN (#{union.to_sql})")
|
||||
end
|
||||
|
||||
def public_projects
|
||||
@user.contributed_projects.public_only
|
||||
end
|
||||
end
|
|
@ -1,39 +1,44 @@
|
|||
class GroupsFinder
|
||||
def execute(current_user, options = {})
|
||||
all_groups(current_user)
|
||||
# Finds the groups available to the given user.
|
||||
#
|
||||
# current_user - The user to find the groups for.
|
||||
#
|
||||
# Returns an ActiveRecord::Relation.
|
||||
def execute(current_user = nil)
|
||||
if current_user
|
||||
relation = groups_visible_to_user(current_user)
|
||||
else
|
||||
relation = public_groups
|
||||
end
|
||||
|
||||
relation.order_id_desc
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def all_groups(current_user)
|
||||
group_ids = if current_user
|
||||
if current_user.authorized_groups.any?
|
||||
# User has access to groups
|
||||
#
|
||||
# Return only:
|
||||
# groups with public projects
|
||||
# groups with internal projects
|
||||
# groups with joined projects
|
||||
#
|
||||
Project.public_and_internal_only.pluck(:namespace_id) +
|
||||
current_user.authorized_groups.pluck(:id)
|
||||
else
|
||||
# User has no group membership
|
||||
#
|
||||
# Return only:
|
||||
# groups with public projects
|
||||
# groups with internal projects
|
||||
#
|
||||
Project.public_and_internal_only.pluck(:namespace_id)
|
||||
end
|
||||
else
|
||||
# Not authenticated
|
||||
#
|
||||
# Return only:
|
||||
# groups with public projects
|
||||
Project.public_only.pluck(:namespace_id)
|
||||
end
|
||||
# This method returns the groups "current_user" can see.
|
||||
def groups_visible_to_user(current_user)
|
||||
base = groups_for_projects(public_and_internal_projects)
|
||||
|
||||
Group.where("public IS TRUE OR id IN(?)", group_ids)
|
||||
union = Gitlab::SQL::Union.
|
||||
new([base.select(:id), current_user.authorized_groups.select(:id)])
|
||||
|
||||
Group.where("namespaces.id IN (#{union.to_sql})")
|
||||
end
|
||||
|
||||
def public_groups
|
||||
groups_for_projects(public_projects)
|
||||
end
|
||||
|
||||
def groups_for_projects(projects)
|
||||
Group.public_and_given_groups(projects.select(:namespace_id))
|
||||
end
|
||||
|
||||
def public_projects
|
||||
Project.unscoped.public_only
|
||||
end
|
||||
|
||||
def public_and_internal_projects
|
||||
Project.unscoped.public_and_internal_only
|
||||
end
|
||||
end
|
||||
|
|
|
@ -62,10 +62,10 @@ class IssuableFinder
|
|||
|
||||
if project?
|
||||
@project = Project.find(params[:project_id])
|
||||
|
||||
|
||||
unless Ability.abilities.allowed?(current_user, :read_project, @project)
|
||||
@project = nil
|
||||
end
|
||||
end
|
||||
else
|
||||
@project = nil
|
||||
end
|
||||
|
@ -77,11 +77,11 @@ class IssuableFinder
|
|||
return @projects if defined?(@projects)
|
||||
|
||||
if project?
|
||||
project
|
||||
@projects = project
|
||||
elsif current_user && params[:authorized_only].presence && !current_user_related?
|
||||
current_user.authorized_projects
|
||||
@projects = current_user.authorized_projects
|
||||
else
|
||||
ProjectsFinder.new.execute(current_user)
|
||||
@projects = ProjectsFinder.new.execute(current_user)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -190,8 +190,10 @@ class IssuableFinder
|
|||
|
||||
def by_project(items)
|
||||
items =
|
||||
if projects
|
||||
items.of_projects(projects).references(:project)
|
||||
if project?
|
||||
items.of_projects(projects).references_project
|
||||
elsif projects
|
||||
items.merge(projects.reorder(nil)).join_project
|
||||
else
|
||||
items.none
|
||||
end
|
||||
|
@ -206,7 +208,9 @@ class IssuableFinder
|
|||
end
|
||||
|
||||
def sort(items)
|
||||
items.sort(params[:sort])
|
||||
# Ensure we always have an explicit sort order (instead of inheriting
|
||||
# multiple orders when combining ActiveRecord::Relation objects).
|
||||
params[:sort] ? items.sort(params[:sort]) : items.reorder(id: :desc)
|
||||
end
|
||||
|
||||
def by_assignee(items)
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
# Class for finding the groups a user is a member of.
|
||||
class JoinedGroupsFinder
|
||||
def initialize(user = nil)
|
||||
@user = user
|
||||
end
|
||||
|
||||
# Finds the groups of the source user, optionally limited to those visible to
|
||||
# the current user.
|
||||
#
|
||||
# current_user - If given the groups of "@user" will only include the groups
|
||||
# "current_user" can also see.
|
||||
#
|
||||
# Returns an ActiveRecord::Relation.
|
||||
def execute(current_user = nil)
|
||||
if current_user
|
||||
relation = groups_visible_to_user(current_user)
|
||||
else
|
||||
relation = public_groups
|
||||
end
|
||||
|
||||
relation.order_id_desc
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Returns the groups the user in "current_user" can see.
|
||||
#
|
||||
# This list includes all public/internal projects as well as the projects of
|
||||
# "@user" that "current_user" also has access to.
|
||||
def groups_visible_to_user(current_user)
|
||||
base = @user.authorized_groups.visible_to_user(current_user)
|
||||
extra = public_and_internal_groups
|
||||
union = Gitlab::SQL::Union.new([base.select(:id), extra.select(:id)])
|
||||
|
||||
Group.where("namespaces.id IN (#{union.to_sql})")
|
||||
end
|
||||
|
||||
def public_groups
|
||||
groups_for_projects(@user.authorized_projects.public_only)
|
||||
end
|
||||
|
||||
def public_and_internal_groups
|
||||
groups_for_projects(@user.authorized_projects.public_and_internal_only)
|
||||
end
|
||||
|
||||
def groups_for_projects(projects)
|
||||
@user.groups.public_and_given_groups(projects.select(:namespace_id))
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
class MilestonesFinder
|
||||
def execute(projects, params)
|
||||
milestones = Milestone.of_projects(projects)
|
||||
milestones = milestones.order("due_date ASC")
|
||||
|
||||
case params[:state]
|
||||
when 'closed' then milestones.closed
|
||||
when 'all' then milestones
|
||||
else milestones.active
|
||||
end
|
||||
end
|
||||
end
|
|
@ -12,9 +12,9 @@ class NotesFinder
|
|||
when "commit"
|
||||
project.notes.for_commit_id(target_id).not_inline
|
||||
when "issue"
|
||||
project.issues.find(target_id).notes.inc_author
|
||||
project.issues.find(target_id).notes.nonawards.inc_author
|
||||
when "merge_request"
|
||||
project.merge_requests.find(target_id).mr_and_commit_notes.inc_author
|
||||
project.merge_requests.find(target_id).mr_and_commit_notes.nonawards.inc_author
|
||||
when "snippet", "project_snippet"
|
||||
project.snippets.find(target_id).notes
|
||||
else
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
class PersonalProjectsFinder
|
||||
def initialize(user)
|
||||
@user = user
|
||||
end
|
||||
|
||||
# Finds the projects belonging to the user in "@user", limited to either
|
||||
# public projects or projects visible to the given user.
|
||||
#
|
||||
# current_user - When given the list of projects is limited to those only
|
||||
# visible by this user.
|
||||
#
|
||||
# Returns an ActiveRecord::Relation.
|
||||
def execute(current_user = nil)
|
||||
if current_user
|
||||
relation = projects_visible_to_user(current_user)
|
||||
else
|
||||
relation = public_projects
|
||||
end
|
||||
|
||||
relation.includes(:namespace).order_id_desc
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def projects_visible_to_user(current_user)
|
||||
authorized = @user.personal_projects.visible_to_user(current_user)
|
||||
|
||||
union = Gitlab::SQL::Union.
|
||||
new([authorized.select(:id), public_and_internal_projects.select(:id)])
|
||||
|
||||
Project.where("projects.id IN (#{union.to_sql})")
|
||||
end
|
||||
|
||||
def public_projects
|
||||
@user.personal_projects.public_only
|
||||
end
|
||||
|
||||
def public_and_internal_projects
|
||||
@user.personal_projects.public_and_internal_only
|
||||
end
|
||||
end
|
|
@ -1,11 +1,39 @@
|
|||
class ProjectsFinder
|
||||
def execute(current_user, options = {})
|
||||
# Returns all projects, optionally including group projects a user has access
|
||||
# to.
|
||||
#
|
||||
# ## Examples
|
||||
#
|
||||
# Retrieving all public projects:
|
||||
#
|
||||
# ProjectsFinder.new.execute
|
||||
#
|
||||
# Retrieving all public/internal projects and those the given user has access
|
||||
# to:
|
||||
#
|
||||
# ProjectsFinder.new.execute(some_user)
|
||||
#
|
||||
# Retrieving all public/internal projects as well as the group's projects the
|
||||
# user has access to:
|
||||
#
|
||||
# ProjectsFinder.new.execute(some_user, group: some_group)
|
||||
#
|
||||
# Returns an ActiveRecord::Relation.
|
||||
def execute(current_user = nil, options = {})
|
||||
group = options[:group]
|
||||
|
||||
if group
|
||||
group_projects(current_user, group)
|
||||
segments = group_projects(current_user, group)
|
||||
else
|
||||
all_projects(current_user)
|
||||
segments = all_projects(current_user)
|
||||
end
|
||||
|
||||
if segments.length > 1
|
||||
union = Gitlab::SQL::Union.new(segments.map { |s| s.select(:id) })
|
||||
|
||||
Project.where("projects.id IN (#{union.to_sql})")
|
||||
else
|
||||
segments.first
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -13,77 +41,36 @@ class ProjectsFinder
|
|||
|
||||
def group_projects(current_user, group)
|
||||
if current_user
|
||||
if group.users.include?(current_user)
|
||||
# User is group member
|
||||
#
|
||||
# Return ALL group projects
|
||||
group.projects
|
||||
else
|
||||
projects_members = ProjectMember.in_projects(group.projects).
|
||||
with_user(current_user)
|
||||
|
||||
if projects_members.any?
|
||||
# User is a project member
|
||||
#
|
||||
# Return only:
|
||||
# public projects
|
||||
# internal projects
|
||||
# joined projects
|
||||
#
|
||||
group.projects.where(
|
||||
"projects.id IN (?) OR projects.visibility_level IN (?)",
|
||||
projects_members.pluck(:source_id),
|
||||
Project.public_and_internal_levels
|
||||
)
|
||||
else
|
||||
# User has no access to group or group projects
|
||||
#
|
||||
# Return only:
|
||||
# public projects
|
||||
# internal projects
|
||||
#
|
||||
group.projects.public_and_internal_only
|
||||
end
|
||||
end
|
||||
[
|
||||
group_projects_for_user(current_user, group),
|
||||
group.projects.public_and_internal_only
|
||||
]
|
||||
else
|
||||
# Not authenticated
|
||||
#
|
||||
# Return only:
|
||||
# public projects
|
||||
group.projects.public_only
|
||||
[group.projects.public_only]
|
||||
end
|
||||
end
|
||||
|
||||
def all_projects(current_user)
|
||||
if current_user
|
||||
if current_user.authorized_projects.any?
|
||||
# User has access to private projects
|
||||
#
|
||||
# Return only:
|
||||
# public projects
|
||||
# internal projects
|
||||
# joined projects
|
||||
#
|
||||
Project.where(
|
||||
"projects.id IN (?) OR projects.visibility_level IN (?)",
|
||||
current_user.authorized_projects.pluck(:id),
|
||||
Project.public_and_internal_levels
|
||||
)
|
||||
else
|
||||
# User has no access to private projects
|
||||
#
|
||||
# Return only:
|
||||
# public projects
|
||||
# internal projects
|
||||
#
|
||||
Project.public_and_internal_only
|
||||
end
|
||||
[current_user.authorized_projects, public_and_internal_projects]
|
||||
else
|
||||
# Not authenticated
|
||||
#
|
||||
# Return only:
|
||||
# public projects
|
||||
Project.public_only
|
||||
[Project.public_only]
|
||||
end
|
||||
end
|
||||
|
||||
def group_projects_for_user(current_user, group)
|
||||
if group.users.include?(current_user)
|
||||
group.projects
|
||||
else
|
||||
group.projects.visible_to_user(current_user)
|
||||
end
|
||||
end
|
||||
|
||||
def public_projects
|
||||
Project.unscoped.public_only
|
||||
end
|
||||
|
||||
def public_and_internal_projects
|
||||
Project.unscoped.public_and_internal_only
|
||||
end
|
||||
end
|
||||
|
|
|
@ -68,7 +68,7 @@ module ApplicationHelper
|
|||
end
|
||||
end
|
||||
|
||||
def avatar_icon(user_or_email = nil, size = nil)
|
||||
def avatar_icon(user_or_email = nil, size = nil, scale = 2)
|
||||
if user_or_email.is_a?(User)
|
||||
user = user_or_email
|
||||
else
|
||||
|
@ -78,12 +78,12 @@ module ApplicationHelper
|
|||
if user
|
||||
user.avatar_url(size) || default_avatar
|
||||
else
|
||||
gravatar_icon(user_or_email, size)
|
||||
gravatar_icon(user_or_email, size, scale)
|
||||
end
|
||||
end
|
||||
|
||||
def gravatar_icon(user_email = '', size = nil)
|
||||
GravatarService.new.execute(user_email, size) ||
|
||||
def gravatar_icon(user_email = '', size = nil, scale = 2)
|
||||
GravatarService.new.execute(user_email, size, scale) ||
|
||||
default_avatar
|
||||
end
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ module BlobHelper
|
|||
if Gitlab::MarkupHelper.previewable?(filename)
|
||||
'Preview'
|
||||
else
|
||||
'Preview changes'
|
||||
'Preview Changes'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
module ButtonHelper
|
||||
# Output a "Copy to Clipboard" button
|
||||
#
|
||||
# data - Data attributes passed to `content_tag`
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# # Define the clipboard's text
|
||||
# clipboard_button(clipboard_text: "Foo")
|
||||
# # => "<button class='...' data-clipboard-text='Foo'>...</button>"
|
||||
#
|
||||
# # Define the target element
|
||||
# clipboard_button(clipboard_target: "#foo")
|
||||
# # => "<button class='...' data-clipboard-target='#foo'>...</button>"
|
||||
#
|
||||
# See http://clipboardjs.com/#usage
|
||||
def clipboard_button(data = {})
|
||||
content_tag :button,
|
||||
icon('clipboard'),
|
||||
class: 'btn btn-xs btn-clipboard',
|
||||
data: data,
|
||||
type: :button
|
||||
end
|
||||
|
||||
def http_clone_button(project)
|
||||
klass = 'btn js-protocol-switch'
|
||||
klass << ' active' if default_clone_protocol == 'http'
|
||||
klass << ' has_tooltip' if current_user.try(:require_password?)
|
||||
|
||||
protocol = gitlab_config.protocol.upcase
|
||||
|
||||
content_tag :button, protocol,
|
||||
class: klass,
|
||||
data: {
|
||||
clone: project.http_url_to_repo,
|
||||
container: 'body',
|
||||
html: 'true',
|
||||
title: "Set a password on your account<br>to pull or push via #{protocol}"
|
||||
},
|
||||
type: :button
|
||||
end
|
||||
|
||||
def ssh_clone_button(project)
|
||||
klass = 'btn js-protocol-switch'
|
||||
klass << ' active' if default_clone_protocol == 'ssh'
|
||||
klass << ' has_tooltip' if current_user.try(:require_ssh_key?)
|
||||
|
||||
content_tag :button, 'SSH',
|
||||
class: klass,
|
||||
data: {
|
||||
clone: project.ssh_url_to_repo,
|
||||
container: 'body',
|
||||
html: 'true',
|
||||
title: 'Add an SSH key to your profile<br>to pull or push via SSH.'
|
||||
},
|
||||
type: :button
|
||||
end
|
||||
end
|
|
@ -1,8 +0,0 @@
|
|||
module ClipboardHelper
|
||||
def clipboard_button
|
||||
content_tag :button,
|
||||
icon('clipboard'),
|
||||
class: 'btn btn-xs btn-clipboard js-clipboard-trigger',
|
||||
type: :button
|
||||
end
|
||||
end
|
|
@ -109,7 +109,7 @@ module CommitsHelper
|
|||
)
|
||||
elsif @path.present?
|
||||
return link_to(
|
||||
"Browse Dir »",
|
||||
"Browse Directory »",
|
||||
namespace_project_tree_path(project.namespace, project,
|
||||
tree_join(commit.id, @path)),
|
||||
class: "pull-right"
|
||||
|
@ -117,7 +117,7 @@ module CommitsHelper
|
|||
end
|
||||
end
|
||||
link_to(
|
||||
"Browse Code »",
|
||||
"Browse Files »",
|
||||
namespace_project_tree_path(project.namespace, project, commit),
|
||||
class: "pull-right"
|
||||
)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue