Upstream version 8.5.8+dfsg

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJW/73JAAoJEM4fnGdFEsIqMWYP/1LkqLBkCQhgWDsKugRru2dc
 vbVkQjMf9K0JG2FGPoHuxQfb1WaZD4dVbbdDhrGPSm/soE0uWcqxzZDjlBL2tZTH
 d0T3IoZi0J25+8sIJsLCYuM34PsP39ripI/iUoerEyHNaAnaRGyi1bElMARD9HWH
 e3obzwjPwewoMJZRVNp4fZBcuIolt2bEi7ckHYLhdt98AVVnwTSONEAnaWj0KaLW
 CGmUB+KM6fn/wcsS/gJr5PkiHj/yRzIh44yQHregTWkuDU23u/OUYg44GHSefSpR
 4WuDMjb2AS8n/7BoOl8miziuhwuwKcPze3tDC/DoESeFWEWpbx5H2TGXE0FNCp4B
 6XFCFUxkJjoMgqmJdeGxUmM9j32GHvlfywITc1Yl6E7Cp0gHpmenLq3KtvZakt+9
 EMWzi7nXItKkC5lOJ197OstFImmvAyTbmrhuAsRxAGa3k0uYKhYHRwZY+CecRrvB
 RmXi4U4REA2EjQtI5O2mo+5IlznX/LDaRaCaoe50rEXrpppMvw51B8BE2rGQlF68
 rNn+1FzFda73sstxEB0NjkfukUoufyjyudL6/PHUVyF0fi4GrLMXS6gYdM6liZcp
 mXugxdoJmdKkoa/hLY/WFlBt0TBbN0vaVVTQPLC2spihOXe2e/38ceT9dzFChuLU
 bQK7HsC+xbPs/d1WIx7k
 =mNQB
 -----END PGP SIGNATURE-----

Merge tag 'upstream/8.5.8+dfsg'

Upstream version 8.5.8+dfsg

# gpg: Signature made Saturday 02 April 2016 06:10:41 PM IST using RSA key ID 4512C22A
# gpg: Good signature from "Praveen Arimbrathodiyil (piratepin) <praveen@debian.org>"
# gpg:                 aka "Pirate Praveen (pirates.org.in) <praveen@onenetbeyond.org>"
# gpg:                 aka "Pirate Praveen (piratesin) <me@j4v4m4n.in>"
# gpg:                 aka "Pirate Praveen (PP) <praveen@privacyrequired.com>"
# gpg:                 aka "Praveen Arimbrathodiyil (j4v4m4n) <pravi.a@gmail.com>"
This commit is contained in:
Praveen Arimbrathodiyil 2016-04-02 18:10:49 +05:30
commit 4502604cf3
786 changed files with 45567 additions and 7670 deletions

1
.gitignore vendored
View file

@ -23,6 +23,7 @@ config/gitlab.yml
config/gitlab_ci.yml
config/initializers/rack_attack.rb
config/initializers/smtp_settings.rb
config/initializers/relative_url.rb
config/resque.yml
config/unicorn.rb
config/secrets.yml

View file

@ -5,11 +5,16 @@ services:
- postgres:latest
- redis:latest
cache:
key: "ruby21"
paths:
- vendor
variables:
MYSQL_ALLOW_EMPTY_PASSWORD: "1"
before_script:
- ./scripts/prepare_build.sh
- source ./scripts/prepare_build.sh
- ruby -v
- which ruby
- gem install bundler --no-ri --no-rdoc
@ -17,7 +22,7 @@ before_script:
- touch log/application.log
- touch log/test.log
- bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}"
- bundle exec rake db:reset db:create RAILS_ENV=test
- RAILS_ENV=test bundle exec rake db:drop db:create db:schema:load db:migrate
spec:feature:
script:
@ -127,10 +132,155 @@ flay:
- mysql
bundler:audit:
script:
script:
- "bundle exec bundle-audit update"
- "bundle exec bundle-audit check"
tags:
- ruby
- mysql
allow_failure: true
# Ruby 2.2 jobs
spec:feature:ruby22:
image: ruby:2.2
only:
- master
script:
- RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:feature
cache:
key: "ruby22"
paths:
- vendor
tags:
- ruby
- mysql
spec:api:ruby22:
image: ruby:2.2
only:
- master
script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:api
cache:
key: "ruby22"
paths:
- vendor
tags:
- ruby
- mysql
spec:models:ruby22:
image: ruby:2.2
only:
- master
script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:models
cache:
key: "ruby22"
paths:
- vendor
tags:
- ruby
- mysql
spec:lib:ruby22:
image: ruby:2.2
only:
- master
script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:lib
cache:
key: "ruby22"
paths:
- vendor
tags:
- ruby
- mysql
spec:services:ruby22:
image: ruby:2.2
only:
- master
script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:services
cache:
key: "ruby22"
paths:
- vendor
tags:
- ruby
- mysql
spec:benchmark:ruby22:
image: ruby:2.2
only:
- master
script:
- RAILS_ENV=test bundle exec rake spec:benchmark
cache:
key: "ruby22"
paths:
- vendor
tags:
- ruby
- mysql
allow_failure: true
spec:other:ruby22:
image: ruby:2.2
only:
- master
script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:other
cache:
key: "ruby22"
paths:
- vendor
tags:
- ruby
- mysql
spinach:project:half:ruby22:
image: ruby:2.2
only:
- master
script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:half
cache:
key: "ruby22"
paths:
- vendor
tags:
- ruby
- mysql
spinach:project:rest:ruby22:
image: ruby:2.2
only:
- master
script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:rest
cache:
key: "ruby22"
paths:
- vendor
tags:
- ruby
- mysql
spinach:other:ruby22:
image: ruby:2.2
only:
- master
script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:other
cache:
key: "ruby22"
paths:
- vendor
tags:
- ruby
- mysql

View file

@ -1 +1 @@
2.1.7
2.1.8

164
CHANGELOG
View file

@ -1,5 +1,163 @@
Please view this file on the master branch, on stable branches it's out of date.
v 8.6.0 (unreleased)
- Contributions to forked projects are included in calendar
- Improve the formatting for the user page bio (Connor Shea)
- Fix issue when pushing to projects ending in .wiki
- Fix avatar stretching by providing a cropping feature (Johann Pardanaud)
- Don't load all of GitLab in mail_room
- Strip leading and trailing spaces in URL validator (evuez)
- Return empty array instead of 404 when commit has no statuses in commit status API
- Update documentation to reflect Guest role not being enforced on internal projects
- Allow search for logged out users
- Don't show Issues/MRs from archived projects in Groups view
- Increase the notes polling timeout over time (Roberto Dip)
- Add shortcut to toggle markdown preview (Florent Baldino)
- Show labels in dashboard and group milestone views
- Add main language of a project in the list of projects (Tiago Botelho)
- Add ability to show archived projects on dashboard, explore and group pages
v 8.5.8
- Bump Git version requirement to 2.7.4
v 8.5.7
- Bump Git version requirement to 2.7.3
v 8.5.6
- Obtain a lease before querying LDAP
v 8.5.5
- Ensure removing a project removes associated Todo entries
- Prevent a 500 error in Todos when author was removed
- Fix pagination for filtered dashboard and explore pages
- Fix "Show all" link behavior
v 8.5.4
- Do not cache requests for badges (including builds badge)
v 8.5.3
- Flush repository caches before renaming projects
v 8.5.2
- Fix sidebar overlapping content when screen width was below 1200px
- Don't repeat labels listed on Labels tab
- Bring the "branded appearance" feature from EE to CE
- Fix error 500 when commenting on a commit
- Show days remaining instead of elapsed time for Milestone
- Fix broken icons on installations with relative URL (Artem Sidorenko)
- Fix issue where tag list wasn't refreshed after deleting a tag
- Fix import from gitlab.com (KazSawada)
- Improve implementation to check read access to forks and add pagination
- Don't show any "2FA required" message if it's not actually required
- Fix help keyboard shortcut on relative URL setups (Artem Sidorenko)
- Update Rails to 4.2.5.2
- Fix permissions for deprecated CI build status badge
- Don't show "Welcome to GitLab" when the search didn't return any projects
- Add Todos documentation
v 8.5.1
- Fix group projects styles
- Show Crowd login tab when sign in is disabled and Crowd is enabled (Peter Hudec)
- Fix a set of small UI glitches in project, profile, and wiki pages
- Restrict permissions on public/uploads
- Fix the merge request side-by-side view after loading diff results
- Fix the look of tooltip for the "Revert" button
- Add when the Builds & Runners API changes got introduced
- Fix error 500 on some merged merge requests
- Fix an issue causing the content of the issuable sidebar to disappear
- Fix error 500 when trying to mark an already done todo as "done"
- Fix an issue where MRs weren't sortable
- Issues can now be dragged & dropped into empty milestone lists. This is also
possible with MRs
- Changed padding & background color for highlighted notes
- Re-add the newrelic_rpm gem which was removed without any deprecation or warning (Stan Hu)
- Update sentry-raven gem to 0.15.6
v 8.5.0
- Fix duplicate "me" in tooltip of the "thumbsup" awards Emoji (Stan Hu)
- Cache various Repository methods to improve performance (Yorick Peterse)
- Fix duplicated branch creation/deletion Web hooks/service notifications when using Web UI (Stan Hu)
- Ensure rake tasks that don't need a DB connection can be run without one
- Update New Relic gem to 3.14.1.311 (Stan Hu)
- Add "visibility" flag to GET /projects api endpoint
- Add an option to supply root email through an environmental variable (Koichiro Mikami)
- Ignore binary files in code search to prevent Error 500 (Stan Hu)
- Render sanitized SVG images (Stan Hu)
- Support download access by PRIVATE-TOKEN header (Stan Hu)
- Upgrade gitlab_git to 7.2.23 to fix commit message mentions in first branch push
- Add option to include the sender name in body of Notify email (Jason Lee)
- New UI for pagination
- Don't prevent sign out when 2FA enforcement is enabled and user hasn't yet
set it up
- API: Added "merge_requests/:merge_request_id/closes_issues" (Gal Schlezinger)
- Fix diff comments loaded by AJAX to load comment with diff in discussion tab
- Fix relative links in other markup formats (Ben Boeckel)
- Whitelist raw "abbr" elements when parsing Markdown (Benedict Etzel)
- Fix label links for a merge request pointing to issues list
- Don't vendor minified JS
- Increase project import timeout to 15 minutes
- Be more permissive with email address validation: it only has to contain a single '@'
- Display 404 error on group not found
- Track project import failure
- Support Two-factor Authentication for LDAP users
- Display database type and version in Administration dashboard
- Allow limited Markdown in Broadcast Messages
- Fix visibility level text in admin area (Zeger-Jan van de Weg)
- Warn admin during OAuth of granting admin rights (Zeger-Jan van de Weg)
- Update the ExternalIssue regex pattern (Blake Hitchcock)
- Remember user's inline/side-by-side diff view preference in a cookie (Kirill Katsnelson)
- Optimized performance of finding issues to be closed by a merge request
- Add `avatar_url`, `description`, `git_ssh_url`, `git_http_url`, `path_with_namespace`
and `default_branch` in `project` in push, issue, merge-request and note webhooks data (Kirill Zaitsev)
- Deprecate the `ssh_url` in favor of `git_ssh_url` and `http_url` in favor of `git_http_url`
in `project` for push, issue, merge-request and note webhooks data (Kirill Zaitsev)
- Deprecate the `repository` key in push, issue, merge-request and note webhooks data, use `project` instead (Kirill Zaitsev)
- API: Expose MergeRequest#merge_status (Andrei Dziahel)
- Revert "Add IP check against DNSBLs at account sign-up"
- Actually use the `skip_merges` option in Repository#commits (Tony Chu)
- Fix API to keep request parameters in Link header (Michael Potthoff)
- Deprecate API "merge_request/:merge_request_id/comments". Use "merge_requests/:merge_request_id/notes" instead
- Deprecate API "merge_request/:merge_request_id/...". Use "merge_requests/:merge_request_id/..." instead
- Prevent parse error when name of project ends with .atom and prevent path issues
- Discover branches for commit statuses ref-less when doing merge when succeeded
- Mark inline difference between old and new paths when a file is renamed
- Support Akismet spam checking for creation of issues via API (Stan Hu)
- API: Allow to set or update a merge-request's milestone (Kirill Skachkov)
- Improve UI consistency between projects and groups lists
- Add sort dropdown to dashboard projects page
- Fixed logo animation on Safari (Roman Rott)
- Fix Merge When Succeeded when multiple stages
- Hide remove source branch button when the MR is merged but new commits are pushed (Zeger-Jan van de Weg)
- In seach autocomplete show only groups and projects you are member of
- Don't process cross-reference notes from forks
- Fix: init.d script not working on OS X
- Faster snippet search
- Added API to download build artifacts
- Title for milestones should be unique (Zeger-Jan van de Weg)
- Validate correctness of maximum attachment size application setting
- Replaces "Create merge request" link with one to the "Merge Request" when one exists
- Fix CI builds badge, add a new link to builds badge, deprecate the old one
- Fix broken link to project in build notification emails
- Ability to see and sort on vote count from Issues and MR lists
- Fix builds scheduler when first build in stage was allowed to fail
- User project limit is reached notice is hidden if the projects limit is zero
- Add API support for managing runners and project's runners
- Allow SAML users to login with no previous account without having to allow
all Omniauth providers to do so.
- Allow existing users to auto link their SAML credentials by logging in via SAML
- Make it possible to erase a build (trace, artifacts) using UI and API
- Ability to revert changes from a Merge Request or Commit
- Emoji comment on diffs are not award emoji
- Add label description (Nuttanart Pornprasitsakul)
- Show label row when filtering issues or merge requests by label (Nuttanart Pornprasitsakul)
- Add Todos
v 8.4.4
- Update omniauth-saml gem to 1.4.2
- Prevent long-running backup tasks from timing out the database connection
- Add a Project setting to allow guests to view build logs (defaults to true)
- Sort project milestones by due date including issue editor (Oliver Rogers / Orih)
v 8.4.3
- Increase lfs_objects size column to 8-byte integer to allow files larger
than 2.1GB
@ -22,12 +180,14 @@ v 8.4.2
track them in Performance Monitoring.
- Increase contrast between highlighted code comments and inline diff marker
- Fix method undefined when using external commit status in builds
- Fix highlighting in blame view.
v 8.4.1
- Apply security updates for Rails (4.2.5.1), rails-html-sanitizer (1.0.3),
and Nokogiri (1.6.7.2)
- Fix redirect loop during import
- Fix diff highlighting for all syntax themes
- Delete project and associations in a background worker
v 8.4.0
- Allow LDAP users to change their email if it was not set by the LDAP server
@ -71,7 +231,7 @@ v 8.4.0
- Show 'All' tab by default in the builds page
- Add Open Graph and Twitter Card data to all pages
- Fix API project lookups when querying with a namespace with dots (Stan Hu)
- Enable forcing Two-Factor authentication sitewide, with optional grace period
- Enable forcing Two-factor authentication sitewide, with optional grace period
- Import GitHub Pull Requests into GitLab
- Change single user API endpoint to return more detailed data (Michael Potthoff)
- Update version check images to use SVG
@ -149,6 +309,7 @@ v 8.3.0
- Handle and report SSL errors in Web hook test (Stan Hu)
- Bump Redis requirement to 2.8 for Sidekiq 4 (Stan Hu)
- Fix: Assignee selector is empty when 'Unassigned' is selected (Jose Corcuera)
- WIP identifier on merge requests no longer requires trailing space
- Add rake tasks for git repository maintainance (Zeger-Jan van de Weg)
- Fix 500 error when update group member permission
- Fix: As an admin, cannot add oneself as a member to a group/project
@ -331,6 +492,7 @@ v 8.1.0
- Improved performance of the trending projects page
- Remove CI migration task
- Improved performance of finding projects by their namespace
- Add assignee data to Issuables' hook_data (Bram Daams)
- Fix bug where transferring a project would result in stale commit links (Stan Hu)
- Fix build trace updating
- Include full path of source and target branch names in New Merge Request page (Stan Hu)

View file

@ -1,3 +1,29 @@
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Contribute to GitLab](#contribute-to-gitlab)
- [Contributor license agreement](#contributor-license-agreement)
- [Security vulnerability disclosure](#security-vulnerability-disclosure)
- [Closing policy for issues and merge requests](#closing-policy-for-issues-and-merge-requests)
- [Helping others](#helping-others)
- [I want to contribute!](#i-want-to-contribute)
- [Issue tracker](#issue-tracker)
- [Feature proposals](#feature-proposals)
- [Issue tracker guidelines](#issue-tracker-guidelines)
- [Issue weight](#issue-weight)
- [Regression issues](#regression-issues)
- [Merge requests](#merge-requests)
- [Merge request guidelines](#merge-request-guidelines)
- [Merge request description format](#merge-request-description-format)
- [Contribution acceptance criteria](#contribution-acceptance-criteria)
- [Changes for Stable Releases](#changes-for-stable-releases)
- [Definition of done](#definition-of-done)
- [Style guides](#style-guides)
- [Code of conduct](#code-of-conduct)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
# Contribute to GitLab
Thank you for your interest in contributing to GitLab. This guide details how
@ -147,7 +173,7 @@ sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true)
sudo gitlab-rake gitlab:env:info)
(For installations from source run and paste the output of:
sudo -u git -H bundle exec rake gitlab:env:info)
sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production)
## Possible fixes
@ -177,6 +203,26 @@ is probably 1, adding a new Git Hook maybe 4 or 5, big features 7-9.
issues or chunks. You can simply not set the weight of a parent issue and set
weights to children issues.
### Regression issues
Every monthly release has a corresponding issue on the CE issue tracker to keep
track of functionality broken by that release and any fixes that need to be
included in a patch release (see [8.3 Regressions] as an example).
As outlined in the issue description, the intended workflow is to post one note
with a reference to an issue describing the regression, and then to update that
note with a reference to the merge request that fixes it as it becomes available.
If you're a contributor who doesn't have the required permissions to update
other users' notes, please post a new note with a reference to both the issue
and the merge request.
The release manager will [update the notes] in the regression issue as fixes are
addressed.
[8.3 Regressions]: https://gitlab.com/gitlab-org/gitlab-ce/issues/4127
[update the notes]: https://gitlab.com/gitlab-org/release-tools/blob/master/doc/pro-tips.md#update-the-regression-issue
## Merge requests
We welcome merge requests with fixes and improvements to GitLab code, tests,
@ -214,15 +260,17 @@ request is as follows:
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
and make sure to read the [documentation styleguide][doc-styleguide]
1. If you have multiple commits please combine them into one commit by
[squashing them][git-squash]
1. Push the commit(s) 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
1. The MR description should give a motive for your change and the method you
used to achieve it
used to achieve it, see the [merge request description format]
(#merge-request-description-format)
1. If the MR changes the UI it should include before and after screenshots
1. If the MR changes CSS classes please include the list of affected pages
1. If the MR changes CSS classes please include the list of affected pages,
`grep css-class ./app -R`
1. Link any relevant [issues][ce-tracker] in the merge request description and
leave a comment on them with a link back to the MR
@ -255,6 +303,69 @@ For examples of feedback on merge requests please look at already
request feel free to mention one of the Merge Marshalls of the [core team][].
Please ensure that your merge request meets the contribution acceptance criteria.
When having your code reviewed and when reviewing merge requests please take the
[thoughtbot code review guidelines](https://github.com/thoughtbot/guides/tree/master/code-review)
into account.
### Merge request description format
Please submit merge requests using the following template in the merge request
description area. Copy-paste it to retain the markdown format.
```
## What does this MR do?
## Are there points in the code the reviewer needs to double check?
## Why was this MR needed?
## What are the relevant issue numbers?
## Screenshots (if relevant)
```
### Contribution acceptance criteria
1. The change is as small as possible
1. Include proper tests and make all tests pass (unless it contains a test
exposing a bug in existing code)
1. If you suspect a failing CI build is unrelated to your contribution, you may
try and restart the failing CI job or ask a developer to fix the
aforementioned failing test
1. Your MR initially contains a single commit (please use `git rebase -i` to
squash commits)
1. Your changes can merge without problems (if not please merge `master`, never
rebase commits pushed to the remote server)
1. Does not break any existing functionality
1. Fixes one specific issue or implements one specific feature (do not combine
things, send separate merge requests if needed)
1. Migrations should do only one thing (e.g., either create a table, move data
to a new table or remove an old table) to aid retrying on failure
1. Keeps the GitLab code base clean and well structured
1. Contains functionality we think other users will benefit from too
1. Doesn't add configuration options since they complicate future changes
1. Changes after submitting the merge request should be in separate commits
(no squashing). If necessary, you will be asked to squash when the review is
over, before merging.
1. It conforms to the [style guides](#style-guides) and the following:
- If your change touches a line that does not follow the style, modify the
entire line to follow it. This prevents linting tools from generating warnings.
- Don't touch neighbouring lines. As an exception, automatic mass
refactoring modifications may leave style non-compliant.
## Changes for Stable Releases
Sometimes certain changes have to be added to an existing stable release.
Two examples are bug fixes and performance improvements. In these cases the
corresponding merge request should be updated to have the following:
1. A milestone indicating what release the merge request should be merged into.
1. The label "Pick into Stable"
This makes it easier for release managers to keep track of what still has to be
merged and where changes have to be merged into.
Like all merge requests the target should be master so all bugfixes are in master.
## Definition of done
If you contribute to GitLab please know that changes involve more than just
@ -264,7 +375,7 @@ the feature you contribute through all of these steps.
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
1. [Documented][doc-styleguide] in the /doc directory
1. Changelog entry added
1. Reviewed and any concerns are addressed
1. Merged by the project lead
@ -285,43 +396,6 @@ merge request:
1. Test suite https://gitlab.com/gitlab-org/gitlab-ce/blob/master/scripts/prepare_build.sh
1. Omnibus package creator https://gitlab.com/gitlab-org/omnibus-gitlab
## Merge request description format
1. What does this MR do?
1. Are there points in the code the reviewer needs to double check?
1. Why was this MR needed?
1. What are the relevant issue numbers?
1. Screenshots (if relevant)
## Contribution acceptance criteria
1. The change is as small as possible (see the above paragraph for details)
1. Include proper tests and make all tests pass (unless it contains a test
exposing a bug in existing code)
1. If you suspect a failing CI build is unrelated to your contribution, you may
try and restart the failing CI job or ask a developer to fix the
aforementioned failing test
1. Your MR initially contains a single commit (please use `git rebase -i` to
squash commits)
1. Your changes can merge without problems (if not please merge `master`, never
rebase commits pushed to the remote server)
1. Does not break any existing functionality
1. Fixes one specific issue or implements one specific feature (do not combine
things, send separate merge requests if needed)
1. Migrations should do only one thing (eg: either create a table, move data to
a new table or remove an old table) to aid retrying on failure
1. Keeps the GitLab code base clean and well structured
1. Contains functionality we think other users will benefit from too
1. Doesn't add configuration options since they complicate future changes
1. Changes after submitting the merge request should be in separate commits
(no squashing). If necessary, you will be asked to squash when the review is
over, before merging.
1. It conforms to the following style guides:
* If your change touches a line that does not follow the style, modify the
entire line to follow it. This prevents linting tools from generating warnings.
* Don't touch neighbouring lines. As an exception, automatic mass
refactoring modifications may leave style non-compliant.
## Style guides
1. [Ruby](https://github.com/bbatsov/ruby-style-guide).
@ -336,7 +410,7 @@ merge request:
contributors to enhance security
1. [Database Migrations](doc/development/migration_style_guide.md)
1. [Markdown](http://www.cirosantilli.com/markdown-styleguide)
1. [Documentation styleguide](doc/development/doc_styleguide.md)
1. [Documentation styleguide][doc-styleguide]
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
@ -377,7 +451,7 @@ reported by emailing `contact@gitlab.com`.
This Code of Conduct is adapted from the [Contributor Covenant][], version 1.1.0,
available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/).
[core team]: https://about.gitlab.com/core-team/
[core-team]: https://about.gitlab.com/core-team/
[getting help page]: https://about.gitlab.com/getting-help/
[Codetriage]: http://www.codetriage.com/gitlabhq/gitlabhq
[up-for-grabs]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=up-for-grabs
@ -398,3 +472,4 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[Contributor Covenant]: http://contributor-covenant.org
[rss-source]: https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#source-code-layout
[rss-naming]: https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#naming
[doc-styleguide]: doc/development/doc_styleguide.md "Documentation styleguide"

View file

@ -1 +1 @@
0.6.2
0.6.4

29
Gemfile
View file

@ -1,6 +1,6 @@
source "https://rubygems.org"
gem 'rails', '4.2.5.1'
gem 'rails', '4.2.5.2'
gem 'rails-deprecated_sanitizer', '~> 1.0.3'
# Responders respond_to and respond_with
@ -21,7 +21,7 @@ gem "pg", '~> 0.18.2', group: :postgres
gem 'devise', '~> 3.5.4'
gem 'devise-async', '~> 0.9.0'
gem 'doorkeeper', '~> 2.2.0'
gem 'omniauth', '~> 1.2.2'
gem 'omniauth', '~> 1.3.1'
gem 'omniauth-azure-oauth2', '~> 0.0.6'
gem 'omniauth-bitbucket', '~> 0.0.2'
gem 'omniauth-cas3', '~> 1.1.2'
@ -30,14 +30,15 @@ gem 'omniauth-github', '~> 1.1.1'
gem 'omniauth-gitlab', '~> 1.0.0'
gem 'omniauth-google-oauth2', '~> 0.2.0'
gem 'omniauth-kerberos', '~> 0.3.0', group: :kerberos
gem 'omniauth-saml', '~> 1.4.0'
gem 'omniauth-saml', '~> 1.4.2'
gem 'omniauth-shibboleth', '~> 1.2.0'
gem 'omniauth-twitter', '~> 1.2.0'
gem 'omniauth_crowd', '~> 2.2.0'
gem 'rack-oauth2', '~> 1.2.1'
# reCAPTCHA protection
# Spam and anti-bot protection
gem 'recaptcha', require: 'recaptcha/rails'
gem 'akismet', '~> 2.0'
# Two-factor authentication
gem 'devise-two-factor', '~> 2.0.0'
@ -49,7 +50,7 @@ gem "browser", '~> 1.0.0'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
gem "gitlab_git", '~> 7.2.22'
gem "gitlab_git", '~> 8.2'
# LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes
@ -104,7 +105,7 @@ gem 'rouge', '~> 1.10.1'
# See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s
# and https://groups.google.com/forum/#!topic/ruby-security-ann/Dy7YiKb_pMM
gem 'nokogiri', '1.6.7.2'
gem 'nokogiri', '~> 1.6.7', '>= 1.6.7.2'
# Diffs
gem 'diffy', '~> 3.0.3'
@ -179,6 +180,9 @@ gem "underscore-rails", "~> 1.8.0"
gem "sanitize", '~> 2.0'
gem 'babosa', '~> 1.0.2'
# Sanitizes SVG input
gem "loofah", "~> 2.0.3"
# Protect against bruteforcing
gem "rack-attack", '~> 4.3.1'
@ -200,7 +204,7 @@ gem 'jquery-turbolinks', '~> 2.1.0'
gem 'addressable', '~> 2.3.8'
gem 'bootstrap-sass', '~> 3.3.0'
gem 'font-awesome-rails', '~> 4.2'
gem 'gitlab_emoji', '~> 0.2.0'
gem 'gitlab_emoji', '~> 0.3.0'
gem 'gon', '~> 6.0.1'
gem 'jquery-atwho-rails', '~> 1.3.2'
gem 'jquery-rails', '~> 4.0.0'
@ -213,6 +217,9 @@ gem 'select2-rails', '~> 3.5.9'
gem 'virtus', '~> 1.0.1'
gem 'net-ssh', '~> 3.0.1'
# Sentry integration
gem 'sentry-raven', '~> 0.15'
# Metrics
group :metrics do
gem 'allocations', '~> 1.0', require: false, platform: :mri
@ -294,15 +301,11 @@ end
group :production do
gem "gitlab_meta", '7.0'
# Sentry integration
gem 'sentry-raven'
end
gem "newrelic_rpm", '~> 3.9.4.245'
gem 'newrelic-grape'
gem "newrelic_rpm", '~> 3.14'
gem 'octokit', '~> 3.7.0'
gem 'octokit', '~> 3.8.0'
gem "mail_room", "~> 0.6.1"

View file

@ -4,41 +4,41 @@ GEM
CFPropertyList (2.3.2)
RedCloth (4.2.9)
ace-rails-ap (2.0.1)
actionmailer (4.2.5.1)
actionpack (= 4.2.5.1)
actionview (= 4.2.5.1)
activejob (= 4.2.5.1)
actionmailer (4.2.5.2)
actionpack (= 4.2.5.2)
actionview (= 4.2.5.2)
activejob (= 4.2.5.2)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 1.0, >= 1.0.5)
actionpack (4.2.5.1)
actionview (= 4.2.5.1)
activesupport (= 4.2.5.1)
actionpack (4.2.5.2)
actionview (= 4.2.5.2)
activesupport (= 4.2.5.2)
rack (~> 1.6)
rack-test (~> 0.6.2)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (4.2.5.1)
activesupport (= 4.2.5.1)
actionview (4.2.5.2)
activesupport (= 4.2.5.2)
builder (~> 3.1)
erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
activejob (4.2.5.1)
activesupport (= 4.2.5.1)
activejob (4.2.5.2)
activesupport (= 4.2.5.2)
globalid (>= 0.3.0)
activemodel (4.2.5.1)
activesupport (= 4.2.5.1)
activemodel (4.2.5.2)
activesupport (= 4.2.5.2)
builder (~> 3.1)
activerecord (4.2.5.1)
activemodel (= 4.2.5.1)
activesupport (= 4.2.5.1)
activerecord (4.2.5.2)
activemodel (= 4.2.5.2)
activesupport (= 4.2.5.2)
arel (~> 6.0)
activerecord-deprecated_finders (1.0.4)
activerecord-session_store (0.1.2)
actionpack (>= 4.0.0, < 5)
activerecord (>= 4.0.0, < 5)
railties (>= 4.0.0, < 5)
activesupport (4.2.5.1)
activesupport (4.2.5.2)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
@ -49,7 +49,8 @@ GEM
addressable (2.3.8)
after_commit_queue (1.3.0)
activerecord (>= 3.0)
allocations (1.0.3)
akismet (2.0.0)
allocations (1.0.4)
annotate (2.6.10)
activerecord (>= 3.2, <= 4.3)
rake (~> 10.4)
@ -335,11 +336,11 @@ GEM
ruby-progressbar (~> 1.4)
gemnasium-gitlab-service (0.2.6)
rugged (~> 0.21)
gemojione (2.1.1)
gemojione (2.2.1)
json
get_process_mem (0.2.0)
gherkin-ruby (0.3.2)
github-linguist (4.7.3)
github-linguist (4.7.5)
charlock_holmes (~> 0.7.3)
escape_utils (~> 1.1.0)
mime-types (>= 1.19)
@ -354,13 +355,13 @@ GEM
diff-lcs (~> 1.1)
mime-types (~> 1.15)
posix-spawn (~> 0.3)
gitlab_emoji (0.2.0)
gemojione (~> 2.1)
gitlab_git (7.2.24)
gitlab_emoji (0.3.1)
gemojione (~> 2.2, >= 2.2.1)
gitlab_git (8.2.0)
activesupport (~> 4.0)
charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0)
rugged (~> 0.23.3)
rugged (~> 0.24.0b13)
gitlab_meta (7.0)
gitlab_omniauth-ldap (1.2.1)
net-ldap (~> 0.9)
@ -478,10 +479,7 @@ GEM
net-ldap (0.12.1)
net-ssh (3.0.1)
netrc (0.11.0)
newrelic-grape (2.1.0)
grape
newrelic_rpm
newrelic_rpm (3.9.4.245)
newrelic_rpm (3.14.1.311)
nokogiri (1.6.7.2)
mini_portile2 (~> 2.0.0.rc2)
nprogress-rails (0.1.6.7)
@ -492,11 +490,11 @@ GEM
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (~> 1.2)
octokit (3.7.1)
octokit (3.8.0)
sawyer (~> 0.6.0, >= 0.5.3)
omniauth (1.2.2)
omniauth (1.3.1)
hashie (>= 1.2, < 4)
rack (~> 1.0)
rack (>= 1.0, < 3)
omniauth-azure-oauth2 (0.0.6)
jwt (~> 1.0)
omniauth (~> 1.0)
@ -534,9 +532,9 @@ GEM
omniauth-oauth2 (1.3.1)
oauth2 (~> 1.0)
omniauth (~> 1.2)
omniauth-saml (1.4.1)
omniauth-saml (1.4.2)
omniauth (~> 1.1)
ruby-saml (~> 1.0.0)
ruby-saml (~> 1.1, >= 1.1.1)
omniauth-shibboleth (1.2.1)
omniauth (>= 1.0.0)
omniauth-twitter (1.2.1)
@ -588,16 +586,16 @@ GEM
rack
rack-test (0.6.3)
rack (>= 1.0)
rails (4.2.5.1)
actionmailer (= 4.2.5.1)
actionpack (= 4.2.5.1)
actionview (= 4.2.5.1)
activejob (= 4.2.5.1)
activemodel (= 4.2.5.1)
activerecord (= 4.2.5.1)
activesupport (= 4.2.5.1)
rails (4.2.5.2)
actionmailer (= 4.2.5.2)
actionpack (= 4.2.5.2)
actionview (= 4.2.5.2)
activejob (= 4.2.5.2)
activemodel (= 4.2.5.2)
activerecord (= 4.2.5.2)
activesupport (= 4.2.5.2)
bundler (>= 1.3.0, < 2.0)
railties (= 4.2.5.1)
railties (= 4.2.5.2)
sprockets-rails
rails-deprecated_sanitizer (1.0.3)
activesupport (>= 4.2.0.alpha)
@ -607,9 +605,9 @@ GEM
rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.0.3)
loofah (~> 2.0)
railties (4.2.5.1)
actionpack (= 4.2.5.1)
activesupport (= 4.2.5.1)
railties (4.2.5.2)
actionpack (= 4.2.5.2)
activesupport (= 4.2.5.2)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rainbow (2.0.0)
@ -692,7 +690,7 @@ GEM
ruby-fogbugz (0.2.1)
crack (~> 0.4)
ruby-progressbar (1.7.5)
ruby-saml (1.0.0)
ruby-saml (1.1.1)
nokogiri (>= 1.5.10)
uuid (~> 2.3)
ruby2ruby (2.2.0)
@ -703,7 +701,7 @@ GEM
rubyntlm (0.5.2)
rubypants (0.2.0)
rufus-scheduler (3.1.10)
rugged (0.23.3)
rugged (0.24.0b13)
safe_yaml (1.0.4)
sanitize (2.1.0)
nokogiri (>= 1.4.4)
@ -725,7 +723,7 @@ GEM
activesupport (>= 3.1, < 4.3)
select2-rails (3.5.9.3)
thor (~> 0.14)
sentry-raven (0.15.4)
sentry-raven (0.15.6)
faraday (>= 0.7.6)
settingslogic (2.0.9)
sexp_processor (4.6.0)
@ -884,6 +882,7 @@ DEPENDENCIES
acts-as-taggable-on (~> 3.4)
addressable (~> 2.3.8)
after_commit_queue
akismet (~> 2.0)
allocations (~> 1.0)
annotate (~> 2.6.0)
asana (~> 0.4.0)
@ -933,8 +932,8 @@ DEPENDENCIES
github-linguist (~> 4.7.0)
github-markup (~> 1.3.1)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab_emoji (~> 0.2.0)
gitlab_git (~> 7.2.22)
gitlab_emoji (~> 0.3.0)
gitlab_git (~> 8.2)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.1.0)
@ -953,6 +952,7 @@ DEPENDENCIES
jquery-ui-rails (~> 5.0.0)
kaminari (~> 0.16.3)
letter_opener (~> 1.1.2)
loofah (~> 2.0.3)
mail_room (~> 0.6.1)
method_source (~> 0.8)
minitest (~> 5.7.0)
@ -960,13 +960,12 @@ DEPENDENCIES
mysql2 (~> 0.3.16)
nested_form (~> 0.3.2)
net-ssh (~> 3.0.1)
newrelic-grape
newrelic_rpm (~> 3.9.4.245)
nokogiri (= 1.6.7.2)
newrelic_rpm (~> 3.14)
nokogiri (~> 1.6.7, >= 1.6.7.2)
nprogress-rails (~> 0.1.6.7)
oauth2 (~> 1.0.0)
octokit (~> 3.7.0)
omniauth (~> 1.2.2)
octokit (~> 3.8.0)
omniauth (~> 1.3.1)
omniauth-azure-oauth2 (~> 0.0.6)
omniauth-bitbucket (~> 0.0.2)
omniauth-cas3 (~> 1.1.2)
@ -975,7 +974,7 @@ DEPENDENCIES
omniauth-gitlab (~> 1.0.0)
omniauth-google-oauth2 (~> 0.2.0)
omniauth-kerberos (~> 0.3.0)
omniauth-saml (~> 1.4.0)
omniauth-saml (~> 1.4.2)
omniauth-shibboleth (~> 1.2.0)
omniauth-twitter (~> 1.2.0)
omniauth_crowd (~> 2.2.0)
@ -988,7 +987,7 @@ DEPENDENCIES
rack-attack (~> 4.3.1)
rack-cors (~> 0.4.0)
rack-oauth2 (~> 1.2.1)
rails (= 4.2.5.1)
rails (= 4.2.5.2)
rails-deprecated_sanitizer (~> 1.0.3)
raphael-rails (~> 2.1.2)
rblineprof
@ -1010,7 +1009,7 @@ DEPENDENCIES
sdoc (~> 0.3.20)
seed-fu (~> 2.3.5)
select2-rails (~> 3.5.9)
sentry-raven
sentry-raven (~> 0.15)
settingslogic (~> 2.0.9)
sham_rack
shoulda-matchers (~> 2.8.0)

View file

@ -68,7 +68,7 @@ GitLab is a Ruby on Rails application that runs on the following software:
- Ubuntu/Debian/CentOS/RHEL
- Ruby (MRI) 2.1
- Git 1.7.10+
- Git 2.7.4+
- Redis 2.8+
- MySQL or PostgreSQL

View file

@ -4,4 +4,7 @@
require File.expand_path('../config/application', __FILE__)
relative_url_conf = File.expand_path('../config/initializers/relative_url', __FILE__)
require relative_url_conf if File.exist?("#{relative_url_conf}.rb")
Gitlab::Application.load_tasks

View file

@ -1 +1 @@
8.4.3
8.5.8

Binary file not shown.

Before

Width:  |  Height:  |  Size: 813 KiB

After

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 KiB

View file

@ -12,19 +12,6 @@ class @Admin
e.preventDefault()
$('.js-toggle-colors-container').toggle()
$('input#broadcast_message_color').on 'input', ->
previewColor = $(@).val()
$('div.broadcast-message-preview').css('background-color', previewColor)
$('input#broadcast_message_font').on 'input', ->
previewColor = $(@).val()
$('div.broadcast-message-preview').css('color', previewColor)
$('textarea#broadcast_message_message').on 'input', ->
previewMessage = $(@).val()
previewMessage = "Your message here" if previewMessage.trim() == ''
$('div.broadcast-message-preview span').text(previewMessage)
$('.log-tabs a').click (e) ->
e.preventDefault()
$(this).tab('show')

View file

@ -47,7 +47,7 @@
callback(namespaces)
# Return projects list. Filtered by query
projects: (query, callback) ->
projects: (query, order, callback) ->
url = Api.buildUrl(Api.projects_path)
$.ajax(
@ -55,6 +55,7 @@
data:
private_token: gon.api_token
search: query
order_by: order
per_page: 20
dataType: "json"
).done (projects) ->

View file

@ -5,7 +5,10 @@
# the compiled file.
#
#= require jquery
#= require jquery-ui
#= require jquery-ui/autocomplete
#= require jquery-ui/datepicker
#= require jquery-ui/effect-highlight
#= require jquery-ui/sortable
#= require jquery_ujs
#= require jquery.cookie
#= require jquery.endless-scroll
@ -21,9 +24,9 @@
#= require bootstrap
#= require select2
#= require raphael
#= require g.raphael-min
#= require g.bar-min
#= require chart-lib.min
#= require g.raphael
#= require g.bar
#= require Chart
#= require branch-graph
#= require ace/ace
#= require ace/ext-searchbox
@ -38,9 +41,9 @@
#= require shortcuts_dashboard_navigation
#= require shortcuts_issuable
#= require shortcuts_network
#= require jquery.nicescroll.min
#= require jquery.nicescroll
#= require_tree .
#= require fuzzaldrin-plus.min
#= require fuzzaldrin-plus
window.slugify = (text) ->
text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase()
@ -203,4 +206,94 @@ $ ->
form = btn.closest("form")
new ConfirmDangerModal(form, text)
$('input[type="search"]').each ->
$this = $(this)
$this.attr 'value', $this.val()
return
$(document)
.off 'keyup', 'input[type="search"]'
.on 'keyup', 'input[type="search"]' , (e) ->
$this = $(this)
$this.attr 'value', $this.val()
$(document)
.off 'breakpoint:change'
.on 'breakpoint:change', (e, breakpoint) ->
if breakpoint is 'sm' or breakpoint is 'xs'
$gutterIcon = $('.gutter-toggle').find('i')
if $gutterIcon.hasClass('fa-angle-double-right')
$gutterIcon.closest('a').trigger('click')
$(document)
.off 'click', 'aside .gutter-toggle'
.on 'click', 'aside .gutter-toggle', (e) ->
e.preventDefault()
$this = $(this)
$thisIcon = $this.find 'i'
if $thisIcon.hasClass('fa-angle-double-right')
$thisIcon
.removeClass('fa-angle-double-right')
.addClass('fa-angle-double-left')
$this
.closest('aside')
.removeClass('right-sidebar-expanded')
.addClass('right-sidebar-collapsed')
$('.page-with-sidebar')
.removeClass('right-sidebar-expanded')
.addClass('right-sidebar-collapsed')
else
$thisIcon
.removeClass('fa-angle-double-left')
.addClass('fa-angle-double-right')
$this
.closest('aside')
.removeClass('right-sidebar-collapsed')
.addClass('right-sidebar-expanded')
$('.page-with-sidebar')
.removeClass('right-sidebar-collapsed')
.addClass('right-sidebar-expanded')
$.cookie("collapsed_gutter",
$('.right-sidebar')
.hasClass('right-sidebar-collapsed'), { path: '/' })
bootstrapBreakpoint = undefined;
checkBootstrapBreakpoints = ->
if $('.device-xs').is(':visible')
bootstrapBreakpoint = "xs"
else if $('.device-sm').is(':visible')
bootstrapBreakpoint = "sm"
else if $('.device-md').is(':visible')
bootstrapBreakpoint = "md"
else if $('.device-lg').is(':visible')
bootstrapBreakpoint = "lg"
setBootstrapBreakpoints = ->
if $('.device-xs').length
return
$("body")
.append('<div class="device-xs visible-xs"></div>'+
'<div class="device-sm visible-sm"></div>'+
'<div class="device-md visible-md"></div>'+
'<div class="device-lg visible-lg"></div>')
checkBootstrapBreakpoints()
fitSidebarForSize = ->
oldBootstrapBreakpoint = bootstrapBreakpoint
checkBootstrapBreakpoints()
if bootstrapBreakpoint != oldBootstrapBreakpoint
$(document).trigger('breakpoint:change', [bootstrapBreakpoint])
checkInitialSidebarSize = ->
if bootstrapBreakpoint is "xs" or "sm"
$(document).trigger('breakpoint:change', [bootstrapBreakpoint])
$(window)
.off "resize"
.on "resize", (e) ->
fitSidebarForSize()
setBootstrapBreakpoints()
checkInitialSidebarSize()
new Aside()

View file

@ -4,6 +4,7 @@ class @AwardsHandler
event.stopPropagation()
event.preventDefault()
$(".emoji-menu").show()
$("#emoji_search").focus()
$("html").on 'click', (event) ->
if !$(event.target).closest(".emoji-menu").length
@ -48,10 +49,11 @@ class @AwardsHandler
counter.text(parseInt(counter.text()) - 1)
emojiIcon.removeClass("active")
@removeMeFromAuthorList(emoji)
else if emoji =="thumbsup" || emoji == "thumbsdown"
else if emoji == "thumbsup" || emoji == "thumbsdown"
emojiIcon.tooltip("destroy")
counter.text(0)
emojiIcon.removeClass("active")
@removeMeFromAuthorList(emoji)
else
emojiIcon.tooltip("destroy")
emojiIcon.remove()

View file

@ -0,0 +1,22 @@
$ ->
$('input#broadcast_message_color').on 'input', ->
previewColor = $(@).val()
$('div.broadcast-message-preview').css('background-color', previewColor)
$('input#broadcast_message_font').on 'input', ->
previewColor = $(@).val()
$('div.broadcast-message-preview').css('color', previewColor)
previewPath = $('textarea#broadcast_message_message').data('preview-path')
$('textarea#broadcast_message_message').on 'input', ->
message = $(@).val()
if message == ''
$('.js-broadcast-message-preview').text("Your message here")
else
$.ajax(
url: previewPath
type: "POST"
data: { broadcast_message: { message: message } }
)

View file

@ -1,3 +1,31 @@
class @Dashboard
constructor: ->
new ProjectsList()
@Dashboard =
init: ->
$(".projects-list-filter").off('keyup')
this.initSearch()
initSearch: ->
@timer = null
$(".projects-list-filter").on('keyup', ->
clearTimeout(@timer)
@timer = setTimeout(Dashboard.filterResults, 500)
)
filterResults: =>
$('.projects-list-holder').fadeTo(250, 0.5)
form = null
form = $("form#project-filter-form")
search = $(".projects-list-filter").val()
project_filter_url = form.attr('action') + '?' + form.serialize()
$.ajax
type: "GET"
url: form.attr('action')
data: form.serialize()
complete: ->
$('.projects-list-holder').fadeTo(250, 1)
success: (data) ->
$('.projects-list-holder').replaceWith(data.html)
# Change url so if user reload a page - search results are saved
history.replaceState {page: project_filter_url}, document.title, project_filter_url
dataType: "json"

View file

@ -16,6 +16,8 @@ class Dispatcher
shortcut_handler = null
switch page
when 'explore:projects:index', 'explore:projects:starred', 'explore:projects:trending'
Dashboard.init()
when 'projects:issues:index'
Issues.init()
shortcut_handler = new ShortcutsNavigation()
@ -58,7 +60,7 @@ class Dispatcher
shortcut_handler = new ShortcutsNavigation()
MergeRequests.init()
when 'dashboard:show', 'root:show'
new Dashboard()
Dashboard.init()
when 'dashboard:activity'
new Activities()
when 'dashboard:projects:starred'
@ -86,6 +88,7 @@ class Dispatcher
when 'groups:new', 'groups:edit', 'admin:groups:edit', 'admin:groups:new'
new GroupAvatar()
when 'projects:tree:show'
shortcut_handler = new ShortcutsNavigation()
new TreeView()
when 'projects:find_file:show'
shortcut_handler = true

View file

@ -65,8 +65,7 @@ class @DropzoneInput
return
success: (header, response) ->
child = $(dropzone[0]).children("textarea")
$(child).val $(child).val() + response.link.markdown + "\n"
pasteText response.link.markdown
return
error: (temp, errorMessage) ->
@ -128,6 +127,7 @@ class @DropzoneInput
beforeSelection = $(child).val().substring 0, caretStart
afterSelection = $(child).val().substring caretEnd, textEnd
$(child).val beforeSelection + text + afterSelection
child.get(0).setSelectionRange caretStart + text.length, caretEnd + text.length
form_textarea.trigger "input"
getFilename = (e) ->

View file

@ -10,20 +10,10 @@ class @IssuableContext
$(".issuable-sidebar .inline-update").on "change", ".js-assignee", ->
$(this).submit()
$('.issuable-details').waitForImages ->
$('.issuable-affix').on 'affix.bs.affix', ->
$(@).width($(@).outerWidth())
.on 'affixed-top.bs.affix affixed-bottom.bs.affix', ->
$(@).width('')
$('.issuable-affix').affix offset:
top: ->
@top = ($('.issuable-affix').offset().top - 70)
bottom: ->
@bottom = $('.footer').outerHeight(true)
$(".edit-link").click (e) ->
$(document).on "click",".edit-link", (e) ->
block = $(@).parents('.block')
block.find('.selectbox').show()
block.find('.value').hide()
block.find('.js-select2').select2("open")
$(".right-sidebar").niceScroll()

View file

@ -50,6 +50,7 @@ class @Issue
new Flash(issueFailMessage, 'alert')
success: (data, textStatus, jqXHR) ->
if data.saved
$(document).trigger('issuable:change');
if isClose
$('a.btn-close').addClass('hidden')
$('a.btn-reopen').removeClass('hidden')

View file

@ -42,3 +42,9 @@ work = ->
$(document).on('page:fetch', start)
$(document).on('page:change', stop)
$ ->
# Make logo clickable as part of a workaround for Safari visited
# link behaviour (See !2690).
$('#logo').on 'click', ->
$('#js-shortcuts-home').get(0).click()

View file

@ -146,6 +146,7 @@ class @MergeRequestTabs
success: (data) =>
document.querySelector("div#diffs").innerHTML = data.html
$('div#diffs .js-syntax-highlight').syntaxHighlight()
@expandViewContainer() if @diffViewType() is 'parallel'
@diffsLoaded = true
@scrollToElement("#diffs")
@ -177,3 +178,10 @@ class @MergeRequestTabs
options = $.extend({}, defaults, options)
$.ajax(options)
# Returns diff view type
diffViewType: ->
$('.inline-parallel-buttons a.active').data('view-type')
expandViewContainer: ->
$('.container-fluid').removeClass('container-limited')

View file

@ -62,14 +62,24 @@ class @Milestone
dataType: "json"
constructor: ->
oldMouseStart = $.ui.sortable.prototype._mouseStart
$.ui.sortable.prototype._mouseStart = (event, overrideHandle, noActivation) ->
this._trigger "beforeStart", event, this._uiHash()
oldMouseStart.apply this, [event, overrideHandle, noActivation]
@bindIssuesSorting()
@bindMergeRequestSorting()
@bindTabsSwitching
bindIssuesSorting: ->
$("#issues-list-unassigned, #issues-list-ongoing, #issues-list-closed").sortable(
connectWith: ".issues-sortable-list",
dropOnEmpty: true,
items: "li:not(.ui-sort-disabled)",
beforeStart: (event, ui) ->
$(".issues-sortable-list").css "min-height", ui.item.outerHeight()
stop: (event, ui) ->
$(".issues-sortable-list").css "min-height", "0px"
update: (event, ui) ->
data = $(this).sortable("serialize")
Milestone.sortIssues(data)
@ -95,10 +105,22 @@ class @Milestone
).disableSelection()
bindMergeRequestSorting: ->
$('a[data-toggle="tab"]').on 'show.bs.tab', (e) ->
currentTabClass = $(e.target).data('show')
previousTabClass = $(e.relatedTarget).data('show')
$(previousTabClass).hide()
$(currentTabClass).removeClass('hidden')
$(currentTabClass).show()
$("#merge_requests-list-unassigned, #merge_requests-list-ongoing, #merge_requests-list-closed").sortable(
connectWith: ".merge_requests-sortable-list",
dropOnEmpty: true,
items: "li:not(.ui-sort-disabled)",
beforeStart: (event, ui) ->
$(".merge_requests-sortable-list").css "min-height", ui.item.outerHeight()
stop: (event, ui) ->
$(".merge_requests-sortable-list").css "min-height", "0px"
update: (event, ui) ->
data = $(this).sortable("serialize")
Milestone.sortMergeRequests(data)

View file

@ -15,6 +15,8 @@ class @Notes
@last_fetched_at = last_fetched_at
@view = view
@noteable_url = document.URL
@notesCountBadge ||= $(".issuable-details").find(".notes-tab .badge")
@initRefresh()
@setupMainTargetNoteForm()
@cleanBinding()
@ -62,6 +64,9 @@ class @Notes
# fetch notes when tab becomes visible
$(document).on "visibilitychange", @visibilityChange
# when issue status changes, we need to refresh data
$(document).on "issuable:change", @refresh
cleanBinding: ->
$(document).off "ajax:success", ".js-main-target-form"
$(document).off "ajax:success", ".js-discussion-note-form"
@ -89,7 +94,7 @@ class @Notes
, 15000
refresh: ->
unless document.hidden or (@noteable_url != document.URL)
if not document.hidden and document.URL.indexOf(@noteable_url) is 0
@getContent()
getContent: ->
@ -101,7 +106,10 @@ class @Notes
notes = data.notes
@last_fetched_at = data.last_fetched_at
$.each notes, (i, note) =>
@renderNote(note)
if note.discussion_with_diff_html?
@renderDiscussionNote(note)
else
@renderNote(note)
###
@ -116,19 +124,22 @@ class @Notes
flash.pinTo('.header-content')
return
# render note if it not present in loaded list
# or skip if rendered
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)
awards_handler.scrollToAwards()
# render note if it not present in loaded list
# or skip if rendered
else if @isNewNote(note)
@note_ids.push(note.id)
$('ul.main-notes-list')
.append(note.html)
.syntaxHighlight()
@initTaskList()
@updateNotesCount(1)
###
Check if note does not exists on page
###
@ -144,34 +155,39 @@ class @Notes
Note: for rendering inline notes use renderDiscussionNote
###
renderDiscussionNote: (note) ->
return unless @isNewNote(note)
@note_ids.push(note.id)
form = $("form[rel='" + note.discussion_id + "']")
form = $("#new-discussion-note-form-#{note.discussion_id}")
row = form.closest("tr")
note_html = $(note.html)
note_html.syntaxHighlight()
# is this the first note of discussion?
if row.is(".js-temp-notes-holder")
discussionContainer = $(".notes[data-discussion-id='" + note.discussion_id + "']")
if discussionContainer.length is 0
# insert the note and the reply button after the temp row
row.after note.discussion_html
# remove the note (will be added again below)
row.next().find(".note").remove()
# Before that, the container didn't exist
discussionContainer = $(".notes[data-discussion-id='" + note.discussion_id + "']")
# Add note to 'Changes' page discussions
$(".notes[rel='" + note.discussion_id + "']").append note_html
discussionContainer.append note_html
# Init discussion on 'Discussion' page if it is merge request page
if $('body').attr('data-page').indexOf('projects:merge_request') == 0
discussion_html = $(note.discussion_with_diff_html)
discussion_html.syntaxHighlight()
$('ul.main-notes-list').append(discussion_html)
if $('body').attr('data-page').indexOf('projects:merge_request') is 0
$('ul.main-notes-list')
.append(note.discussion_with_diff_html)
.syntaxHighlight()
else
# append new note to all matching discussions
$(".notes[rel='" + note.discussion_id + "']").append note_html
discussionContainer.append note_html
# cleanup after successfully creating a diff/discussion note
@removeDiscussionNoteForm(form)
@updateNotesCount(1)
###
Called in response the main target form has been successfully submitted.
@ -278,6 +294,9 @@ class @Notes
addDiscussionNote: (xhr, note, status) =>
@renderDiscussionNote(note)
# cleanup after successfully creating a diff/discussion note
@removeDiscussionNoteForm($("#new-discussion-note-form-#{note.discussion_id}"))
###
Called in response to the edit note form being submitted
@ -320,6 +339,7 @@ class @Notes
form.show()
textarea = form.find("textarea")
textarea.focus()
autosize(textarea)
# HACK (rspeicher/DouweM): Work around a Chrome 43 bug(?).
# The textarea has the correct value, Chrome just won't show it unless we
@ -348,30 +368,32 @@ class @Notes
Removes the actual note from view.
Removes the whole discussion if the last note is being removed.
###
removeNote: ->
note = $(this).closest(".note")
note_id = note.attr('id')
removeNote: (e) =>
noteId = $(e.currentTarget)
.closest(".note")
.attr("id")
$('.note[id="' + note_id + '"]').each ->
note = $(this)
# A same note appears in the "Discussion" and in the "Changes" tab, we have
# to remove all. Using $(".note[id='noteId']") ensure we get all the notes,
# where $("#noteId") would return only one.
$(".note[id='#{noteId}']").each (i, el) =>
note = $(el)
notes = note.closest(".notes")
count = notes.closest(".issuable-details").find(".notes-tab .badge")
# check if this is the last note for this line
if notes.find(".note").length is 1
# for discussions
notes.closest(".discussion").remove()
# "Discussions" tab
notes.closest(".timeline-entry").remove()
# for diff lines
# "Changes" tab / commit view
notes.closest("tr").remove()
# update notes count
oldNum = parseInt(count.text())
count.text(oldNum - 1)
note.remove()
# Decrement the "Discussions" counter only once
@updateNotesCount(-1)
###
Called in response to clicking the delete attachment link
@ -411,7 +433,7 @@ class @Notes
###
setupDiscussionNoteForm: (dataHolder, form) =>
# setup note target
form.attr "rel", dataHolder.data("discussionId")
form.attr 'id', "new-discussion-note-form-#{dataHolder.data("discussionId")}"
form.find("#line_type").val dataHolder.data("lineType")
form.find("#note_commit_id").val dataHolder.data("commitId")
form.find("#note_line_code").val dataHolder.data("lineCode")
@ -541,3 +563,6 @@ class @Notes
updateTaskList: ->
$('form', this).submit()
updateNotesCount: (updateCount) ->
@notesCountBadge.text(parseInt(@notesCountBadge.text()) + updateCount)

View file

@ -50,3 +50,19 @@ class @Project
$('#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'
@projectSelectDropdown()
projectSelectDropdown: ->
new ProjectSelect()
$('.project-item-select').on 'click', (e) =>
@changeProject $(e.currentTarget).val()
$('.js-projects-dropdown-toggle').on 'click', (e) ->
e.preventDefault()
$('.js-projects-dropdown').select2('open')
changeProject: (url) ->
window.location = url

View file

@ -3,6 +3,7 @@ class @ProjectSelect
$('.ajax-project-select').each (i, select) ->
@groupId = $(select).data('group-id')
@includeGroups = $(select).data('include-groups')
@orderBy = $(select).data('order-by') || 'id'
placeholder = "Search for project"
placeholder += " or group" if @includeGroups
@ -28,7 +29,7 @@ class @ProjectSelect
if @groupId
Api.groupProjects @groupId, query.term, projectsCallback
else
Api.projects query.term, projectsCallback
Api.projects query.term, @orderBy, projectsCallback
id: (project) ->
project.web_url

View file

@ -2,23 +2,31 @@ class @ProjectsList
constructor: ->
$(".projects-list .js-expand").on 'click', (e) ->
e.preventDefault()
list = $(this).closest('.projects-list')
list.find("li").show()
list.find("li.bottom").hide()
$projectsList = $(this).closest('.projects-list')
ProjectsList.showPagination($projectsList)
$projectsList.find('li.bottom').hide()
$(".projects-list-filter").keyup ->
terms = $(this).val()
uiBox = $('div.projects-list-holder')
if terms == "" || terms == undefined
uiBox.find("ul.projects-list li").show()
else
uiBox.find("ul.projects-list li").each (index) ->
name = $(this).find("span.filter-title").text()
$("#filter_projects").on 'keyup', ->
ProjectsList.filter_results($("#filter_projects"))
if name.toLowerCase().search(terms.toLowerCase()) == -1
$(this).hide()
else
$(this).show()
uiBox.find("ul.projects-list li.bottom").hide()
@showPagination: ($projectsList) ->
$projectsList.find('li').show()
$('.gl-pagination').show()
@filter_results: ($element) ->
terms = $element.val()
filterSelector = $element.data('filter-selector') || 'span.filter-title'
$projectsList = $('.projects-list')
if not terms
ProjectsList.showPagination($projectsList)
else
$projectsList.find('li').each (index) ->
$this = $(this)
name = $this.find(filterSelector).text()
if name.toLowerCase().indexOf(terms.toLowerCase()) == -1
$this.hide()
else
$this.show()
$('.gl-pagination').hide()

View file

@ -13,8 +13,10 @@ class @Shortcuts
if $('#modal-shortcuts').length > 0
$('#modal-shortcuts').modal('show')
else
url = '/help/shortcuts'
url = gon.relative_url_root + url if gon.relative_url_root?
$.ajax(
url: '/help/shortcuts',
url: url,
dataType: 'script',
success: (e) ->
if location and location.length > 0

View file

@ -5,23 +5,42 @@ class @ShortcutsIssuable extends ShortcutsNavigation
constructor: (isMergeRequest) ->
super()
Mousetrap.bind('a', ->
$('.js-assignee').select2('open')
$('.block.assignee .edit-link').trigger('click')
return false
)
Mousetrap.bind('m', ->
$('.js-milestone').select2('open')
$('.block.milestone .edit-link').trigger('click')
return false
)
Mousetrap.bind('r', =>
@replyWithSelectedText()
return false
)
Mousetrap.bind('j', =>
@prevIssue()
return false
)
Mousetrap.bind('k', =>
@nextIssue()
return false
)
if isMergeRequest
@enabledHelp.push('.hidden-shortcut.merge_requests')
else
@enabledHelp.push('.hidden-shortcut.issues')
prevIssue: ->
$prevBtn = $('.prev-btn')
if not $prevBtn.hasClass('disabled')
Turbolinks.visit($prevBtn.attr('href'))
nextIssue: ->
$nextBtn = $('.next-btn')
if not $nextBtn.hasClass('disabled')
Turbolinks.visit($nextBtn.attr('href'))
replyWithSelectedText: ->
if window.getSelection
selected = window.getSelection().toString()

View file

@ -8,4 +8,10 @@ $(document).on("click", '.toggle-nav-collapse', (e) ->
$('.sidebar-wrapper').toggleClass("sidebar-collapsed sidebar-expanded")
$('.toggle-nav-collapse i').toggleClass("fa-angle-right fa-angle-left")
$.cookie("collapsed_nav", $('.page-with-sidebar').hasClass(collapsed), { path: '/' })
setTimeout ( ->
niceScrollBars = $('.nicescroll').niceScroll();
niceScrollBars.updateScrollBar();
), 300
)

View file

@ -2,7 +2,7 @@
class @Wikis
constructor: ->
$('.build-new-wiki').bind 'click', (e) =>
$('.new-wiki-page').on 'submit', (e) =>
$('[data-error~=slug]').addClass('hidden')
field = $('#new_wiki_path')
slug = @slugify(field.val())
@ -10,6 +10,7 @@ class @Wikis
if (slug.length > 0)
path = field.attr('data-wikis-path')
location.href = path + '/' + slug
e.preventDefault()
dasherize: (value) ->
value.replace(/[_\s]+/g, '-')

View file

@ -24,6 +24,7 @@
&.s26 { width: 26px; height: 26px; margin-right: 8px; }
&.s32 { width: 32px; height: 32px; margin-right: 10px; }
&.s36 { width: 36px; height: 36px; margin-right: 10px; }
&.s40 { width: 40px; height: 40px; margin-right: 10px; }
&.s46 { width: 46px; height: 46px; margin-right: 15px; }
&.s48 { width: 48px; height: 48px; margin-right: 10px; }
&.s60 { width: 60px; height: 60px; margin-right: 12px; }
@ -40,7 +41,8 @@
&.s16 { font-size: 12px; line-height: 1.33; }
&.s24 { font-size: 14px; line-height: 1.8; }
&.s26 { font-size: 20px; line-height: 1.33; }
&.s32 { font-size: 22px; line-height: 32px; }
&.s32 { font-size: 20px; line-height: 32px; }
&.s40 { font-size: 16px; line-height: 40px; }
&.s60 { font-size: 32px; line-height: 60px; }
&.s90 { font-size: 36px; line-height: 90px; }
&.s110 { font-size: 40px; line-height: 112px; font-weight: 300; }

View file

@ -146,6 +146,10 @@
border-bottom: 1px solid $border-color;
&.oneline-block {
line-height: 42px;
line-height: 36px;
}
> .controls {
float: right;
}
}

View file

@ -2,7 +2,7 @@
@include border-radius(3px);
font-size: $gl-font-size;
font-weight: 500;
padding: $gl-vert-padding $gl-padding;
padding: $gl-vert-padding $gl-btn-padding;
&:focus,
&:active {
@ -82,8 +82,7 @@
&.btn-success,
&.btn-new,
&.btn-create,
&.btn-save,
&.btn-green {
&.btn-save {
@include btn-green;
}
@ -159,7 +158,6 @@
.input-group-btn {
.btn {
@include btn-gray;
@include btn-middle;
&:hover {
@ -186,8 +184,4 @@
border: 1px solid #c6cacf !important;
background-color: #e4e7ed !important;
}
.btn-green {
@include btn-green
}
}

View file

@ -376,11 +376,11 @@ table {
margin-bottom: $gl-padding;
}
.new-project-item-select-holder {
.project-item-select-holder {
display: inline-block;
position: relative;
.new-project-item-select {
.project-item-select {
position: absolute;
top: 0;
right: 0;

View file

@ -36,6 +36,20 @@
}
}
.filename {
&.old {
span.idiff {
background-color: #f8cbcb;
}
}
&.new {
span.idiff {
background-color: #a6f3a6;
}
}
}
.left-options {
margin-top: -3px;
}
@ -144,7 +158,7 @@
}
&:hover {
background: $hover;
background: $row-hover;
}
}
}
@ -158,3 +172,15 @@
}
}
}
span.idiff {
&.left {
border-top-left-radius: 2px;
border-bottom-left-radius: 2px;
}
&.right {
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
}
}

View file

@ -2,11 +2,42 @@ textarea {
resize: vertical;
}
input[type='search'].search-text-input {
background-image: image-url("icon-search.png");
input {
border-radius: $border-radius-base;
}
input[type='search'] {
background-color: white;
padding-left: 10px;
}
input[type='search'].search-input {
background-repeat: no-repeat;
background-position: 10px;
padding-left: 25px;
background-size: 16px;
background-position-x: 30%;
padding-left: 10px;
background-color: $gray-light;
&.search-input[value=""] {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAAFu0lEQVRIia1WTahkVxH+quqce7vf6zdvJpHoIlkYJ2SiJiIokmQjgoGgIAaEIYuYXWICgojiwkmC4taFwhjcyIDusogEIwwiSSCKPwsdwzAg0SjJ9Izzk5n3+nXfe8+pqizOvd395scfsJqi6dPnnDr11Vc/NJ1OwUTosqJLCmYCHCAC2mSHs+ojZv6AO46Y+20AhIneJsafhPhXVZSXDk7qi+aOLhtQNuBmQtcarAKjTXpn2+l3u2yPunvZSABRucjcAV/eMZuM48/Go/g1d19kc4wq+e8MZjWkbI/P5t2P3RFFbv7SQdyBlBUx8N8OTuqjMcof+N94yMPrY2DMm/ytnb32J0QrY+6AqsHM4Q64O9SKDmerKDD3Oy/tNL9vk342CC8RuU6n0ymCMHb22scu7zQngtASOjUHE1BX4UUAv4b7Ow6qiXCXuz/UdvogAAweDY943/b4cAz0ZlYHXeMsnT07RVb7wMUr8ykI4H5HVkMd5Rcb4/jNURVOL5qErAaAUUdCCIJ5kx5q2nw8m39ImEAAsjpE6PStB0YfMcd1wqqG3Xn7A3PfZyyKnNjaqD4fmE/fCNKshirIyY1xvI+Av6g5QIAIIWX7cJPssboSiBBEeKmsZne0Sb8kzAUWNYyq8NvbDo0fZ6beqxuLmqOOMr/lwOh+YXpXtbjERGja9JyZ9+HxpXKb9Gj5oywRESbj+Cj1ENG1QViTGBl1FbC1We1tbVRfHWIoQkhqH9xbpE92XUbb6VJZ1R4crjRz1JWcDMJvLdoMcyAEhjuwHo8Bfndg3mbszhOY+adVlMtD3po51OwzIQiEaams7oeJhxRw1FFOVpFRRUYIhMBAFRnjOsC8IFHHUA4TQQhgAqpAiIFfGbxkIqj54ayGbL7UoOqHCniAEKHLNr26l+D9wQJzeUwMAnfHvEnLECzZRwRV++d60ptjW9VLZeolEJG6GwCCE0CFVNB+Ay0NEqoQYG4YYFu7B8IEVRt3uRzy/osIoLV9QZimWXGHUMFdmI6M64DUF2Je88R9VZqCSP+QlcF5k+4tCzSsXaqjINuK6UyE0+s/mk6/qFq8oAIL9pqMLhkGsNrOyoOIlszust3aJv0U9+kFdwjTGwWl1YdF+KWlQSZ0Se/psj8yGVdg5tJyfH96EBWmLtoEMwMzMFt031NzGWLLzKhC+KV7H5ZeeaMOPxemma2x68puc0LN3+/u6LJiePS6MKHvn4wu6cPzJj0hsioeMfDrEvjv5r6W9gBvjKJujuKzQ0URIZj75NylvT+mbHfXQa4rwAMaVRTMm/SFyzvNy0yF6+4AM+1ubcSnqkAIUjQKl1RKSbE5jt+vovx1MBqF0WW7/d1Z80ab9BtmuJ3Xk5cJKds9TZt/uLPXvtiTrQ+dIwqfAejUvM1os6FNikXKUHfQ+ekUsXT5u85enJ0CaBSkkGEo1syUQ+DfMdE/4GA1uzupf9zdbzhOmLsF4efHVXjaHHAzmDtGdQRd/Nc5wAEJjNki3XfhyvwVNz80xANrht3LsENY9cBBdN1L9GUyyvFRFZ42t75sBvCQRykbRlU4tT2pPxoCvzx09d4GmPs200M6wKdWSDGK8mppYSWdhAlt0qeaLv+IadXU9/Evq4FAZ8ej+LmtcTxaRX4NWI0Uag5Vg1p5MYg8BnlhXIdPHDow+vTWZvVMVttXDLqkTzZdPj6Qii6cP1cSvIdl3iQkNYyi9HH0I22y+93tY3DcQkTZgQtM+POoCr8x97eylkmtrgKuztrvXJ21x/aNKuqIkZ/fntRfCdcTfhUTAIhRzoDojJD0aSNLLwMzmpT7+JaLtyf1MwDo6qz9djFaUq3t9MlFmy/c1OCSceY9fMsVaL9mvH9ocXdkdWxv1scAePG0THAhMOaLdOw/Gvxfxb1w4eCapyIENUcV5M3/u8FitAxZ25P6GAHT3UX39Srw+QOb1ZffA98Dl2Wy1BYkAAAAAElFTkSuQmCC');
}
&.search-input::-webkit-input-placeholder {
text-align: center;
}
&.search-input:-moz-placeholder { /* Firefox 18- */
text-align: center;
}
&.search-input::-moz-placeholder { /* Firefox 19+ */
text-align: center;
}
&.search-input:-ms-input-placeholder {
text-align: center;
}
}
input[type='text'].danger {
@ -74,6 +105,7 @@ label {
.form-control {
@include box-shadow(none);
border-radius: 3px;
}
.form-control-inline {

View file

@ -117,4 +117,4 @@ body {
&.ui_violet {
@include gitlab-theme(#9988CC, $theme-violet, #443366, #332255);
}
}
}

View file

@ -73,7 +73,6 @@ header {
.title {
margin: 0;
overflow: hidden;
font-size: 19px;
line-height: $header-height;
font-weight: normal;
@ -88,6 +87,22 @@ header {
text-decoration: underline;
}
}
.dropdown-toggle-caret {
position: relative;
top: -2px;
width: 12px;
line-height: 12px;
margin-left: 5px;
font-size: 10px;
text-align: center;
cursor: pointer;
}
.project-item-select {
right: auto;
left: 0;
}
}
.navbar-collapse {
@ -108,16 +123,10 @@ header {
.search-input {
width: 220px;
background-image: image-url("icon-search.png");
background-repeat: no-repeat;
background-position: 195px;
@include input-big;
&:focus {
@include box-shadow(none);
outline: none;
border-color: #DDD;
background-color: #FFF;
}
}
}
@ -132,9 +141,13 @@ header {
}
@media (max-width: $screen-md-max) {
.header-collapsed, .header-expanded {
@include collapsed-header;
.header-collapsed {
margin-left: $sidebar_collapsed_width;
}
.header-expanded {
margin-left: $sidebar_width;
}
}
@media(min-width: $screen-md-max) {

View file

@ -9,7 +9,7 @@
display: block;
float: left;
padding: 0 $gl-padding;
padding: 0 $gl-btn-padding;
font-weight: normal;
margin-right: 10px;
font-size: $gl-font-size;

View file

@ -48,8 +48,19 @@
.ui-state-hover,
.ui-state-focus {
border: 1px solid $hover;
background: $hover;
border: 1px solid $row-hover;
background: $row-hover;
color: #333;
}
}
.ui-sortable-handle {
cursor: move;
cursor: -webkit-grab;
cursor: -moz-grab;
&:active {
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
}
}

View file

@ -38,7 +38,7 @@
&.smoke { background-color: $background-color; }
&:hover {
background: $hover;
background: $row-hover;
}
&:last-child {
@ -109,7 +109,6 @@ ul.content-list {
padding: 0;
> li {
padding: $gl-padding 0;
border-color: $table-border-color;
color: $gl-gray;

View file

@ -116,7 +116,7 @@
display: none;
}
aside {
aside:not(.right-sidebar){
display: none;
}

View file

@ -37,3 +37,102 @@
}
}
}
.top-area {
@include clearfix;
border-bottom: 1px solid #EEE;
.nav-text {
padding-top: 16px;
padding-bottom: 11px;
display: inline-block;
width: 50%;
line-height: 28px;
/* Small devices (phones, tablets, 768px and lower) */
@media (max-width: $screen-sm-min) {
width: 100%;
}
}
.nav-links {
display: inline-block;
width: 50%;
margin-bottom: 0px;
border-bottom: none;
/* Small devices (phones, tablets, 768px and lower) */
@media (max-width: $screen-sm-min) {
width: 100%;
}
}
.nav-controls {
width: 50%;
display: inline-block;
float: right;
text-align: right;
padding: 11px 0;
margin-bottom: 0px;
> .dropdown {
margin-right: $gl-padding-top;
display: inline-block;
}
> .btn {
margin-right: $gl-padding-top;
display: inline-block;
&:last-child {
margin-right: 0;
}
}
> .btn-grouped {
float: none;
}
> form {
display: inline-block;
}
input {
height: 34px;
display: inline-block;
position: relative;
top: 1px;
margin-right: $gl-padding-top;
/* Medium devices (desktops, 992px and up) */
@media (min-width: $screen-md-min) { width: 200px; }
/* Large devices (large desktops, 1200px and up) */
@media (min-width: $screen-lg-min) { width: 250px; }
&.input-short {
/* Medium devices (desktops, 992px and up) */
@media (min-width: $screen-md-min) { width: 170px; }
/* Large devices (large desktops, 1200px and up) */
@media (min-width: $screen-lg-min) { width: 210px; }
}
}
/* Hide on extra small devices (phones) */
@media (max-width: $screen-xs-max) {
display: none;
}
/* Small devices (tablets, 768px and lower) */
@media (max-width: $screen-sm-max) {
width: 100%;
text-align: left;
input {
width: 300px;
}
}
}
}

View file

@ -1,35 +1,11 @@
.gl-pagination {
text-align: center;
border-top: 1px solid $border-color;
background-color: $background-color;
margin: -$gl-padding;
margin: 0;
margin-top: 0;
.pagination {
padding: 0;
margin: 0;
display: block;
li.first,
li.last,
li.next,
li.prev {
> a {
color: $link-color;
&:hover {
color: #fff;
}
}
}
li > a,
li > span {
border: none;
margin: 0;
@include border-radius(0 !important);
padding: 13px 19px;
border-right: 1px solid $border-color;
}
}
}

View file

@ -2,7 +2,13 @@
margin-bottom: $gl-padding;
.panel-heading {
padding: 7px $gl-padding;
padding: $gl-vert-padding $gl-padding;
line-height: 36px;
.controls {
margin-top: -2px;
float: right;
}
}
.panel-body {
@ -14,7 +20,3 @@
}
}
}
.container-blank .panel .panel-heading {
line-height: 42px !important;
}

View file

@ -12,6 +12,23 @@
height: 100%;
transition-duration: .3s;
}
.gitlab-text-container-link {
z-index: 1;
position: absolute;
left: 0px;
}
#logo {
z-index: 2;
position: absolute;
width: 58px;
cursor: pointer;
}
&.right-sidebar-expanded {
padding-right: $gutter_width;
}
}
.sidebar-wrapper {
@ -70,7 +87,7 @@
width: 158px;
float: left;
margin: 0;
margin-left: 14px;
margin-left: 50px;
font-size: 19px;
line-height: 41px;
font-weight: normal;
@ -181,6 +198,10 @@
@mixin expanded-sidebar {
padding-left: $sidebar_width;
&.right-sidebar-collapsed {
padding-right: $sidebar_collapsed_width;
}
.sidebar-wrapper {
width: $sidebar_width;
@ -203,6 +224,10 @@
@mixin collapsed-sidebar {
padding-left: $sidebar_collapsed_width;
&.right-sidebar-collapsed {
padding-right: $sidebar_collapsed_width;
}
.sidebar-wrapper {
width: $sidebar_collapsed_width;
@ -266,26 +291,10 @@
background: #f2f6f7;
}
@media (max-width: $screen-md-max) {
.page-sidebar-collapsed {
@include collapsed-sidebar;
}
.page-sidebar-expanded {
@include collapsed-sidebar;
}
.collapse-nav {
display: none;
}
.page-sidebar-collapsed {
@include collapsed-sidebar;
}
@media(min-width: $screen-md-max) {
.page-sidebar-collapsed {
@include collapsed-sidebar;
}
.page-sidebar-expanded {
@include expanded-sidebar;
}
.page-sidebar-expanded {
@include expanded-sidebar;
}

View file

@ -5,13 +5,13 @@
padding: 0;
.timeline-entry {
padding: $gl-padding 0;
padding: $gl-padding $gl-btn-padding;
border-color: $table-border-color;
color: $gl-gray;
border-bottom: 1px solid $border-white-light;
&:target {
background: $hover;
background: $row-hover;
}
&:last-child {

View file

@ -114,22 +114,9 @@
*
*/
.container-blank .panel .panel-heading {
font-size: 17px;
line-height: 38px;
}
.panel {
box-shadow: none;
.panel-heading {
.panel-head-actions {
position: relative;
top: -5px;
float: right;
}
}
.panel-body {
form, pre {
margin: 0;

View file

@ -22,9 +22,9 @@ $brand-info: $gl-info;
$brand-warning: $gl-warning;
$brand-danger: $gl-danger;
$border-radius-base: 2px !default;
$border-radius-large: 2px !default;
$border-radius-small: 2px !default;
$border-radius-base: 3px !default;
$border-radius-large: 3px !default;
$border-radius-small: 3px !default;
//== Scaffolding
@ -66,20 +66,20 @@ $legend-color: $text-color;
//##
$pagination-color: $gl-gray;
$pagination-bg: $background-color;
$pagination-border: transparent;
$pagination-bg: #fff;
$pagination-border: $border-color;
$pagination-hover-color: #fff;
$pagination-hover-bg: $brand-info;
$pagination-hover-border: transparent;
$pagination-hover-color: $gl-gray;
$pagination-hover-bg: $row-hover;
$pagination-hover-border: $border-color;
$pagination-active-color: #fff;
$pagination-active-bg: $brand-info;
$pagination-active-border: transparent;
$pagination-active-color: $blue-dark;
$pagination-active-bg: #fff;
$pagination-active-border: $border-color;
$pagination-disabled-color: #fff;
$pagination-disabled-bg: lighten($brand-info, 15%);
$pagination-disabled-border: transparent;
$pagination-disabled-color: #cdcdcd;
$pagination-disabled-bg: $background-color;
$pagination-disabled-border: $border-color;
//== Form states and alerts

View file

@ -115,7 +115,7 @@
ul, ol {
padding: 0;
margin: 6px 0 6px 18px !important;
margin: 6px 0 6px 28px !important;
}
li {

View file

@ -1,4 +1,4 @@
$hover: #faf9f9;
$row-hover: #f4f8fe;
$gl-text-color: #54565B;
$gl-text-green: #4A2;
$gl-text-red: #D12F19;
@ -12,6 +12,9 @@ $gl-font-size: 15px;
$list-font-size: 15px;
$sidebar_collapsed_width: 62px;
$sidebar_width: 230px;
$gutter_collapsed_width: 62px;
$gutter_width: 290px;
$gutter_inner_width: 258px;
$avatar_radius: 50%;
$code_font_size: 13px;
$code_line_height: 1.5;
@ -22,10 +25,12 @@ $header-height: 58px;
$fixed-layout-width: 1280px;
$gl-gray: #5a5a5a;
$gl-padding: 16px;
$gl-btn-padding: 10px;
$gl-vert-padding: 6px;
$gl-padding-top:10px;
$gl-avatar-size: 46px;
$gl-avatar-size: 40px;
$secondary-text: #7f8fa4;
$error-exclamation-point: #E62958;
/*
* Color schema
@ -35,11 +40,12 @@ $white-light: #FFFFFF;
$white-normal: #ededed;
$white-dark: #ededed;
$gray-light: #f7f7f7;
$gray-normal: #ededed;
$gray-light: #faf9f9;
$gray-normal: #f5f5f5;
$gray-dark: #ededed;
$gray-darkest: #c9c9c9;
$green-light: #31AF64;
$green-light: #38ae67;
$green-normal: #2FAA60;
$green-dark: #2CA05B;
@ -51,7 +57,7 @@ $blue-medium-light: #3498CB;
$blue-medium: #2F8EBF;
$blue-medium-dark: #2D86B4;
$orange-light: #FC6443;
$orange-light: rgba(252, 109, 38, 0.80);
$orange-normal: #E75E40;
$orange-dark: #CE5237;
@ -63,8 +69,8 @@ $border-white-light: #F1F2F4;
$border-white-normal: #D6DAE2;
$border-white-dark: #C6CACF;
$border-gray-light: #d1d1d1;
$border-gray-normal: #D6DAE2;
$border-gray-light: rgba(0, 0, 0, 0.06);
$border-gray-normal: rgba(0, 0, 0, 0.10);;
$border-gray-dark: #C6CACF;
$border-green-light: #2FAA60;
@ -75,7 +81,7 @@ $border-blue-light: #2D9FD8;
$border-blue-normal: #2897CE;
$border-blue-dark: #258DC1;
$border-orange-light: #ED5C3D;
$border-orange-light: #fc6d26;
$border-orange-normal: #CE5237;
$border-orange-dark: #C14E35;

View file

@ -55,6 +55,16 @@
@extend .alert-warning;
padding: 10px;
text-align: center;
> div, p {
display: inline;
margin: 0;
a {
color: inherit;
text-decoration: underline;
}
}
}
.broadcast-message-preview {

View file

@ -0,0 +1,11 @@
.appearance-logo-preview {
max-width: 400px;
margin-bottom: 20px;
}
.appearance-light-logo-preview {
background-color: $background-color;
max-width: 72px;
padding: 10px;
margin-bottom: 10px;
}

View file

@ -40,10 +40,6 @@
.avatar {
@include border-radius(50%);
}
.identicon {
line-height: 46px;
}
}
.dash-project-access-icon {

View file

@ -12,6 +12,14 @@
.identifier {
color: #5c5d5e;
}
.issue_created_ago, .author_link {
white-space: nowrap;
}
.issue-meta {
margin-left: 65px
}
}
.detail-page-description {

View file

@ -56,6 +56,7 @@
width: 100%;
font-family: $monospace_font;
border: none;
border-collapse: separate;
margin: 0px;
padding: 0px;
.line_holder td {

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,7 @@
*/
.event-item {
font-size: $gl-font-size;
padding: $gl-padding 0 $gl-padding ($gl-avatar-size + 15px);
padding: $gl-padding-top 0 $gl-padding-top ($gl-avatar-size + $gl-padding-top);
border-bottom: 1px solid $table-border-color;
color: #7f8fa4;
@ -16,7 +16,7 @@
.event-title,
.event-item-timestamp {
line-height: 44px;
line-height: 40px;
}
}
@ -25,7 +25,7 @@
}
.avatar {
margin-left: -($gl-avatar-size + 15px);
margin-left: -($gl-avatar-size + $gl-padding-top);
}
.event-title {
@ -41,7 +41,6 @@
margin-right: 174px;
.event-note {
margin-top: 5px;
word-wrap: break-word;
.md {
@ -98,8 +97,6 @@
&:last-child { border:none }
.event_commits {
margin-top: 9px;
li {
&.commit {
background: transparent;

View file

@ -6,11 +6,3 @@
font-size: 30px;
}
}
.explore-trending-block {
.lead {
line-height: 32px;
font-size: 18px;
margin-top: 10px;
}
}

View file

@ -1,5 +1,15 @@
.member-search-form {
float: left;
input[type='search'] {
width: 225px;
vertical-align: bottom;
@media (max-width: $screen-xs-max) {
width: 100px;
vertical-align: bottom;
}
}
}
.milestone-row {
@ -11,3 +21,21 @@
height: 42px;
}
}
.group-row {
&.no-description {
.group-name {
line-height: 44px;
}
}
.stats {
float: right;
line-height: 44px;
color: $gl-gray;
span {
margin-right: 15px;
}
}
}

View file

@ -29,21 +29,8 @@
}
}
.project-issuable-filter {
.controls {
float: right;
margin-top: 11px;
}
.nav-links {
text-align: left;
}
}
.issuable-details {
section {
border-right: 1px solid $border-white-light;
.issuable-discussion {
margin-right: 1px;
}
@ -73,11 +60,41 @@
.block {
@include clearfix;
padding: $gl-padding 0;
border-bottom: 1px solid #F0F0F0;
border-bottom: 1px solid $border-gray-light;
// This prevents the mess when resizing the sidebar
// of elements repositioning themselves..
width: $gutter_inner_width;
// --
&:first-child {
padding-top: 5px;
}
&:last-child {
border: none;
}
span {
margin-top: 7px;
display: inline-block;
}
.select2-container span {
margin-top: 0;
}
.issuable-count {
}
.gutter-toggle {
margin-left: 20px;
padding-left: 10px;
&:hover {
color: $gray-darkest;
}
}
}
.title {
@ -133,3 +150,105 @@
margin-right: 2px;
}
}
.right-sidebar {
position: fixed;
top: 58px;
bottom: 0;
right: 0;
transition: width .3s;
background: $gray-light;
padding: 10px 20px;
&.right-sidebar-expanded {
width: $gutter_width;
hr {
display: none;
}
.sidebar-collapsed-icon {
display: none;
}
.gutter-toggle {
border-left: 1px solid $border-gray-light;
}
}
.subscribe-button {
span {
margin-top: 0;
}
}
&.right-sidebar-collapsed {
width: $sidebar_collapsed_width;
padding-top: 0;
hr {
margin: 0;
color: $gray-normal;
border-color: $gray-normal;
width: 62px;
margin-left: -20px
}
.block {
width: $sidebar_collapsed_width - 1px;
margin-left: -19px;
padding: 15px 0 0 0;
border-bottom: none;
overflow: hidden;
}
.hide-collapsed {
display: none;
}
.gutter-toggle {
margin-left: -36px;
}
.sidebar-collapsed-icon {
display: block;
width: 100%;
text-align: center;
padding-bottom: 10px;
color: #999999;
span {
display: block;
margin-top: 0;
}
.btn-clipboard {
border: none;
&:hover {
background: transparent;
}
i {
color: #999999;
}
}
}
}
.btn {
background: $gray-normal;
border: 1px solid $border-gray-normal;
&:hover {
background: $gray-dark;
border: 1px solid $border-gray-dark;
}
}
}
.detail-page-description {
small {
color: $gray-darkest;
}
}

View file

@ -49,11 +49,6 @@
.issue-search-form {
margin: 0;
height: 24px;
.issue_search {
border: 1px solid #DDD !important;
background-color: #f4f4f4;
}
}
form.edit-issue {
@ -70,10 +65,6 @@ form.edit-issue {
width: 3em;
}
.merge-request-info {
padding-left: 5px;
}
.merge-request-status {
color: $gl-gray;
font-size: 15px;
@ -148,4 +139,4 @@ form.edit-issue {
.issue-closed-by-widget {
color: $secondary-text;
margin-left: 52px;
}
}

View file

@ -9,7 +9,7 @@
}
}
.manage-labels-list {
.label-row {
.label {
padding: 9px;
font-size: 14px;

View file

@ -201,3 +201,39 @@
.mr-source-target {
line-height: 31px;
}
.disabled-comment-area {
padding: 16px 0;
.disabled-profile {
width: 40px;
height: 40px;
background: $border-gray-dark;
border-radius: 20px;
display: inline-block;
margin-right: 10px;
}
.disabled-comment {
background: $gray-light;
display: inline-block;
vertical-align: top;
height: 200px;
border-radius: 4px;
border: 1px solid $border-gray-normal;
padding-top: 90px;
text-align: center;
right: 20px;
position: absolute;
left: 70px;
margin-bottom: 20px;
span {
color: #B2B2B2;
a {
color: $md-link-color;
}
}
}
}

View file

@ -11,3 +11,60 @@ li.milestone {
height: 6px;
}
}
.milestone-content {
.issues-count {
margin-right: 17px;
float: right;
width: 105px;
}
.issue-row {
.color-label {
border-radius: 2px;
padding: 3px !important;
}
// Issue title
span a {
color: rgba(0,0,0,0.64);
}
}
}
.milestone-summary {
margin-bottom: 25px;
.milestone-stat {
margin-right: 10px;
}
.remaining-days {
color: $orange-light;
}
}
.issues-sortable-list {
.issue-detail {
display: block;
.issue-number{
color: rgba(0,0,0,0.44);
margin-right: 5px;
}
.color-label {
padding: 6px 10px;
margin-right: 7px;
margin-top: 10px;
}
.avatar {
float: none;
}
}
}
.milestone-detail {
border-bottom: 1px solid $border-color;
padding: 20px 0;
}

View file

@ -73,31 +73,26 @@
font-weight: normal;
}
.visibility-icon {
display: inline-block;
margin-left: 5px;
font-size: 18px;
color: $gray;
}
p {
padding: 0 $gl-padding;
color: #5c5d5e;
}
}
.visibility-level-label {
@extend .btn;
@extend .btn-gray;
color: $gray;
cursor: default;
i {
color: inherit;
}
}
.project-repo-buttons {
margin-top: 12px;
margin-top: 20px;
margin-bottom: 0px;
.count-buttons {
display: block;
margin-bottom: 12px;
margin-bottom: 20px;
}
.clone-row {
@ -163,7 +158,7 @@
line-height: 13px;
padding: $gl-vert-padding $gl-padding;
letter-spacing: .4px;
padding: 10px;
padding: 10px 14px;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
@ -281,36 +276,6 @@
margin-top: -1px;
}
.top-area {
border-bottom: 1px solid #EEE;
ul.nav-links {
display: inline-block;
width: 50%;
margin-bottom: 0px;
border-bottom: none;
}
.projects-search-form {
width: 50%;
display: inline-block;
float: right;
padding-top: 11px;
text-align: right;
.btn-green {
margin-left: 10px;
float: right;
}
}
@media (max-width: $screen-xs-max) {
.projects-search-form {
padding-top: 15px;
}
}
}
.fork-namespaces {
.fork-thumbnail {
text-align: center;
@ -386,22 +351,6 @@ pre.light-well {
border-color: #f1f1f1;
}
.projects-search-form {
padding: $gl-padding 0;
padding-bottom: 0;
margin-bottom: 0px;
input {
display: inline-block;
width: calc(100% - 151px);
}
.btn {
display: inline-block;
width: 135px;
}
}
.git-empty {
margin: 0 7px 0 7px;
@ -437,12 +386,11 @@ pre.light-well {
@include basic-list;
.project-row {
padding: $gl-padding 0;
border-color: $table-border-color;
&.no-description {
.project {
line-height: 44px;
line-height: 40px;
}
}
@ -455,12 +403,16 @@ pre.light-well {
.project-controls {
float: right;
color: $gl-gray;
line-height: 45px;
line-height: 40px;
color: #7f8fa4;
a:hover {
text-decoration: none;
}
> span {
margin-left: 10px;
}
}
.project-description {
@ -558,3 +510,19 @@ pre.light-well {
width: 101%;
}
}
.cannot-be-merged,
.cannot-be-merged:hover {
color: #E62958;
margin-top: 2px;
}
.private-forks-notice .private-fork-icon {
i:nth-child(1) {
color: #2AA056;
}
i:nth-child(2) {
color: #FFFFFF;
}
}

View file

@ -0,0 +1,124 @@
/**
* Dashboard Todos
*
*/
.navbar-nav {
li {
.badge.todos-pending-count {
background-color: #7f8fa4;
margin-top: -5px;
}
}
}
.todos {
.panel {
border-top: none;
margin-bottom: 0;
}
}
.todo-item {
font-size: $gl-font-size;
padding: $gl-padding-top 0 $gl-padding-top ($gl-avatar-size + $gl-padding-top);
border-bottom: 1px solid $table-border-color;
color: #7f8fa4;
&.todo-inline {
.avatar {
position: relative;
top: -2px;
}
.todo-title {
line-height: 40px;
}
}
a {
color: #4c4e54;
}
.avatar {
margin-left: -($gl-avatar-size + $gl-padding-top);
}
.todo-title {
@include str-truncated(calc(100% - 174px));
font-weight: 600;
.author_name {
color: #333;
}
}
.todo-body {
margin-right: 174px;
.todo-note {
word-wrap: break-word;
.md {
color: #7f8fa4;
font-size: $gl-font-size;
p {
color: #5c5d5e;
}
}
pre {
border: none;
background: #f9f9f9;
border-radius: 0;
color: #777;
margin: 0 20px;
overflow: hidden;
}
.note-image-attach {
margin-top: 4px;
margin-left: 0px;
max-width: 200px;
float: none;
}
p:last-child {
margin-bottom: 0;
}
}
.todo-note-icon {
color: #777;
float: left;
font-size: $gl-font-size;
line-height: 16px;
margin-right: 5px;
}
}
&:last-child { border:none }
}
@media (max-width: $screen-xs-max) {
.todo-item {
padding-left: $gl-padding;
.todo-title {
white-space: normal;
overflow: visible;
max-width: 100%;
}
.avatar {
display: none;
}
.todo-body {
margin: 0;
border-left: 2px solid #DDD;
padding-left: 10px;
}
}
}

View file

@ -21,7 +21,7 @@
&:hover {
td {
background: $hover;
background: $row-hover;
}
cursor: pointer;
}

View file

@ -4,8 +4,3 @@
margin-right: auto;
padding-right: 7px;
}
.wiki-last-edit-by {
font-size: 80%;
font-weight: normal;
}

View file

@ -0,0 +1,57 @@
class Admin::AppearancesController < Admin::ApplicationController
before_action :set_appearance, except: :create
def show
end
def preview
end
def create
@appearance = Appearance.new(appearance_params)
if @appearance.save
redirect_to admin_appearances_path, notice: 'Appearance was successfully created.'
else
render action: 'show'
end
end
def update
if @appearance.update(appearance_params)
redirect_to admin_appearances_path, notice: 'Appearance was successfully updated.'
else
render action: 'show'
end
end
def logo
@appearance.remove_logo!
@appearance.save
redirect_to admin_appearances_path, notice: 'Logo was succesfully removed.'
end
def header_logos
@appearance.remove_header_logo!
@appearance.save
redirect_to admin_appearances_path, notice: 'Header logo was succesfully removed.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_appearance
@appearance = Appearance.last || Appearance.new
end
# Only allow a trusted parameter "white list" through.
def appearance_params
params.require(:appearance).permit(
:title, :description, :logo, :logo_cache, :header_logo, :header_logo_cache,
:updated_by
)
end
end

View file

@ -74,13 +74,14 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:metrics_timeout,
:metrics_method_call_threshold,
:metrics_sample_interval,
:ip_blocking_enabled,
:dnsbl_servers_list,
:recaptcha_enabled,
:recaptcha_site_key,
:recaptcha_private_key,
:sentry_enabled,
:sentry_dsn,
:akismet_enabled,
:akismet_api_key,
:email_author_in_body,
restricted_visibility_levels: [],
import_sources: []
)

View file

@ -2,7 +2,7 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
before_action :finder, only: [:edit, :update, :destroy]
def index
@broadcast_messages = BroadcastMessage.reorder("starts_at ASC").page(params[:page])
@broadcast_messages = BroadcastMessage.reorder("ends_at DESC").page(params[:page])
@broadcast_message = BroadcastMessage.new
end
@ -36,6 +36,10 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
end
end
def preview
@message = broadcast_message_params[:message]
end
protected
def finder

View file

@ -53,6 +53,6 @@ class Admin::LabelsController < Admin::ApplicationController
end
def label_params
params[:label].permit(:title, :color)
params[:label].permit(:title, :description, :color)
end
end

View file

@ -0,0 +1,17 @@
class Admin::SpamLogsController < Admin::ApplicationController
def index
@spam_logs = SpamLog.order(id: :desc).page(params[:page])
end
def destroy
spam_log = SpamLog.find(params[:id])
if params[:remove_user]
spam_log.remove_user
redirect_to admin_spam_logs_path, notice: "User #{spam_log.user.username} was successfully removed."
else
spam_log.destroy
render nothing: true
end
end
end

View file

@ -25,7 +25,7 @@ class ApplicationController < ActionController::Base
helper_method :abilities, :can?, :current_application_settings
helper_method :import_sources_enabled?, :github_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :gitorious_import_enabled?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled?
helper_method :repository
helper_method :repository, :can_collaborate_with_project?
rescue_from Encoding::CompatibilityError do |exception|
log_exception(exception)
@ -60,6 +60,8 @@ class ApplicationController < ActionController::Base
params[:authenticity_token].presence
elsif params[:private_token].presence
params[:private_token].presence
elsif request.headers['PRIVATE-TOKEN'].present?
request.headers['PRIVATE-TOKEN']
end
user = user_token && User.find_by_authentication_token(user_token.to_s)
@ -162,7 +164,7 @@ class ApplicationController < ActionController::Base
end
def git_not_found!
render html: "errors/git_not_found", layout: "errors", status: 404
render "errors/git_not_found.html", layout: "errors", status: 404
end
def method_missing(method_sym, *arguments, &block)
@ -244,6 +246,8 @@ class ApplicationController < ActionController::Base
def ldap_security_check
if current_user && current_user.requires_ldap_check?
return unless current_user.try_obtain_ldap_lease
unless Gitlab::LDAP::Access.allowed?(current_user)
sign_out current_user
flash[:alert] = "Access denied for your LDAP account."
@ -275,9 +279,10 @@ class ApplicationController < ActionController::Base
}
end
def view_to_html_string(partial)
def view_to_html_string(partial, locals = {})
render_to_string(
partial,
locals: locals,
layout: false,
formats: [:html]
)
@ -298,7 +303,8 @@ class ApplicationController < ActionController::Base
end
def set_filters_params
params[:sort] ||= 'id_desc'
set_default_sort
params[:scope] = 'all' if params[:scope].blank?
params[:state] = 'opened' if params[:state].blank?
@ -405,4 +411,31 @@ class ApplicationController < ActionController::Base
current_user.nil? && root_path == request.path
end
def can_collaborate_with_project?(project = nil)
project ||= @project
can?(current_user, :push_code, project) ||
(current_user && current_user.already_forked?(project))
end
private
def set_default_sort
key = if is_a_listing_page_for?('issues') || is_a_listing_page_for?('merge_requests')
'issuable_sort'
end
cookies[key] = params[:sort] if key && params[:sort].present?
params[:sort] = cookies[key] if key
params[:sort] ||= 'id_desc'
end
def is_a_listing_page_for?(page_type)
controller_name, action_name = params.values_at(:controller, :action)
(controller_name == "projects/#{page_type}" && action_name == 'index') ||
(controller_name == 'groups' && action_name == page_type) ||
(controller_name == 'dashboard' && action_name == page_type)
end
end

View file

@ -3,52 +3,5 @@ module Ci
def self.railtie_helpers_paths
"app/helpers/ci"
end
private
def authorize_access_project!
unless can?(current_user, :read_project, project)
return page_404
end
end
def authorize_manage_builds!
unless can?(current_user, :manage_builds, project)
return page_404
end
end
def authenticate_admin!
return render_404 unless current_user.is_admin?
end
def authorize_manage_project!
unless can?(current_user, :admin_project, project)
return page_404
end
end
def page_404
render file: "#{Rails.root}/public/404.html", status: 404, layout: false
end
def default_headers
headers['X-Frame-Options'] = 'DENY'
headers['X-XSS-Protection'] = '1; mode=block'
end
# JSON for infinite scroll via Pager object
def pager_json(partial, count)
html = render_to_string(
partial,
layout: false,
formats: [:html]
)
render json: {
html: html,
count: count
}
end
end
end

View file

@ -1,9 +1,9 @@
module Ci
class ProjectsController < Ci::ApplicationController
before_action :project, except: [:index]
before_action :authenticate_user!, except: [:index, :build, :badge]
before_action :authorize_access_project!, except: [:index, :badge]
before_action :project
before_action :authorize_read_project!, except: [:badge]
before_action :no_cache, only: [:badge]
skip_before_action :authenticate_user!, only: [:badge]
protect_from_forgery
def show
@ -13,9 +13,14 @@ module Ci
# Project status badge
# Image with build status for sha or ref
#
# This action in DEPRECATED, this is here only for backwards compatibility
# with projects migrated from GitLab CI.
#
def badge
image = Ci::ImageForBuildService.new.execute(@project, params)
return render_404 unless @project
image = Ci::ImageForBuildService.new.execute(@project, params)
send_file image.path, filename: image.name, disposition: 'inline', type:"image/svg+xml"
end

View file

@ -13,17 +13,11 @@ module CreatesCommit
result = service.new(@tree_edit_project, current_user, commit_params).execute
if result[:status] == :success
flash[:notice] = success_notice || "Your changes have been successfully committed."
if create_merge_request?
success_path = new_merge_request_path
target = different_project? ? "project" : "branch"
flash[:notice] << " You can now submit a merge request to get this change into the original #{target}."
end
update_flash_notice(success_notice)
respond_to do |format|
format.html { redirect_to success_path }
format.json { render json: { message: "success", filePath: success_path } }
format.html { redirect_to final_success_path(success_path) }
format.json { render json: { message: "success", filePath: final_success_path(success_path) } }
end
else
flash[:alert] = result[:message]
@ -41,14 +35,32 @@ module CreatesCommit
end
def authorize_edit_tree!
return if can?(current_user, :push_code, project)
return if current_user && current_user.already_forked?(project)
return if can_collaborate_with_project?
access_denied!
end
private
def update_flash_notice(success_notice)
flash[:notice] = success_notice || "Your changes have been successfully committed."
if create_merge_request?
if merge_request_exists?
flash[:notice] = nil
else
target = different_project? ? "project" : "branch"
flash[:notice] << " You can now submit a merge request to get this change into the original #{target}."
end
end
end
def final_success_path(success_path)
return success_path unless create_merge_request?
merge_request_exists? ? existing_merge_request_path : new_merge_request_path
end
def new_merge_request_path
new_namespace_project_merge_request_path(
@mr_source_project.namespace,
@ -62,6 +74,19 @@ module CreatesCommit
)
end
def existing_merge_request_path
namespace_project_merge_request_path(@mr_target_project.namespace, @mr_target_project, @merge_request)
end
def merge_request_exists?
return @merge_request if defined?(@merge_request)
@merge_request = @mr_target_project.merge_requests.opened.find_by(
source_branch: @mr_source_branch,
target_branch: @mr_target_branch
)
end
def different_project?
@mr_source_project != @mr_target_project
end
@ -75,7 +100,7 @@ module CreatesCommit
end
def set_commit_variables
@mr_source_branch = @target_branch
@mr_source_branch ||= @target_branch
if can?(current_user, :push_code, @project)
# Edit file in this project
@ -89,7 +114,7 @@ module CreatesCommit
else
# Merge request to this project
@mr_target_project = @project
@mr_target_branch = @ref
@mr_target_branch ||= @ref
end
else
# Edit file in fork
@ -97,7 +122,7 @@ module CreatesCommit
# Merge request from fork to this project
@mr_source_project = @tree_edit_project
@mr_target_project = @project
@mr_target_branch = @ref
@mr_target_branch ||= @ref
end
end
end

View file

@ -6,6 +6,8 @@ module IssuesAction
@issues = @issues.page(params[:page]).per(ApplicationController::PER_PAGE)
@issues = @issues.preload(:author, :project)
@label = @issuable_finder.labels.first
respond_to do |format|
format.html
format.atom { render layout: false }

View file

@ -5,5 +5,7 @@ module MergeRequestsAction
@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)
@label = @issuable_finder.labels.first
end
end

View file

@ -3,7 +3,16 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
def index
@projects = current_user.authorized_projects.sorted_by_activity.non_archived
@projects = @projects.sort(@sort = params[:sort])
@projects = @projects.includes(:namespace)
terms = params[:filter_projects]
if terms.present?
@projects = @projects.search(terms)
end
@projects = @projects.page(params[:page]).per(PER_PAGE)
@last_push = current_user.recent_push
respond_to do |format|
@ -13,6 +22,11 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
load_events
render layout: false
end
format.json do
render json: {
html: view_to_html_string("dashboard/projects/_projects", locals: { projects: @projects })
}
end
end
end
@ -20,6 +34,14 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
@projects = current_user.starred_projects
@projects = @projects.includes(:namespace, :forked_from_project, :tags)
@projects = @projects.sort(@sort = params[:sort])
terms = params[:filter_projects]
if terms.present?
@projects = @projects.search(terms)
end
@projects = @projects.page(params[:page]).per(PER_PAGE)
@last_push = current_user.recent_push
@groups = []
@ -27,8 +49,9 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
format.html
format.json do
load_events
pager_json("events/_events", @events.count)
render json: {
html: view_to_html_string("dashboard/projects/_projects", locals: { projects: @projects })
}
end
end
end
@ -36,7 +59,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
private
def load_events
@events = Event.in_projects(@projects.pluck(:id))
@events = Event.in_projects(@projects)
@events = @event_filter.apply_filter(@events).with_associations
@events = @events.limit(20).offset(params[:offset] || 0)
end

View file

@ -0,0 +1,35 @@
class Dashboard::TodosController < Dashboard::ApplicationController
before_action :find_todos, only: [:index, :destroy_all]
def index
@todos = @todos.page(params[:page]).per(PER_PAGE)
end
def destroy
todo.done!
respond_to do |format|
format.html { redirect_to dashboard_todos_path, notice: 'Todo was successfully marked as done.' }
format.js { render nothing: true }
end
end
def destroy_all
@todos.each(&:done!)
respond_to do |format|
format.html { redirect_to dashboard_todos_path, notice: 'All todos were marked as done.' }
format.js { render nothing: true }
end
end
private
def todo
@todo ||= current_user.todos.find(params[:id])
end
def find_todos
@todos = TodosFinder.new(current_user, params).execute
end
end

View file

@ -23,14 +23,14 @@ class DashboardController < Dashboard::ApplicationController
protected
def load_events
project_ids =
projects =
if params[:filter] == "starred"
current_user.starred_projects
else
current_user.authorized_projects
end.pluck(:id)
end
@events = Event.in_projects(project_ids)
@events = Event.in_projects(projects)
@events = @event_filter.apply_filter(@events).with_associations
@events = @events.limit(20).offset(params[:offset] || 0)
end

View file

@ -6,19 +6,49 @@ class Explore::ProjectsController < Explore::ApplicationController
@projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present?
@projects = @projects.non_archived
@projects = @projects.search(params[:search]) if params[:search].present?
@projects = @projects.search(params[:filter_projects]) if params[:filter_projects].present?
@projects = @projects.sort(@sort = params[:sort])
@projects = @projects.includes(:namespace).page(params[:page]).per(PER_PAGE)
respond_to do |format|
format.html
format.json do
render json: {
html: view_to_html_string("dashboard/projects/_projects", locals: { projects: @projects })
}
end
end
end
def trending
@trending_projects = TrendingProjectsFinder.new.execute(current_user)
@trending_projects = @trending_projects.non_archived
@trending_projects = @trending_projects.page(params[:page]).per(PER_PAGE)
@projects = TrendingProjectsFinder.new.execute(current_user)
@projects = @projects.non_archived
@projects = @projects.search(params[:filter_projects]) if params[:filter_projects].present?
@projects = @projects.page(params[:page]).per(PER_PAGE)
respond_to do |format|
format.html
format.json do
render json: {
html: view_to_html_string("dashboard/projects/_projects", locals: { projects: @projects })
}
end
end
end
def starred
@starred_projects = ProjectsFinder.new.execute(current_user)
@starred_projects = @starred_projects.reorder('star_count DESC')
@starred_projects = @starred_projects.page(params[:page]).per(PER_PAGE)
@projects = ProjectsFinder.new.execute(current_user)
@projects = @projects.search(params[:filter_projects]) if params[:filter_projects].present?
@projects = @projects.reorder('star_count DESC')
@projects = @projects.page(params[:page]).per(PER_PAGE)
respond_to do |format|
format.html
format.json do
render json: {
html: view_to_html_string("dashboard/projects/_projects", locals: { projects: @projects })
}
end
end
end
end

View file

@ -2,18 +2,19 @@ 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]
skip_before_action :authenticate_user!, only: [:index, :show, :issues, :merge_requests]
before_action :group, except: [:index, :new, :create]
# Authorize
before_action :authorize_read_group!, except: [:show, :new, :create, :autocomplete]
before_action :authorize_read_group!, except: [:index, :show, :new, :create, :autocomplete]
before_action :authorize_admin_group!, only: [:edit, :update, :destroy, :projects]
before_action :authorize_create_group!, only: [:new, :create]
# Load group projects
before_action :load_projects, except: [:new, :create, :projects, :edit, :update, :autocomplete]
before_action :event_filter, only: :show
before_action :load_projects, except: [:index, :new, :create, :projects, :edit, :update, :autocomplete]
before_action :event_filter, only: [:show, :events]
layout :determine_layout
@ -40,13 +41,16 @@ class GroupsController < Groups::ApplicationController
def show
@last_push = current_user.recent_push if current_user
@projects = @projects.includes(:namespace)
@projects = @projects.search(params[:filter_projects]) if params[:filter_projects].present?
@projects = @projects.page(params[:page]).per(PER_PAGE) if params[:filter_projects].blank?
respond_to do |format|
format.html
format.json do
load_events
pager_json("events/_events", @events.count)
render json: {
html: view_to_html_string("dashboard/projects/_projects", locals: { projects: @projects })
}
end
format.atom do
@ -56,6 +60,15 @@ class GroupsController < Groups::ApplicationController
end
end
def events
respond_to do |format|
format.json do
load_events
pager_json("events/_events", @events.count)
end
end
end
def edit
end
@ -81,16 +94,13 @@ class GroupsController < Groups::ApplicationController
def group
@group ||= Group.find_by(path: params[:id])
@group || render_404
end
def load_projects
@projects ||= ProjectsFinder.new.execute(current_user, group: group).sorted_by_activity.non_archived
end
def project_ids
@projects.pluck(:id)
end
# Dont allow unauthorized access to group
def authorize_read_group!
unless @group and (@projects.present? or can?(current_user, :read_group, @group))
@ -123,7 +133,7 @@ class GroupsController < Groups::ApplicationController
end
def load_events
@events = Event.in_projects(project_ids)
@events = Event.in_projects(@projects)
@events = event_filter.apply_filter(@events).with_associations
@events = @events.limit(20).offset(params[:offset] || 0)
end

View file

@ -1,4 +1,5 @@
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
include AuthenticatesWithTwoFactor
protect_from_forgery except: [:kerberos, :saml, :cas3]
@ -29,14 +30,38 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
# Do additional LDAP checks for the user filter and EE features
if ldap_user.allowed?
log_audit_event(@user, with: :ldap)
sign_in_and_redirect(@user)
if @user.two_factor_enabled?
prompt_for_two_factor(@user)
else
log_audit_event(@user, with: :ldap)
sign_in_and_redirect(@user)
end
else
flash[:alert] = "Access denied for your LDAP account."
redirect_to new_user_session_path
end
end
def saml
if current_user
log_audit_event(current_user, with: :saml)
# Update SAML identity if data has changed.
identity = current_user.identities.find_by(extern_uid: oauth['uid'], provider: :saml)
if identity.nil?
current_user.identities.create(extern_uid: oauth['uid'], provider: :saml)
redirect_to profile_account_path, notice: 'Authentication method updated'
else
redirect_to after_sign_in_path_for(current_user)
end
else
saml_user = Gitlab::Saml::User.new(oauth)
saml_user.save
@user = saml_user.gl_user
continue_login_process
end
end
def omniauth_error
@provider = params[:provider]
@error = params[:error]
@ -60,25 +85,11 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
log_audit_event(current_user, with: oauth['provider'])
redirect_to profile_account_path, notice: 'Authentication method updated'
else
@user = Gitlab::OAuth::User.new(oauth)
@user.save
oauth_user = Gitlab::OAuth::User.new(oauth)
oauth_user.save
@user = oauth_user.gl_user
# Only allow properly saved users to login.
if @user.persisted? && @user.valid?
log_audit_event(@user.gl_user, with: oauth['provider'])
sign_in_and_redirect(@user.gl_user)
else
error_message =
if @user.gl_user.errors.any?
@user.gl_user.errors.map do |attribute, message|
"#{attribute} #{message}"
end.join(", ")
else
''
end
redirect_to omniauth_error_path(oauth['provider'], error: error_message) and return
end
continue_login_process
end
rescue Gitlab::OAuth::SignupDisabledError
label = Gitlab::OAuth::Provider.label_for(oauth['provider'])
@ -99,6 +110,18 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
session[:service_tickets][provider] = ticket
end
def continue_login_process
# Only allow properly saved users to login.
if @user.persisted? && @user.valid?
log_audit_event(@user, with: oauth['provider'])
sign_in_and_redirect(@user)
else
error_message = @user.errors.full_messages.to_sentence
redirect_to omniauth_error_path(oauth['provider'], error: error_message) and return
end
end
def oauth
@oauth ||= request.env['omniauth.auth']
end

View file

@ -12,11 +12,13 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
current_user.save! if current_user.changed?
if two_factor_grace_period_expired?
flash.now[:alert] = 'You must configure Two-Factor Authentication in your account.'
else
grace_period_deadline = current_user.otp_grace_period_started_at + two_factor_grace_period.hours
flash.now[:alert] = "You must configure Two-Factor Authentication in your account until #{l(grace_period_deadline)}."
if two_factor_authentication_required?
if two_factor_grace_period_expired?
flash.now[:alert] = 'You must enable Two-factor Authentication for your account.'
else
grace_period_deadline = current_user.otp_grace_period_started_at + two_factor_grace_period.hours
flash.now[:alert] = "You must enable Two-factor Authentication for your account before #{l(grace_period_deadline)}."
end
end
@qr_code = build_qr_code

View file

@ -28,6 +28,11 @@ class Projects::ApplicationController < ApplicationController
private
def apply_diff_view_cookie!
view = params[:view] || cookies[:diff_view]
cookies.permanent[:diff_view] = params[:view] = view if view
end
def builds_enabled
return render_404 unless @project.builds_enabled?
end

View file

@ -1,6 +1,6 @@
class Projects::ArtifactsController < Projects::ApplicationController
layout 'project'
before_action :authorize_read_build_artifacts!
before_action :authorize_read_build!
def download
unless artifacts_file.file_storage?
@ -43,14 +43,4 @@ class Projects::ArtifactsController < Projects::ApplicationController
def artifacts_file
@artifacts_file ||= build.artifacts_file
end
def authorize_read_build_artifacts!
unless can?(current_user, :read_build_artifacts, @project)
if current_user.nil?
return authenticate_user!
else
return render_404
end
end
end
end

View file

@ -2,15 +2,13 @@ class Projects::AvatarsController < Projects::ApplicationController
before_action :project
def show
@blob = @project.repository.blob_at_branch('master', @project.avatar_in_git)
@blob = @repository.blob_at_branch('master', @project.avatar_in_git)
if @blob
headers['X-Content-Type-Options'] = 'nosniff'
send_data(
@blob.data,
type: @blob.mime_type,
disposition: 'inline',
filename: @blob.name
)
headers.store(*Gitlab::Workhorse.send_git_blob(@repository, @blob))
headers['Content-Disposition'] = 'inline'
headers['Content-Type'] = @blob.content_type
head :ok # 'render nothing: true' messes up the Content-Type
else
render_404
end

View file

@ -0,0 +1,24 @@
class Projects::BadgesController < Projects::ApplicationController
before_action :set_no_cache
def build
respond_to do |format|
format.html { render_404 }
format.svg do
image = Ci::ImageForBuildService.new.execute(project, ref: params[:ref])
send_file(image.path, filename: image.name, disposition: 'inline', type: 'image/svg+xml')
end
end
end
private
def set_no_cache
expires_now
# Add some deprecated headers for older agents
#
response.headers['Pragma'] = 'no-cache'
response.headers['Expires'] = 'Fri, 01 Jan 1990 00:00:00 GMT'
end
end

View file

@ -33,6 +33,7 @@ class Projects::BlobController < Projects::ApplicationController
def edit
@last_commit = Gitlab::Git::Commit.last_for_path(@repository, @ref, @path).sha
blob.load_all_data!(@repository)
end
def update
@ -51,6 +52,7 @@ class Projects::BlobController < Projects::ApplicationController
def preview
@content = params[:content]
@blob.load_all_data!(@repository)
diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3', include_diff_info: true)
diff_lines = diffy.diff.scan(/.*\n/)[2..-1]
diff_lines = Gitlab::Diff::Parser.new.parse(diff_lines)

View file

@ -1,9 +1,8 @@
class Projects::BuildsController < Projects::ApplicationController
before_action :build, except: [:index, :cancel_all]
before_action :authorize_manage_builds!, except: [:index, :show, :status]
layout "project"
before_action :authorize_read_build!, except: [:cancel, :cancel_all, :retry]
before_action :authorize_update_build!, except: [:index, :show, :status]
layout 'project'
def index
@scope = params[:scope]
@ -23,7 +22,6 @@ class Projects::BuildsController < Projects::ApplicationController
def cancel_all
@project.builds.running_or_pending.each(&:cancel)
redirect_to namespace_project_builds_path(project.namespace, project)
end
@ -46,18 +44,22 @@ class Projects::BuildsController < Projects::ApplicationController
end
build = Ci::Build.retry(@build)
redirect_to build_path(build)
end
def cancel
@build.cancel
redirect_to build_path(@build)
end
def status
render json: @build.to_json(only: [:status, :id, :sha, :coverage], methods: :sha)
end
def cancel
@build.cancel
redirect_to build_path(@build)
def erase
@build.erase(erased_by: current_user)
redirect_to namespace_project_build_path(project.namespace, project, @build),
notice: "Build has been sucessfully erased!"
end
private
@ -69,10 +71,4 @@ class Projects::BuildsController < Projects::ApplicationController
def build_path(build)
namespace_project_build_path(build.project.namespace, build.project, build)
end
def authorize_manage_builds!
unless can?(current_user, :manage_builds, project)
return render_404
end
end
end

View file

@ -2,16 +2,19 @@
#
# Not to be confused with CommitsController, plural.
class Projects::CommitController < Projects::ApplicationController
include CreatesCommit
# Authorize
before_action :require_non_empty_project
before_action :authorize_download_code!, except: [:cancel_builds]
before_action :authorize_manage_builds!, only: [:cancel_builds]
before_action :authorize_download_code!, except: [:cancel_builds, :retry_builds]
before_action :authorize_update_build!, only: [:cancel_builds, :retry_builds]
before_action :authorize_read_commit_status!, only: [:builds]
before_action :commit
before_action :authorize_manage_builds!, only: [:cancel_builds, :retry_builds]
before_action :define_show_vars, only: [:show, :builds]
before_action :authorize_edit_tree!, only: [:revert]
def show
return git_not_found! unless @commit
apply_diff_view_cookie!
@line_notes = commit.notes.inline
@note = @project.build_commit_note(commit)
@ -55,8 +58,37 @@ class Projects::CommitController < Projects::ApplicationController
render layout: false
end
def revert
assign_revert_commit_vars
return render_404 if @target_branch.blank?
create_commit(Commits::RevertService, success_notice: "The #{revert_type_title} has been successfully reverted.",
success_path: successful_revert_path, failure_path: failed_revert_path)
end
private
def revert_type_title
@commit.merged_merge_request ? 'merge request' : 'commit'
end
def successful_revert_path
return referenced_merge_request_url if @commit.merged_merge_request
namespace_project_commits_url(@project.namespace, @project, @target_branch)
end
def failed_revert_path
return referenced_merge_request_url if @commit.merged_merge_request
namespace_project_commit_url(@project.namespace, @project, params[:id])
end
def referenced_merge_request_url
namespace_project_merge_request_url(@project.namespace, @project, @commit.merged_merge_request)
end
def commit
@commit ||= @project.commit(params[:id])
end
@ -66,6 +98,8 @@ class Projects::CommitController < Projects::ApplicationController
end
def define_show_vars
return git_not_found! unless commit
if params[:w].to_i == 1
@diffs = commit.diffs({ ignore_whitespace_change: true })
else
@ -78,9 +112,15 @@ class Projects::CommitController < Projects::ApplicationController
@statuses = ci_commit.statuses if ci_commit
end
def authorize_manage_builds!
unless can?(current_user, :manage_builds, project)
return render_404
end
def assign_revert_commit_vars
@commit = project.commit(params[:id])
@target_branch = params[:target_branch]
@mr_source_branch = @commit.revert_branch_name
@mr_target_branch = @target_branch
@commit_params = {
commit: @commit,
revert_type_title: revert_type_title,
create_merge_request: params[:create_merge_request].present? || different_project?
}
end
end

View file

@ -21,6 +21,9 @@ class Projects::CommitsController < Projects::ApplicationController
@note_counts = project.notes.where(commit_id: @commits.map(&:id)).
group(:commit_id).count
@merge_request = @project.merge_requests.opened.
find_by(source_project: @project, source_branch: @ref, target_branch: @repository.root_ref)
respond_to do |format|
format.html
format.json { pager_json("projects/commits/_commits", @commits.size) }

View file

@ -4,24 +4,23 @@ class Projects::CompareController < Projects::ApplicationController
# Authorize
before_action :require_non_empty_project
before_action :authorize_download_code!
before_action :assign_ref_vars, only: [:index, :show]
before_action :merge_request, only: [:index, :show]
def index
@ref = Addressable::URI.unescape(params[:to])
end
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, diff_options)
execute(@project, @head_ref, @project, @base_ref, diff_options)
if compare_result
@commits = Commit.decorate(compare_result.commits, @project)
@diffs = compare_result.diffs
@commit = @project.commit(head_ref)
@base_commit = @project.merge_base_commit(base_ref, head_ref)
@commit = @project.commit(@head_ref)
@base_commit = @project.merge_base_commit(@base_ref, @head_ref)
@diff_refs = [@base_commit, @commit]
@line_notes = []
end
@ -31,4 +30,16 @@ class Projects::CompareController < Projects::ApplicationController
redirect_to namespace_project_compare_path(@project.namespace, @project,
params[:from], params[:to])
end
private
def assign_ref_vars
@base_ref = Addressable::URI.unescape(params[:from])
@ref = @head_ref = Addressable::URI.unescape(params[:to])
end
def merge_request
@merge_request ||= @project.merge_requests.opened.
find_by(source_project: @project, source_branch: @head_ref, target_branch: @base_ref)
end
end

Some files were not shown because too many files have changed in this diff Show more