Merge branch '8-4-stable' into ci/api-triggers
* 8-4-stable: (280 commits) Add Changelog entry for build traces data integrity fix Update doc_styleguide.md [ci skip] Added hint that you can search users by name, username, or email. Add changelog Version 8.4.0.rc1 Randomize metrics sample intervals Make the metrics sampler interval configurable Don't automatically require awesome_print Disable colorization if STDOUT is not a tty Block the reported user before destroying the record changes `$quote-gray` to `$secondary-text` makes message plural for multiple MRs and removes from loop. Duh. Prepare Installation and Update docs for 8.4 RC1 Mention channel/key bug in irkerd docs Revert "Remove the `:coffee` and `:coffeescript` Haml filters" gets merge request discussion working again adds back in discussion.haml.html for issues commenting and closing/reopening properly. removing last chunk of MR ajax changes, rest will be in another MR reverting more MR ajax files, will appear in different commit reverting MR ajax changes, which will be in a different MR ...
This commit is contained in:
commit
57a67c4fdb
|
@ -26,6 +26,7 @@ config/initializers/smtp_settings.rb
|
|||
config/resque.yml
|
||||
config/unicorn.rb
|
||||
config/secrets.yml
|
||||
config/sidekiq.yml
|
||||
coverage/*
|
||||
db/*.sqlite3
|
||||
db/*.sqlite3-journal
|
||||
|
|
52
CHANGELOG
52
CHANGELOG
|
@ -1,22 +1,67 @@
|
|||
Please view this file on the master branch, on stable branches it's out of date.
|
||||
|
||||
v 8.4.0 (unreleased)
|
||||
- Autocomplete data is now always loaded, instead of when focusing a comment text area (Yorick Peterse)
|
||||
- Improved performance of finding issues for an entire group (Yorick Peterse)
|
||||
- Added custom application performance measuring system powered by InfluxDB (Yorick Peterse)
|
||||
- Bump fog to 1.36.0 (Stan Hu)
|
||||
- Add user's last used IP addresses to admin page (Stan Hu)
|
||||
- Add housekeeping function to project settings page
|
||||
- The default GitLab logo now acts as a loading indicator
|
||||
- Fix caching issue where build status was not updating in project dashboard (Stan Hu)
|
||||
- Accept 2xx status codes for successful Web hook triggers (Stan Hu)
|
||||
- Fix missing date of month in network graph when commits span a month (Stan Hu)
|
||||
- Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu)
|
||||
- Don't notify users twice if they are both project watchers and subscribers (Stan Hu)
|
||||
- Implement new UI for group page
|
||||
- Implement search inside emoji picker
|
||||
- Add API support for looking up a user by username (Stan Hu)
|
||||
- Add project permissions to all project API endpoints (Stan Hu)
|
||||
- Link to milestone in "Milestone changed" system note
|
||||
- Only allow group/project members to mention `@all`
|
||||
- Expose Git's version in the admin area (Trey Davis)
|
||||
- Add "Frequently used" category to emoji picker
|
||||
- Add CAS support (tduehr)
|
||||
- Add link to merge request on build detail page
|
||||
- Fix: Problem with projects ending with .keys (Jose Corcuera)
|
||||
- Revert back upvote and downvote button to the issue and MR pages
|
||||
- Swap position of Assignee and Author selector on Issuables (Zeger-Jan van de Weg)
|
||||
- Add system hook messages for project rename and transfer (Steve Norman)
|
||||
- Fix version check image in Safari
|
||||
- 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
|
||||
- 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
|
||||
- Validate README format before displaying
|
||||
- Enable Microsoft Azure OAuth2 support (Janis Meybohm)
|
||||
- Properly set task-list class on single item task lists
|
||||
- Add file finder feature in tree view (Kyungchul Shin)
|
||||
- Ajax filter by message for commits page
|
||||
- API: Add support for deleting a tag via the API (Robert Schilling)
|
||||
- Allow subsequent validations in CI Linter
|
||||
- Fix Encoding::CompatibilityError bug when markdown content has some complex URL (Jason Lee)
|
||||
|
||||
v 8.3.3 (unreleased)
|
||||
v 8.3.4
|
||||
- Use gitlab-workhorse 0.5.4 (fixes API routing bug)
|
||||
|
||||
v 8.3.3
|
||||
- Preserve CE behavior with JIRA integration by only calling API if URL is set
|
||||
- Fix duplicated branch creation/deletion events when using Web UI (Stan Hu)
|
||||
- Add configurable LDAP server query timeout
|
||||
- Get "Merge when build succeeds" to work when commits were pushed to MR target branch while builds were running
|
||||
- Suppress e-mails on failed builds if allow_failure is set (Stan Hu)
|
||||
- Fix project transfer e-mail sending incorrect paths in e-mail notification (Stan Hu)
|
||||
- Better support for referencing and closing issues in Asana service (Mike Wyatt)
|
||||
- Enable "Add key" button when user fills in a proper key (Stan Hu)
|
||||
- Fix error in processing reply-by-email messages (Jason Lee)
|
||||
- Fix Error 500 when visiting build page of project with nil runners_token (Stan Hu)
|
||||
- Use WOFF versions of SourceSansPro fonts
|
||||
- Fix regression when builds were not generated for tags created through web/api interface
|
||||
- Fix: maintain milestone filter between Open and Closed tabs (Greg Smethells)
|
||||
- Fix missing artifacts and build traces for build created before 8.3
|
||||
|
||||
v 8.3.2
|
||||
- Disable --follow in `git log` to avoid loading duplicate commit data in infinite scroll (Stan Hu)
|
||||
|
@ -27,7 +72,6 @@ v 8.3.1
|
|||
- Fix Error 500 when doing a search in dashboard before visiting any project (Stan Hu)
|
||||
- Fix LDAP identity and user retrieval when special characters are used
|
||||
- Move Sidekiq-cron configuration to gitlab.yml
|
||||
- Enable forcing Two-Factor authentication sitewide, with optional grace period
|
||||
|
||||
v 8.3.0
|
||||
- Bump rack-attack to 4.3.1 for security fix (Stan Hu)
|
||||
|
@ -91,6 +135,8 @@ v 8.3.0
|
|||
- Do not show build status unless builds are enabled and `.gitlab-ci.yml` is present
|
||||
- Persist runners registration token in database
|
||||
- Fix online editor should not remove newlines at the end of the file
|
||||
- Expose Git's version in the admin area
|
||||
- Show "New Merge Request" buttons on canonical repos when you have a fork (Josh Frye)
|
||||
|
||||
v 8.2.3
|
||||
- Fix application settings cache not expiring after changes (Stan Hu)
|
||||
|
@ -149,6 +195,8 @@ v 8.2.0
|
|||
- Allow to define cache in `.gitlab-ci.yml`
|
||||
- Fix: 500 error returned if destroy request without HTTP referer (Kazuki Shimizu)
|
||||
- Remove deprecated CI events from project settings page
|
||||
- Use issue editor as cross reference comment author when issue is edited with a new mention.
|
||||
- Add graphs of commits ahead and behind default branch (Jeff Stubler)
|
||||
- Improve personal snippet access workflow (Douglas Alexandre)
|
||||
- [API] Add ability to fetch the commit ID of the last commit that actually touched a file
|
||||
- Fix omniauth documentation setting for omnibus configuration (Jon Cairns)
|
||||
|
|
|
@ -334,9 +334,9 @@ merge request:
|
|||
1. [CoffeeScript](https://github.com/thoughtbot/guides/tree/master/style/coffeescript)
|
||||
1. [Shell commands](doc/development/shell_commands.md) created by GitLab
|
||||
contributors to enhance security
|
||||
1. [Markdown](http://www.cirosantilli.com/markdown-styleguide)
|
||||
1. [Database Migrations](doc/development/migration_style_guide.md)
|
||||
1. [Documentation styleguide](doc_styleguide.md)
|
||||
1. [Markdown](http://www.cirosantilli.com/markdown-styleguide)
|
||||
1. [Documentation styleguide](doc/development/doc_styleguide.md)
|
||||
1. Interface text should be written subjectively instead of objectively. It
|
||||
should be the GitLab core team addressing a person. It should be written in
|
||||
present time and never use past tense (has been/was). For example instead
|
||||
|
|
|
@ -1 +1 @@
|
|||
2.6.9
|
||||
2.6.10
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.5.1
|
||||
0.5.4
|
||||
|
|
19
Gemfile
19
Gemfile
|
@ -22,6 +22,7 @@ gem 'devise', '~> 3.5.3'
|
|||
gem 'devise-async', '~> 0.9.0'
|
||||
gem 'doorkeeper', '~> 2.2.0'
|
||||
gem 'omniauth', '~> 1.2.2'
|
||||
gem 'omniauth-azure-oauth2', '~> 0.0.6'
|
||||
gem 'omniauth-bitbucket', '~> 0.0.2'
|
||||
gem 'omniauth-cas3', '~> 1.1.2'
|
||||
gem 'omniauth-facebook', '~> 3.0.0'
|
||||
|
@ -32,7 +33,7 @@ gem 'omniauth-kerberos', '~> 0.3.0', group: :kerberos
|
|||
gem 'omniauth-saml', '~> 1.4.0'
|
||||
gem 'omniauth-shibboleth', '~> 1.2.0'
|
||||
gem 'omniauth-twitter', '~> 1.2.0'
|
||||
gem 'omniauth_crowd'
|
||||
gem 'omniauth_crowd', '~> 2.2.0'
|
||||
gem 'rack-oauth2', '~> 1.2.1'
|
||||
|
||||
# reCAPTCHA protection
|
||||
|
@ -48,7 +49,7 @@ gem "browser", '~> 1.0.0'
|
|||
|
||||
# Extracting information from a git repository
|
||||
# Provide access to Gitlab::Git library
|
||||
gem "gitlab_git", '~> 7.2.20'
|
||||
gem "gitlab_git", '~> 7.2.22'
|
||||
|
||||
# LDAP Auth
|
||||
# GitLab fork with several improvements to original library. For full list of changes
|
||||
|
@ -66,10 +67,6 @@ gem 'grape', '~> 0.13.0'
|
|||
gem 'grape-entity', '~> 0.4.2'
|
||||
gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
|
||||
|
||||
# Format dates and times
|
||||
# based on human-friendly examples
|
||||
gem "stamp", '~> 0.6.0'
|
||||
|
||||
# Pagination
|
||||
gem "kaminari", "~> 0.16.3"
|
||||
|
||||
|
@ -83,7 +80,7 @@ gem "carrierwave", '~> 0.9.0'
|
|||
gem 'dropzonejs-rails', '~> 0.7.1'
|
||||
|
||||
# for aws storage
|
||||
gem "fog", "~> 1.25.0"
|
||||
gem "fog", "~> 1.36.0"
|
||||
gem "unf", '~> 0.1.4'
|
||||
|
||||
# Authorization
|
||||
|
@ -169,10 +166,10 @@ gem 'asana', '~> 0.4.0'
|
|||
gem 'ruby-fogbugz', '~> 0.2.1'
|
||||
|
||||
# d3
|
||||
gem 'd3_rails', '~> 3.5.5'
|
||||
gem 'd3_rails', '~> 3.5.0'
|
||||
|
||||
#cal-heatmap
|
||||
gem "cal-heatmap-rails", "~> 0.0.1"
|
||||
gem 'cal-heatmap-rails', '~> 3.5.0'
|
||||
|
||||
# underscore-rails
|
||||
gem "underscore-rails", "~> 1.8.0"
|
||||
|
@ -200,7 +197,7 @@ gem 'turbolinks', '~> 2.5.0'
|
|||
gem 'jquery-turbolinks', '~> 2.1.0'
|
||||
|
||||
gem 'addressable', '~> 2.3.8'
|
||||
gem 'bootstrap-sass', '~> 3.0'
|
||||
gem 'bootstrap-sass', '~> 3.3.0'
|
||||
gem 'font-awesome-rails', '~> 4.2'
|
||||
gem 'gitlab_emoji', '~> 0.2.0'
|
||||
gem 'gon', '~> 6.0.1'
|
||||
|
@ -250,7 +247,7 @@ group :development, :test do
|
|||
gem 'byebug', platform: :mri
|
||||
gem 'pry-rails'
|
||||
|
||||
gem 'awesome_print', '~> 1.2.0'
|
||||
gem 'awesome_print', '~> 1.2.0', require: false
|
||||
gem 'fuubar', '~> 2.0.0'
|
||||
|
||||
gem 'database_cleaner', '~> 1.4.0'
|
||||
|
|
109
Gemfile.lock
109
Gemfile.lock
|
@ -66,7 +66,7 @@ GEM
|
|||
attr_encrypted (1.3.4)
|
||||
encryptor (>= 1.3.0)
|
||||
attr_required (1.0.0)
|
||||
autoprefixer-rails (6.1.2)
|
||||
autoprefixer-rails (6.2.3)
|
||||
execjs
|
||||
json
|
||||
awesome_print (1.2.0)
|
||||
|
@ -82,9 +82,9 @@ GEM
|
|||
erubis (>= 2.6.6)
|
||||
binding_of_caller (0.7.2)
|
||||
debug_inspector (>= 0.0.1)
|
||||
bootstrap-sass (3.3.5)
|
||||
autoprefixer-rails (>= 5.0.0.1)
|
||||
sass (>= 3.2.19)
|
||||
bootstrap-sass (3.3.6)
|
||||
autoprefixer-rails (>= 5.2.1)
|
||||
sass (>= 3.3.4)
|
||||
brakeman (3.1.4)
|
||||
erubis (~> 2.6)
|
||||
fastercsv (~> 1.5)
|
||||
|
@ -106,7 +106,7 @@ GEM
|
|||
bundler (~> 1.2)
|
||||
thor (~> 0.18)
|
||||
byebug (8.2.1)
|
||||
cal-heatmap-rails (0.0.1)
|
||||
cal-heatmap-rails (3.5.1)
|
||||
capybara (2.4.4)
|
||||
mime-types (>= 1.16)
|
||||
nokogiri (>= 1.3.3)
|
||||
|
@ -219,21 +219,45 @@ GEM
|
|||
flowdock (0.7.1)
|
||||
httparty (~> 0.7)
|
||||
multi_json
|
||||
fog (1.25.0)
|
||||
fog (1.36.0)
|
||||
fog-aliyun (>= 0.1.0)
|
||||
fog-atmos
|
||||
fog-aws (>= 0.6.0)
|
||||
fog-brightbox (~> 0.4)
|
||||
fog-core (~> 1.25)
|
||||
fog-core (~> 1.32)
|
||||
fog-dynect (~> 0.0.2)
|
||||
fog-ecloud (~> 0.1)
|
||||
fog-google (<= 0.1.0)
|
||||
fog-json
|
||||
fog-local
|
||||
fog-powerdns (>= 0.1.1)
|
||||
fog-profitbricks
|
||||
fog-radosgw (>= 0.0.2)
|
||||
fog-riakcs
|
||||
fog-sakuracloud (>= 0.0.4)
|
||||
fog-serverlove
|
||||
fog-softlayer
|
||||
fog-storm_on_demand
|
||||
fog-terremark
|
||||
fog-vmfusion
|
||||
fog-voxel
|
||||
fog-xenserver
|
||||
fog-xml (~> 0.1.1)
|
||||
ipaddress (~> 0.5)
|
||||
nokogiri (~> 1.5, >= 1.5.11)
|
||||
opennebula
|
||||
fog-aliyun (0.1.0)
|
||||
fog-core (~> 1.27)
|
||||
fog-json (~> 1.0)
|
||||
ipaddress (~> 0.8)
|
||||
xml-simple (~> 1.1)
|
||||
fog-atmos (0.1.0)
|
||||
fog-core
|
||||
fog-xml
|
||||
fog-aws (0.8.1)
|
||||
fog-core (~> 1.27)
|
||||
fog-json (~> 1.0)
|
||||
fog-xml (~> 0.1)
|
||||
ipaddress (~> 0.8)
|
||||
fog-brightbox (0.10.1)
|
||||
fog-core (~> 1.22)
|
||||
fog-json
|
||||
|
@ -242,21 +266,48 @@ GEM
|
|||
builder
|
||||
excon (~> 0.45)
|
||||
formatador (~> 0.2)
|
||||
fog-dynect (0.0.2)
|
||||
fog-core
|
||||
fog-json
|
||||
fog-xml
|
||||
fog-ecloud (0.3.0)
|
||||
fog-core
|
||||
fog-xml
|
||||
fog-google (0.1.0)
|
||||
fog-core
|
||||
fog-json
|
||||
fog-xml
|
||||
fog-json (1.0.2)
|
||||
fog-core (~> 1.0)
|
||||
multi_json (~> 1.10)
|
||||
fog-local (0.2.1)
|
||||
fog-core (~> 1.27)
|
||||
fog-powerdns (0.1.1)
|
||||
fog-core (~> 1.27)
|
||||
fog-json (~> 1.0)
|
||||
fog-xml (~> 0.1)
|
||||
fog-profitbricks (0.0.5)
|
||||
fog-core
|
||||
fog-xml
|
||||
nokogiri
|
||||
fog-radosgw (0.0.4)
|
||||
fog-radosgw (0.0.5)
|
||||
fog-core (>= 1.21.0)
|
||||
fog-json
|
||||
fog-xml (>= 0.0.1)
|
||||
fog-sakuracloud (1.5.0)
|
||||
fog-riakcs (0.1.0)
|
||||
fog-core
|
||||
fog-json
|
||||
fog-softlayer (1.0.2)
|
||||
fog-xml
|
||||
fog-sakuracloud (1.7.5)
|
||||
fog-core
|
||||
fog-json
|
||||
fog-serverlove (0.1.2)
|
||||
fog-core
|
||||
fog-json
|
||||
fog-softlayer (1.0.3)
|
||||
fog-core
|
||||
fog-json
|
||||
fog-storm_on_demand (0.1.1)
|
||||
fog-core
|
||||
fog-json
|
||||
fog-terremark (0.1.0)
|
||||
|
@ -268,6 +319,9 @@ GEM
|
|||
fog-voxel (0.1.0)
|
||||
fog-core
|
||||
fog-xml
|
||||
fog-xenserver (0.2.2)
|
||||
fog-core
|
||||
fog-xml
|
||||
fog-xml (0.1.2)
|
||||
fog-core
|
||||
nokogiri (~> 1.5, >= 1.5.11)
|
||||
|
@ -377,7 +431,7 @@ GEM
|
|||
influxdb (0.2.3)
|
||||
cause
|
||||
json
|
||||
ipaddress (0.8.0)
|
||||
ipaddress (0.8.2)
|
||||
jquery-atwho-rails (1.3.2)
|
||||
jquery-rails (4.0.5)
|
||||
rails-dom-testing (~> 1.0)
|
||||
|
@ -443,6 +497,10 @@ GEM
|
|||
omniauth (1.2.2)
|
||||
hashie (>= 1.2, < 4)
|
||||
rack (~> 1.0)
|
||||
omniauth-azure-oauth2 (0.0.6)
|
||||
jwt (~> 1.0)
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth2 (~> 1.1)
|
||||
omniauth-bitbucket (0.0.2)
|
||||
multi_json (~> 1.7)
|
||||
omniauth (~> 1.1)
|
||||
|
@ -488,10 +546,6 @@ GEM
|
|||
activesupport
|
||||
nokogiri (>= 1.4.4)
|
||||
omniauth (~> 1.0)
|
||||
opennebula (4.14.2)
|
||||
json
|
||||
nokogiri
|
||||
rbvmomi
|
||||
org-ruby (0.9.12)
|
||||
rubypants (~> 0.2)
|
||||
orm_adapter (0.5.0)
|
||||
|
@ -567,10 +621,6 @@ GEM
|
|||
ffi (>= 0.5.0)
|
||||
rblineprof (0.3.6)
|
||||
debugger-ruby_core_source (~> 1.3)
|
||||
rbvmomi (1.8.2)
|
||||
builder
|
||||
nokogiri (>= 1.4.1)
|
||||
trollop
|
||||
rdoc (3.12.2)
|
||||
json (~> 1.4)
|
||||
recaptcha (1.0.2)
|
||||
|
@ -730,7 +780,6 @@ GEM
|
|||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
sprockets (>= 2.8, < 4.0)
|
||||
stamp (0.6.0)
|
||||
state_machines (0.4.0)
|
||||
state_machines-activemodel (0.3.0)
|
||||
activemodel (~> 4.1)
|
||||
|
@ -770,7 +819,6 @@ GEM
|
|||
multi_json (~> 1.7)
|
||||
twitter-stream (~> 0.1)
|
||||
tins (1.6.0)
|
||||
trollop (2.1.2)
|
||||
turbolinks (2.5.3)
|
||||
coffee-rails
|
||||
twitter-stream (0.1.16)
|
||||
|
@ -819,6 +867,7 @@ GEM
|
|||
builder
|
||||
expression_parser
|
||||
rinku
|
||||
xml-simple (1.1.5)
|
||||
xpath (2.0.0)
|
||||
nokogiri (~> 1.3)
|
||||
|
||||
|
@ -843,13 +892,13 @@ DEPENDENCIES
|
|||
benchmark-ips
|
||||
better_errors (~> 1.0.1)
|
||||
binding_of_caller (~> 0.7.2)
|
||||
bootstrap-sass (~> 3.0)
|
||||
bootstrap-sass (~> 3.3.0)
|
||||
brakeman (~> 3.1.0)
|
||||
browser (~> 1.0.0)
|
||||
bullet
|
||||
bundler-audit
|
||||
byebug
|
||||
cal-heatmap-rails (~> 0.0.1)
|
||||
cal-heatmap-rails (~> 3.5.0)
|
||||
capybara (~> 2.4.0)
|
||||
capybara-screenshot (~> 1.0.0)
|
||||
carrierwave (~> 0.9.0)
|
||||
|
@ -859,7 +908,7 @@ DEPENDENCIES
|
|||
connection_pool (~> 2.0)
|
||||
coveralls (~> 0.8.2)
|
||||
creole (~> 0.5.0)
|
||||
d3_rails (~> 3.5.5)
|
||||
d3_rails (~> 3.5.0)
|
||||
database_cleaner (~> 1.4.0)
|
||||
default_value_for (~> 3.0.0)
|
||||
devise (~> 3.5.3)
|
||||
|
@ -874,7 +923,7 @@ DEPENDENCIES
|
|||
ffaker (~> 2.0.0)
|
||||
flay
|
||||
flog
|
||||
fog (~> 1.25.0)
|
||||
fog (~> 1.36.0)
|
||||
font-awesome-rails (~> 4.2)
|
||||
foreman
|
||||
fuubar (~> 2.0.0)
|
||||
|
@ -883,7 +932,7 @@ DEPENDENCIES
|
|||
github-markup (~> 1.3.1)
|
||||
gitlab-flowdock-git-hook (~> 1.0.1)
|
||||
gitlab_emoji (~> 0.2.0)
|
||||
gitlab_git (~> 7.2.20)
|
||||
gitlab_git (~> 7.2.22)
|
||||
gitlab_meta (= 7.0)
|
||||
gitlab_omniauth-ldap (~> 1.2.1)
|
||||
gollum-lib (~> 4.1.0)
|
||||
|
@ -916,6 +965,7 @@ DEPENDENCIES
|
|||
oauth2 (~> 1.0.0)
|
||||
octokit (~> 3.7.0)
|
||||
omniauth (~> 1.2.2)
|
||||
omniauth-azure-oauth2 (~> 0.0.6)
|
||||
omniauth-bitbucket (~> 0.0.2)
|
||||
omniauth-cas3 (~> 1.1.2)
|
||||
omniauth-facebook (~> 3.0.0)
|
||||
|
@ -926,7 +976,7 @@ DEPENDENCIES
|
|||
omniauth-saml (~> 1.4.0)
|
||||
omniauth-shibboleth (~> 1.2.0)
|
||||
omniauth-twitter (~> 1.2.0)
|
||||
omniauth_crowd
|
||||
omniauth_crowd (~> 2.2.0)
|
||||
org-ruby (~> 0.9.12)
|
||||
paranoia (~> 2.0)
|
||||
pg (~> 0.18.2)
|
||||
|
@ -973,7 +1023,6 @@ DEPENDENCIES
|
|||
spring-commands-spinach (~> 1.0.0)
|
||||
spring-commands-teaspoon (~> 0.0.2)
|
||||
sprockets (~> 2.12.3)
|
||||
stamp (~> 0.6.0)
|
||||
state_machines-activerecord (~> 0.3.0)
|
||||
task_list (~> 1.0.2)
|
||||
teaspoon (~> 1.0.0)
|
||||
|
@ -994,4 +1043,4 @@ DEPENDENCIES
|
|||
wikicloth (= 0.8.1)
|
||||
|
||||
BUNDLED WITH
|
||||
1.10.6
|
||||
1.11.2
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
|
||||
Copyright 2010, 2012, 2014 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 986 B |
|
@ -10,12 +10,12 @@
|
|||
#= require jquery.cookie
|
||||
#= require jquery.endless-scroll
|
||||
#= require jquery.highlight
|
||||
#= require jquery.history
|
||||
#= require jquery.waitforimages
|
||||
#= require jquery.atwho
|
||||
#= require jquery.scrollTo
|
||||
#= require jquery.blockUI
|
||||
#= require jquery.turbolinks
|
||||
#= require d3
|
||||
#= require cal-heatmap
|
||||
#= require turbolinks
|
||||
#= require autosave
|
||||
#= require bootstrap
|
||||
|
@ -27,7 +27,6 @@
|
|||
#= require branch-graph
|
||||
#= require ace/ace
|
||||
#= require ace/ext-searchbox
|
||||
#= require d3
|
||||
#= require underscore
|
||||
#= require nprogress
|
||||
#= require nprogress-turbolinks
|
||||
|
@ -39,9 +38,9 @@
|
|||
#= require shortcuts_dashboard_navigation
|
||||
#= require shortcuts_issuable
|
||||
#= require shortcuts_network
|
||||
#= require cal-heatmap
|
||||
#= require jquery.nicescroll.min
|
||||
#= require_tree .
|
||||
#= require fuzzaldrin-plus.min
|
||||
|
||||
window.slugify = (text) ->
|
||||
text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase()
|
||||
|
|
|
@ -66,7 +66,7 @@ class @BranchGraph
|
|||
r.rect(40, 0, 30, @barHeight).attr fill: "#444"
|
||||
|
||||
for day, mm in @days
|
||||
if cuday isnt day[0]
|
||||
if cuday isnt day[0] || cumonth isnt day[1]
|
||||
# Dates
|
||||
r.text(55, @offsetY + @unitTime * mm, day[0])
|
||||
.attr(
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
class @Calendar
|
||||
options =
|
||||
month: "short"
|
||||
day: "numeric"
|
||||
year: "numeric"
|
||||
|
||||
constructor: (timestamps, starting_year, starting_month, calendar_activities_path) ->
|
||||
cal = new CalHeatMap()
|
||||
cal.init
|
||||
|
|
|
@ -1,15 +1,5 @@
|
|||
class @CommitsList
|
||||
@data =
|
||||
ref: null
|
||||
limit: 0
|
||||
offset: 0
|
||||
@disable = false
|
||||
|
||||
@showProgress: ->
|
||||
$('.loading').show()
|
||||
|
||||
@hideProgress: ->
|
||||
$('.loading').hide()
|
||||
@timer = null
|
||||
|
||||
@init: (ref, limit) ->
|
||||
$("body").on "click", ".day-commits-table li.commit", (event) ->
|
||||
|
@ -18,38 +8,32 @@ class @CommitsList
|
|||
e.stopPropagation()
|
||||
return false
|
||||
|
||||
@data.ref = ref
|
||||
@data.limit = limit
|
||||
@data.offset = limit
|
||||
Pager.init limit, false
|
||||
|
||||
this.initLoadMore()
|
||||
this.showProgress()
|
||||
@content = $("#commits-list")
|
||||
@searchField = $("#commits-search")
|
||||
@initSearch()
|
||||
|
||||
@initSearch: ->
|
||||
@timer = null
|
||||
@searchField.keyup =>
|
||||
clearTimeout(@timer)
|
||||
@timer = setTimeout(@filterResults, 500)
|
||||
|
||||
@filterResults: =>
|
||||
form = $(".commits-search-form")
|
||||
search = @searchField.val()
|
||||
commitsUrl = form.attr("action") + '?' + form.serialize()
|
||||
@content.fadeTo('fast', 0.5)
|
||||
|
||||
@getOld: ->
|
||||
this.showProgress()
|
||||
$.ajax
|
||||
type: "GET"
|
||||
url: location.href
|
||||
data: @data
|
||||
complete: this.hideProgress
|
||||
success: (data) ->
|
||||
CommitsList.append(data.count, data.html)
|
||||
url: form.attr("action")
|
||||
data: form.serialize()
|
||||
complete: =>
|
||||
@content.fadeTo('fast', 1.0)
|
||||
success: (data) =>
|
||||
@content.html(data.html)
|
||||
# Change url so if user reload a page - search results are saved
|
||||
history.replaceState {page: commitsUrl}, document.title, commitsUrl
|
||||
dataType: "json"
|
||||
|
||||
@append: (count, html) ->
|
||||
$("#commits-list").append(html)
|
||||
if count > 0
|
||||
@data.offset += count
|
||||
else
|
||||
@disable = true
|
||||
|
||||
@initLoadMore: ->
|
||||
$(document).unbind('scroll')
|
||||
$(document).endlessScroll
|
||||
bottomPixels: 400
|
||||
fireDelay: 1000
|
||||
fireOnce: true
|
||||
ceaseFire: =>
|
||||
@disable
|
||||
callback: =>
|
||||
this.getOld()
|
||||
|
|
|
@ -87,7 +87,9 @@ class Dispatcher
|
|||
new GroupAvatar()
|
||||
when 'projects:tree:show'
|
||||
new TreeView()
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
shortcut_handler = new ShortcutsTree()
|
||||
when 'projects:find_file:show'
|
||||
shortcut_handler = true
|
||||
when 'projects:blob:show'
|
||||
new LineHighlighter()
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
|
|
|
@ -66,7 +66,7 @@ class @DropzoneInput
|
|||
|
||||
success: (header, response) ->
|
||||
child = $(dropzone[0]).children("textarea")
|
||||
$(child).val $(child).val() + formatLink(response.link) + "\n"
|
||||
$(child).val $(child).val() + response.link.markdown + "\n"
|
||||
return
|
||||
|
||||
error: (temp, errorMessage) ->
|
||||
|
@ -99,11 +99,6 @@ class @DropzoneInput
|
|||
|
||||
child = $(dropzone[0]).children("textarea")
|
||||
|
||||
formatLink = (link) ->
|
||||
text = "[#{link.alt}](#{link.url})"
|
||||
text = "!#{text}" if link.is_image
|
||||
text
|
||||
|
||||
handlePaste = (event) ->
|
||||
pasteEvent = event.originalEvent
|
||||
if pasteEvent.clipboardData and pasteEvent.clipboardData.items
|
||||
|
@ -162,7 +157,7 @@ class @DropzoneInput
|
|||
closeAlertMessage()
|
||||
|
||||
success: (e, textStatus, response) ->
|
||||
insertToTextArea(filename, formatLink(response.responseJSON.link))
|
||||
insertToTextArea(filename, response.responseJSON.link.markdown)
|
||||
|
||||
error: (response) ->
|
||||
showError(response.responseJSON.message)
|
||||
|
@ -202,8 +197,3 @@ class @DropzoneInput
|
|||
e.preventDefault()
|
||||
$(@).closest('.gfm-form').find('.div-dropzone').click()
|
||||
return
|
||||
|
||||
formatLink: (link) ->
|
||||
text = "[#{link.alt}](#{link.url})"
|
||||
text = "!#{text}" if link.is_image
|
||||
text
|
||||
|
|
|
@ -34,7 +34,7 @@ GitLab.GfmAutoComplete =
|
|||
searchKey: 'search'
|
||||
callbacks:
|
||||
beforeSave: (members) ->
|
||||
$.map members, (m) ->
|
||||
$.map members, (m) ->
|
||||
title = m.name
|
||||
title += " (#{m.count})" if m.count
|
||||
|
||||
|
@ -50,7 +50,7 @@ GitLab.GfmAutoComplete =
|
|||
insertTpl: '${atwho-at}${id}'
|
||||
callbacks:
|
||||
beforeSave: (issues) ->
|
||||
$.map issues, (i) ->
|
||||
$.map issues, (i) ->
|
||||
id: i.iid
|
||||
title: sanitize(i.title)
|
||||
search: "#{i.iid} #{i.title}"
|
||||
|
@ -63,12 +63,12 @@ GitLab.GfmAutoComplete =
|
|||
insertTpl: '${atwho-at}${id}'
|
||||
callbacks:
|
||||
beforeSave: (merges) ->
|
||||
$.map merges, (m) ->
|
||||
$.map merges, (m) ->
|
||||
id: m.iid
|
||||
title: sanitize(m.title)
|
||||
search: "#{m.iid} #{m.title}"
|
||||
|
||||
input.one 'focus', =>
|
||||
if @dataSource
|
||||
$.getJSON(@dataSource).done (data) ->
|
||||
# load members
|
||||
input.atwho 'load', '@', data.members
|
||||
|
|
|
@ -16,12 +16,16 @@ class @Issue
|
|||
$(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList
|
||||
|
||||
initIssueBtnEventListeners: ->
|
||||
_this = @
|
||||
issueFailMessage = 'Unable to update this issue at this time.'
|
||||
$('a.btn-close, a.btn-reopen').on 'click', (e) ->
|
||||
e.preventDefault()
|
||||
e.stopImmediatePropagation()
|
||||
$this = $(this)
|
||||
isClose = $this.hasClass('btn-close')
|
||||
shouldSubmit = $this.hasClass('btn-comment')
|
||||
if shouldSubmit
|
||||
_this.submitNoteForm($this.closest('form'))
|
||||
$this.prop('disabled', true)
|
||||
url = $this.attr('href')
|
||||
$.ajax
|
||||
|
@ -32,12 +36,13 @@ class @Issue
|
|||
new Flash(issueFailMessage, 'alert')
|
||||
success: (data, textStatus, jqXHR) ->
|
||||
if data.saved
|
||||
$this.addClass('hidden')
|
||||
if isClose
|
||||
$('a.btn-close').addClass('hidden')
|
||||
$('a.btn-reopen').removeClass('hidden')
|
||||
$('div.status-box-closed').removeClass('hidden')
|
||||
$('div.status-box-open').addClass('hidden')
|
||||
else
|
||||
$('a.btn-reopen').addClass('hidden')
|
||||
$('a.btn-close').removeClass('hidden')
|
||||
$('div.status-box-closed').addClass('hidden')
|
||||
$('div.status-box-open').removeClass('hidden')
|
||||
|
@ -45,6 +50,11 @@ class @Issue
|
|||
new Flash(issueFailMessage, 'alert')
|
||||
$this.prop('disabled', false)
|
||||
|
||||
submitNoteForm: (form) =>
|
||||
noteText = form.find("textarea.js-note-text").val()
|
||||
if noteText.trim().length > 0
|
||||
form.submit()
|
||||
|
||||
disableTaskList: ->
|
||||
$('.detail-page-description .js-task-list-container').taskList('disable')
|
||||
$(document).off 'tasklist:changed', '.detail-page-description .js-task-list-container'
|
||||
|
|
|
@ -15,13 +15,6 @@
|
|||
$(this).html totalIssues + 1
|
||||
else
|
||||
$(this).html totalIssues - 1
|
||||
$("body").on "click", ".issues-other-filters .dropdown-menu a", ->
|
||||
$('.issues-list').block(
|
||||
message: null,
|
||||
overlayCSS:
|
||||
backgroundColor: '#DDD'
|
||||
opacity: .4
|
||||
)
|
||||
|
||||
reload: ->
|
||||
Issues.initSelects()
|
||||
|
@ -54,7 +47,7 @@
|
|||
form = $("#issue_search_form")
|
||||
search = $("#issue_search").val()
|
||||
$('.issues-holder').css("opacity", '0.5')
|
||||
issues_url = form.attr('action') + '? '+ form.serialize()
|
||||
issues_url = form.attr('action') + '?' + form.serialize()
|
||||
|
||||
$.ajax
|
||||
type: "GET"
|
||||
|
@ -65,7 +58,7 @@
|
|||
success: (data) ->
|
||||
$('.issues-holder').html(data.html)
|
||||
# Change url so if user reload a page - search results are saved
|
||||
History.replaceState {page: issues_url}, document.title, issues_url
|
||||
history.replaceState {page: issues_url}, document.title, issues_url
|
||||
Issues.reload()
|
||||
dataType: "json"
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
NProgress.configure(showSpinner: false)
|
||||
|
||||
defaultClass = 'tanuki-shape'
|
||||
pieces = [
|
||||
'path#tanuki-right-cheek',
|
||||
'path#tanuki-right-eye, path#tanuki-right-ear',
|
||||
'path#tanuki-nose',
|
||||
'path#tanuki-left-eye, path#tanuki-left-ear',
|
||||
'path#tanuki-left-cheek',
|
||||
]
|
||||
pieceIndex = 0
|
||||
firstPiece = pieces[0]
|
||||
|
||||
currentTimer = null
|
||||
delay = 150
|
||||
|
||||
clearHighlights = ->
|
||||
$(".#{defaultClass}.highlight").attr('class', defaultClass)
|
||||
|
||||
start = ->
|
||||
clearHighlights()
|
||||
pieceIndex = 0
|
||||
pieces.reverse() unless pieces[0] == firstPiece
|
||||
clearInterval(currentTimer) if currentTimer
|
||||
currentTimer = setInterval(work, delay)
|
||||
|
||||
stop = ->
|
||||
clearInterval(currentTimer)
|
||||
clearHighlights()
|
||||
|
||||
work = ->
|
||||
clearHighlights()
|
||||
$(pieces[pieceIndex]).attr('class', "#{defaultClass} highlight")
|
||||
|
||||
# If we hit the last piece, reset the index and then reverse the array to
|
||||
# get a nice back-and-forth sweeping look
|
||||
if pieceIndex == pieces.length - 1
|
||||
pieceIndex = 0
|
||||
pieces.reverse()
|
||||
else
|
||||
pieceIndex++
|
||||
|
||||
$(document).on('page:fetch', start)
|
||||
$(document).on('page:change', stop)
|
|
@ -19,6 +19,7 @@ class @MergeRequest
|
|||
|
||||
# Prevent duplicate event bindings
|
||||
@disableTaskList()
|
||||
@initMRBtnListeners()
|
||||
|
||||
if $("a.btn-close").length
|
||||
@initTaskList()
|
||||
|
@ -43,6 +44,27 @@ class @MergeRequest
|
|||
$('.detail-page-description .js-task-list-container').taskList('enable')
|
||||
$(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList
|
||||
|
||||
initMRBtnListeners: ->
|
||||
_this = @
|
||||
$('a.btn-close, a.btn-reopen').on 'click', (e) ->
|
||||
$this = $(this)
|
||||
if $this.data('submitted')
|
||||
return
|
||||
e.preventDefault()
|
||||
e.stopImmediatePropagation()
|
||||
shouldSubmit = $this.hasClass('btn-comment')
|
||||
console.log("shouldSubmit")
|
||||
if shouldSubmit
|
||||
_this.submitNoteForm($this.closest('form'),$this)
|
||||
|
||||
submitNoteForm: (form, $button) =>
|
||||
noteText = form.find("textarea.js-note-text").val()
|
||||
if noteText.trim().length > 0
|
||||
form.submit()
|
||||
$button.data('submitted',true)
|
||||
$button.trigger('click')
|
||||
|
||||
|
||||
disableTaskList: ->
|
||||
$('.detail-page-description .js-task-list-container').taskList('disable')
|
||||
$(document).off 'tasklist:changed', '.detail-page-description .js-task-list-container'
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
form = $("#issue_search_form")
|
||||
search = $("#issue_search").val()
|
||||
$('.merge-requests-holder').css("opacity", '0.5')
|
||||
issues_url = form.attr('action') + '? '+ form.serialize()
|
||||
issues_url = form.attr('action') + '?' + form.serialize()
|
||||
|
||||
$.ajax
|
||||
type: "GET"
|
||||
|
@ -27,7 +27,7 @@
|
|||
success: (data) ->
|
||||
$('.merge-requests-holder').html(data.html)
|
||||
# Change url so if user reload a page - search results are saved
|
||||
History.replaceState {page: issues_url}, document.title, issues_url
|
||||
history.replaceState {page: issues_url}, document.title, issues_url
|
||||
MergeRequests.reload()
|
||||
dataType: "json"
|
||||
|
||||
|
|
|
@ -33,8 +33,6 @@ class @Notes
|
|||
$(document).on "click", ".note-edit-cancel", @cancelEdit
|
||||
|
||||
# Reopen and close actions for Issue/MR combined with note form submit
|
||||
$(document).on "click", ".js-note-target-reopen", @targetReopen
|
||||
$(document).on "click", ".js-note-target-close", @targetClose
|
||||
$(document).on "click", ".js-comment-button", @updateCloseButton
|
||||
$(document).on "keyup", ".js-note-text", @updateTargetButtons
|
||||
|
||||
|
@ -512,17 +510,6 @@ class @Notes
|
|||
visibilityChange: =>
|
||||
@refresh()
|
||||
|
||||
targetReopen: (e) =>
|
||||
@submitNoteForm($(e.target).parents('form'))
|
||||
|
||||
targetClose: (e) =>
|
||||
@submitNoteForm($(e.target).parents('form'))
|
||||
|
||||
submitNoteForm: (form) =>
|
||||
noteText = form.find(".js-note-text").val()
|
||||
if noteText.trim().length > 0
|
||||
form.submit()
|
||||
|
||||
updateCloseButton: (e) =>
|
||||
textarea = $(e.target)
|
||||
form = textarea.parents('form')
|
||||
|
@ -531,7 +518,6 @@ class @Notes
|
|||
updateTargetButtons: (e) =>
|
||||
textarea = $(e.target)
|
||||
form = textarea.parents('form')
|
||||
|
||||
if textarea.val().trim().length > 0
|
||||
form.find('.js-note-target-reopen').text('Comment & reopen')
|
||||
form.find('.js-note-target-close').text('Comment & close')
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
class @ProjectFindFile
|
||||
constructor: (@element, @options)->
|
||||
@filePaths = {}
|
||||
@inputElement = @element.find(".file-finder-input")
|
||||
|
||||
# init event
|
||||
@initEvent()
|
||||
|
||||
# focus text input box
|
||||
@inputElement.focus()
|
||||
|
||||
# load file list
|
||||
@load(@options.url)
|
||||
|
||||
# init event
|
||||
initEvent: ->
|
||||
@inputElement.off "keyup"
|
||||
@inputElement.on "keyup", (event) =>
|
||||
target = $(event.target)
|
||||
value = target.val()
|
||||
oldValue = target.data("oldValue") ? ""
|
||||
|
||||
if value != oldValue
|
||||
target.data("oldValue", value)
|
||||
@findFile()
|
||||
@element.find("tr.tree-item").eq(0).addClass("selected").focus()
|
||||
|
||||
@element.find(".tree-content-holder .tree-table").on "click", (event) ->
|
||||
if (event.target.nodeName != "A")
|
||||
path = @element.find(".tree-item-file-name a", this).attr("href")
|
||||
location.href = path if path
|
||||
|
||||
# find file
|
||||
findFile: ->
|
||||
searchText = @inputElement.val()
|
||||
result = if searchText.length > 0 then fuzzaldrinPlus.filter(@filePaths, searchText) else @filePaths
|
||||
@renderList result, searchText
|
||||
|
||||
# files pathes load
|
||||
load: (url) ->
|
||||
$.ajax
|
||||
url: url
|
||||
method: "get"
|
||||
dataType: "json"
|
||||
success: (data) =>
|
||||
@element.find(".loading").hide()
|
||||
@filePaths = data
|
||||
@findFile()
|
||||
@element.find(".files-slider tr.tree-item").eq(0).addClass("selected").focus()
|
||||
|
||||
# render result
|
||||
renderList: (filePaths, searchText) ->
|
||||
@element.find(".tree-table > tbody").empty()
|
||||
|
||||
for filePath, i in filePaths
|
||||
break if i == 20
|
||||
|
||||
if searchText
|
||||
matches = fuzzaldrinPlus.match(filePath, searchText)
|
||||
|
||||
blobItemUrl = "#{@options.blobUrlTemplate}/#{filePath}"
|
||||
|
||||
html = @makeHtml filePath, matches, blobItemUrl
|
||||
@element.find(".tree-table > tbody").append(html)
|
||||
|
||||
# highlight text(awefwbwgtc -> <b>a</b>wefw<b>b</b>wgt<b>c</b> )
|
||||
highlighter = (element, text, matches) ->
|
||||
lastIndex = 0
|
||||
highlightText = ""
|
||||
matchedChars = []
|
||||
|
||||
for matchIndex in matches
|
||||
unmatched = text.substring(lastIndex, matchIndex)
|
||||
|
||||
if unmatched
|
||||
element.append(matchedChars.join("").bold()) if matchedChars.length
|
||||
matchedChars = []
|
||||
element.append(document.createTextNode(unmatched))
|
||||
|
||||
matchedChars.push(text[matchIndex])
|
||||
lastIndex = matchIndex + 1
|
||||
|
||||
element.append(matchedChars.join("").bold()) if matchedChars.length
|
||||
element.append(document.createTextNode(text.substring(lastIndex)))
|
||||
|
||||
# make tbody row html
|
||||
makeHtml: (filePath, matches, blobItemUrl) ->
|
||||
$tr = $("<tr class='tree-item'><td class='tree-item-file-name'><i class='fa fa-file-text-o fa-fw'></i><span class='str-truncated'><a></a></span></td></tr>")
|
||||
if matches
|
||||
$tr.find("a").replaceWith(highlighter($tr.find("a"), filePath, matches).attr("href", blobItemUrl))
|
||||
else
|
||||
$tr.find("a").attr("href", blobItemUrl).text(filePath)
|
||||
|
||||
return $tr
|
||||
|
||||
selectRow: (type) ->
|
||||
rows = @element.find(".files-slider tr.tree-item")
|
||||
selectedRow = @element.find(".files-slider tr.tree-item.selected")
|
||||
|
||||
if rows && rows.length > 0
|
||||
if selectedRow && selectedRow.length > 0
|
||||
if type == "UP"
|
||||
next = selectedRow.prev()
|
||||
else if type == "DOWN"
|
||||
next = selectedRow.next()
|
||||
|
||||
if next.length > 0
|
||||
selectedRow.removeClass "selected"
|
||||
selectedRow = next
|
||||
else
|
||||
selectedRow = rows.eq(0)
|
||||
selectedRow.addClass("selected").focus()
|
||||
|
||||
selectRowUp: =>
|
||||
@selectRow "UP"
|
||||
|
||||
selectRowDown: =>
|
||||
@selectRow "DOWN"
|
||||
|
||||
goToTree: =>
|
||||
location.href = @options.treeUrl
|
||||
|
||||
goToBlob: =>
|
||||
path = @element.find(".tree-item.selected .tree-item-file-name a").attr("href")
|
||||
location.href = path if path
|
|
@ -0,0 +1,19 @@
|
|||
#= require shortcuts_navigation
|
||||
|
||||
class @ShortcutsFindFile extends ShortcutsNavigation
|
||||
constructor: (@projectFindFile) ->
|
||||
super()
|
||||
_oldStopCallback = Mousetrap.stopCallback
|
||||
# override to fire shortcuts action when focus in textbox
|
||||
Mousetrap.stopCallback = (event, element, combo) =>
|
||||
if element == @projectFindFile.inputElement[0] and (combo == 'up' or combo == 'down' or combo == 'esc' or combo == 'enter')
|
||||
# when press up/down key in textbox, cusor prevent to move to home/end
|
||||
event.preventDefault()
|
||||
return false
|
||||
|
||||
return _oldStopCallback(event, element, combo)
|
||||
|
||||
Mousetrap.bind('up', @projectFindFile.selectRowUp)
|
||||
Mousetrap.bind('down', @projectFindFile.selectRowDown)
|
||||
Mousetrap.bind('esc', @projectFindFile.goToTree)
|
||||
Mousetrap.bind('enter', @projectFindFile.goToBlob)
|
|
@ -0,0 +1,4 @@
|
|||
class @ShortcutsTree extends ShortcutsNavigation
|
||||
constructor: ->
|
||||
super()
|
||||
Mousetrap.bind('t', -> ShortcutsTree.findAndFollowLink('.shortcuts-find-file'))
|
|
@ -1,56 +1,80 @@
|
|||
# Zen Mode (full screen) textarea
|
||||
#
|
||||
#= provides zen_mode:enter
|
||||
#= provides zen_mode:leave
|
||||
#
|
||||
#= require jquery.scrollTo
|
||||
#= require dropzone
|
||||
#= require mousetrap
|
||||
#= require mousetrap/pause
|
||||
|
||||
#
|
||||
# ### Events
|
||||
#
|
||||
# `zen_mode:enter`
|
||||
#
|
||||
# Fired when the "Edit in fullscreen" link is clicked.
|
||||
#
|
||||
# **Synchronicity** Sync
|
||||
# **Bubbles** Yes
|
||||
# **Cancelable** No
|
||||
# **Target** a.js-zen-enter
|
||||
#
|
||||
# `zen_mode:leave`
|
||||
#
|
||||
# Fired when the "Leave Fullscreen" link is clicked.
|
||||
#
|
||||
# **Synchronicity** Sync
|
||||
# **Bubbles** Yes
|
||||
# **Cancelable** No
|
||||
# **Target** a.js-zen-leave
|
||||
#
|
||||
class @ZenMode
|
||||
constructor: ->
|
||||
@active_zen_area = null
|
||||
@active_checkbox = null
|
||||
@scroll_position = 0
|
||||
@active_backdrop = null
|
||||
@active_textarea = null
|
||||
|
||||
$(window).scroll =>
|
||||
if not @active_checkbox
|
||||
@scroll_position = window.pageYOffset
|
||||
|
||||
$('body').on 'click', '.zen-enter-link', (e) =>
|
||||
$(document).on 'click', '.js-zen-enter', (e) ->
|
||||
e.preventDefault()
|
||||
$(e.currentTarget).closest('.zennable').find('.zen-toggle-comment').prop('checked', true).change()
|
||||
$(e.currentTarget).trigger('zen_mode:enter')
|
||||
|
||||
$('body').on 'click', '.zen-leave-link', (e) =>
|
||||
$(document).on 'click', '.js-zen-leave', (e) ->
|
||||
e.preventDefault()
|
||||
$(e.currentTarget).closest('.zennable').find('.zen-toggle-comment').prop('checked', false).change()
|
||||
$(e.currentTarget).trigger('zen_mode:leave')
|
||||
|
||||
$('body').on 'change', '.zen-toggle-comment', (e) =>
|
||||
checkbox = e.currentTarget
|
||||
if checkbox.checked
|
||||
# Disable other keyboard shortcuts in ZEN mode
|
||||
Mousetrap.pause()
|
||||
@updateActiveZenArea(checkbox)
|
||||
else
|
||||
@exitZenMode()
|
||||
$(document).on 'zen_mode:enter', (e) =>
|
||||
@enter(e.target.parentNode)
|
||||
$(document).on 'zen_mode:leave', (e) =>
|
||||
@exit()
|
||||
|
||||
$(document).on 'keydown', (e) =>
|
||||
if e.keyCode is 27 # Esc
|
||||
@exitZenMode()
|
||||
$(document).on 'keydown', (e) ->
|
||||
if e.keyCode == 27 # Esc
|
||||
e.preventDefault()
|
||||
$(document).trigger('zen_mode:leave')
|
||||
|
||||
enter: (backdrop) ->
|
||||
Mousetrap.pause()
|
||||
|
||||
@active_backdrop = $(backdrop)
|
||||
@active_backdrop.addClass('fullscreen')
|
||||
|
||||
@active_textarea = @active_backdrop.find('textarea')
|
||||
|
||||
updateActiveZenArea: (checkbox) =>
|
||||
@active_checkbox = $(checkbox)
|
||||
@active_checkbox.prop('checked', true)
|
||||
@active_zen_area = @active_checkbox.parent().find('textarea')
|
||||
# Prevent a user-resized textarea from persisting to fullscreen
|
||||
@active_zen_area.removeAttr('style')
|
||||
@active_zen_area.focus()
|
||||
@active_textarea.removeAttr('style')
|
||||
@active_textarea.focus()
|
||||
|
||||
exitZenMode: =>
|
||||
if @active_zen_area isnt null
|
||||
exit: ->
|
||||
if @active_textarea
|
||||
Mousetrap.unpause()
|
||||
@active_checkbox.prop('checked', false)
|
||||
@active_zen_area = null
|
||||
@active_checkbox = null
|
||||
@restoreScroll(@scroll_position)
|
||||
# Enable dropzone when leaving ZEN mode
|
||||
|
||||
@active_textarea.closest('.zen-backdrop').removeClass('fullscreen')
|
||||
|
||||
@scrollTo(@active_textarea)
|
||||
|
||||
@active_textarea = null
|
||||
@active_backdrop = null
|
||||
|
||||
Dropzone.forElement('.div-dropzone').enable()
|
||||
|
||||
restoreScroll: (y) ->
|
||||
window.scrollTo(window.pageXOffset, y)
|
||||
scrollTo: (zen_area) ->
|
||||
$.scrollTo(zen_area, 0, offset: -150)
|
||||
|
|
|
@ -72,6 +72,15 @@
|
|||
> p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.block-controls {
|
||||
float: right;
|
||||
|
||||
.control {
|
||||
float: left;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cover-block {
|
||||
|
|
|
@ -19,38 +19,33 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This overwrites the default values of the cal-heatmap gem
|
||||
*/
|
||||
.calendar {
|
||||
.qi {
|
||||
background-color: #999;
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
.q1 {
|
||||
background-color: #dae289;
|
||||
fill: #ededed;
|
||||
fill: #ededed !important;
|
||||
}
|
||||
|
||||
.q2 {
|
||||
background-color: #cedb9c;
|
||||
fill: #ACD5F2;
|
||||
fill: #ACD5F2 !important;
|
||||
}
|
||||
|
||||
.q3 {
|
||||
background-color: #b5cf6b;
|
||||
fill: #7FA8D1;
|
||||
fill: #7FA8D1 !important;
|
||||
}
|
||||
|
||||
.q4 {
|
||||
background-color: #637939;
|
||||
fill: #49729B;
|
||||
fill: #49729B !important;
|
||||
}
|
||||
|
||||
.q5 {
|
||||
background-color: #3b6427;
|
||||
fill: #254E77;
|
||||
fill: #254E77 !important;
|
||||
}
|
||||
|
||||
.domain-background {
|
||||
|
@ -59,32 +54,7 @@
|
|||
}
|
||||
|
||||
.ch-tooltip {
|
||||
position: absolute;
|
||||
display: none;
|
||||
margin-top: 22px;
|
||||
margin-left: 1px;
|
||||
font-size: 13px;
|
||||
padding: 3px;
|
||||
font-weight: 550;
|
||||
background-color: #222;
|
||||
span {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
text-align: center;
|
||||
visibility: hidden;
|
||||
border-radius: 10px;
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
margin-left: -8px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 8px solid #000000;
|
||||
border-right: 8px solid transparent;
|
||||
border-left: 8px solid transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,23 +3,23 @@
|
|||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), font-url('SourceSansPro-Light.ttf');
|
||||
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), font-url('SourceSansPro-Light.ttf.woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro'), local('SourceSansPro-Regular'), font-url('SourceSansPro-Regular.ttf');
|
||||
src: local('Source Sans Pro'), local('SourceSansPro-Regular'), font-url('SourceSansPro-Regular.ttf.woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'), font-url('SourceSansPro-Semibold.ttf');
|
||||
src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'), font-url('SourceSansPro-Semibold.ttf.woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), font-url('SourceSansPro-Bold.ttf');
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), font-url('SourceSansPro-Bold.ttf.woff');
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
|
||||
|
||||
/** light list with border-bottom between li **/
|
||||
ul.bordered-list {
|
||||
ul.bordered-list, ul.unstyled-list {
|
||||
@include basic-list;
|
||||
|
||||
&.top-list {
|
||||
|
@ -88,6 +88,10 @@ ul.bordered-list {
|
|||
}
|
||||
}
|
||||
|
||||
ul.unstyled-list > li {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
ul.task-list {
|
||||
li.task-list-item {
|
||||
list-style-type: none;
|
||||
|
|
|
@ -105,7 +105,7 @@
|
|||
.tanuki-shape {
|
||||
transition: all 0.8s;
|
||||
|
||||
&:hover {
|
||||
&:hover, &.highlight {
|
||||
fill: rgb(255, 255, 255);
|
||||
transition: all 0.1s;
|
||||
}
|
||||
|
|
|
@ -54,17 +54,17 @@
|
|||
|
||||
h3 {
|
||||
margin: 24px 0 12px 0;
|
||||
font-size: 1.25em;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 24px 0 12px 0;
|
||||
font-size: 1.1em;
|
||||
font-size: 0.98em;
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin: 24px 0 12px 0;
|
||||
font-size: 1em;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
h6 {
|
||||
|
|
|
@ -24,6 +24,7 @@ $gl-gray: #5a5a5a;
|
|||
$gl-padding: 16px;
|
||||
$gl-padding-top:10px;
|
||||
$gl-avatar-size: 46px;
|
||||
$secondary-text: #7f8fa4;
|
||||
|
||||
/*
|
||||
* Color schema
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
.zennable {
|
||||
.zen-toggle-comment {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.zen-enter-link {
|
||||
a.js-zen-enter {
|
||||
color: $gl-gray;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
|
@ -11,7 +7,7 @@
|
|||
line-height: 40px;
|
||||
}
|
||||
|
||||
.zen-leave-link {
|
||||
a.js-zen-leave {
|
||||
display: none;
|
||||
color: $gl-text-color;
|
||||
position: absolute;
|
||||
|
@ -25,62 +21,41 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Hide the Enter link when we're in Zen mode
|
||||
input:checked ~ .zen-backdrop .zen-enter-link {
|
||||
display: none;
|
||||
}
|
||||
.zen-backdrop {
|
||||
&.fullscreen {
|
||||
background-color: white;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1031;
|
||||
|
||||
// Show the Leave link when we're in Zen mode
|
||||
input:checked ~ .zen-backdrop .zen-leave-link {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
textarea {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
color: #000;
|
||||
font-size: 20px;
|
||||
line-height: 26px;
|
||||
padding: 30px;
|
||||
display: block;
|
||||
outline: none;
|
||||
resize: none;
|
||||
height: 100vh;
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
input:checked ~ .zen-backdrop {
|
||||
background-color: white;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1031;
|
||||
a.js-zen-enter {
|
||||
display: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
color: #000;
|
||||
font-size: 20px;
|
||||
line-height: 26px;
|
||||
padding: 30px;
|
||||
display: block;
|
||||
outline: none;
|
||||
resize: none;
|
||||
height: 100vh;
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
a.js-zen-leave {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make the color of the placeholder text in the Zenned-out textarea darker,
|
||||
// so it becomes visible
|
||||
|
||||
input:checked ~ .zen-backdrop textarea::-webkit-input-placeholder {
|
||||
color: #A8A8A8;
|
||||
}
|
||||
|
||||
input:checked ~ .zen-backdrop textarea:-moz-placeholder {
|
||||
color: #A8A8A8;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
input:checked ~ .zen-backdrop textarea::-moz-placeholder {
|
||||
color: #A8A8A8;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
input:checked ~ .zen-backdrop textarea:-ms-input-placeholder {
|
||||
color: #A8A8A8;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,10 +28,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.commits-feed-holder {
|
||||
float: right;
|
||||
}
|
||||
|
||||
li.commit {
|
||||
list-style: none;
|
||||
|
||||
|
@ -122,3 +118,59 @@ li.commit {
|
|||
color: $gl-gray;
|
||||
}
|
||||
}
|
||||
|
||||
.divergence-graph {
|
||||
padding: 12px 12px 0 0;
|
||||
float: right;
|
||||
|
||||
.graph-side {
|
||||
position: relative;
|
||||
width: 80px;
|
||||
height: 22px;
|
||||
padding: 5px 0 13px;
|
||||
float: left;
|
||||
|
||||
.bar {
|
||||
position: absolute;
|
||||
height: 4px;
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
||||
.bar-behind {
|
||||
right: 0;
|
||||
border-radius: 3px 0 0 3px;
|
||||
}
|
||||
|
||||
.bar-ahead {
|
||||
left: 0;
|
||||
border-radius: 0 3px 3px 0;
|
||||
}
|
||||
|
||||
.count {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 0px;
|
||||
font-size: 12px;
|
||||
color: #333;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.count-behind {
|
||||
padding-right: 4px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.count-ahead {
|
||||
padding-left: 4px;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
.graph-separator {
|
||||
position: relative;
|
||||
width: 1px;
|
||||
height: 18px;
|
||||
margin: 5px 0 0;
|
||||
float: left;
|
||||
background-color: #ccc;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,6 +138,7 @@
|
|||
*/
|
||||
.event-last-push {
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
.event-last-push-text {
|
||||
@include str-truncated(100%);
|
||||
padding: 5px 0;
|
||||
|
|
|
@ -94,8 +94,16 @@
|
|||
}
|
||||
|
||||
.cross-project-reference {
|
||||
font-weight: bold;
|
||||
color: $gl-link-color;
|
||||
|
||||
span {
|
||||
white-space: nowrap;
|
||||
width: 85%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
button {
|
||||
float: right;
|
||||
|
|
|
@ -144,3 +144,8 @@ form.edit-issue {
|
|||
.issue-form .select2-container {
|
||||
width: 250px !important;
|
||||
}
|
||||
|
||||
.issue-closed-by-widget {
|
||||
color: $secondary-text;
|
||||
margin-left: 52px;
|
||||
}
|
|
@ -26,6 +26,13 @@
|
|||
}
|
||||
|
||||
.project-home-panel {
|
||||
|
||||
.cover-controls {
|
||||
.project-settings-dropdown {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.project-identicon-holder {
|
||||
margin-bottom: 16px;
|
||||
|
||||
|
@ -288,10 +295,9 @@
|
|||
|
||||
border: 1px solid #c6cacf !important;
|
||||
background-color: #e4e7ed !important;
|
||||
text-transform: uppercase;
|
||||
text-transform: none;
|
||||
color: #313236 !important;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
|
@ -404,10 +410,15 @@ ul.nav.nav-projects-tabs {
|
|||
}
|
||||
}
|
||||
|
||||
.last-push-widget {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.top-area {
|
||||
border-bottom: 1px solid #EEE;
|
||||
margin: 0 -16px;
|
||||
padding: 0 $gl-padding;
|
||||
height: 42px;
|
||||
|
||||
ul.left-top-menu {
|
||||
display: inline-block;
|
||||
|
@ -514,6 +525,7 @@ pre.light-well {
|
|||
.projects-search-form {
|
||||
margin: -$gl-padding;
|
||||
padding: $gl-padding;
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 0px;
|
||||
|
||||
input {
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
.tree-holder {
|
||||
|
||||
.file-finder {
|
||||
width: 50%;
|
||||
.file-finder-input {
|
||||
width: 95%;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.tree-table {
|
||||
margin-bottom: 0;
|
||||
|
||||
|
|
|
@ -9,12 +9,10 @@ class AbuseReportsController < ApplicationController
|
|||
@abuse_report.reporter = current_user
|
||||
|
||||
if @abuse_report.save
|
||||
if current_application_settings.admin_notification_email.present?
|
||||
AbuseReportMailer.notify(@abuse_report.id).deliver_later
|
||||
end
|
||||
@abuse_report.notify
|
||||
|
||||
message = "Thank you for your report. A GitLab administrator will look into it shortly."
|
||||
redirect_to root_path, notice: message
|
||||
redirect_to @abuse_report.user, notice: message
|
||||
else
|
||||
render :new
|
||||
end
|
||||
|
@ -23,6 +21,9 @@ class AbuseReportsController < ApplicationController
|
|||
private
|
||||
|
||||
def report_params
|
||||
params.require(:abuse_report).permit(:user_id, :message)
|
||||
params.require(:abuse_report).permit(%i(
|
||||
message
|
||||
user_id
|
||||
))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,11 +6,9 @@ class Admin::AbuseReportsController < Admin::ApplicationController
|
|||
def destroy
|
||||
abuse_report = AbuseReport.find(params[:id])
|
||||
|
||||
if params[:remove_user]
|
||||
abuse_report.user.destroy
|
||||
end
|
||||
|
||||
abuse_report.remove_user if params[:remove_user]
|
||||
abuse_report.destroy
|
||||
|
||||
render nothing: true
|
||||
end
|
||||
end
|
||||
|
|
|
@ -70,11 +70,10 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
|
|||
:metrics_enabled,
|
||||
:metrics_host,
|
||||
:metrics_port,
|
||||
:metrics_username,
|
||||
:metrics_password,
|
||||
:metrics_pool_size,
|
||||
:metrics_timeout,
|
||||
:metrics_method_call_threshold,
|
||||
:metrics_sample_interval,
|
||||
:recaptcha_enabled,
|
||||
:recaptcha_site_key,
|
||||
:recaptcha_private_key,
|
||||
|
|
|
@ -5,12 +5,12 @@ class Admin::BuildsController < Admin::ApplicationController
|
|||
@builds = @all_builds.order('created_at DESC')
|
||||
@builds =
|
||||
case @scope
|
||||
when 'all'
|
||||
@builds
|
||||
when 'running'
|
||||
@builds.running_or_pending.reverse_order
|
||||
when 'finished'
|
||||
@builds.finished
|
||||
else
|
||||
@builds.running_or_pending.reverse_order
|
||||
@builds
|
||||
end
|
||||
@builds = @builds.page(params[:page]).per(30)
|
||||
end
|
||||
|
|
|
@ -286,7 +286,7 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
def set_filters_params
|
||||
params[:sort] ||= 'created_desc'
|
||||
params[:sort] ||= 'id_desc'
|
||||
params[:scope] = 'all' if params[:scope].blank?
|
||||
params[:state] = 'opened' if params[:state].blank?
|
||||
|
||||
|
|
|
@ -6,11 +6,13 @@ module Ci
|
|||
end
|
||||
|
||||
def create
|
||||
if params[:content].blank?
|
||||
@content = params[:content]
|
||||
|
||||
if @content.blank?
|
||||
@status = false
|
||||
@error = "Please provide content of .gitlab-ci.yml"
|
||||
else
|
||||
@config_processor = Ci::GitlabCiYamlProcessor.new params[:content]
|
||||
@config_processor = Ci::GitlabCiYamlProcessor.new(@content)
|
||||
@stages = @config_processor.stages
|
||||
@builds = @config_processor.builds
|
||||
@status = true
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class Explore::GroupsController < Explore::ApplicationController
|
||||
def index
|
||||
@groups = GroupsFinder.new.execute(current_user)
|
||||
@groups = Group.order_id_desc
|
||||
@groups = @groups.search(params[:search]) if params[:search].present?
|
||||
@groups = @groups.sort(@sort = params[:sort])
|
||||
@groups = @groups.page(params[:page]).per(PER_PAGE)
|
||||
|
|
|
@ -9,6 +9,11 @@ class Projects::BranchesController < Projects::ApplicationController
|
|||
@sort = params[:sort] || 'name'
|
||||
@branches = @repository.branches_sorted_by(@sort)
|
||||
@branches = Kaminari.paginate_array(@branches).page(params[:page]).per(PER_PAGE)
|
||||
|
||||
@max_commits = @branches.reduce(0) do |memo, branch|
|
||||
diverging_commit_counts = repository.diverging_commit_counts(branch)
|
||||
[memo, diverging_commit_counts[:behind], diverging_commit_counts[:ahead]].max
|
||||
end
|
||||
end
|
||||
|
||||
def recent
|
||||
|
|
|
@ -12,12 +12,12 @@ class Projects::BuildsController < Projects::ApplicationController
|
|||
@builds = @all_builds.order('created_at DESC')
|
||||
@builds =
|
||||
case @scope
|
||||
when 'all'
|
||||
@builds
|
||||
when 'running'
|
||||
@builds.running_or_pending.reverse_order
|
||||
when 'finished'
|
||||
@builds.finished
|
||||
else
|
||||
@builds.running_or_pending.reverse_order
|
||||
@builds
|
||||
end
|
||||
@builds = @builds.page(params[:page]).per(30)
|
||||
end
|
||||
|
|
|
@ -8,10 +8,16 @@ class Projects::CommitsController < Projects::ApplicationController
|
|||
before_action :authorize_download_code!
|
||||
|
||||
def show
|
||||
@repo = @project.repository
|
||||
@limit, @offset = (params[:limit] || 40).to_i, (params[:offset] || 0).to_i
|
||||
search = params[:search]
|
||||
|
||||
@commits =
|
||||
if search.present?
|
||||
@repository.find_commits_by_message(search, @ref, @path, @limit, @offset).compact
|
||||
else
|
||||
@repository.commits(@ref, @path, @limit, @offset)
|
||||
end
|
||||
|
||||
@commits = @repo.commits(@ref, @path, @limit, @offset)
|
||||
@note_counts = project.notes.where(commit_id: @commits.map(&:id)).
|
||||
group(:commit_id).count
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# Controller for viewing a repository's file structure
|
||||
class Projects::FindFileController < Projects::ApplicationController
|
||||
include ExtractsPath
|
||||
include ActionView::Helpers::SanitizeHelper
|
||||
include TreeHelper
|
||||
|
||||
before_action :require_non_empty_project
|
||||
before_action :assign_ref_vars
|
||||
before_action :authorize_download_code!
|
||||
|
||||
def show
|
||||
return render_404 unless @repository.commit(@ref)
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
end
|
||||
end
|
||||
|
||||
def list
|
||||
file_paths = @repo.ls_files(@ref)
|
||||
|
||||
respond_to do |format|
|
||||
format.json { render json: file_paths }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -153,7 +153,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def merge_check
|
||||
@merge_request.check_if_can_be_merged if @merge_request.unchecked?
|
||||
@merge_request.check_if_can_be_merged
|
||||
|
||||
render partial: "projects/merge_requests/widget/show.html.haml", layout: false
|
||||
end
|
||||
|
|
|
@ -20,6 +20,8 @@ class Projects::RefsController < Projects::ApplicationController
|
|||
namespace_project_network_path(@project.namespace, @project, @id, @options)
|
||||
when "graphs"
|
||||
namespace_project_graph_path(@project.namespace, @project, @id)
|
||||
when "find_file"
|
||||
namespace_project_find_file_path(@project.namespace, @project, @id)
|
||||
when "graphs_commits"
|
||||
commits_namespace_project_graph_path(@project.namespace, @project, @id)
|
||||
else
|
||||
|
|
|
@ -8,7 +8,7 @@ class ProjectsController < ApplicationController
|
|||
before_action :assign_ref_vars, :tree, only: [:show], if: :repo_exists?
|
||||
|
||||
# Authorize
|
||||
before_action :authorize_admin_project!, only: [:edit, :update]
|
||||
before_action :authorize_admin_project!, only: [:edit, :update, :housekeeping]
|
||||
before_action :event_filter, only: [:show, :activity]
|
||||
|
||||
layout :determine_layout
|
||||
|
@ -166,6 +166,15 @@ class ProjectsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def housekeeping
|
||||
::Projects::HousekeepingService.new(@project).execute
|
||||
|
||||
respond_to do |format|
|
||||
flash[:notice] = "Housekeeping successfully started."
|
||||
format.html { redirect_to project_path(@project) }
|
||||
end
|
||||
end
|
||||
|
||||
def toggle_star
|
||||
current_user.toggle_star(@project)
|
||||
@project.reload
|
||||
|
|
|
@ -7,7 +7,7 @@ class UsersController < ApplicationController
|
|||
|
||||
@projects = PersonalProjectsFinder.new(@user).execute(current_user)
|
||||
|
||||
@groups = JoinedGroupsFinder.new(@user).execute(current_user)
|
||||
@groups = @user.groups.order_id_desc
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
class GroupsFinder
|
||||
# Finds the groups available to the given user.
|
||||
#
|
||||
# current_user - The user to find the groups for.
|
||||
#
|
||||
# Returns an ActiveRecord::Relation.
|
||||
def execute(current_user = nil)
|
||||
if current_user
|
||||
relation = groups_visible_to_user(current_user)
|
||||
else
|
||||
relation = public_groups
|
||||
end
|
||||
|
||||
relation.order_id_desc
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# This method returns the groups "current_user" can see.
|
||||
def groups_visible_to_user(current_user)
|
||||
base = groups_for_projects(public_and_internal_projects)
|
||||
|
||||
union = Gitlab::SQL::Union.
|
||||
new([base.select(:id), current_user.authorized_groups.select(:id)])
|
||||
|
||||
Group.where("namespaces.id IN (#{union.to_sql})")
|
||||
end
|
||||
|
||||
def public_groups
|
||||
groups_for_projects(public_projects)
|
||||
end
|
||||
|
||||
def groups_for_projects(projects)
|
||||
Group.public_and_given_groups(projects.select(:namespace_id))
|
||||
end
|
||||
|
||||
def public_projects
|
||||
Project.unscoped.public_only
|
||||
end
|
||||
|
||||
def public_and_internal_projects
|
||||
Project.unscoped.public_and_internal_only
|
||||
end
|
||||
end
|
|
@ -79,9 +79,9 @@ class IssuableFinder
|
|||
if project?
|
||||
@projects = project
|
||||
elsif current_user && params[:authorized_only].presence && !current_user_related?
|
||||
@projects = current_user.authorized_projects
|
||||
@projects = current_user.authorized_projects.reorder(nil)
|
||||
else
|
||||
@projects = ProjectsFinder.new.execute(current_user)
|
||||
@projects = ProjectsFinder.new.execute(current_user).reorder(nil)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
# Class for finding the groups a user is a member of.
|
||||
class JoinedGroupsFinder
|
||||
def initialize(user = nil)
|
||||
@user = user
|
||||
end
|
||||
|
||||
# Finds the groups of the source user, optionally limited to those visible to
|
||||
# the current user.
|
||||
#
|
||||
# current_user - If given the groups of "@user" will only include the groups
|
||||
# "current_user" can also see.
|
||||
#
|
||||
# Returns an ActiveRecord::Relation.
|
||||
def execute(current_user = nil)
|
||||
if current_user
|
||||
relation = groups_visible_to_user(current_user)
|
||||
else
|
||||
relation = public_groups
|
||||
end
|
||||
|
||||
relation.order_id_desc
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Returns the groups the user in "current_user" can see.
|
||||
#
|
||||
# This list includes all public/internal projects as well as the projects of
|
||||
# "@user" that "current_user" also has access to.
|
||||
def groups_visible_to_user(current_user)
|
||||
base = @user.authorized_groups.visible_to_user(current_user)
|
||||
extra = public_and_internal_groups
|
||||
union = Gitlab::SQL::Union.new([base.select(:id), extra.select(:id)])
|
||||
|
||||
Group.where("namespaces.id IN (#{union.to_sql})")
|
||||
end
|
||||
|
||||
def public_groups
|
||||
groups_for_projects(@user.authorized_projects.public_only)
|
||||
end
|
||||
|
||||
def public_and_internal_groups
|
||||
groups_for_projects(@user.authorized_projects.public_and_internal_only)
|
||||
end
|
||||
|
||||
def groups_for_projects(projects)
|
||||
@user.groups.public_and_given_groups(projects.select(:namespace_id))
|
||||
end
|
||||
end
|
|
@ -205,8 +205,8 @@ module ApplicationHelper
|
|||
def time_ago_with_tooltip(time, placement: 'top', html_class: 'time_ago', skip_js: false)
|
||||
element = content_tag :time, time.to_s,
|
||||
class: "#{html_class} js-timeago js-timeago-pending",
|
||||
datetime: time.getutc.iso8601,
|
||||
title: time.in_time_zone.stamp('Aug 21, 2011 9:23pm'),
|
||||
datetime: time.to_time.getutc.iso8601,
|
||||
title: time.in_time_zone.to_s(:medium),
|
||||
data: { toggle: 'tooltip', placement: placement, container: 'body' }
|
||||
|
||||
unless skip_js
|
||||
|
@ -266,7 +266,7 @@ module ApplicationHelper
|
|||
state: params[:state],
|
||||
scope: params[:scope],
|
||||
label_name: params[:label_name],
|
||||
milestone_id: params[:milestone_id],
|
||||
milestone_title: params[:milestone_title],
|
||||
assignee_id: params[:assignee_id],
|
||||
author_id: params[:author_id],
|
||||
sort: params[:sort],
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
module AuthHelper
|
||||
PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2 facebook).freeze
|
||||
PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2 facebook azure_oauth2).freeze
|
||||
FORM_BASED_PROVIDERS = [/\Aldap/, 'crowd'].freeze
|
||||
|
||||
def ldap_enabled?
|
||||
|
|
|
@ -80,7 +80,7 @@ module IssuesHelper
|
|||
xml.link href: namespace_project_issue_url(issue.project.namespace,
|
||||
issue.project, issue)
|
||||
xml.title truncate(issue.title, length: 80)
|
||||
xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
xml.updated issue.created_at.xmlschema
|
||||
xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(issue.author_email))
|
||||
xml.author do |author|
|
||||
xml.name issue.author_name
|
||||
|
@ -99,13 +99,16 @@ module IssuesHelper
|
|||
end
|
||||
|
||||
def emoji_icon(name, unicode = nil, aliases = [])
|
||||
unicode ||= Emoji.emoji_filename(name)
|
||||
unicode ||= Emoji.emoji_filename(name) rescue ""
|
||||
|
||||
content_tag :div, "",
|
||||
class: "icon emoji-icon emoji-#{unicode}",
|
||||
"data-emoji" => name,
|
||||
"data-aliases" => aliases.join(" "),
|
||||
"data-unicode-name" => unicode
|
||||
title: name,
|
||||
data: {
|
||||
aliases: aliases.join(' '),
|
||||
emoji: name,
|
||||
unicode_name: unicode
|
||||
}
|
||||
end
|
||||
|
||||
def emoji_author_list(notes, current_user)
|
||||
|
|
|
@ -67,7 +67,7 @@ module NotesHelper
|
|||
line_type: line_type
|
||||
}
|
||||
|
||||
button_tag class: 'btn reply-btn js-discussion-reply-button',
|
||||
button_tag class: 'btn btn-nr reply-btn js-discussion-reply-button',
|
||||
data: data, title: 'Add a reply' do
|
||||
link_text = icon('comment')
|
||||
link_text << ' Reply'
|
||||
|
|
|
@ -27,35 +27,20 @@ module PageLayoutHelper
|
|||
#
|
||||
# Returns an HTML-safe String.
|
||||
def page_description(description = nil)
|
||||
@page_description ||= page_description_default
|
||||
|
||||
if description.present?
|
||||
@page_description = description.squish
|
||||
else
|
||||
elsif @page_description.present?
|
||||
sanitize(@page_description, tags: []).truncate_words(30)
|
||||
end
|
||||
end
|
||||
|
||||
# Default value for page_description when one hasn't been defined manually by
|
||||
# a view
|
||||
def page_description_default
|
||||
if @project
|
||||
@project.description || brand_title
|
||||
else
|
||||
brand_title
|
||||
end
|
||||
end
|
||||
|
||||
def page_image
|
||||
default = image_url('gitlab_logo.png')
|
||||
|
||||
if @project
|
||||
@project.avatar_url || default
|
||||
elsif @user
|
||||
avatar_icon(@user)
|
||||
else
|
||||
default
|
||||
end
|
||||
subject = @project || @user || @group
|
||||
|
||||
image = subject.avatar_url if subject.present?
|
||||
image || default
|
||||
end
|
||||
|
||||
# Define or get attributes to be used as Twitter card metadata
|
||||
|
|
|
@ -70,7 +70,7 @@ module SearchHelper
|
|||
|
||||
# Autocomplete results for the current user's groups
|
||||
def groups_autocomplete(term, limit = 5)
|
||||
GroupsFinder.new.execute(current_user).search(term).limit(limit).map do |group|
|
||||
Group.search(term).limit(limit).map do |group|
|
||||
{
|
||||
label: "group: #{search_result_sanitize(group.name)}",
|
||||
url: group_path(group)
|
||||
|
|
|
@ -19,7 +19,7 @@ module SortingHelper
|
|||
end
|
||||
|
||||
def sort_title_recently_updated
|
||||
'Recently updated'
|
||||
'Last updated'
|
||||
end
|
||||
|
||||
def sort_title_oldest_created
|
||||
|
@ -27,7 +27,7 @@ module SortingHelper
|
|||
end
|
||||
|
||||
def sort_title_recently_created
|
||||
'Recently created'
|
||||
'Last created'
|
||||
end
|
||||
|
||||
def sort_title_milestone_soon
|
||||
|
@ -63,11 +63,11 @@ module SortingHelper
|
|||
end
|
||||
|
||||
def sort_value_oldest_created
|
||||
'created_asc'
|
||||
'id_asc'
|
||||
end
|
||||
|
||||
def sort_value_recently_created
|
||||
'created_desc'
|
||||
'id_desc'
|
||||
end
|
||||
|
||||
def sort_value_milestone_soon
|
||||
|
|
|
@ -2,11 +2,19 @@ class AbuseReportMailer < BaseMailer
|
|||
include Gitlab::CurrentSettings
|
||||
|
||||
def notify(abuse_report_id)
|
||||
return unless deliverable?
|
||||
|
||||
@abuse_report = AbuseReport.find(abuse_report_id)
|
||||
|
||||
mail(
|
||||
to: current_application_settings.admin_notification_email,
|
||||
to: current_application_settings.admin_notification_email,
|
||||
subject: "#{@abuse_report.user.name} (#{@abuse_report.user.username}) was reported for abuse"
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def deliverable?
|
||||
current_application_settings.admin_notification_email.present?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -48,7 +48,7 @@ module Emails
|
|||
|
||||
yield
|
||||
|
||||
SentNotification.record(@note, recipient_id, reply_key)
|
||||
SentNotification.record_note(@note, recipient_id, reply_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -69,7 +69,7 @@ class Ability
|
|||
subject.group
|
||||
end
|
||||
|
||||
if group && group.public_profile?
|
||||
if group && group.projects.public_only.any?
|
||||
[:read_group]
|
||||
else
|
||||
[]
|
||||
|
|
|
@ -18,4 +18,15 @@ class AbuseReport < ActiveRecord::Base
|
|||
validates :user, presence: true
|
||||
validates :message, presence: true
|
||||
validates :user_id, uniqueness: true
|
||||
|
||||
def remove_user
|
||||
user.block
|
||||
user.destroy
|
||||
end
|
||||
|
||||
def notify
|
||||
return unless self.persisted?
|
||||
|
||||
AbuseReportMailer.notify(self.id).deliver_later
|
||||
end
|
||||
end
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue