Merge branch 'master' into awardables
This commit is contained in:
		
						commit
						7e6dcf9cd0
					
				|  | @ -115,6 +115,11 @@ bundler:audit: | ||||||
|   script: |   script: | ||||||
|     - "bundle exec bundle-audit check --update --ignore OSVDB-115941" |     - "bundle exec bundle-audit check --update --ignore OSVDB-115941" | ||||||
| 
 | 
 | ||||||
|  | db-migrate-reset: | ||||||
|  |   stage: test | ||||||
|  |   script: | ||||||
|  |     - RAILS_ENV=test bundle exec rake db:migrate:reset | ||||||
|  | 
 | ||||||
| # Ruby 2.2 jobs | # Ruby 2.2 jobs | ||||||
| 
 | 
 | ||||||
| spec:feature:ruby22: | spec:feature:ruby22: | ||||||
|  |  | ||||||
|  | @ -728,7 +728,7 @@ Metrics/ParameterLists: | ||||||
| # A complexity metric geared towards measuring complexity for a human reader. | # A complexity metric geared towards measuring complexity for a human reader. | ||||||
| Metrics/PerceivedComplexity: | Metrics/PerceivedComplexity: | ||||||
|   Enabled: true |   Enabled: true | ||||||
|   Max: 17 |   Max: 18 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #################### Lint ################################ | #################### Lint ################################ | ||||||
|  | @ -953,10 +953,9 @@ Performance/DoubleStartEndWith: | ||||||
| Performance/EndWith: | Performance/EndWith: | ||||||
|   Enabled: false |   Enabled: false | ||||||
| 
 | 
 | ||||||
| # TODO: Enable LstripRstrip Cop. |  | ||||||
| # Use `strip` instead of `lstrip.rstrip`. | # Use `strip` instead of `lstrip.rstrip`. | ||||||
| Performance/LstripRstrip: | Performance/LstripRstrip: | ||||||
|   Enabled: false |   Enabled: true | ||||||
| 
 | 
 | ||||||
| # TODO: Enable RangeInclude Cop. | # TODO: Enable RangeInclude Cop. | ||||||
| # Use `Range#cover?` instead of `Range#include?`. | # Use `Range#cover?` instead of `Range#include?`. | ||||||
|  |  | ||||||
|  | @ -65,7 +65,7 @@ linters: | ||||||
|    |    | ||||||
|   # Reports when you have an empty rule set. |   # Reports when you have an empty rule set. | ||||||
|   EmptyRule: |   EmptyRule: | ||||||
|     enabled: false |     enabled: true | ||||||
|    |    | ||||||
|   # Reports when you have an @extend directive. |   # Reports when you have an @extend directive. | ||||||
|   ExtendDirective: |   ExtendDirective: | ||||||
|  | @ -244,11 +244,11 @@ linters: | ||||||
|    |    | ||||||
|   # URLs should be valid and not contain protocols or domain names. |   # URLs should be valid and not contain protocols or domain names. | ||||||
|   UrlFormat: |   UrlFormat: | ||||||
|     enabled: false |     enabled: true | ||||||
| 
 | 
 | ||||||
|   # URLs should always be enclosed within quotes. |   # URLs should always be enclosed within quotes. | ||||||
|   UrlQuotes: |   UrlQuotes: | ||||||
|     enabled: false |     enabled: true | ||||||
| 
 | 
 | ||||||
|   # Properties, like color and font, are easier to read and maintain |   # Properties, like color and font, are easier to read and maintain | ||||||
|   # when defined using variables rather than literals. |   # when defined using variables rather than literals. | ||||||
|  |  | ||||||
							
								
								
									
										181
									
								
								CHANGELOG
								
								
								
								
							
							
						
						
									
										181
									
								
								CHANGELOG
								
								
								
								
							|  | @ -1,26 +1,105 @@ | ||||||
| Please view this file on the master branch, on stable branches it's out of date. | Please view this file on the master branch, on stable branches it's out of date. | ||||||
| 
 | 
 | ||||||
| v 8.7.0 (unreleased) | v 8.8.0 (unreleased) | ||||||
|  |   - Assign labels and milestone to target project when moving issue. !3934 (Long Nguyen) | ||||||
|  |   - Use a case-insensitive comparison in sanitizing URI schemes | ||||||
|  |   - Project#open_branches has been cleaned up and no longer loads entire records into memory. | ||||||
|  |   - Escape HTML in commit titles in system note messages | ||||||
|  |   - Improve multiple branch push performance by memoizing permission checking | ||||||
|  |   - Log to application.log when an admin starts and stops impersonating a user | ||||||
|  |   - Updated gitlab_git to 10.1.0 | ||||||
|  |   - GitAccess#protected_tag? no longer loads all tags just to check if a single one exists | ||||||
|  |   - Reduce delay in destroying a project from 1-minute to immediately | ||||||
|  |   - Make build status canceled if any of the jobs was canceled and none failed | ||||||
|  |   - Upgrade Sidekiq to 4.1.2 | ||||||
|  |   - Sanitize repo paths in new project error message | ||||||
|  |   - Bump mail_room to 0.7.0 to fix stuck IDLE connections | ||||||
|  |   - Remove future dates from contribution calendar graph. | ||||||
|  |   - Support e-mail notifications for comments on project snippets | ||||||
|  |   - Use ActionDispatch Remote IP for Akismet checking | ||||||
|  |   - Fix error when visiting commit builds page before build was updated | ||||||
|  |   - Add 'l' shortcut to open Label dropdown on issuables and 'i' to create new issue on a project | ||||||
|  |   - Update SVG sanitizer to conform to SVG 1.1 | ||||||
|  |   - Updated search UI | ||||||
|  |   - Display informative message when new milestone is created | ||||||
|  |   - Sanitize milestones and labels titles | ||||||
|  |   - Support multi-line tag messages. !3833 (Calin Seciu) | ||||||
|  |   - Allow "NEWS" and "CHANGES" as alternative names for CHANGELOG. !3768 (Connor Shea) | ||||||
|  |   - Added button to toggle whitespaces changes on diff view | ||||||
|  |   - Backport GitHub Enterprise import support from EE | ||||||
|  |   - Create tags using Rugged for performance reasons. !3745 | ||||||
|  |   - API: Expose Issue#user_notes_count. !3126 (Anton Popov) | ||||||
|  |   - Files over 5MB can only be viewed in their raw form, files over 1MB without highlighting !3718 | ||||||
|  |   - Add support for supressing text diffs using .gitattributes on the default branch (Matt Oakes) | ||||||
|  |   - Added multiple colors for labels in dropdowns when dups happen. | ||||||
|  |   - Improve description for the Two-factor Authentication sign-in screen. (Connor Shea) | ||||||
|  |   - API support for the 'since' and 'until' operators on commit requests (Paco Guzman) | ||||||
|  |   - Fix Gravatar hint in user profile when Gravatar is disabled. !3988 (Artem Sidorenko) | ||||||
|  |   - Expire repository exists? and has_visible_content? caches after a push if necessary | ||||||
|  |   - Fix unintentional filtering bug in issues sorted by milestone due (Takuya Noguchi) | ||||||
|  |   - Fix adding a todo for private group members (Ahmad Sherif) | ||||||
|  | 
 | ||||||
|  | v 8.7.4 | ||||||
|  |   - Fix always showing build notification message when switching between merge requests | ||||||
|  |   - Links for Redmine issue references are generated correctly again (Benedikt Huss) | ||||||
|  | 
 | ||||||
|  | v 8.7.3 | ||||||
|  |   - Emails, Gitlab::Email::Message, Gitlab::Diff, and Premailer::Adapter::Nokogiri are now instrumented | ||||||
|  |   - Merge request widget displays TeamCity build state and code coverage correctly again. | ||||||
|  |   - Fix the line code when importing PR review comments from GitHub. !4010 | ||||||
|  |   - Wikis are now initialized on legacy projects when checking repositories | ||||||
|  | 
 | ||||||
|  | v 8.7.2 | ||||||
|  |   - The "New Branch" button is now loaded asynchronously | ||||||
|  |   - Fix error 500 when trying to create a wiki page | ||||||
|  |   - Updated spacing between notification label and button | ||||||
|  |   - Label titles in filters are now escaped properly | ||||||
|  | 
 | ||||||
|  | v 8.7.1 | ||||||
|  |   - Throttle the update of `project.last_activity_at` to 1 minute. !3848 | ||||||
|  |   - Fix .gitlab-ci.yml parsing issue when hidde job is a template without script definition. !3849 | ||||||
|  |   - Fix license detection to detect all license files, not only known licenses. !3878 | ||||||
|  |   - Use the `can?` helper instead of `current_user.can?`. !3882 | ||||||
|  |   - Prevent users from deleting Webhooks via API they do not own | ||||||
|  |   - Fix Error 500 due to stale cache when projects are renamed or transferred | ||||||
|  |   - Update width of search box to fix Safari bug. !3900 (Jedidiah) | ||||||
|  |   - Use the `can?` helper instead of `current_user.can?` | ||||||
|  | 
 | ||||||
|  | v 8.7.0 | ||||||
|  |   - Gitlab::GitAccess and Gitlab::GitAccessWiki are now instrumented | ||||||
|  |   - Fix vulnerability that made it possible to gain access to private labels and milestones | ||||||
|  |   - The number of InfluxDB points stored per UDP packet can now be configured | ||||||
|  |   - Fix error when cross-project label reference used with non-existent project | ||||||
|  |   - Transactions for /internal/allowed now have an "action" tag set | ||||||
|  |   - Method instrumentation now uses Module#prepend instead of aliasing methods | ||||||
|  |   - Repository.clean_old_archives is now instrumented | ||||||
|  |   - Add support for environment variables on a job level in CI configuration file | ||||||
|  |   - SQL query counts are now tracked per transaction | ||||||
|   - The Projects::HousekeepingService class has extra instrumentation |   - The Projects::HousekeepingService class has extra instrumentation | ||||||
|   - All service classes (those residing in app/services) are now instrumented |   - All service classes (those residing in app/services) are now instrumented | ||||||
|   - Developers can now add custom tags to transactions |   - Developers can now add custom tags to transactions | ||||||
|   - Loading of an issue's referenced merge requests and related branches is now done asynchronously |   - Loading of an issue's referenced merge requests and related branches is now done asynchronously | ||||||
|   - Enable gzip for assets, makes the page size significantly smaller. !3544 / !3632 (Connor Shea) |   - Enable gzip for assets, makes the page size significantly smaller. !3544 / !3632 (Connor Shea) | ||||||
|  |   - Add support to cherry-pick any commit into any branch in the web interface (Minqi Pan) | ||||||
|   - Project switcher uses new dropdown styling |   - Project switcher uses new dropdown styling | ||||||
|   - Load award emoji images separately unless opening the full picker. Saves several hundred KBs of data for most pages. (Connor Shea) |   - Load award emoji images separately unless opening the full picker. Saves several hundred KBs of data for most pages. (Connor Shea) | ||||||
|   - Do not include award_emojis in issue and merge_request comment_count !3610 (Lucas Charles) |   - Do not include award_emojis in issue and merge_request comment_count !3610 (Lucas Charles) | ||||||
|  |   - Restrict user profiles when public visibility level is restricted. | ||||||
|  |   - Add ability set due date to issues, sort and filter issues by due date (Mehmet Beydogan) | ||||||
|   - All images in discussions and wikis now link to their source files !3464 (Connor Shea). |   - All images in discussions and wikis now link to their source files !3464 (Connor Shea). | ||||||
|   - Return status code 303 after a branch DELETE operation to avoid project deletion (Stan Hu) |   - Return status code 303 after a branch DELETE operation to avoid project deletion (Stan Hu) | ||||||
|   - Add setting for customizing the list of trusted proxies !3524 |   - Add setting for customizing the list of trusted proxies !3524 | ||||||
|   - Allow projects to be transfered to a lower visibility level group |   - Allow projects to be transfered to a lower visibility level group | ||||||
|   - Fix `signed_in_ip` being set to 127.0.0.1 when using a reverse proxy !3524 |   - Fix `signed_in_ip` being set to 127.0.0.1 when using a reverse proxy !3524 | ||||||
|   - Improved Markdown rendering performance !3389 |   - Improved Markdown rendering performance !3389 | ||||||
|  |   - Make shared runners text in box configurable | ||||||
|   - Don't attempt to look up an avatar in repo if repo directory does not exist (Stan Hu) |   - Don't attempt to look up an avatar in repo if repo directory does not exist (Stan Hu) | ||||||
|   - API: Ability to subscribe and unsubscribe from issues and merge requests (Robert Schilling) |   - API: Ability to subscribe and unsubscribe from issues and merge requests (Robert Schilling) | ||||||
|   - Expose project badges in project settings |   - Expose project badges in project settings | ||||||
|   - Make /profile/keys/new redirect to /profile/keys for back-compat. !3717 |   - Make /profile/keys/new redirect to /profile/keys for back-compat. !3717 | ||||||
|   - Preserve time notes/comments have been updated at when moving issue |   - Preserve time notes/comments have been updated at when moving issue | ||||||
|   - Make HTTP(s) label consistent on clone bar (Stan Hu) |   - Make HTTP(s) label consistent on clone bar (Stan Hu) | ||||||
|  |   - Add support for `after_script`, requires Runner 1.2 (Kamil Trzciński) | ||||||
|   - Expose label description in API (Mariusz Jachimowicz) |   - Expose label description in API (Mariusz Jachimowicz) | ||||||
|   - API: Ability to update a group (Robert Schilling) |   - API: Ability to update a group (Robert Schilling) | ||||||
|   - API: Ability to move issues (Robert Schilling) |   - API: Ability to move issues (Robert Schilling) | ||||||
|  | @ -28,6 +107,8 @@ v 8.7.0 (unreleased) | ||||||
|   - Fix a bug whith trailing slash in teamcity_url (Charles May) |   - Fix a bug whith trailing slash in teamcity_url (Charles May) | ||||||
|   - Allow back dating on issues when created or updated through the API |   - Allow back dating on issues when created or updated through the API | ||||||
|   - Allow back dating on issue notes when created through the API |   - Allow back dating on issue notes when created through the API | ||||||
|  |   - Propose license template when creating a new LICENSE file | ||||||
|  |   - API: Expose /licenses and /licenses/:key | ||||||
|   - Fix avatar stretching by providing a cropping feature |   - Fix avatar stretching by providing a cropping feature | ||||||
|   - API: Expose `subscribed` for issues and merge requests (Robert Schilling) |   - API: Expose `subscribed` for issues and merge requests (Robert Schilling) | ||||||
|   - Allow SAML to handle external users based on user's information !3530 |   - Allow SAML to handle external users based on user's information !3530 | ||||||
|  | @ -35,8 +116,9 @@ v 8.7.0 (unreleased) | ||||||
|   - Add endpoints to archive or unarchive a project !3372 |   - Add endpoints to archive or unarchive a project !3372 | ||||||
|   - Fix a bug whith trailing slash in bamboo_url |   - Fix a bug whith trailing slash in bamboo_url | ||||||
|   - Add links to CI setup documentation from project settings and builds pages |   - Add links to CI setup documentation from project settings and builds pages | ||||||
|  |   - Display project members page to all members | ||||||
|   - Handle nil descriptions in Slack issue messages (Stan Hu) |   - Handle nil descriptions in Slack issue messages (Stan Hu) | ||||||
|   - Add automated repository integrity checks |   - Add automated repository integrity checks (OFF by default) | ||||||
|   - API: Expose open_issues_count, closed_issues_count, open_merge_requests_count for labels (Robert Schilling) |   - API: Expose open_issues_count, closed_issues_count, open_merge_requests_count for labels (Robert Schilling) | ||||||
|   - API: Ability to star and unstar a project (Robert Schilling) |   - API: Ability to star and unstar a project (Robert Schilling) | ||||||
|   - Add default scope to projects to exclude projects pending deletion |   - Add default scope to projects to exclude projects pending deletion | ||||||
|  | @ -45,6 +127,7 @@ v 8.7.0 (unreleased) | ||||||
|   - Use rugged to change HEAD in Project#change_head (P.S.V.R) |   - Use rugged to change HEAD in Project#change_head (P.S.V.R) | ||||||
|   - API: Ability to filter milestones by state `active` and `closed` (Robert Schilling) |   - API: Ability to filter milestones by state `active` and `closed` (Robert Schilling) | ||||||
|   - API: Fix milestone filtering by `iid` (Robert Schilling) |   - API: Fix milestone filtering by `iid` (Robert Schilling) | ||||||
|  |   - Make before_script and after_script overridable on per-job (Kamil Trzciński) | ||||||
|   - API: Delete notes of issues, snippets, and merge requests (Robert Schilling) |   - API: Delete notes of issues, snippets, and merge requests (Robert Schilling) | ||||||
|   - Implement 'Groups View' as an option for dashboard preferences !3379 (Elias W.) |   - Implement 'Groups View' as an option for dashboard preferences !3379 (Elias W.) | ||||||
|   - Better errors handling when creating milestones inside groups |   - Better errors handling when creating milestones inside groups | ||||||
|  | @ -52,34 +135,77 @@ v 8.7.0 (unreleased) | ||||||
|   - Hide `Create a group` help block when creating a new project in a group |   - Hide `Create a group` help block when creating a new project in a group | ||||||
|   - Implement 'TODOs View' as an option for dashboard preferences !3379 (Elias W.) |   - Implement 'TODOs View' as an option for dashboard preferences !3379 (Elias W.) | ||||||
|   - Allow issues and merge requests to be assigned to the author !2765 |   - Allow issues and merge requests to be assigned to the author !2765 | ||||||
|  |   - Make Ci::Commit to group only similar builds and make it stateful (ref, tag) | ||||||
|   - Gracefully handle notes on deleted commits in merge requests (Stan Hu) |   - Gracefully handle notes on deleted commits in merge requests (Stan Hu) | ||||||
|   - Decouple membership and notifications |   - Decouple membership and notifications | ||||||
|   - Fix creation of merge requests for orphaned branches (Stan Hu) |   - Fix creation of merge requests for orphaned branches (Stan Hu) | ||||||
|   - API: Ability to retrieve a single tag (Robert Schilling) |   - API: Ability to retrieve a single tag (Robert Schilling) | ||||||
|  |   - While signing up, don't persist the user password across form redisplays | ||||||
|   - Fall back to `In-Reply-To` and `References` headers when sub-addressing is not available (David Padilla) |   - Fall back to `In-Reply-To` and `References` headers when sub-addressing is not available (David Padilla) | ||||||
|   - Remove "Congratulations!" tweet button on newly-created project. (Connor Shea) |   - Remove "Congratulations!" tweet button on newly-created project. (Connor Shea) | ||||||
|   - Fix admin/projects when using visibility levels on search (PotHix) |   - Fix admin/projects when using visibility levels on search (PotHix) | ||||||
|   - Build status notifications |   - Build status notifications | ||||||
|  |   - Update email confirmation interface | ||||||
|   - API: Expose user location (Robert Schilling) |   - API: Expose user location (Robert Schilling) | ||||||
|   - API: Do not leak group existence via return code (Robert Schilling) |   - API: Do not leak group existence via return code (Robert Schilling) | ||||||
|   - ClosingIssueExtractor regex now also works with colons. e.g. "Fixes: #1234" !3591 |   - ClosingIssueExtractor regex now also works with colons. e.g. "Fixes: #1234" !3591 | ||||||
|   - Update number of Todos in the sidebar when it's marked as "Done". !3600 |   - Update number of Todos in the sidebar when it's marked as "Done". !3600 | ||||||
|  |   - Sanitize branch names created for confidential issues | ||||||
|   - API: Expose 'updated_at' for issue, snippet, and merge request notes (Robert Schilling) |   - API: Expose 'updated_at' for issue, snippet, and merge request notes (Robert Schilling) | ||||||
|   - API: User can leave a project through the API when not master or owner. !3613 |   - API: User can leave a project through the API when not master or owner. !3613 | ||||||
|   - Fix repository cache invalidation issue when project is recreated with an empty repo (Stan Hu) |   - Fix repository cache invalidation issue when project is recreated with an empty repo (Stan Hu) | ||||||
|   - Fix: Allow empty recipients list for builds emails service when pushed is added (Frank Groeneveld) |   - Fix: Allow empty recipients list for builds emails service when pushed is added (Frank Groeneveld) | ||||||
|   - Improved markdown forms |   - Improved markdown forms | ||||||
|  |   - Diff design updates (colors, button styles, etc) | ||||||
|  |   - Copying and pasting a diff no longer pastes the line numbers or +/- | ||||||
|  |   - Add null check to formData when updating profile content to fix Firefox bug | ||||||
|  |   - Disable spellcheck and autocorrect for username field in admin page | ||||||
|   - Delete tags using Rugged for performance reasons (Robert Schilling) |   - Delete tags using Rugged for performance reasons (Robert Schilling) | ||||||
|  |   - Add Slack notifications when Wiki is edited (Sebastian Klier) | ||||||
|   - Diffs load at the correct point when linking from from number |   - Diffs load at the correct point when linking from from number | ||||||
|   - Selected diff rows highlight |   - Selected diff rows highlight | ||||||
|   - Fix emoji categories in the emoji picker |   - Fix emoji categories in the emoji picker | ||||||
|  |   - API: Properly display annotated tags for GET /projects/:id/repository/tags (Robert Schilling) | ||||||
|   - Add encrypted credentials for imported projects and migrate old ones |   - Add encrypted credentials for imported projects and migrate old ones | ||||||
|  |   - Properly format all merge request references with ! rather than # !3740 (Ben Bodenmiller) | ||||||
|   - Author and participants are displayed first on users autocompletion |   - Author and participants are displayed first on users autocompletion | ||||||
|  |   - Show number sign on external issue reference text (Florent Baldino) | ||||||
|  |   - Updated print style for issues | ||||||
|  |   - Use GitHub Issue/PR number as iid to keep references | ||||||
|  |   - Import GitHub labels | ||||||
|  |   - Add option to filter by "Owned projects" on dashboard page | ||||||
|  |   - Import GitHub milestones | ||||||
|  |   - Execute system web hooks on push to the project | ||||||
|  |   - Allow enable/disable push events for system hooks | ||||||
|  |   - Fix GitHub project's link in the import page when provider has a custom URL | ||||||
|  |   - Add RAW build trace output and button on build page | ||||||
|  |   - Add incremental build trace update into CI API | ||||||
|  | 
 | ||||||
|  | v 8.6.8 | ||||||
|  |   - Prevent privilege escalation via "impersonate" feature | ||||||
|  |   - Prevent privilege escalation via notes API | ||||||
|  |   - Prevent privilege escalation via project webhook API | ||||||
|  |   - Prevent XSS via Git branch and tag names | ||||||
|  |   - Prevent XSS via custom issue tracker URL | ||||||
|  |   - Prevent XSS via `window.opener` | ||||||
|  |   - Prevent XSS via label drop-down | ||||||
|  |   - Prevent information disclosure via milestone API | ||||||
|  |   - Prevent information disclosure via snippet API | ||||||
|  |   - Prevent information disclosure via project labels | ||||||
|  |   - Prevent information disclosure via new merge request page | ||||||
|  | 
 | ||||||
|  | v 8.6.7 | ||||||
|  |   - Fix persistent XSS vulnerability in `commit_person_link` helper | ||||||
|  |   - Fix persistent XSS vulnerability in Label and Milestone dropdowns | ||||||
|  |   - Fix vulnerability that made it possible to enumerate private projects belonging to group | ||||||
| 
 | 
 | ||||||
| v 8.6.6 | v 8.6.6 | ||||||
|   - Expire the exists cache before deletion to ensure project dir actually exists (Stan Hu). !3413 |   - Expire the exists cache before deletion to ensure project dir actually exists (Stan Hu). !3413 | ||||||
|   - Fix error on language detection when repository has no HEAD (e.g., master branch) (Jeroen Bobbeldijk). !3654 |   - Fix error on language detection when repository has no HEAD (e.g., master branch) (Jeroen Bobbeldijk). !3654 | ||||||
|   - Fix revoking of authorized OAuth applications (Connor Shea). !3690 |   - Fix revoking of authorized OAuth applications (Connor Shea). !3690 | ||||||
|  |   - Fix error on language detection when repository has no HEAD (e.g., master branch). !3654 (Jeroen Bobbeldijk) | ||||||
|  |   - Issuable header is consistent between issues and merge requests | ||||||
|  |   - Improved spacing in issuable header on mobile | ||||||
| 
 | 
 | ||||||
| v 8.6.5 | v 8.6.5 | ||||||
|   - Fix importing from GitHub Enterprise. !3529 |   - Fix importing from GitHub Enterprise. !3529 | ||||||
|  | @ -209,6 +335,20 @@ v 8.6.0 | ||||||
|   - Trigger a todo for mentions on commits page |   - Trigger a todo for mentions on commits page | ||||||
|   - Let project owners and admins soft delete issues and merge requests |   - Let project owners and admins soft delete issues and merge requests | ||||||
| 
 | 
 | ||||||
|  | v 8.5.12 | ||||||
|  |   - Prevent privilege escalation via "impersonate" feature | ||||||
|  |   - Prevent privilege escalation via notes API | ||||||
|  |   - Prevent privilege escalation via project webhook API | ||||||
|  |   - Prevent XSS via Git branch and tag names | ||||||
|  |   - Prevent XSS via custom issue tracker URL | ||||||
|  |   - Prevent XSS via `window.opener` | ||||||
|  |   - Prevent information disclosure via snippet API | ||||||
|  |   - Prevent information disclosure via project labels | ||||||
|  |   - Prevent information disclosure via new merge request page | ||||||
|  | 
 | ||||||
|  | v 8.5.11 | ||||||
|  |   - Fix persistent XSS vulnerability in `commit_person_link` helper | ||||||
|  | 
 | ||||||
| v 8.5.10 | v 8.5.10 | ||||||
|   - Fix a 2FA authentication spoofing vulnerability. |   - Fix a 2FA authentication spoofing vulnerability. | ||||||
| 
 | 
 | ||||||
|  | @ -356,6 +496,20 @@ v 8.5.0 | ||||||
|   - Show label row when filtering issues or merge requests by label (Nuttanart Pornprasitsakul) |   - Show label row when filtering issues or merge requests by label (Nuttanart Pornprasitsakul) | ||||||
|   - Add Todos |   - Add Todos | ||||||
| 
 | 
 | ||||||
|  | v 8.4.10 | ||||||
|  |   - Prevent privilege escalation via "impersonate" feature | ||||||
|  |   - Prevent privilege escalation via notes API | ||||||
|  |   - Prevent privilege escalation via project webhook API | ||||||
|  |   - Prevent XSS via Git branch and tag names | ||||||
|  |   - Prevent XSS via custom issue tracker URL | ||||||
|  |   - Prevent XSS via `window.opener` | ||||||
|  |   - Prevent information disclosure via snippet API | ||||||
|  |   - Prevent information disclosure via project labels | ||||||
|  |   - Prevent information disclosure via new merge request page | ||||||
|  | 
 | ||||||
|  | v 8.4.9 | ||||||
|  |   - Fix persistent XSS vulnerability in `commit_person_link` helper | ||||||
|  | 
 | ||||||
| v 8.4.8 | v 8.4.8 | ||||||
|   - Fix a 2FA authentication spoofing vulnerability. |   - Fix a 2FA authentication spoofing vulnerability. | ||||||
| 
 | 
 | ||||||
|  | @ -478,6 +632,18 @@ v 8.4.0 | ||||||
|   - Add IP check against DNSBLs at account sign-up |   - Add IP check against DNSBLs at account sign-up | ||||||
|   - Added cache:key to .gitlab-ci.yml allowing to fine tune the caching |   - Added cache:key to .gitlab-ci.yml allowing to fine tune the caching | ||||||
| 
 | 
 | ||||||
|  | v 8.3.9 | ||||||
|  |   - Prevent privilege escalation via "impersonate" feature | ||||||
|  |   - Prevent privilege escalation via notes API | ||||||
|  |   - Prevent privilege escalation via project webhook API | ||||||
|  |   - Prevent XSS via custom issue tracker URL | ||||||
|  |   - Prevent XSS via `window.opener` | ||||||
|  |   - Prevent information disclosure via project labels | ||||||
|  |   - Prevent information disclosure via new merge request page | ||||||
|  | 
 | ||||||
|  | v 8.3.8 | ||||||
|  |   - Fix persistent XSS vulnerability in `commit_person_link` helper | ||||||
|  | 
 | ||||||
| v 8.3.7 | v 8.3.7 | ||||||
|   - Fix a 2FA authentication spoofing vulnerability. |   - Fix a 2FA authentication spoofing vulnerability. | ||||||
| 
 | 
 | ||||||
|  | @ -584,6 +750,17 @@ v 8.3.0 | ||||||
|   - Expose Git's version in the admin area |   - Expose Git's version in the admin area | ||||||
|   - Show "New Merge Request" buttons on canonical repos when you have a fork (Josh Frye) |   - Show "New Merge Request" buttons on canonical repos when you have a fork (Josh Frye) | ||||||
| 
 | 
 | ||||||
|  | v 8.2.5 | ||||||
|  |   - Prevent privilege escalation via "impersonate" feature | ||||||
|  |   - Prevent privilege escalation via notes API | ||||||
|  |   - Prevent privilege escalation via project webhook API | ||||||
|  |   - Prevent XSS via `window.opener` | ||||||
|  |   - Prevent information disclosure via project labels | ||||||
|  |   - Prevent information disclosure via new merge request page | ||||||
|  | 
 | ||||||
|  | v 8.2.4 | ||||||
|  |   - Bump Git version requirement to 2.7.4 | ||||||
|  | 
 | ||||||
| v 8.2.3 | v 8.2.3 | ||||||
|   - Fix application settings cache not expiring after changes (Stan Hu) |   - Fix application settings cache not expiring after changes (Stan Hu) | ||||||
|   - Fix Error 500s when creating global milestones with Unicode characters (Stan Hu) |   - Fix Error 500s when creating global milestones with Unicode characters (Stan Hu) | ||||||
|  |  | ||||||
|  | @ -38,7 +38,7 @@ source edition, and GitLab Enterprise Edition (EE) which is our commercial | ||||||
| edition. Throughout this guide you will see references to CE and EE for | edition. Throughout this guide you will see references to CE and EE for | ||||||
| abbreviation. | abbreviation. | ||||||
| 
 | 
 | ||||||
| If you have read this guide and want to know how the GitLab [core team][core-team] | If you have read this guide and want to know how the GitLab [core team] | ||||||
| operates please see [the GitLab contributing process](PROCESS.md). | operates please see [the GitLab contributing process](PROCESS.md). | ||||||
| 
 | 
 | ||||||
| ## Contributor license agreement | ## Contributor license agreement | ||||||
|  | @ -135,12 +135,23 @@ For feature proposals for EE, open an issue on the | ||||||
| 
 | 
 | ||||||
| In order to help track the feature proposals, we have created a | In order to help track the feature proposals, we have created a | ||||||
| [`feature proposal`][fpl] label. For the time being, users that are not members | [`feature proposal`][fpl] label. For the time being, users that are not members | ||||||
| of the project cannot add labels. You can instead ask one of the [core team][core-team] | of the project cannot add labels. You can instead ask one of the [core team] | ||||||
| members to add the label `feature proposal` to the issue. | members to add the label `feature proposal` to the issue or add the following | ||||||
|  | code snippet right after your description in a new line: `~"feature proposal"`. | ||||||
| 
 | 
 | ||||||
| Please keep feature proposals as small and simple as possible, complex ones | Please keep feature proposals as small and simple as possible, complex ones | ||||||
| might be edited to make them small and simple. | might be edited to make them small and simple. | ||||||
| 
 | 
 | ||||||
|  | You are encouraged to use the template below for feature proposals. | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | ## Description including problem, use cases, benefits, and/or goals | ||||||
|  | 
 | ||||||
|  | ## Proposal | ||||||
|  | 
 | ||||||
|  | ## Links / references | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
| For changes in the interface, it can be helpful to create a mockup first. | For changes in the interface, it can be helpful to create a mockup first. | ||||||
| If you want to create something yourself, consider opening an issue first to | If you want to create something yourself, consider opening an issue first to | ||||||
| discuss whether it is interesting to include this in GitLab. | discuss whether it is interesting to include this in GitLab. | ||||||
|  | @ -323,6 +334,7 @@ request is as follows: | ||||||
|    [shell command guidelines](doc/development/shell_commands.md) |    [shell command guidelines](doc/development/shell_commands.md) | ||||||
| 1. If your code creates new files on disk please read the | 1. If your code creates new files on disk please read the | ||||||
|    [shared files guidelines](doc/development/shared_files.md). |    [shared files guidelines](doc/development/shared_files.md). | ||||||
|  | 1. When writing commit messages please follow [these](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) [guidelines](http://chris.beams.io/posts/git-commit/). | ||||||
| 
 | 
 | ||||||
| The **official merge window** is in the beginning of the month from the 1st to | The **official merge window** is in the beginning of the month from the 1st to | ||||||
| the 7th day of the month. This is the best time to submit an MR and get | the 7th day of the month. This is the best time to submit an MR and get | ||||||
|  | @ -343,12 +355,11 @@ is it will be merged (quickly). After that you can send more MRs to enhance it. | ||||||
| For examples of feedback on merge requests please look at already | For examples of feedback on merge requests please look at already | ||||||
| [closed merge requests][closed-merge-requests]. If you would like quick feedback | [closed merge requests][closed-merge-requests]. If you would like quick feedback | ||||||
| on your merge request feel free to mention one of the Merge Marshalls in the | on your merge request feel free to mention one of the Merge Marshalls in the | ||||||
| [core team][core-team] or one of the | [core team] or one of the [Merge request coaches](https://about.gitlab.com/team/). | ||||||
| [Merge request coaches](https://about.gitlab.com/team/). |  | ||||||
| Please ensure that your merge request meets the contribution acceptance criteria. | Please ensure that your merge request meets the contribution acceptance criteria. | ||||||
| 
 | 
 | ||||||
| When having your code reviewed and when reviewing merge requests please take the | When having your code reviewed and when reviewing merge requests please take the | ||||||
| [Thoughtbot code review guide] into account. | [code review guidelines](doc/development/code_review.md) into account. | ||||||
| 
 | 
 | ||||||
| ### Merge request description format | ### Merge request description format | ||||||
| 
 | 
 | ||||||
|  | @ -496,7 +507,7 @@ reported by emailing `contact@gitlab.com`. | ||||||
| This Code of Conduct is adapted from the [Contributor Covenant][contributor-covenant], version 1.1.0, | This Code of Conduct is adapted from the [Contributor Covenant][contributor-covenant], version 1.1.0, | ||||||
| available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/). | available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/). | ||||||
| 
 | 
 | ||||||
| [core-team]: https://about.gitlab.com/core-team/ | [core team]: https://about.gitlab.com/core-team/ | ||||||
| [getting-help]: https://about.gitlab.com/getting-help/ | [getting-help]: https://about.gitlab.com/getting-help/ | ||||||
| [codetriage]: http://www.codetriage.com/gitlabhq/gitlabhq | [codetriage]: http://www.codetriage.com/gitlabhq/gitlabhq | ||||||
| [up-for-grabs]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=up-for-grabs | [up-for-grabs]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=up-for-grabs | ||||||
|  | @ -522,4 +533,3 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor | ||||||
| [gitlab-design]: https://gitlab.com/gitlab-org/gitlab-design | [gitlab-design]: https://gitlab.com/gitlab-org/gitlab-design | ||||||
| [free Antetype viewer (Mac OSX only)]: https://itunes.apple.com/us/app/antetype-viewer/id824152298?mt=12 | [free Antetype viewer (Mac OSX only)]: https://itunes.apple.com/us/app/antetype-viewer/id824152298?mt=12 | ||||||
| [`gitlab1.atype` file]: https://gitlab.com/gitlab-org/gitlab-design/tree/master/gitlab1.atype/ | [`gitlab1.atype` file]: https://gitlab.com/gitlab-org/gitlab-design/tree/master/gitlab1.atype/ | ||||||
| [Thoughtbot code review guide]: https://github.com/thoughtbot/guides/tree/master/code-review |  | ||||||
|  |  | ||||||
							
								
								
									
										18
									
								
								Gemfile
								
								
								
								
							
							
						
						
									
										18
									
								
								Gemfile
								
								
								
								
							|  | @ -19,8 +19,8 @@ gem "pg", '~> 0.18.2', group: :postgres | ||||||
| 
 | 
 | ||||||
| # Authentication libraries | # Authentication libraries | ||||||
| gem 'devise',                 '~> 3.5.4' | gem 'devise',                 '~> 3.5.4' | ||||||
|  | gem 'doorkeeper',             '~> 3.1' | ||||||
| gem 'devise-async',           '~> 0.9.0' | gem 'devise-async',           '~> 0.9.0' | ||||||
| gem 'doorkeeper',             '~> 2.2.0' |  | ||||||
| gem 'omniauth',               '~> 1.3.1' | gem 'omniauth',               '~> 1.3.1' | ||||||
| gem 'omniauth-auth0',         '~> 1.4.1' | gem 'omniauth-auth0',         '~> 1.4.1' | ||||||
| gem 'omniauth-azure-oauth2',  '~> 0.0.6' | gem 'omniauth-azure-oauth2',  '~> 0.0.6' | ||||||
|  | @ -178,7 +178,7 @@ gem 'ruby-fogbugz', '~> 0.2.1' | ||||||
| gem 'd3_rails', '~> 3.5.0' | gem 'd3_rails', '~> 3.5.0' | ||||||
| 
 | 
 | ||||||
| #cal-heatmap | #cal-heatmap | ||||||
| gem 'cal-heatmap-rails', '~> 3.5.0' | gem 'cal-heatmap-rails', '~> 3.6.0' | ||||||
| 
 | 
 | ||||||
| # underscore-rails | # underscore-rails | ||||||
| gem "underscore-rails", "~> 1.8.0" | gem "underscore-rails", "~> 1.8.0" | ||||||
|  | @ -190,6 +190,9 @@ gem 'babosa', '~> 1.0.2' | ||||||
| # Sanitizes SVG input | # Sanitizes SVG input | ||||||
| gem "loofah", "~> 2.0.3" | gem "loofah", "~> 2.0.3" | ||||||
| 
 | 
 | ||||||
|  | # Working with license | ||||||
|  | gem 'licensee', '~> 8.0.0' | ||||||
|  | 
 | ||||||
| # Protect against bruteforcing | # Protect against bruteforcing | ||||||
| gem "rack-attack", '~> 4.3.1' | gem "rack-attack", '~> 4.3.1' | ||||||
| 
 | 
 | ||||||
|  | @ -214,7 +217,7 @@ gem 'font-awesome-rails', '~> 4.2' | ||||||
| gem 'gitlab_emoji',       '~> 0.3.0' | gem 'gitlab_emoji',       '~> 0.3.0' | ||||||
| gem 'gon',                '~> 6.0.1' | gem 'gon',                '~> 6.0.1' | ||||||
| gem 'jquery-atwho-rails', '~> 1.3.2' | gem 'jquery-atwho-rails', '~> 1.3.2' | ||||||
| gem 'jquery-rails',       '~> 4.0.0' | gem 'jquery-rails',       '~> 4.1.0' | ||||||
| gem 'jquery-scrollto-rails', '~> 1.4.3' | gem 'jquery-scrollto-rails', '~> 1.4.3' | ||||||
| gem 'jquery-ui-rails',    '~> 5.0.0' | gem 'jquery-ui-rails',    '~> 5.0.0' | ||||||
| gem 'raphael-rails',      '~> 2.1.2' | gem 'raphael-rails',      '~> 2.1.2' | ||||||
|  | @ -239,8 +242,7 @@ group :development do | ||||||
|   gem "foreman" |   gem "foreman" | ||||||
|   gem 'brakeman', '~> 3.2.0', require: false |   gem 'brakeman', '~> 3.2.0', require: false | ||||||
| 
 | 
 | ||||||
|   gem "annotate", "~> 2.7.0" |   gem 'letter_opener_web', '~> 1.3.0' | ||||||
|   gem "letter_opener", '~> 1.1.2' |  | ||||||
|   gem 'quiet_assets', '~> 1.0.2' |   gem 'quiet_assets', '~> 1.0.2' | ||||||
|   gem 'rerun', '~> 0.11.0' |   gem 'rerun', '~> 0.11.0' | ||||||
|   gem 'bullet', require: false |   gem 'bullet', require: false | ||||||
|  | @ -267,7 +269,7 @@ group :development, :test do | ||||||
| 
 | 
 | ||||||
|   gem 'database_cleaner',   '~> 1.4.0' |   gem 'database_cleaner',   '~> 1.4.0' | ||||||
|   gem 'factory_girl_rails', '~> 4.6.0' |   gem 'factory_girl_rails', '~> 4.6.0' | ||||||
|   gem 'rspec-rails',        '~> 3.3.0' |   gem 'rspec-rails',        '~> 3.4.0' | ||||||
|   gem 'rspec-retry' |   gem 'rspec-retry' | ||||||
|   gem 'spinach-rails',      '~> 0.2.1' |   gem 'spinach-rails',      '~> 0.2.1' | ||||||
|   gem 'spinach-rerun-reporter', '~> 0.0.2' |   gem 'spinach-rerun-reporter', '~> 0.0.2' | ||||||
|  | @ -315,9 +317,9 @@ end | ||||||
| 
 | 
 | ||||||
| gem "newrelic_rpm", '~> 3.14' | gem "newrelic_rpm", '~> 3.14' | ||||||
| 
 | 
 | ||||||
| gem 'octokit', '~> 3.8.0' | gem 'octokit', '~> 4.3.0' | ||||||
| 
 | 
 | ||||||
| gem "mail_room", "~> 0.6.1" | gem "mail_room", "~> 0.7" | ||||||
| 
 | 
 | ||||||
| gem 'email_reply_parser', '~> 0.5.8' | gem 'email_reply_parser', '~> 0.5.8' | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										98
									
								
								Gemfile.lock
								
								
								
								
							
							
						
						
									
										98
									
								
								Gemfile.lock
								
								
								
								
							|  | @ -51,9 +51,6 @@ GEM | ||||||
|       activerecord (>= 3.0) |       activerecord (>= 3.0) | ||||||
|     akismet (2.0.0) |     akismet (2.0.0) | ||||||
|     allocations (1.0.4) |     allocations (1.0.4) | ||||||
|     annotate (2.7.0) |  | ||||||
|       activerecord (>= 3.2, < 6.0) |  | ||||||
|       rake (~> 10.4) |  | ||||||
|     arel (6.0.3) |     arel (6.0.3) | ||||||
|     asana (0.4.0) |     asana (0.4.0) | ||||||
|       faraday (~> 0.9) |       faraday (~> 0.9) | ||||||
|  | @ -103,7 +100,7 @@ GEM | ||||||
|       bundler (~> 1.2) |       bundler (~> 1.2) | ||||||
|       thor (~> 0.18) |       thor (~> 0.18) | ||||||
|     byebug (8.2.1) |     byebug (8.2.1) | ||||||
|     cal-heatmap-rails (3.5.1) |     cal-heatmap-rails (3.6.0) | ||||||
|     capybara (2.6.2) |     capybara (2.6.2) | ||||||
|       addressable |       addressable | ||||||
|       mime-types (>= 1.16) |       mime-types (>= 1.16) | ||||||
|  | @ -134,7 +131,7 @@ GEM | ||||||
|       execjs |       execjs | ||||||
|     coffee-script-source (1.10.0) |     coffee-script-source (1.10.0) | ||||||
|     colorize (0.7.7) |     colorize (0.7.7) | ||||||
|     concurrent-ruby (1.0.0) |     concurrent-ruby (1.0.2) | ||||||
|     connection_pool (2.2.0) |     connection_pool (2.2.0) | ||||||
|     coveralls (0.8.13) |     coveralls (0.8.13) | ||||||
|       json (~> 1.8) |       json (~> 1.8) | ||||||
|  | @ -175,7 +172,7 @@ GEM | ||||||
|     diff-lcs (1.2.5) |     diff-lcs (1.2.5) | ||||||
|     diffy (3.0.7) |     diffy (3.0.7) | ||||||
|     docile (1.1.5) |     docile (1.1.5) | ||||||
|     doorkeeper (2.2.2) |     doorkeeper (3.1.0) | ||||||
|       railties (>= 3.2) |       railties (>= 3.2) | ||||||
|     dropzonejs-rails (0.7.2) |     dropzonejs-rails (0.7.2) | ||||||
|       rails (> 3.1) |       rails (> 3.1) | ||||||
|  | @ -186,7 +183,7 @@ GEM | ||||||
|     encryptor (1.3.0) |     encryptor (1.3.0) | ||||||
|     equalizer (0.0.11) |     equalizer (0.0.11) | ||||||
|     erubis (2.7.0) |     erubis (2.7.0) | ||||||
|     escape_utils (1.1.0) |     escape_utils (1.1.1) | ||||||
|     eventmachine (1.0.8) |     eventmachine (1.0.8) | ||||||
|     excon (0.45.4) |     excon (0.45.4) | ||||||
|     execjs (2.6.0) |     execjs (2.6.0) | ||||||
|  | @ -336,7 +333,7 @@ GEM | ||||||
|       json |       json | ||||||
|     get_process_mem (0.2.0) |     get_process_mem (0.2.0) | ||||||
|     gherkin-ruby (0.3.2) |     gherkin-ruby (0.3.2) | ||||||
|     github-linguist (4.7.5) |     github-linguist (4.7.6) | ||||||
|       charlock_holmes (~> 0.7.3) |       charlock_holmes (~> 0.7.3) | ||||||
|       escape_utils (~> 1.1.0) |       escape_utils (~> 1.1.0) | ||||||
|       mime-types (>= 1.19) |       mime-types (>= 1.19) | ||||||
|  | @ -346,14 +343,14 @@ GEM | ||||||
|       flowdock (~> 0.7) |       flowdock (~> 0.7) | ||||||
|       gitlab-grit (>= 2.4.1) |       gitlab-grit (>= 2.4.1) | ||||||
|       multi_json |       multi_json | ||||||
|     gitlab-grit (2.7.3) |     gitlab-grit (2.8.1) | ||||||
|       charlock_holmes (~> 0.6) |       charlock_holmes (~> 0.6) | ||||||
|       diff-lcs (~> 1.1) |       diff-lcs (~> 1.1) | ||||||
|       mime-types (~> 1.15) |       mime-types (>= 1.16, < 3) | ||||||
|       posix-spawn (~> 0.3) |       posix-spawn (~> 0.3) | ||||||
|     gitlab_emoji (0.3.1) |     gitlab_emoji (0.3.1) | ||||||
|       gemojione (~> 2.2, >= 2.2.1) |       gemojione (~> 2.2, >= 2.2.1) | ||||||
|     gitlab_git (10.0.0) |     gitlab_git (10.1.0) | ||||||
|       activesupport (~> 4.0) |       activesupport (~> 4.0) | ||||||
|       charlock_holmes (~> 0.7.3) |       charlock_holmes (~> 0.7.3) | ||||||
|       github-linguist (~> 4.7.0) |       github-linguist (~> 4.7.0) | ||||||
|  | @ -431,8 +428,8 @@ GEM | ||||||
|       json |       json | ||||||
|     ipaddress (0.8.2) |     ipaddress (0.8.2) | ||||||
|     jquery-atwho-rails (1.3.2) |     jquery-atwho-rails (1.3.2) | ||||||
|     jquery-rails (4.0.5) |     jquery-rails (4.1.1) | ||||||
|       rails-dom-testing (~> 1.0) |       rails-dom-testing (>= 1, < 3) | ||||||
|       railties (>= 4.2.0) |       railties (>= 4.2.0) | ||||||
|       thor (>= 0.14, < 2.0) |       thor (>= 0.14, < 2.0) | ||||||
|     jquery-scrollto-rails (1.4.3) |     jquery-scrollto-rails (1.4.3) | ||||||
|  | @ -450,8 +447,14 @@ GEM | ||||||
|     kgio (2.10.0) |     kgio (2.10.0) | ||||||
|     launchy (2.4.3) |     launchy (2.4.3) | ||||||
|       addressable (~> 2.3) |       addressable (~> 2.3) | ||||||
|     letter_opener (1.1.2) |     letter_opener (1.4.1) | ||||||
|       launchy (~> 2.2) |       launchy (~> 2.2) | ||||||
|  |     letter_opener_web (1.3.0) | ||||||
|  |       actionmailer (>= 3.2) | ||||||
|  |       letter_opener (~> 1.0) | ||||||
|  |       railties (>= 3.2) | ||||||
|  |     licensee (8.0.0) | ||||||
|  |       rugged (>= 0.24b) | ||||||
|     listen (3.0.5) |     listen (3.0.5) | ||||||
|       rb-fsevent (>= 0.9.3) |       rb-fsevent (>= 0.9.3) | ||||||
|       rb-inotify (>= 0.9) |       rb-inotify (>= 0.9) | ||||||
|  | @ -461,9 +464,9 @@ GEM | ||||||
|       systemu (~> 2.6.2) |       systemu (~> 2.6.2) | ||||||
|     mail (2.6.4) |     mail (2.6.4) | ||||||
|       mime-types (>= 1.16, < 4) |       mime-types (>= 1.16, < 4) | ||||||
|     mail_room (0.6.1) |     mail_room (0.7.0) | ||||||
|     method_source (0.8.2) |     method_source (0.8.2) | ||||||
|     mime-types (1.25.1) |     mime-types (2.99.1) | ||||||
|     mimemagic (0.3.0) |     mimemagic (0.3.0) | ||||||
|     mini_portile2 (2.0.0) |     mini_portile2 (2.0.0) | ||||||
|     minitest (5.7.0) |     minitest (5.7.0) | ||||||
|  | @ -485,8 +488,8 @@ GEM | ||||||
|       multi_json (~> 1.3) |       multi_json (~> 1.3) | ||||||
|       multi_xml (~> 0.5) |       multi_xml (~> 0.5) | ||||||
|       rack (~> 1.2) |       rack (~> 1.2) | ||||||
|     octokit (3.8.0) |     octokit (4.3.0) | ||||||
|       sawyer (~> 0.6.0, >= 0.5.3) |       sawyer (~> 0.7.0, >= 0.5.3) | ||||||
|     omniauth (1.3.1) |     omniauth (1.3.1) | ||||||
|       hashie (>= 1.2, < 4) |       hashie (>= 1.2, < 4) | ||||||
|       rack (>= 1.0, < 3) |       rack (>= 1.0, < 3) | ||||||
|  | @ -627,7 +630,7 @@ GEM | ||||||
|     recaptcha (1.0.2) |     recaptcha (1.0.2) | ||||||
|       json |       json | ||||||
|     redcarpet (3.3.3) |     redcarpet (3.3.3) | ||||||
|     redis (3.2.2) |     redis (3.3.0) | ||||||
|     redis-actionpack (4.0.1) |     redis-actionpack (4.0.1) | ||||||
|       actionpack (~> 4) |       actionpack (~> 4) | ||||||
|       redis-rack (~> 1.5.0) |       redis-rack (~> 1.5.0) | ||||||
|  | @ -658,29 +661,29 @@ GEM | ||||||
|       chunky_png |       chunky_png | ||||||
|     rqrcode-rails3 (0.1.7) |     rqrcode-rails3 (0.1.7) | ||||||
|       rqrcode (>= 0.4.2) |       rqrcode (>= 0.4.2) | ||||||
|     rspec (3.3.0) |     rspec (3.4.0) | ||||||
|       rspec-core (~> 3.3.0) |       rspec-core (~> 3.4.0) | ||||||
|       rspec-expectations (~> 3.3.0) |       rspec-expectations (~> 3.4.0) | ||||||
|       rspec-mocks (~> 3.3.0) |       rspec-mocks (~> 3.4.0) | ||||||
|     rspec-core (3.3.2) |     rspec-core (3.4.4) | ||||||
|       rspec-support (~> 3.3.0) |       rspec-support (~> 3.4.0) | ||||||
|     rspec-expectations (3.3.1) |     rspec-expectations (3.4.0) | ||||||
|       diff-lcs (>= 1.2.0, < 2.0) |       diff-lcs (>= 1.2.0, < 2.0) | ||||||
|       rspec-support (~> 3.3.0) |       rspec-support (~> 3.4.0) | ||||||
|     rspec-mocks (3.3.2) |     rspec-mocks (3.4.1) | ||||||
|       diff-lcs (>= 1.2.0, < 2.0) |       diff-lcs (>= 1.2.0, < 2.0) | ||||||
|       rspec-support (~> 3.3.0) |       rspec-support (~> 3.4.0) | ||||||
|     rspec-rails (3.3.3) |     rspec-rails (3.4.2) | ||||||
|       actionpack (>= 3.0, < 4.3) |       actionpack (>= 3.0, < 4.3) | ||||||
|       activesupport (>= 3.0, < 4.3) |       activesupport (>= 3.0, < 4.3) | ||||||
|       railties (>= 3.0, < 4.3) |       railties (>= 3.0, < 4.3) | ||||||
|       rspec-core (~> 3.3.0) |       rspec-core (~> 3.4.0) | ||||||
|       rspec-expectations (~> 3.3.0) |       rspec-expectations (~> 3.4.0) | ||||||
|       rspec-mocks (~> 3.3.0) |       rspec-mocks (~> 3.4.0) | ||||||
|       rspec-support (~> 3.3.0) |       rspec-support (~> 3.4.0) | ||||||
|     rspec-retry (0.4.5) |     rspec-retry (0.4.5) | ||||||
|       rspec-core |       rspec-core | ||||||
|     rspec-support (3.3.0) |     rspec-support (3.4.1) | ||||||
|     rubocop (0.38.0) |     rubocop (0.38.0) | ||||||
|       parser (>= 2.3.0.6, < 3.0) |       parser (>= 2.3.0.6, < 3.0) | ||||||
|       powerpack (~> 0.1) |       powerpack (~> 0.1) | ||||||
|  | @ -712,8 +715,8 @@ GEM | ||||||
|       sprockets (>= 2.8, < 4.0) |       sprockets (>= 2.8, < 4.0) | ||||||
|       sprockets-rails (>= 2.0, < 4.0) |       sprockets-rails (>= 2.0, < 4.0) | ||||||
|       tilt (>= 1.1, < 3) |       tilt (>= 1.1, < 3) | ||||||
|     sawyer (0.6.0) |     sawyer (0.7.0) | ||||||
|       addressable (~> 2.3.5) |       addressable (>= 2.3.5, < 2.5) | ||||||
|       faraday (~> 0.8, < 0.10) |       faraday (~> 0.8, < 0.10) | ||||||
|     scss_lint (0.47.1) |     scss_lint (0.47.1) | ||||||
|       rake (>= 0.9, < 11) |       rake (>= 0.9, < 11) | ||||||
|  | @ -734,10 +737,9 @@ GEM | ||||||
|       rack |       rack | ||||||
|     shoulda-matchers (2.8.0) |     shoulda-matchers (2.8.0) | ||||||
|       activesupport (>= 3.0.0) |       activesupport (>= 3.0.0) | ||||||
|     sidekiq (4.0.1) |     sidekiq (4.1.2) | ||||||
|       concurrent-ruby (~> 1.0) |       concurrent-ruby (~> 1.0) | ||||||
|       connection_pool (~> 2.2, >= 2.2.0) |       connection_pool (~> 2.2, >= 2.2.0) | ||||||
|       json (~> 1.0) |  | ||||||
|       redis (~> 3.2, >= 3.2.1) |       redis (~> 3.2, >= 3.2.1) | ||||||
|     sidekiq-cron (0.4.0) |     sidekiq-cron (0.4.0) | ||||||
|       redis-namespace (>= 1.5.2) |       redis-namespace (>= 1.5.2) | ||||||
|  | @ -888,7 +890,6 @@ DEPENDENCIES | ||||||
|   after_commit_queue |   after_commit_queue | ||||||
|   akismet (~> 2.0) |   akismet (~> 2.0) | ||||||
|   allocations (~> 1.0) |   allocations (~> 1.0) | ||||||
|   annotate (~> 2.7.0) |  | ||||||
|   asana (~> 0.4.0) |   asana (~> 0.4.0) | ||||||
|   asciidoctor (~> 1.5.2) |   asciidoctor (~> 1.5.2) | ||||||
|   attr_encrypted (~> 1.3.4) |   attr_encrypted (~> 1.3.4) | ||||||
|  | @ -903,7 +904,7 @@ DEPENDENCIES | ||||||
|   bullet |   bullet | ||||||
|   bundler-audit |   bundler-audit | ||||||
|   byebug |   byebug | ||||||
|   cal-heatmap-rails (~> 3.5.0) |   cal-heatmap-rails (~> 3.6.0) | ||||||
|   capybara (~> 2.6.2) |   capybara (~> 2.6.2) | ||||||
|   capybara-screenshot (~> 1.0.0) |   capybara-screenshot (~> 1.0.0) | ||||||
|   carrierwave (~> 0.10.0) |   carrierwave (~> 0.10.0) | ||||||
|  | @ -920,7 +921,7 @@ DEPENDENCIES | ||||||
|   devise-async (~> 0.9.0) |   devise-async (~> 0.9.0) | ||||||
|   devise-two-factor (~> 2.0.0) |   devise-two-factor (~> 2.0.0) | ||||||
|   diffy (~> 3.0.3) |   diffy (~> 3.0.3) | ||||||
|   doorkeeper (~> 2.2.0) |   doorkeeper (~> 3.1) | ||||||
|   dropzonejs-rails (~> 0.7.1) |   dropzonejs-rails (~> 0.7.1) | ||||||
|   email_reply_parser (~> 0.5.8) |   email_reply_parser (~> 0.5.8) | ||||||
|   email_spec (~> 1.6.0) |   email_spec (~> 1.6.0) | ||||||
|  | @ -951,14 +952,15 @@ DEPENDENCIES | ||||||
|   httparty (~> 0.13.3) |   httparty (~> 0.13.3) | ||||||
|   influxdb (~> 0.2) |   influxdb (~> 0.2) | ||||||
|   jquery-atwho-rails (~> 1.3.2) |   jquery-atwho-rails (~> 1.3.2) | ||||||
|   jquery-rails (~> 4.0.0) |   jquery-rails (~> 4.1.0) | ||||||
|   jquery-scrollto-rails (~> 1.4.3) |   jquery-scrollto-rails (~> 1.4.3) | ||||||
|   jquery-turbolinks (~> 2.1.0) |   jquery-turbolinks (~> 2.1.0) | ||||||
|   jquery-ui-rails (~> 5.0.0) |   jquery-ui-rails (~> 5.0.0) | ||||||
|   kaminari (~> 0.16.3) |   kaminari (~> 0.16.3) | ||||||
|   letter_opener (~> 1.1.2) |   letter_opener_web (~> 1.3.0) | ||||||
|  |   licensee (~> 8.0.0) | ||||||
|   loofah (~> 2.0.3) |   loofah (~> 2.0.3) | ||||||
|   mail_room (~> 0.6.1) |   mail_room (~> 0.7) | ||||||
|   method_source (~> 0.8) |   method_source (~> 0.8) | ||||||
|   minitest (~> 5.7.0) |   minitest (~> 5.7.0) | ||||||
|   mousetrap-rails (~> 1.4.6) |   mousetrap-rails (~> 1.4.6) | ||||||
|  | @ -968,7 +970,7 @@ DEPENDENCIES | ||||||
|   newrelic_rpm (~> 3.14) |   newrelic_rpm (~> 3.14) | ||||||
|   nokogiri (~> 1.6.7, >= 1.6.7.2) |   nokogiri (~> 1.6.7, >= 1.6.7.2) | ||||||
|   oauth2 (~> 1.0.0) |   oauth2 (~> 1.0.0) | ||||||
|   octokit (~> 3.8.0) |   octokit (~> 4.3.0) | ||||||
|   omniauth (~> 1.3.1) |   omniauth (~> 1.3.1) | ||||||
|   omniauth-auth0 (~> 1.4.1) |   omniauth-auth0 (~> 1.4.1) | ||||||
|   omniauth-azure-oauth2 (~> 0.0.6) |   omniauth-azure-oauth2 (~> 0.0.6) | ||||||
|  | @ -1008,7 +1010,7 @@ DEPENDENCIES | ||||||
|   responders (~> 2.0) |   responders (~> 2.0) | ||||||
|   rouge (~> 1.10.1) |   rouge (~> 1.10.1) | ||||||
|   rqrcode-rails3 (~> 0.1.7) |   rqrcode-rails3 (~> 0.1.7) | ||||||
|   rspec-rails (~> 3.3.0) |   rspec-rails (~> 3.4.0) | ||||||
|   rspec-retry |   rspec-retry | ||||||
|   rubocop (~> 0.38.0) |   rubocop (~> 0.38.0) | ||||||
|   ruby-fogbugz (~> 0.2.1) |   ruby-fogbugz (~> 0.2.1) | ||||||
|  | @ -1055,4 +1057,4 @@ DEPENDENCIES | ||||||
|   wikicloth (= 0.8.1) |   wikicloth (= 0.8.1) | ||||||
| 
 | 
 | ||||||
| BUNDLED WITH | BUNDLED WITH | ||||||
|    1.11.2 |    1.12.3 | ||||||
|  |  | ||||||
							
								
								
									
										22
									
								
								PROCESS.md
								
								
								
								
							
							
						
						
									
										22
									
								
								PROCESS.md
								
								
								
								
							|  | @ -59,7 +59,7 @@ core team members will mention this person. | ||||||
| 
 | 
 | ||||||
| Workflow labels are purposely not very detailed since that would be hard to keep | Workflow labels are purposely not very detailed since that would be hard to keep | ||||||
| updated as you would need to re-evaluate them after every comment. We optionally | updated as you would need to re-evaluate them after every comment. We optionally | ||||||
| use functional labels on demand when want to group related issues to get an | use functional labels on demand when we want to group related issues to get an | ||||||
| overview (for example all issues related to RVM, to tackle them in one go) and | overview (for example all issues related to RVM, to tackle them in one go) and | ||||||
| to add details to the issue. | to add details to the issue. | ||||||
| 
 | 
 | ||||||
|  | @ -73,6 +73,7 @@ in support or comment for further detail. Do not use `feature request`. | ||||||
| - ~bug is an issue reporting undesirable or incorrect behavior. | - ~bug is an issue reporting undesirable or incorrect behavior. | ||||||
| - ~customer is an issue reported by enterprise subscribers. This label should | - ~customer is an issue reported by enterprise subscribers. This label should | ||||||
| be accompanied by *bug* or *feature proposal* labels. | be accompanied by *bug* or *feature proposal* labels. | ||||||
|  | 
 | ||||||
| Example workflow: when a UX designer provided a design but it needs frontend work they remove the UX label and add the frontend label. | Example workflow: when a UX designer provided a design but it needs frontend work they remove the UX label and add the frontend label. | ||||||
| 
 | 
 | ||||||
| ## Functional labels | ## Functional labels | ||||||
|  | @ -105,6 +106,25 @@ sensitive as to how you word things. Use Emoji to express your feelings (heart, | ||||||
| star, smile, etc.). Some good tips about giving feedback to merge requests is in | star, smile, etc.). Some good tips about giving feedback to merge requests is in | ||||||
| the [Thoughtbot code review guide]. | the [Thoughtbot code review guide]. | ||||||
| 
 | 
 | ||||||
|  | ## Feature Freeze | ||||||
|  | 
 | ||||||
|  | 5 working days before the 22nd the stable branches for the upcoming release will | ||||||
|  | be frozen for major changes. Merge requests may still be merged into master | ||||||
|  | during this period. By freezing the stable branches prior to a release there's | ||||||
|  | no need to worry about last minute merge requests potentially breaking a lot of | ||||||
|  | things. | ||||||
|  | 
 | ||||||
|  | What is considered to be a major change is determined on a case by case basis as | ||||||
|  | this definition depends very much on the context of changes. For example, a 5 | ||||||
|  | line change might have a big impact on the entire application. Ultimately the | ||||||
|  | decision will be made by those reviewing a merge request and the release | ||||||
|  | manager. | ||||||
|  | 
 | ||||||
|  | During the feature freeze all merge requests that are meant to go into the next | ||||||
|  | release should have the correct milestone assigned _and_ have the label | ||||||
|  | ~"Pick into Stable" set. Merge requests without a milestone and this label will | ||||||
|  | not be merged into any stable branches. | ||||||
|  | 
 | ||||||
| ## Copy & paste responses | ## Copy & paste responses | ||||||
| 
 | 
 | ||||||
| ### Improperly formatted issue | ### Improperly formatted issue | ||||||
|  |  | ||||||
							
								
								
									
										12
									
								
								README.md
								
								
								
								
							
							
						
						
									
										12
									
								
								README.md
								
								
								
								
							|  | @ -1,6 +1,6 @@ | ||||||
| # GitLab | # GitLab | ||||||
| 
 | 
 | ||||||
| [](https://ci.gitlab.com/projects/1?ref=master) | [](https://gitlab.com/gitlab-org/gitlab-ce/commits/master) | ||||||
| [](https://semaphoreci.com/gitlabhq/gitlabhq) | [](https://semaphoreci.com/gitlabhq/gitlabhq) | ||||||
| [](https://codeclimate.com/github/gitlabhq/gitlabhq) | [](https://codeclimate.com/github/gitlabhq/gitlabhq) | ||||||
| [](https://coveralls.io/r/gitlabhq/gitlabhq?branch=master) | [](https://coveralls.io/r/gitlabhq/gitlabhq?branch=master) | ||||||
|  | @ -20,6 +20,10 @@ To see how GitLab looks please see the [features page on our website](https://ab | ||||||
| - Completely free and open source (MIT Expat license) | - Completely free and open source (MIT Expat license) | ||||||
| - Powered by [Ruby on Rails](https://github.com/rails/rails) | - Powered by [Ruby on Rails](https://github.com/rails/rails) | ||||||
| 
 | 
 | ||||||
|  | ## Hiring | ||||||
|  | 
 | ||||||
|  | We're hiring developers, support people, and production engineers all the time, please see our [jobs page](https://about.gitlab.com/jobs/). | ||||||
|  | 
 | ||||||
| ## Editions | ## Editions | ||||||
| 
 | 
 | ||||||
| There are two editions of GitLab: | There are two editions of GitLab: | ||||||
|  | @ -31,11 +35,11 @@ There are two editions of GitLab: | ||||||
| 
 | 
 | ||||||
| On [about.gitlab.com](https://about.gitlab.com/) you can find more information about: | On [about.gitlab.com](https://about.gitlab.com/) you can find more information about: | ||||||
| 
 | 
 | ||||||
| - [Subscriptions](https://about.gitlab.com/subscription/) | - [Subscriptions](https://about.gitlab.com/pricing/) | ||||||
| - [Consultancy](https://about.gitlab.com/consultancy/) | - [Consultancy](https://about.gitlab.com/consultancy/) | ||||||
| - [Community](https://about.gitlab.com/community/) | - [Community](https://about.gitlab.com/community/) | ||||||
| - [Hosted GitLab.com](https://about.gitlab.com/gitlab-com/) use GitLab as a free service | - [Hosted GitLab.com](https://about.gitlab.com/gitlab-com/) use GitLab as a free service | ||||||
| - [GitLab Enterprise Edition](https://about.gitlab.com/gitlab-ee/) with additional features aimed at larger organizations. | - [GitLab Enterprise Edition](https://about.gitlab.com/features/#enterprise) with additional features aimed at larger organizations. | ||||||
| - [GitLab CI](https://about.gitlab.com/gitlab-ci/) a continuous integration (CI) server that is easy to integrate with GitLab. | - [GitLab CI](https://about.gitlab.com/gitlab-ci/) a continuous integration (CI) server that is easy to integrate with GitLab. | ||||||
| 
 | 
 | ||||||
| ## Requirements | ## Requirements | ||||||
|  | @ -80,7 +84,7 @@ There are a lot of [third-party applications integrating with GitLab](https://ab | ||||||
| 
 | 
 | ||||||
| ## GitLab release cycle | ## GitLab release cycle | ||||||
| 
 | 
 | ||||||
| For more information about the release process see the [release documentation](http://doc.gitlab.com/ce/release/). | For more information about the release process see the [release documentation](https://gitlab.com/gitlab-org/release-tools/blob/master/README.md). | ||||||
| 
 | 
 | ||||||
| ## Upgrading | ## Upgrading | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ | ||||||
|   group_projects_path: "/api/:version/groups/:id/projects.json" |   group_projects_path: "/api/:version/groups/:id/projects.json" | ||||||
|   projects_path: "/api/:version/projects.json" |   projects_path: "/api/:version/projects.json" | ||||||
|   labels_path: "/api/:version/projects/:id/labels" |   labels_path: "/api/:version/projects/:id/labels" | ||||||
|  |   license_path: "/api/:version/licenses/:key" | ||||||
| 
 | 
 | ||||||
|   group: (group_id, callback) -> |   group: (group_id, callback) -> | ||||||
|     url = Api.buildUrl(Api.group_path) |     url = Api.buildUrl(Api.group_path) | ||||||
|  | @ -92,6 +93,16 @@ | ||||||
|     ).done (projects) -> |     ).done (projects) -> | ||||||
|       callback(projects) |       callback(projects) | ||||||
| 
 | 
 | ||||||
|  |   # Return text for a specific license | ||||||
|  |   licenseText: (key, data, callback) -> | ||||||
|  |     url = Api.buildUrl(Api.license_path).replace(':key', key) | ||||||
|  | 
 | ||||||
|  |     $.ajax( | ||||||
|  |       url: url | ||||||
|  |       data: data | ||||||
|  |     ).done (license) -> | ||||||
|  |       callback(license) | ||||||
|  | 
 | ||||||
|   buildUrl: (url) -> |   buildUrl: (url) -> | ||||||
|     url = gon.relative_url_root + url if gon.relative_url_root? |     url = gon.relative_url_root + url if gon.relative_url_root? | ||||||
|     return url.replace(':version', gon.api_version) |     return url.replace(':version', gon.api_version) | ||||||
|  |  | ||||||
|  | @ -174,7 +174,7 @@ $ -> | ||||||
|   $('.trigger-submit').on 'change', -> |   $('.trigger-submit').on 'change', -> | ||||||
|     $(@).parents('form').submit() |     $(@).parents('form').submit() | ||||||
| 
 | 
 | ||||||
|   gl.utils.localTimeAgo($('abbr.timeago, .js-timeago'), false) |   gl.utils.localTimeAgo($('abbr.timeago, .js-timeago'), true) | ||||||
| 
 | 
 | ||||||
|   # Flash |   # Flash | ||||||
|   if (flash = $(".flash-container")).length > 0 |   if (flash = $(".flash-container")).length > 0 | ||||||
|  | @ -204,6 +204,7 @@ $ -> | ||||||
|     $('.header-content .title').toggle() |     $('.header-content .title').toggle() | ||||||
|     $('.header-content .navbar-collapse').toggle() |     $('.header-content .navbar-collapse').toggle() | ||||||
|     $('.navbar-toggle').toggleClass('active') |     $('.navbar-toggle').toggleClass('active') | ||||||
|  |     $('.navbar-toggle i').toggleClass("fa-angle-right fa-angle-left") | ||||||
| 
 | 
 | ||||||
|   # Show/hide comments on diff |   # Show/hide comments on diff | ||||||
|   $("body").on "click", ".js-toggle-diff-comments", (e) -> |   $("body").on "click", ".js-toggle-diff-comments", (e) -> | ||||||
|  |  | ||||||
|  | @ -105,7 +105,7 @@ class @AwardsHandler | ||||||
|     @postEmoji awardUrl, emoji, => |     @postEmoji awardUrl, emoji, => | ||||||
|       @addAwardToEmojiBar(emoji) |       @addAwardToEmojiBar(emoji) | ||||||
| 
 | 
 | ||||||
|     $(".emoji-menu").removeClass "is-visible" |     $('.emoji-menu').removeClass 'is-visible' | ||||||
| 
 | 
 | ||||||
|   addAwardToEmojiBar: (emoji) -> |   addAwardToEmojiBar: (emoji) -> | ||||||
|     @addEmojiToFrequentlyUsedList(emoji) |     @addEmojiToFrequentlyUsedList(emoji) | ||||||
|  | @ -168,7 +168,7 @@ class @AwardsHandler | ||||||
|     @resetTooltip(award_block) |     @resetTooltip(award_block) | ||||||
| 
 | 
 | ||||||
|   resetTooltip: (award) -> |   resetTooltip: (award) -> | ||||||
|     award.tooltip("destroy") |     award.tooltip('destroy') | ||||||
| 
 | 
 | ||||||
|     # "destroy" call is asynchronous and there is no appropriate callback on it, this is why we need to set timeout. |     # "destroy" call is asynchronous and there is no appropriate callback on it, this is why we need to set timeout. | ||||||
|     setTimeout (-> |     setTimeout (-> | ||||||
|  | @ -194,13 +194,13 @@ class @AwardsHandler | ||||||
|       $currentBlock.removeClass 'hidden' |       $currentBlock.removeClass 'hidden' | ||||||
| 
 | 
 | ||||||
|   resolveNameToCssClass: (emoji) -> |   resolveNameToCssClass: (emoji) -> | ||||||
|     emoji_icon = $(".emoji-menu-content [data-emoji='#{emoji}']") |     emojiIcon = $(".emoji-menu-content [data-emoji='#{emoji}']") | ||||||
| 
 | 
 | ||||||
|     if emoji_icon.length > 0 |     if emojiIcon.length > 0 | ||||||
|       unicodeName = emoji_icon.data("unicode-name") |       unicodeName = emojiIcon.data('unicode-name') | ||||||
|     else |     else | ||||||
|       # Find by alias |       # Find by alias | ||||||
|       unicodeName = $(".emoji-menu-content [data-aliases*=':#{emoji}:']").data("unicode-name") |       unicodeName = $(".emoji-menu-content [data-aliases*=':#{emoji}:']").data('unicode-name') | ||||||
| 
 | 
 | ||||||
|     "emoji-#{unicodeName}" |     "emoji-#{unicodeName}" | ||||||
| 
 | 
 | ||||||
|  | @ -217,45 +217,42 @@ class @AwardsHandler | ||||||
|       scrollTop: $('.awards').offset().top - 80 |       scrollTop: $('.awards').offset().top - 80 | ||||||
|     }, 200) |     }, 200) | ||||||
| 
 | 
 | ||||||
|   normilizeEmojiName: (emoji) -> |  | ||||||
|     @aliases[emoji] || emoji |  | ||||||
| 
 |  | ||||||
|   addEmojiToFrequentlyUsedList: (emoji) -> |   addEmojiToFrequentlyUsedList: (emoji) -> | ||||||
|     frequently_used_emojis = @getFrequentlyUsedEmojis() |     frequentlyUsedEmojis = @getFrequentlyUsedEmojis() | ||||||
|     frequently_used_emojis.push(emoji) |     frequentlyUsedEmojis.push(emoji) | ||||||
|     $.cookie('frequently_used_emojis', frequently_used_emojis.join(","), { expires: 365 }) |     $.cookie('frequently_used_emojis', frequentlyUsedEmojis.join(','), { expires: 365 }) | ||||||
| 
 | 
 | ||||||
|   getFrequentlyUsedEmojis: -> |   getFrequentlyUsedEmojis: -> | ||||||
|     frequently_used_emojis = ($.cookie('frequently_used_emojis') || "").split(",") |     frequentlyUsedEmojis = ($.cookie('frequently_used_emojis') || '').split(',') | ||||||
|     _.compact(_.uniq(frequently_used_emojis)) |     _.compact(_.uniq(frequentlyUsedEmojis)) | ||||||
| 
 | 
 | ||||||
|   renderFrequentlyUsedBlock: -> |   renderFrequentlyUsedBlock: -> | ||||||
|     if $.cookie('frequently_used_emojis') |     if $.cookie('frequently_used_emojis') | ||||||
|       frequently_used_emojis = @getFrequentlyUsedEmojis() |       frequentlyUsedEmojis = @getFrequentlyUsedEmojis() | ||||||
| 
 | 
 | ||||||
|       ul = $("<ul class='clearfix emoji-menu-list'>") |       ul = $("<ul class='clearfix emoji-menu-list'>") | ||||||
| 
 | 
 | ||||||
|       for emoji in frequently_used_emojis |       for emoji in frequently_used_emojis | ||||||
|         $(".emoji-menu-content [data-emoji='#{emoji}']").closest("li").clone().appendTo(ul) |         $(".emoji-menu-content [data-emoji='#{emoji}']").closest("li").clone().appendTo(ul) | ||||||
| 
 | 
 | ||||||
|       $("input.emoji-search").after(ul).after($("<h5>").text("Frequently used")) |       $('input.emoji-search').after(ul).after($('<h5>').text('Frequently used')) | ||||||
| 
 | 
 | ||||||
|   setupSearch: -> |   setupSearch: -> | ||||||
|     $("input.emoji-search").on 'keyup', (ev) => |     $('input.emoji-search').keyup (ev) => | ||||||
|       term = $(ev.target).val() |       term = $(ev.target).val() | ||||||
| 
 | 
 | ||||||
|       # Clean previous search results |       # Clean previous search results | ||||||
|       $("ul.emoji-menu-search, h5.emoji-search").remove() |       $('ul.emoji-menu-search, h5.emoji-search').remove() | ||||||
| 
 | 
 | ||||||
|       if term |       if term | ||||||
|         # Generate a search result block |         # Generate a search result block | ||||||
|         h5 = $("<h5>").text("Search results").addClass("emoji-search") |         h5 = $('<h5>').text('Search results').addClass('emoji-search') | ||||||
|         found_emojis = @searchEmojis(term).show() |         foundEmojis = @searchEmojis(term).show() | ||||||
|         ul = $("<ul>").addClass("emoji-menu-list emoji-menu-search").append(found_emojis) |         ul = $('<ul>').addClass('emoji-menu-list emoji-menu-search').append(foundEmojis) | ||||||
|         $(".emoji-menu-content ul, .emoji-menu-content h5").hide() |         $('.emoji-menu-content ul, .emoji-menu-content h5').hide() | ||||||
|         $(".emoji-menu-content").append(h5).append(ul) |         $('.emoji-menu-content').append(h5).append(ul) | ||||||
|       else |       else | ||||||
|         $(".emoji-menu-content").children().show() |         $('.emoji-menu-content').children().show() | ||||||
| 
 | 
 | ||||||
|   searchEmojis: (term)-> |   searchEmojis: (term)-> | ||||||
|     $(".emoji-menu-content [data-emoji*='#{term}']").closest("li").clone() |     $(".emoji-menu-content [data-emoji*='#{term}']").closest("li").clone() | ||||||
|  |  | ||||||
|  | @ -0,0 +1,30 @@ | ||||||
|  | class @BlobLicenseSelector | ||||||
|  |   licenseRegex: /^(.+\/)?(licen[sc]e|copying)($|\.)/i | ||||||
|  | 
 | ||||||
|  |   constructor: (editor) -> | ||||||
|  |     @$licenseSelector = $('.js-license-selector') | ||||||
|  |     $fileNameInput = $('#file_name') | ||||||
|  | 
 | ||||||
|  |     initialFileNameValue = if $fileNameInput.length | ||||||
|  |       $fileNameInput.val() | ||||||
|  |     else if $('.editor-file-name').length | ||||||
|  |       $('.editor-file-name').text().trim() | ||||||
|  | 
 | ||||||
|  |     @toggleLicenseSelector(initialFileNameValue) | ||||||
|  | 
 | ||||||
|  |     if $fileNameInput | ||||||
|  |       $fileNameInput.on 'keyup blur', (e) => | ||||||
|  |         @toggleLicenseSelector($(e.target).val()) | ||||||
|  | 
 | ||||||
|  |     $('select.license-select').on 'change', (e) -> | ||||||
|  |       data = | ||||||
|  |         project: $(this).data('project') | ||||||
|  |         fullname: $(this).data('fullname') | ||||||
|  |       Api.licenseText $(this).val(), data, (license) -> | ||||||
|  |         editor.setValue(license.content, -1) | ||||||
|  | 
 | ||||||
|  |   toggleLicenseSelector: (fileName) => | ||||||
|  |     if @licenseRegex.test(fileName) | ||||||
|  |       @$licenseSelector.show() | ||||||
|  |     else | ||||||
|  |       @$licenseSelector.hide() | ||||||
|  | @ -1,44 +1,39 @@ | ||||||
| class @EditBlob | class @EditBlob | ||||||
|   constructor: (assets_path, mode)-> |   constructor: (assets_path, ace_mode = null) -> | ||||||
|     ace.config.set "modePath", assets_path + '/ace' |     ace.config.set "modePath", "#{assets_path}/ace" | ||||||
|     ace.config.loadModule "ace/ext/searchbox" |     ace.config.loadModule "ace/ext/searchbox" | ||||||
|     if mode |     @editor = ace.edit("editor") | ||||||
|       ace_mode = mode |     @editor.focus() | ||||||
|     editor = ace.edit("editor") |     @editor.getSession().setMode "ace/mode/#{ace_mode}" if ace_mode | ||||||
|     editor.focus() |  | ||||||
|     @editor = editor |  | ||||||
| 
 |  | ||||||
|     if ace_mode |  | ||||||
|       editor.getSession().setMode "ace/mode/" + ace_mode |  | ||||||
| 
 | 
 | ||||||
|     # Before a form submission, move the content from the Ace editor into the |     # Before a form submission, move the content from the Ace editor into the | ||||||
|     # submitted textarea |     # submitted textarea | ||||||
|     $('form').submit -> |     $('form').submit => | ||||||
|       $("#file-content").val(editor.getValue()) |       $("#file-content").val(@editor.getValue()) | ||||||
| 
 | 
 | ||||||
|     editModePanes = $(".js-edit-mode-pane") |     @initModePanesAndLinks() | ||||||
|     editModeLinks = $(".js-edit-mode a") |     new BlobLicenseSelector(@editor) | ||||||
|     editModeLinks.click (event) -> |  | ||||||
|       event.preventDefault() |  | ||||||
|       currentLink = $(this) |  | ||||||
|       paneId = currentLink.attr("href") |  | ||||||
|       currentPane = editModePanes.filter(paneId) |  | ||||||
|       editModeLinks.parent().removeClass "active hover" |  | ||||||
|       currentLink.parent().addClass "active hover" |  | ||||||
|       editModePanes.hide() |  | ||||||
|       if paneId is "#preview" |  | ||||||
|         currentPane.fadeIn 200 |  | ||||||
|         $.post currentLink.data("preview-url"), |  | ||||||
|           content: editor.getValue() |  | ||||||
|         , (response) -> |  | ||||||
|           currentPane.empty().append response |  | ||||||
|           currentPane.syntaxHighlight() |  | ||||||
|           return |  | ||||||
| 
 | 
 | ||||||
|       else |   initModePanesAndLinks: -> | ||||||
|         currentPane.fadeIn 200 |     @$editModePanes = $(".js-edit-mode-pane") | ||||||
|         editor.focus() |     @$editModeLinks = $(".js-edit-mode a") | ||||||
|       return |     @$editModeLinks.click @editModeLinkClickHandler | ||||||
| 
 | 
 | ||||||
|   editor: -> |   editModeLinkClickHandler: (event) => | ||||||
|     return @editor |     event.preventDefault() | ||||||
|  |     currentLink = $(event.target) | ||||||
|  |     paneId = currentLink.attr("href") | ||||||
|  |     currentPane = @$editModePanes.filter(paneId) | ||||||
|  |     @$editModeLinks.parent().removeClass "active hover" | ||||||
|  |     currentLink.parent().addClass "active hover" | ||||||
|  |     @$editModePanes.hide() | ||||||
|  |     currentPane.fadeIn 200 | ||||||
|  |     if paneId is "#preview" | ||||||
|  |       $.post currentLink.data("preview-url"), | ||||||
|  |         content: @editor.getValue() | ||||||
|  |       , (response) -> | ||||||
|  |         currentPane.empty().append response | ||||||
|  |         currentPane.syntaxHighlight() | ||||||
|  | 
 | ||||||
|  |     else | ||||||
|  |       @editor.focus() | ||||||
|  |  | ||||||
|  | @ -1,20 +0,0 @@ | ||||||
| class @NewBlob |  | ||||||
|   constructor: (assets_path, mode)-> |  | ||||||
|     ace.config.set "modePath", assets_path + '/ace' |  | ||||||
|     ace.config.loadModule "ace/ext/searchbox" |  | ||||||
|     if mode |  | ||||||
|       ace_mode = mode |  | ||||||
|     editor = ace.edit("editor") |  | ||||||
|     editor.focus() |  | ||||||
|     @editor = editor |  | ||||||
| 
 |  | ||||||
|     if ace_mode |  | ||||||
|       editor.getSession().setMode "ace/mode/" + ace_mode |  | ||||||
| 
 |  | ||||||
|     # Before a form submission, move the content from the Ace editor into the |  | ||||||
|     # submitted textarea |  | ||||||
|     $('form').submit -> |  | ||||||
|       $("#file-content").val(editor.getValue()) |  | ||||||
| 
 |  | ||||||
|   editor: -> |  | ||||||
|     return @editor |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| class @CommitsList | class @CommitsList | ||||||
|   @timer = null |   @timer = null | ||||||
| 
 | 
 | ||||||
|   @init: (ref, limit) -> |   @init: (limit) -> | ||||||
|     $("body").on "click", ".day-commits-table li.commit", (event) -> |     $("body").on "click", ".day-commits-table li.commit", (event) -> | ||||||
|       if event.target.nodeName != "A" |       if event.target.nodeName != "A" | ||||||
|         location.href = $(this).attr("url") |         location.href = $(this).attr("url") | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ class Dispatcher | ||||||
|     switch page |     switch page | ||||||
|       when 'projects:issues:index' |       when 'projects:issues:index' | ||||||
|         Issues.init() |         Issues.init() | ||||||
|  |         Issuable.init() | ||||||
|         shortcut_handler = new ShortcutsNavigation() |         shortcut_handler = new ShortcutsNavigation() | ||||||
|       when 'projects:issues:show' |       when 'projects:issues:show' | ||||||
|         new Issue() |         new Issue() | ||||||
|  | @ -59,7 +60,7 @@ class Dispatcher | ||||||
|         new ZenMode() |         new ZenMode() | ||||||
|       when 'projects:merge_requests:index' |       when 'projects:merge_requests:index' | ||||||
|         shortcut_handler = new ShortcutsNavigation() |         shortcut_handler = new ShortcutsNavigation() | ||||||
|         MergeRequests.init() |         Issuable.init() | ||||||
|       when 'dashboard:activity' |       when 'dashboard:activity' | ||||||
|         new Activities() |         new Activities() | ||||||
|       when 'dashboard:projects:starred' |       when 'dashboard:projects:starred' | ||||||
|  | @ -109,6 +110,8 @@ class Dispatcher | ||||||
|         new BuildArtifacts() |         new BuildArtifacts() | ||||||
|       when 'projects:group_links:index' |       when 'projects:group_links:index' | ||||||
|         new GroupsSelect() |         new GroupsSelect() | ||||||
|  |       when 'search:show' | ||||||
|  |         new Search() | ||||||
| 
 | 
 | ||||||
|     switch path.first() |     switch path.first() | ||||||
|       when 'admin' |       when 'admin' | ||||||
|  |  | ||||||
|  | @ -61,6 +61,7 @@ class @DropzoneInput | ||||||
|         return |         return | ||||||
| 
 | 
 | ||||||
|       drop: -> |       drop: -> | ||||||
|  |         $mdArea.removeClass 'is-dropzone-hover' | ||||||
|         form.find(".div-dropzone-hover").css "opacity", 0 |         form.find(".div-dropzone-hover").css "opacity", 0 | ||||||
|         form_textarea.focus() |         form_textarea.focus() | ||||||
|         return |         return | ||||||
|  |  | ||||||
|  | @ -0,0 +1,64 @@ | ||||||
|  | class @DueDateSelect | ||||||
|  |   constructor: -> | ||||||
|  |     $loading = $('.js-issuable-update .due_date') | ||||||
|  |       .find('.block-loading') | ||||||
|  |       .hide() | ||||||
|  | 
 | ||||||
|  |     $('.js-due-date-select').each (i, dropdown) -> | ||||||
|  |       $dropdown = $(dropdown) | ||||||
|  |       $dropdownParent = $dropdown.closest('.dropdown') | ||||||
|  |       $datePicker = $dropdownParent.find('.js-due-date-calendar') | ||||||
|  |       $block = $dropdown.closest('.block') | ||||||
|  |       $selectbox = $dropdown.closest('.selectbox') | ||||||
|  |       $value = $block.find('.value') | ||||||
|  |       $sidebarValue = $('.js-due-date-sidebar-value', $block) | ||||||
|  | 
 | ||||||
|  |       fieldName = $dropdown.data('field-name') | ||||||
|  |       abilityName = $dropdown.data('ability-name') | ||||||
|  |       issueUpdateURL = $dropdown.data('issue-update') | ||||||
|  | 
 | ||||||
|  |       $dropdown.glDropdown( | ||||||
|  |         hidden: -> | ||||||
|  |           $selectbox.hide() | ||||||
|  |           $value.removeAttr('style') | ||||||
|  |       ) | ||||||
|  | 
 | ||||||
|  |       addDueDate = -> | ||||||
|  |         # Create the post date | ||||||
|  |         value = $("input[name='#{fieldName}']").val() | ||||||
|  |         date = new Date value.replace(new RegExp('-', 'g'), ',') | ||||||
|  |         mediumDate = $.datepicker.formatDate 'M d, yy', date | ||||||
|  | 
 | ||||||
|  |         data = {} | ||||||
|  |         data[abilityName] = {} | ||||||
|  |         data[abilityName].due_date = value | ||||||
|  | 
 | ||||||
|  |         $.ajax( | ||||||
|  |           type: 'PUT' | ||||||
|  |           url: issueUpdateURL | ||||||
|  |           data: data | ||||||
|  |           beforeSend: -> | ||||||
|  |             $loading.fadeIn() | ||||||
|  |             $dropdown.trigger('loading.gl.dropdown') | ||||||
|  |             $selectbox.hide() | ||||||
|  |             $value.removeAttr('style') | ||||||
|  | 
 | ||||||
|  |             $value.html(mediumDate) | ||||||
|  |             $sidebarValue.html(mediumDate) | ||||||
|  |         ).done (data) -> | ||||||
|  |           $dropdown.trigger('loaded.gl.dropdown') | ||||||
|  |           $dropdown.dropdown('toggle') | ||||||
|  |           $loading.fadeOut() | ||||||
|  | 
 | ||||||
|  |       $datePicker.datepicker( | ||||||
|  |         dateFormat: 'yy-mm-dd', | ||||||
|  |         defaultDate: $("input[name='#{fieldName}']").val() | ||||||
|  |         altField: "input[name='#{fieldName}']" | ||||||
|  |         onSelect: -> | ||||||
|  |           addDueDate() | ||||||
|  |       ) | ||||||
|  | 
 | ||||||
|  |     $(document) | ||||||
|  |       .off 'click', '.ui-datepicker-header a' | ||||||
|  |       .on 'click', '.ui-datepicker-header a', (e) -> | ||||||
|  |         e.stopImmediatePropagation() | ||||||
|  | @ -32,10 +32,8 @@ class GitLabDropdownFilter | ||||||
|       else if @input.val() is "" and $inputContainer.hasClass HAS_VALUE_CLASS |       else if @input.val() is "" and $inputContainer.hasClass HAS_VALUE_CLASS | ||||||
|         $inputContainer.removeClass HAS_VALUE_CLASS |         $inputContainer.removeClass HAS_VALUE_CLASS | ||||||
| 
 | 
 | ||||||
|       if keyCode is 13 and @input.val() isnt "" |       if keyCode is 13 | ||||||
|         if @options.enterCallback |         return false | ||||||
|           @options.enterCallback() |  | ||||||
|         return |  | ||||||
| 
 | 
 | ||||||
|       clearTimeout timeout |       clearTimeout timeout | ||||||
|       timeout = setTimeout => |       timeout = setTimeout => | ||||||
|  | @ -132,7 +130,6 @@ class GitLabDropdown | ||||||
|       @filterInput = @getElement(FILTER_INPUT) |       @filterInput = @getElement(FILTER_INPUT) | ||||||
|       @highlight = false |       @highlight = false | ||||||
|       @filterInputBlur = true |       @filterInputBlur = true | ||||||
|       @enterCallback = true |  | ||||||
|     } = @options |     } = @options | ||||||
| 
 | 
 | ||||||
|     self = @ |     self = @ | ||||||
|  | @ -157,6 +154,9 @@ class GitLabDropdown | ||||||
|             @fullData = data |             @fullData = data | ||||||
| 
 | 
 | ||||||
|             @parseData @fullData |             @parseData @fullData | ||||||
|  | 
 | ||||||
|  |             if @options.filterable | ||||||
|  |               @filterInput.trigger 'keyup' | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     # Init filterable |     # Init filterable | ||||||
|  | @ -178,15 +178,15 @@ class GitLabDropdown | ||||||
|         callback: (data) => |         callback: (data) => | ||||||
|           currentIndex = -1 |           currentIndex = -1 | ||||||
|           @parseData data |           @parseData data | ||||||
|         enterCallback: => |  | ||||||
|           if @enterCallback |  | ||||||
|             @selectRowAtIndex 0 |  | ||||||
| 
 | 
 | ||||||
|     # Event listeners |     # Event listeners | ||||||
| 
 | 
 | ||||||
|     @dropdown.on "shown.bs.dropdown", @opened |     @dropdown.on "shown.bs.dropdown", @opened | ||||||
|     @dropdown.on "hidden.bs.dropdown", @hidden |     @dropdown.on "hidden.bs.dropdown", @hidden | ||||||
|     @dropdown.on "click", ".dropdown-menu, .dropdown-menu-close", @shouldPropagate |     @dropdown.on "click", ".dropdown-menu, .dropdown-menu-close", @shouldPropagate | ||||||
|  |     @dropdown.on 'keyup', (e) => | ||||||
|  |       if e.which is 27 # Escape key | ||||||
|  |         $('.dropdown-menu-close', @dropdown).trigger 'click' | ||||||
| 
 | 
 | ||||||
|     if @dropdown.find(".dropdown-toggle-page").length |     if @dropdown.find(".dropdown-toggle-page").length | ||||||
|       @dropdown.find(".dropdown-toggle-page, .dropdown-menu-back").on "click", (e) => |       @dropdown.find(".dropdown-toggle-page, .dropdown-menu-back").on "click", (e) => | ||||||
|  | @ -224,6 +224,9 @@ class GitLabDropdown | ||||||
| 
 | 
 | ||||||
|     menu.toggleClass PAGE_TWO_CLASS |     menu.toggleClass PAGE_TWO_CLASS | ||||||
| 
 | 
 | ||||||
|  |     # Focus first visible input on active page | ||||||
|  |     @dropdown.find('[class^="dropdown-page-"]:visible :text:visible:first').focus() | ||||||
|  | 
 | ||||||
|   parseData: (data) -> |   parseData: (data) -> | ||||||
|     @renderedData = data |     @renderedData = data | ||||||
| 
 | 
 | ||||||
|  | @ -243,7 +246,8 @@ class GitLabDropdown | ||||||
|   shouldPropagate: (e) => |   shouldPropagate: (e) => | ||||||
|     if @options.multiSelect |     if @options.multiSelect | ||||||
|       $target = $(e.target) |       $target = $(e.target) | ||||||
|       if not $target.hasClass('dropdown-menu-close') and not $target.hasClass('dropdown-menu-close-icon') | 
 | ||||||
|  |       if not $target.hasClass('dropdown-menu-close') and not $target.hasClass('dropdown-menu-close-icon') and not $target.data('is-link') | ||||||
|         e.stopPropagation() |         e.stopPropagation() | ||||||
|         return false |         return false | ||||||
|       else |       else | ||||||
|  | @ -378,7 +382,6 @@ class GitLabDropdown | ||||||
|       selectedObject = @renderedData[selectedIndex] |       selectedObject = @renderedData[selectedIndex] | ||||||
|     value = if @options.id then @options.id(selectedObject, el) else selectedObject.id |     value = if @options.id then @options.id(selectedObject, el) else selectedObject.id | ||||||
|     field = @dropdown.parent().find("input[name='#{fieldName}'][value='#{value}']") |     field = @dropdown.parent().find("input[name='#{fieldName}'][value='#{value}']") | ||||||
| 
 |  | ||||||
|     if el.hasClass(ACTIVE_CLASS) |     if el.hasClass(ACTIVE_CLASS) | ||||||
|       el.removeClass(ACTIVE_CLASS) |       el.removeClass(ACTIVE_CLASS) | ||||||
|       field.remove() |       field.remove() | ||||||
|  | @ -389,13 +392,13 @@ class GitLabDropdown | ||||||
|       else |       else | ||||||
|         selectedObject |         selectedObject | ||||||
|     else |     else | ||||||
|       if !value? |       if not @options.multiSelect or el.hasClass('dropdown-clear-active') | ||||||
|         field.remove() |  | ||||||
| 
 |  | ||||||
|       if not @options.multiSelect |  | ||||||
|         @dropdown.find(".#{ACTIVE_CLASS}").removeClass ACTIVE_CLASS |         @dropdown.find(".#{ACTIVE_CLASS}").removeClass ACTIVE_CLASS | ||||||
|         @dropdown.parent().find("input[name='#{fieldName}']").remove() |         @dropdown.parent().find("input[name='#{fieldName}']").remove() | ||||||
| 
 | 
 | ||||||
|  |       if !value? | ||||||
|  |         field.remove() | ||||||
|  | 
 | ||||||
|       # Toggle active class for the tick mark |       # Toggle active class for the tick mark | ||||||
|       el.addClass ACTIVE_CLASS |       el.addClass ACTIVE_CLASS | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -4,18 +4,33 @@ class @ImporterStatus | ||||||
|     this.setAutoUpdate() |     this.setAutoUpdate() | ||||||
| 
 | 
 | ||||||
|   initStatusPage: -> |   initStatusPage: -> | ||||||
|     $(".js-add-to-import").click (event) => |     $('.js-add-to-import') | ||||||
|       new_namespace = null |       .off 'click' | ||||||
|       tr = $(event.currentTarget).closest("tr") |       .on 'click', (e) => | ||||||
|       id = tr.attr("id").replace("repo_", "") |         new_namespace = null | ||||||
|       if tr.find(".import-target input").length > 0 |         $btn = $(e.currentTarget) | ||||||
|         new_namespace = tr.find(".import-target input").prop("value") |         $tr = $btn.closest('tr') | ||||||
|         tr.find(".import-target").empty().append(new_namespace + "/" + tr.find(".import-target").data("project_name")) |         id = $tr.attr('id').replace('repo_', '') | ||||||
|       $.post @import_url, {repo_id: id, new_namespace: new_namespace}, dataType: 'script' |         if $tr.find('.import-target input').length > 0 | ||||||
|  |           new_namespace = $tr.find('.import-target input').prop('value') | ||||||
|  |           $tr.find('.import-target').empty().append("#{new_namespace} / #{$tr.find('.import-target').data('project_name')}") | ||||||
| 
 | 
 | ||||||
|     $(".js-import-all").click (event) => |         $btn | ||||||
|       $(".js-add-to-import").each -> |           .disable() | ||||||
|         $(this).click() |           .addClass 'is-loading' | ||||||
|  | 
 | ||||||
|  |         $.post @import_url, {repo_id: id, new_namespace: new_namespace}, dataType: 'script' | ||||||
|  | 
 | ||||||
|  |     $('.js-import-all') | ||||||
|  |       .off 'click' | ||||||
|  |       .on 'click', (e) -> | ||||||
|  |         $btn = $(@) | ||||||
|  |         $btn | ||||||
|  |           .disable() | ||||||
|  |           .addClass 'is-loading' | ||||||
|  | 
 | ||||||
|  |         $('.js-add-to-import').each -> | ||||||
|  |           $(this).trigger('click') | ||||||
| 
 | 
 | ||||||
|   setAutoUpdate: -> |   setAutoUpdate: -> | ||||||
|     setInterval (=> |     setInterval (=> | ||||||
|  |  | ||||||
|  | @ -0,0 +1,84 @@ | ||||||
|  | @Issuable = | ||||||
|  |   init: -> | ||||||
|  |     Issuable.initTemplates() | ||||||
|  |     Issuable.initSearch() | ||||||
|  | 
 | ||||||
|  |   initTemplates: -> | ||||||
|  |     Issuable.labelRow = _.template( | ||||||
|  |       '<% _.each(labels, function(label){ %> | ||||||
|  |         <span class="label-row"> | ||||||
|  |           <a href="#"><span class="label color-label has-tooltip" style="background-color: <%= label.color %>; color: <%= label.text_color %>" title="<%= _.escape(label.description) %>" data-container="body"><%= _.escape(label.title) %></span></a> | ||||||
|  |         </span> | ||||||
|  |       <% }); %>' | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |   initSearch: -> | ||||||
|  |     @timer = null | ||||||
|  |     $('#issue_search') | ||||||
|  |       .off 'keyup' | ||||||
|  |       .on 'keyup', -> | ||||||
|  |         clearTimeout(@timer) | ||||||
|  |         @timer = setTimeout( -> | ||||||
|  |           Issuable.filterResults $('#issue_search_form') | ||||||
|  |         , 500) | ||||||
|  | 
 | ||||||
|  |   toggleLabelFilters: -> | ||||||
|  |     $filteredLabels = $('.filtered-labels') | ||||||
|  |     if $filteredLabels.find('.label-row').length > 0 | ||||||
|  |       $filteredLabels.removeClass('hidden') | ||||||
|  |     else | ||||||
|  |       $filteredLabels.addClass('hidden') | ||||||
|  | 
 | ||||||
|  |   filterResults: (form) => | ||||||
|  |     formData = form.serialize() | ||||||
|  | 
 | ||||||
|  |     $('.issues-holder, .merge-requests-holder').css('opacity', '0.5') | ||||||
|  |     formAction = form.attr('action') | ||||||
|  |     issuesUrl = formAction | ||||||
|  |     issuesUrl += ("#{if formAction.indexOf('?') < 0 then '?' else '&'}") | ||||||
|  |     issuesUrl += formData | ||||||
|  |     $.ajax | ||||||
|  |       type: 'GET' | ||||||
|  |       url: formAction | ||||||
|  |       data: formData | ||||||
|  |       complete: -> | ||||||
|  |         $('.issues-holder, .merge-requests-holder').css('opacity', '1.0') | ||||||
|  |       success: (data) -> | ||||||
|  |         $('.issues-holder, .merge-requests-holder').html(data.html) | ||||||
|  |         # Change url so if user reload a page - search results are saved | ||||||
|  |         history.replaceState {page: issuesUrl}, document.title, issuesUrl | ||||||
|  |         Issuable.reload() | ||||||
|  |         Issuable.updateStateFilters() | ||||||
|  |         $filteredLabels = $('.filtered-labels') | ||||||
|  | 
 | ||||||
|  |         if typeof Issuable.labelRow is 'function' | ||||||
|  |           $filteredLabels.html(Issuable.labelRow(data)) | ||||||
|  | 
 | ||||||
|  |         Issuable.toggleLabelFilters() | ||||||
|  | 
 | ||||||
|  |       dataType: "json" | ||||||
|  | 
 | ||||||
|  |   reload: -> | ||||||
|  |     if Issues.created | ||||||
|  |       Issues.initChecks() | ||||||
|  | 
 | ||||||
|  |     $('#filter_issue_search').val($('#issue_search').val()) | ||||||
|  | 
 | ||||||
|  |   updateStateFilters: -> | ||||||
|  |     stateFilters =  $('.issues-state-filters') | ||||||
|  |     newParams = {} | ||||||
|  |     paramKeys = ['author_id', 'milestone_title', 'assignee_id', 'issue_search'] | ||||||
|  | 
 | ||||||
|  |     for paramKey in paramKeys | ||||||
|  |       newParams[paramKey] = gl.utils.getParameterValues(paramKey)[0] or '' | ||||||
|  | 
 | ||||||
|  |     if stateFilters.length | ||||||
|  |       stateFilters.find('a').each -> | ||||||
|  |         initialUrl = gl.utils.removeParamQueryString($(this).attr('href'), 'label_name[]') | ||||||
|  |         labelNameValues = gl.utils.getParameterValues('label_name[]') | ||||||
|  |         if labelNameValues | ||||||
|  |           labelNameQueryString = ("label_name[]=#{value}" for value in labelNameValues).join('&') | ||||||
|  |           newUrl = "#{gl.utils.mergeUrlParams(newParams, initialUrl)}&#{labelNameQueryString}" | ||||||
|  |         else | ||||||
|  |           newUrl = gl.utils.mergeUrlParams(newParams, initialUrl) | ||||||
|  |         $(this).attr 'href', newUrl | ||||||
|  | @ -9,21 +9,29 @@ class @IssuableContext | ||||||
|     $(".issuable-sidebar .inline-update").on "change", ".js-assignee", -> |     $(".issuable-sidebar .inline-update").on "change", ".js-assignee", -> | ||||||
|       $(this).submit() |       $(this).submit() | ||||||
| 
 | 
 | ||||||
|     $(document).off("click", ".edit-link").on "click",".edit-link", (e) -> |     $(document) | ||||||
|       $block = $(@).parents('.block') |       .off 'click', '.issuable-sidebar .dropdown-content a' | ||||||
|       $selectbox = $block.find('.selectbox') |       .on 'click', '.issuable-sidebar .dropdown-content a', (e) -> | ||||||
|       if $selectbox.is(':visible') |         e.preventDefault() | ||||||
|         $selectbox.hide() |  | ||||||
|         $block.find('.value').show() |  | ||||||
|       else |  | ||||||
|         $selectbox.show() |  | ||||||
|         $block.find('.value').hide() |  | ||||||
| 
 | 
 | ||||||
|       if $selectbox.is(':visible') |     $(document) | ||||||
|         setTimeout (-> |       .off 'click', '.edit-link' | ||||||
|           $block.find('.dropdown-menu-toggle').trigger 'click' |       .on 'click', '.edit-link', (e) -> | ||||||
|         ), 0 |         e.preventDefault() | ||||||
|        | 
 | ||||||
|  |         $block = $(@).parents('.block') | ||||||
|  |         $selectbox = $block.find('.selectbox') | ||||||
|  |         if $selectbox.is(':visible') | ||||||
|  |           $selectbox.hide() | ||||||
|  |           $block.find('.value').show() | ||||||
|  |         else | ||||||
|  |           $selectbox.show() | ||||||
|  |           $block.find('.value').hide() | ||||||
|  | 
 | ||||||
|  |         if $selectbox.is(':visible') | ||||||
|  |           setTimeout -> | ||||||
|  |             $block.find('.dropdown-menu-toggle').trigger 'click' | ||||||
|  |           , 0 | ||||||
| 
 | 
 | ||||||
|     $(".right-sidebar").niceScroll() |     $(".right-sidebar").niceScroll() | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -12,6 +12,7 @@ class @Issue | ||||||
| 
 | 
 | ||||||
|     @initMergeRequests() |     @initMergeRequests() | ||||||
|     @initRelatedBranches() |     @initRelatedBranches() | ||||||
|  |     @initCanCreateBranch() | ||||||
| 
 | 
 | ||||||
|   initTaskList: -> |   initTaskList: -> | ||||||
|     $('.detail-page-description .js-task-list-container').taskList('enable') |     $('.detail-page-description .js-task-list-container').taskList('enable') | ||||||
|  | @ -92,3 +93,25 @@ class @Issue | ||||||
|       .success (data) -> |       .success (data) -> | ||||||
|         if 'html' of data |         if 'html' of data | ||||||
|           $container.html(data.html) |           $container.html(data.html) | ||||||
|  | 
 | ||||||
|  |   initCanCreateBranch: -> | ||||||
|  |     $container = $('div#new-branch') | ||||||
|  | 
 | ||||||
|  |     # If the user doesn't have the required permissions the container isn't | ||||||
|  |     # rendered at all. | ||||||
|  |     return unless $container | ||||||
|  | 
 | ||||||
|  |     $.getJSON($container.data('path')) | ||||||
|  |       .error -> | ||||||
|  |         $container.find('.checking').hide() | ||||||
|  |         $container.find('.unavailable').show() | ||||||
|  | 
 | ||||||
|  |         new Flash('Failed to check if a new branch can be created.', 'alert') | ||||||
|  |       .success (data) -> | ||||||
|  |         if data.can_create_branch | ||||||
|  |           $container.find('.checking').hide() | ||||||
|  |           $container.find('.available').show() | ||||||
|  |           $container.find('a').attr('disabled', false) | ||||||
|  |         else | ||||||
|  |           $container.find('.checking').hide() | ||||||
|  |           $container.find('.unavailable').show() | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| @Issues = | @Issues = | ||||||
|   init: -> |   init: -> | ||||||
|     Issues.initSearch() |     Issues.created = true | ||||||
|     Issues.initChecks() |     Issues.initChecks() | ||||||
| 
 | 
 | ||||||
|     $("body").on "ajax:success", ".close_issue, .reopen_issue", -> |     $("body").on "ajax:success", ".close_issue, .reopen_issue", -> | ||||||
|  | @ -15,10 +15,6 @@ | ||||||
|         else |         else | ||||||
|           $(this).html totalIssues - 1 |           $(this).html totalIssues - 1 | ||||||
| 
 | 
 | ||||||
|   reload: -> |  | ||||||
|     Issues.initChecks() |  | ||||||
|     $('#filter_issue_search').val($('#issue_search').val()) |  | ||||||
| 
 |  | ||||||
|   initChecks: -> |   initChecks: -> | ||||||
|     $(".check_all_issues").click -> |     $(".check_all_issues").click -> | ||||||
|       $(".selected_issue").prop("checked", @checked) |       $(".selected_issue").prop("checked", @checked) | ||||||
|  | @ -26,51 +22,6 @@ | ||||||
| 
 | 
 | ||||||
|     $(".selected_issue").bind "change", Issues.checkChanged |     $(".selected_issue").bind "change", Issues.checkChanged | ||||||
| 
 | 
 | ||||||
|   # Update state filters if present in page |  | ||||||
|   updateStateFilters: -> |  | ||||||
|     stateFilters =  $('.issues-state-filters') |  | ||||||
|     newParams = {} |  | ||||||
|     paramKeys = ['author_id', 'label_name', 'milestone_title', 'assignee_id', 'issue_search'] |  | ||||||
| 
 |  | ||||||
|     for paramKey in paramKeys |  | ||||||
|       newParams[paramKey] = gl.utils.getUrlParameter(paramKey) or '' |  | ||||||
| 
 |  | ||||||
|     if stateFilters.length |  | ||||||
|       stateFilters.find('a').each -> |  | ||||||
|         initialUrl = $(this).attr 'href' |  | ||||||
|         $(this).attr 'href', gl.utils.mergeUrlParams(newParams, initialUrl) |  | ||||||
| 
 |  | ||||||
|   # Make sure we trigger ajax request only after user stop typing |  | ||||||
|   initSearch: -> |  | ||||||
|     @timer = null |  | ||||||
|     $("#issue_search").keyup -> |  | ||||||
|       clearTimeout(@timer) |  | ||||||
|       @timer = setTimeout( -> |  | ||||||
|         Issues.filterResults $("#issue_search_form") |  | ||||||
|       , 500) |  | ||||||
| 
 |  | ||||||
|   filterResults: (form) => |  | ||||||
|     $('.issues-holder, .merge-requests-holder').css("opacity", '0.5') |  | ||||||
|     formAction = form.attr('action') |  | ||||||
|     formData = form.serialize() |  | ||||||
|     issuesUrl = formAction |  | ||||||
|     issuesUrl += ("#{if formAction.indexOf("?") < 0 then '?' else '&'}") |  | ||||||
|     issuesUrl += formData |  | ||||||
| 
 |  | ||||||
|     $.ajax |  | ||||||
|       type: "GET" |  | ||||||
|       url: formAction |  | ||||||
|       data: formData |  | ||||||
|       complete: -> |  | ||||||
|         $('.issues-holder, .merge-requests-holder').css("opacity", '1.0') |  | ||||||
|       success: (data) -> |  | ||||||
|         $('.issues-holder, .merge-requests-holder').html(data.html) |  | ||||||
|         # Change url so if user reload a page - search results are saved |  | ||||||
|         history.replaceState {page: issuesUrl}, document.title, issuesUrl |  | ||||||
|         Issues.reload() |  | ||||||
|         Issues.updateStateFilters() |  | ||||||
|       dataType: "json" |  | ||||||
| 
 |  | ||||||
|   checkChanged: -> |   checkChanged: -> | ||||||
|     checked_issues = $(".selected_issue:checked") |     checked_issues = $(".selected_issue:checked") | ||||||
|     if checked_issues.length > 0 |     if checked_issues.length > 0 | ||||||
|  |  | ||||||
|  | @ -6,7 +6,7 @@ class @LabelsSelect | ||||||
|       labelUrl = $dropdown.data('labels') |       labelUrl = $dropdown.data('labels') | ||||||
|       issueUpdateURL = $dropdown.data('issueUpdate') |       issueUpdateURL = $dropdown.data('issueUpdate') | ||||||
|       selectedLabel = $dropdown.data('selected') |       selectedLabel = $dropdown.data('selected') | ||||||
|       if selectedLabel? |       if selectedLabel? and not $dropdown.hasClass 'js-multiselect' | ||||||
|         selectedLabel = selectedLabel.split(',') |         selectedLabel = selectedLabel.split(',') | ||||||
|       newLabelField = $('#new_label_name') |       newLabelField = $('#new_label_name') | ||||||
|       newColorField = $('#new_label_color') |       newColorField = $('#new_label_color') | ||||||
|  | @ -16,33 +16,32 @@ class @LabelsSelect | ||||||
|       abilityName = $dropdown.data('ability-name') |       abilityName = $dropdown.data('ability-name') | ||||||
|       $selectbox = $dropdown.closest('.selectbox') |       $selectbox = $dropdown.closest('.selectbox') | ||||||
|       $block = $selectbox.closest('.block') |       $block = $selectbox.closest('.block') | ||||||
|  |       $form = $dropdown.closest('form') | ||||||
|       $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon span') |       $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon span') | ||||||
|       $value = $block.find('.value') |       $value = $block.find('.value') | ||||||
|  |       $newLabelError = $('.js-label-error') | ||||||
|  |       $colorPreview = $('.js-dropdown-label-color-preview') | ||||||
|  |       $newLabelCreateButton = $('.js-new-label-btn') | ||||||
|  | 
 | ||||||
|  |       $newLabelError.hide() | ||||||
|       $loading = $block.find('.block-loading').fadeOut() |       $loading = $block.find('.block-loading').fadeOut() | ||||||
| 
 | 
 | ||||||
|       if newLabelField.length |  | ||||||
|         $newLabelCreateButton = $('.js-new-label-btn') |  | ||||||
|         $colorPreview = $('.js-dropdown-label-color-preview') |  | ||||||
|         $newLabelError = $dropdown.parent().find('.js-label-error') |  | ||||||
|         $newLabelError.hide() |  | ||||||
| 
 |  | ||||||
|         # Suggested colors in the dropdown to chose from pre-chosen colors |  | ||||||
|         $('.suggest-colors-dropdown a').on 'click', (e) -> |  | ||||||
| 
 |  | ||||||
|       issueURLSplit = issueUpdateURL.split('/') if issueUpdateURL? |       issueURLSplit = issueUpdateURL.split('/') if issueUpdateURL? | ||||||
|       if issueUpdateURL |       if issueUpdateURL | ||||||
|         labelHTMLTemplate = _.template( |         labelHTMLTemplate = _.template( | ||||||
|             '<% _.each(labels, function(label){ %> |             '<% _.each(labels, function(label){ %> | ||||||
|             <a href="<%= ["",issueURLSplit[1], issueURLSplit[2],""].join("/") %>issues?label_name=<%= label.title %>"> |             <a href="<%= ["",issueURLSplit[1], issueURLSplit[2],""].join("/") %>issues?label_name[]=<%= _.escape(label.title) %>"> | ||||||
|             <span class="label has-tooltip color-label" title="<%= label.description %>" style="background-color: <%= label.color %>;"> |             <span class="label has-tooltip color-label" title="<%= _.escape(label.description) %>" style="background-color: <%= label.color %>; color: <%= label.text_color %>;"> | ||||||
|             <%= label.title %> |             <%= _.escape(label.title) %> | ||||||
|             </span> |             </span> | ||||||
|             </a> |             </a> | ||||||
|             <% }); %>' |             <% }); %>' | ||||||
|         ); |         ) | ||||||
|         labelNoneHTMLTemplate = _.template('<div class="light">None</div>') |         labelNoneHTMLTemplate = _.template('<div class="light">None</div>') | ||||||
| 
 | 
 | ||||||
|       if newLabelField.length and $dropdown.hasClass 'js-extra-options' |       if newLabelField.length | ||||||
|  | 
 | ||||||
|  |         # Suggested colors in the dropdown to chose from pre-chosen colors | ||||||
|         $('.suggest-colors-dropdown a').on "click", (e) -> |         $('.suggest-colors-dropdown a').on "click", (e) -> | ||||||
|           e.preventDefault() |           e.preventDefault() | ||||||
|           e.stopPropagation() |           e.stopPropagation() | ||||||
|  | @ -81,26 +80,25 @@ class @LabelsSelect | ||||||
|         enableLabelCreateButton = -> |         enableLabelCreateButton = -> | ||||||
|           if newLabelField.val() isnt '' and newColorField.val() isnt '' |           if newLabelField.val() isnt '' and newColorField.val() isnt '' | ||||||
|             $newLabelError.hide() |             $newLabelError.hide() | ||||||
|             $('.js-new-label-btn').disable() |  | ||||||
| 
 |  | ||||||
|             # Create new label with API |  | ||||||
|             Api.newLabel projectId, { |  | ||||||
|               name: newLabelField.val() |  | ||||||
|               color: newColorField.val() |  | ||||||
|             }, (label) -> |  | ||||||
|               $('.js-new-label-btn').enable() |  | ||||||
| 
 |  | ||||||
|               if label.message? |  | ||||||
|                 $newLabelError |  | ||||||
|                   .text label.message |  | ||||||
|                   .show() |  | ||||||
|               else |  | ||||||
|                 $('.dropdown-menu-back', $dropdown.parent()).trigger 'click' |  | ||||||
| 
 |  | ||||||
|             $newLabelCreateButton.enable() |             $newLabelCreateButton.enable() | ||||||
|           else |           else | ||||||
|             $newLabelCreateButton.disable() |             $newLabelCreateButton.disable() | ||||||
| 
 | 
 | ||||||
|  |         saveLabel = -> | ||||||
|  |           # Create new label with API | ||||||
|  |           Api.newLabel projectId, { | ||||||
|  |             name: newLabelField.val() | ||||||
|  |             color: newColorField.val() | ||||||
|  |           }, (label) -> | ||||||
|  |             $newLabelCreateButton.enable() | ||||||
|  | 
 | ||||||
|  |             if label.message? | ||||||
|  |               $newLabelError | ||||||
|  |                 .text label.message | ||||||
|  |                 .show() | ||||||
|  |             else | ||||||
|  |               $('.dropdown-menu-back', $dropdown.parent()).trigger 'click' | ||||||
|  | 
 | ||||||
|         newLabelField.on 'keyup change', enableLabelCreateButton |         newLabelField.on 'keyup change', enableLabelCreateButton | ||||||
| 
 | 
 | ||||||
|         newColorField.on 'keyup change', enableLabelCreateButton |         newColorField.on 'keyup change', enableLabelCreateButton | ||||||
|  | @ -111,24 +109,7 @@ class @LabelsSelect | ||||||
|           .on 'click', (e) -> |           .on 'click', (e) -> | ||||||
|             e.preventDefault() |             e.preventDefault() | ||||||
|             e.stopPropagation() |             e.stopPropagation() | ||||||
| 
 |             saveLabel() | ||||||
|             if newLabelField.val() isnt '' and newColorField.val() isnt '' |  | ||||||
|               $newLabelError.hide() |  | ||||||
|               $('.js-new-label-btn').disable() |  | ||||||
| 
 |  | ||||||
|               # Create new label with API |  | ||||||
|               Api.newLabel projectId, { |  | ||||||
|                 name: newLabelField.val() |  | ||||||
|                 color: newColorField.val() |  | ||||||
|               }, (label) -> |  | ||||||
|                 $('.js-new-label-btn').enable() |  | ||||||
| 
 |  | ||||||
|                 if label.message? |  | ||||||
|                   $newLabelError |  | ||||||
|                     .text label.message |  | ||||||
|                     .show() |  | ||||||
|                 else |  | ||||||
|                   $('.dropdown-menu-back', $dropdown.parent()).trigger 'click' |  | ||||||
| 
 | 
 | ||||||
|       saveLabelData = -> |       saveLabelData = -> | ||||||
|         selected = $dropdown |         selected = $dropdown | ||||||
|  | @ -171,7 +152,7 @@ class @LabelsSelect | ||||||
|             .find('a') |             .find('a') | ||||||
|             .each((i) -> |             .each((i) -> | ||||||
|               setTimeout(=> |               setTimeout(=> | ||||||
|                 glAnimate($(@), 'pulse') |                 gl.animate.animate($(@), 'pulse') | ||||||
|               ,200 * i |               ,200 * i | ||||||
|               ) |               ) | ||||||
|             ) |             ) | ||||||
|  | @ -182,6 +163,21 @@ class @LabelsSelect | ||||||
|           $.ajax( |           $.ajax( | ||||||
|             url: labelUrl |             url: labelUrl | ||||||
|           ).done (data) -> |           ).done (data) -> | ||||||
|  |             data = _.chain data | ||||||
|  |               .groupBy (label) -> | ||||||
|  |                 label.title | ||||||
|  |               .map (label) -> | ||||||
|  |                 color = _.map label, (dup) -> | ||||||
|  |                   dup.color | ||||||
|  | 
 | ||||||
|  |                 return { | ||||||
|  |                   id: label[0].id | ||||||
|  |                   title: label[0].title | ||||||
|  |                   color: color | ||||||
|  |                   duplicate: color.length > 1 | ||||||
|  |                 } | ||||||
|  |               .value() | ||||||
|  | 
 | ||||||
|             if $dropdown.hasClass 'js-extra-options' |             if $dropdown.hasClass 'js-extra-options' | ||||||
|               if showNo |               if showNo | ||||||
|                 data.unshift( |                 data.unshift( | ||||||
|  | @ -197,21 +193,47 @@ class @LabelsSelect | ||||||
| 
 | 
 | ||||||
|               if data.length > 2 |               if data.length > 2 | ||||||
|                 data.splice 2, 0, 'divider' |                 data.splice 2, 0, 'divider' | ||||||
|  | 
 | ||||||
|             callback data |             callback data | ||||||
| 
 | 
 | ||||||
|         renderRow: (label) -> |         renderRow: (label) -> | ||||||
|           selectedClass = '' |           removesAll = label.id is 0 or not label.id? | ||||||
|           if $selectbox.find("input[type='hidden']\ |  | ||||||
|             [name='#{$dropdown.data('field-name')}']\ |  | ||||||
|             [value='#{label.id}']").length |  | ||||||
|             selectedClass = 'is-active' |  | ||||||
| 
 | 
 | ||||||
|           color = if label.color? then "<span class='dropdown-label-box' style='background-color: #{label.color}'></span>" else "" |           selectedClass = [] | ||||||
|  |           if $form.find("input[type='hidden']\ | ||||||
|  |             [name='#{$dropdown.data('fieldName')}']\ | ||||||
|  |             [value='#{this.id(label)}']").length | ||||||
|  |             selectedClass.push 'is-active' | ||||||
|  | 
 | ||||||
|  |           if $dropdown.hasClass('js-multiselect') and removesAll | ||||||
|  |             selectedClass.push 'dropdown-clear-active' | ||||||
|  | 
 | ||||||
|  |           if label.duplicate | ||||||
|  |             spacing = 100 / label.color.length | ||||||
|  | 
 | ||||||
|  |             # Reduce the colors to 4 | ||||||
|  |             label.color = label.color.filter (color, i) -> | ||||||
|  |               i < 4 | ||||||
|  | 
 | ||||||
|  |             color = _.map(label.color, (color, i) -> | ||||||
|  |               percentFirst = Math.floor(spacing * i) | ||||||
|  |               percentSecond = Math.floor(spacing * (i + 1)) | ||||||
|  |               "#{color} #{percentFirst}%,#{color} #{percentSecond}% " | ||||||
|  |             ).join(',') | ||||||
|  |             color = "linear-gradient(#{color})" | ||||||
|  |           else | ||||||
|  |             if label.color? | ||||||
|  |               color = label.color[0] | ||||||
|  | 
 | ||||||
|  |           if color | ||||||
|  |             colorEl = "<span class='dropdown-label-box' style='background: #{color}'></span>" | ||||||
|  |           else | ||||||
|  |             colorEl = '' | ||||||
| 
 | 
 | ||||||
|           "<li> |           "<li> | ||||||
|             <a href='#' class='#{selectedClass}'> |             <a href='#' class='#{selectedClass.join(' ')}'> | ||||||
|               #{color} |               #{colorEl} | ||||||
|               #{label.title} |               #{_.escape(label.title)} | ||||||
|             </a> |             </a> | ||||||
|           </li>" |           </li>" | ||||||
|         filterable: true |         filterable: true | ||||||
|  | @ -219,37 +241,56 @@ class @LabelsSelect | ||||||
|           fields: ['title'] |           fields: ['title'] | ||||||
|         selectable: true |         selectable: true | ||||||
| 
 | 
 | ||||||
|         toggleLabel: (selected) -> |         toggleLabel: (selected, el) -> | ||||||
|  |           selected_labels = $('.js-label-select').siblings('.dropdown-menu-labels').find('.is-active') | ||||||
|  | 
 | ||||||
|           if selected and selected.title? |           if selected and selected.title? | ||||||
|             selected.title |             if selected_labels.length > 1 | ||||||
|  |               "#{selected.title} +#{selected_labels.length - 1} more" | ||||||
|  |             else | ||||||
|  |               selected.title | ||||||
|  |           else if not selected and selected_labels.length isnt 0 | ||||||
|  |             if selected_labels.length > 1 | ||||||
|  |               "#{$(selected_labels[0]).text()} +#{selected_labels.length - 1} more" | ||||||
|  |             else if selected_labels.length is 1 | ||||||
|  |               $(selected_labels).text() | ||||||
|           else |           else | ||||||
|             defaultLabel |             defaultLabel | ||||||
|         fieldName: $dropdown.data('field-name') |         fieldName: $dropdown.data('field-name') | ||||||
|         id: (label) -> |         id: (label) -> | ||||||
|           if label.isAny? |           if $dropdown.hasClass("js-filter-submit") and not label.isAny? | ||||||
|             '' |             _.escape label.title | ||||||
|           else if $dropdown.hasClass "js-filter-submit" |  | ||||||
|             label.title |  | ||||||
|           else |           else | ||||||
|             label.id |             label.id | ||||||
| 
 | 
 | ||||||
|         hidden: -> |         hidden: -> | ||||||
|  |           page = $('body').data 'page' | ||||||
|  |           isIssueIndex = page is 'projects:issues:index' | ||||||
|  |           isMRIndex = page is 'projects:merge_requests:index' | ||||||
|  | 
 | ||||||
|           $selectbox.hide() |           $selectbox.hide() | ||||||
|           # display:block overrides the hide-collapse rule |           # display:block overrides the hide-collapse rule | ||||||
|           $value.removeAttr('style') |           $value.removeAttr('style') | ||||||
|           if $dropdown.hasClass 'js-multiselect' |           if $dropdown.hasClass 'js-multiselect' | ||||||
|             saveLabelData() |             if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex) | ||||||
|  |               selectedLabels = $dropdown | ||||||
|  |                 .closest('form') | ||||||
|  |                 .find("input:hidden[name='#{$dropdown.data('fieldName')}']") | ||||||
|  |               Issuable.filterResults $dropdown.closest('form') | ||||||
|  |             else if $dropdown.hasClass('js-filter-submit') | ||||||
|  |               $dropdown.closest('form').submit() | ||||||
|  |             else | ||||||
|  |               saveLabelData() | ||||||
| 
 | 
 | ||||||
|         multiSelect: $dropdown.hasClass 'js-multiselect' |         multiSelect: $dropdown.hasClass 'js-multiselect' | ||||||
|         clicked: (label) -> |         clicked: (label) -> | ||||||
|           page = $('body').data 'page' |           page = $('body').data 'page' | ||||||
|           isIssueIndex = page is 'projects:issues:index' |           isIssueIndex = page is 'projects:issues:index' | ||||||
|           isMRIndex = page is page is 'projects:merge_requests:index' |           isMRIndex = page is 'projects:merge_requests:index' | ||||||
| 
 |  | ||||||
|           if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex) |           if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex) | ||||||
|             selectedLabel = label.title |             if not $dropdown.hasClass 'js-multiselect' | ||||||
| 
 |               selectedLabel = label.title | ||||||
|             Issues.filterResults $dropdown.closest('form') |               Issuable.filterResults $dropdown.closest('form') | ||||||
|           else if $dropdown.hasClass 'js-filter-submit' |           else if $dropdown.hasClass 'js-filter-submit' | ||||||
|             $dropdown.closest('form').submit() |             $dropdown.closest('form').submit() | ||||||
|           else |           else | ||||||
|  |  | ||||||
|  | @ -1,13 +1,39 @@ | ||||||
| ((w) ->  | ((w) ->  | ||||||
|  |   if not w.gl? then w.gl = {} | ||||||
|  |   if not gl.animate? then gl.animate = {} | ||||||
| 
 | 
 | ||||||
|   w.glAnimate = ($el, animation, done) -> |   gl.animate.animate = ($el, animation, options, done) -> | ||||||
|  |     if options?.cssStart? | ||||||
|  |       $el.css(options.cssStart) | ||||||
|     $el |     $el | ||||||
|       .removeClass() |       .removeClass(animation + ' animated') | ||||||
|       .addClass(animation + ' animated') |       .addClass(animation + ' animated') | ||||||
|       .one 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', -> |       .one 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', -> | ||||||
|         $(this).removeClass() |         $(this).removeClass(animation + ' animated') | ||||||
|  |         if done? | ||||||
|  |           done() | ||||||
|  |         if options?.cssEnd? | ||||||
|  |           $el.css(options.cssEnd) | ||||||
|         return |         return | ||||||
|     return |     return | ||||||
|   return |  | ||||||
| 
 | 
 | ||||||
|  |   gl.animate.animateEach = ($els, animation, time, options, done) -> | ||||||
|  |     dfd = $.Deferred() | ||||||
|  |     if not $els.length | ||||||
|  |       dfd.resolve() | ||||||
|  |     $els.each((i) -> | ||||||
|  |       setTimeout(=> | ||||||
|  |         $this = $(@) | ||||||
|  |         gl.animate.animate($this, animation, options, => | ||||||
|  |           if i is $els.length - 1 | ||||||
|  |             dfd.resolve() | ||||||
|  |             if done? | ||||||
|  |               done() | ||||||
|  |         ) | ||||||
|  |       ,time * i | ||||||
|  |       ) | ||||||
|  |       return | ||||||
|  |     ) | ||||||
|  |     return dfd.promise() | ||||||
|  |   return  | ||||||
| ) window | ) window | ||||||
|  | @ -3,16 +3,20 @@ | ||||||
|   w.gl ?= {} |   w.gl ?= {} | ||||||
|   w.gl.utils ?= {} |   w.gl.utils ?= {} | ||||||
| 
 | 
 | ||||||
|   w.gl.utils.getUrlParameter = (sParam) -> |   # Returns an array containing the value(s) of the | ||||||
|  |   # of the key passed as an argument | ||||||
|  |   w.gl.utils.getParameterValues = (sParam) -> | ||||||
|     sPageURL = decodeURIComponent(window.location.search.substring(1)) |     sPageURL = decodeURIComponent(window.location.search.substring(1)) | ||||||
|     sURLVariables = sPageURL.split('&') |     sURLVariables = sPageURL.split('&') | ||||||
|     sParameterName = undefined |     sParameterName = undefined | ||||||
|  |     values = [] | ||||||
|     i = 0 |     i = 0 | ||||||
|     while i < sURLVariables.length |     while i < sURLVariables.length | ||||||
|       sParameterName = sURLVariables[i].split('=') |       sParameterName = sURLVariables[i].split('=') | ||||||
|       if sParameterName[0] is sParam |       if sParameterName[0] is sParam | ||||||
|         return if sParameterName[1] is undefined then true else sParameterName[1] |         values.push(sParameterName[1]) | ||||||
|       i++ |       i++ | ||||||
|  |     values | ||||||
| 
 | 
 | ||||||
|   # # |   # # | ||||||
|   #  @param {Object} params - url keys and value to merge |   #  @param {Object} params - url keys and value to merge | ||||||
|  | @ -28,4 +32,12 @@ | ||||||
|         newUrl = "#{newUrl}#{(if newUrl.indexOf('?') > 0 then '&' else '?')}#{paramName}=#{paramValue}" |         newUrl = "#{newUrl}#{(if newUrl.indexOf('?') > 0 then '&' else '?')}#{paramName}=#{paramValue}" | ||||||
|     newUrl |     newUrl | ||||||
| 
 | 
 | ||||||
|  |   # removes parameter query string from url. returns the modified url | ||||||
|  |   w.gl.utils.removeParamQueryString = (url, param) -> | ||||||
|  |     url = decodeURIComponent(url) | ||||||
|  |     urlVariables = url.split('&') | ||||||
|  |     ( | ||||||
|  |       variables for variables in urlVariables when variables.indexOf(param) is -1 | ||||||
|  |     ).join('&') | ||||||
|  | 
 | ||||||
| ) window | ) window | ||||||
|  |  | ||||||
|  | @ -87,8 +87,8 @@ class @MergeRequestTabs | ||||||
|     if window.location.hash |     if window.location.hash | ||||||
|       navBarHeight = $('.navbar-gitlab').outerHeight() |       navBarHeight = $('.navbar-gitlab').outerHeight() | ||||||
| 
 | 
 | ||||||
|       $el = $("#{container} #{window.location.hash}") |       $el = $("#{container} #{window.location.hash}:not(.match)") | ||||||
|       $.scrollTo("#{container} #{window.location.hash}", offset: -navBarHeight) if $el.length |       $.scrollTo("#{container} #{window.location.hash}:not(.match)", offset: -navBarHeight) if $el.length | ||||||
| 
 | 
 | ||||||
|   # Activate a tab based on the current action |   # Activate a tab based on the current action | ||||||
|   activateTab: (action) -> |   activateTab: (action) -> | ||||||
|  | @ -176,16 +176,17 @@ class @MergeRequestTabs | ||||||
| 
 | 
 | ||||||
|     if locationHash isnt '' |     if locationHash isnt '' | ||||||
|       hashClassString = ".#{locationHash.replace('#', '')}" |       hashClassString = ".#{locationHash.replace('#', '')}" | ||||||
|       $diffLine = $(locationHash) |       $diffLine = $("#{locationHash}:not(.match)", $('#diffs')) | ||||||
| 
 | 
 | ||||||
|       if $diffLine.is ':not(tr)' |       if not $diffLine.is 'tr' | ||||||
|         $diffLine = $("td#{locationHash}, td#{hashClassString}") |         $diffLine = $('#diffs').find("td#{locationHash}, td#{hashClassString}") | ||||||
|       else |       else | ||||||
|         $diffLine = $('td', $diffLine) |         $diffLine = $diffLine.find('td') | ||||||
| 
 | 
 | ||||||
|       $diffLine.addClass 'hll' |       if $diffLine.length | ||||||
|       diffLineTop = $diffLine.offset().top |         $diffLine.addClass 'hll' | ||||||
|       navBarHeight = $('.navbar-gitlab').outerHeight() |         diffLineTop = $diffLine.offset().top | ||||||
|  |         navBarHeight = $('.navbar-gitlab').outerHeight() | ||||||
| 
 | 
 | ||||||
|   loadBuilds: (source) -> |   loadBuilds: (source) -> | ||||||
|     return if @buildsLoaded |     return if @buildsLoaded | ||||||
|  |  | ||||||
|  | @ -9,11 +9,12 @@ class @MergeRequestWidget | ||||||
|   constructor: (@opts) -> |   constructor: (@opts) -> | ||||||
|     $('#modal_merge_info').modal(show: false) |     $('#modal_merge_info').modal(show: false) | ||||||
|     @firstCICheck = true |     @firstCICheck = true | ||||||
|     @readyForCICheck = true |     @readyForCICheck = false | ||||||
|     clearInterval @fetchBuildStatusInterval |     clearInterval @fetchBuildStatusInterval | ||||||
| 
 | 
 | ||||||
|     @clearEventListeners() |     @clearEventListeners() | ||||||
|     @addEventListeners() |     @addEventListeners() | ||||||
|  |     @getCIStatus(false) | ||||||
|     @pollCIStatus() |     @pollCIStatus() | ||||||
|     notifyPermissions() |     notifyPermissions() | ||||||
| 
 | 
 | ||||||
|  | @ -68,20 +69,18 @@ class @MergeRequestWidget | ||||||
|     $.getJSON @opts.ci_status_url, (data) => |     $.getJSON @opts.ci_status_url, (data) => | ||||||
|       @readyForCICheck = true |       @readyForCICheck = true | ||||||
| 
 | 
 | ||||||
|       if @firstCICheck |       if data.status is '' | ||||||
|         @firstCICheck = false |  | ||||||
|         @opts.ci_status = data.status |  | ||||||
| 
 |  | ||||||
|       if @opts.ci_status is '' |  | ||||||
|         @opts.ci_status = data.status |  | ||||||
|         return |         return | ||||||
| 
 | 
 | ||||||
|       if data.status isnt @opts.ci_status and data.status? |       if @firstCICheck || data.status isnt @opts.ci_status and data.status? | ||||||
|  |         @opts.ci_status = data.status | ||||||
|         @showCIStatus data.status |         @showCIStatus data.status | ||||||
|         if data.coverage |         if data.coverage | ||||||
|           @showCICoverage data.coverage |           @showCICoverage data.coverage | ||||||
| 
 | 
 | ||||||
|         if showNotification |         # The first check should only update the UI, a notification | ||||||
|  |         # should only be displayed on status changes | ||||||
|  |         if showNotification and not @firstCICheck | ||||||
|           status = @ciLabelForStatus(data.status) |           status = @ciLabelForStatus(data.status) | ||||||
| 
 | 
 | ||||||
|           if status is "preparing" |           if status is "preparing" | ||||||
|  | @ -104,8 +103,7 @@ class @MergeRequestWidget | ||||||
|               @close() |               @close() | ||||||
|               Turbolinks.visit _this.opts.builds_path |               Turbolinks.visit _this.opts.builds_path | ||||||
|           ) |           ) | ||||||
| 
 |         @firstCICheck = false | ||||||
|         @opts.ci_status = data.status |  | ||||||
| 
 | 
 | ||||||
|   showCIStatus: (state) -> |   showCIStatus: (state) -> | ||||||
|     $('.ci_widget').hide() |     $('.ci_widget').hide() | ||||||
|  |  | ||||||
|  | @ -1,35 +0,0 @@ | ||||||
| # |  | ||||||
| # * Filter merge requests |  | ||||||
| # |  | ||||||
| @MergeRequests = |  | ||||||
|   init: -> |  | ||||||
|     MergeRequests.initSearch() |  | ||||||
| 
 |  | ||||||
|   # Make sure we trigger ajax request only after user stop typing |  | ||||||
|   initSearch: -> |  | ||||||
|     @timer = null |  | ||||||
|     $("#issue_search").keyup -> |  | ||||||
|       clearTimeout(@timer) |  | ||||||
|       @timer = setTimeout(MergeRequests.filterResults, 500) |  | ||||||
| 
 |  | ||||||
|   filterResults: => |  | ||||||
|     form = $("#issue_search_form") |  | ||||||
|     search = $("#issue_search").val() |  | ||||||
|     $('.merge-requests-holder').css("opacity", '0.5') |  | ||||||
|     issues_url = form.attr('action') + '?' + form.serialize() |  | ||||||
| 
 |  | ||||||
|     $.ajax |  | ||||||
|       type: "GET" |  | ||||||
|       url: form.attr('action') |  | ||||||
|       data: form.serialize() |  | ||||||
|       complete: -> |  | ||||||
|         $('.merge-requests-holder').css("opacity", '1.0') |  | ||||||
|       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 |  | ||||||
|         MergeRequests.reload() |  | ||||||
|       dataType: "json" |  | ||||||
| 
 |  | ||||||
|   reload: -> |  | ||||||
|     $('#filter_issue_search').val($('#issue_search').val()) |  | ||||||
|  | @ -24,7 +24,7 @@ class @MilestoneSelect | ||||||
| 
 | 
 | ||||||
|       if issueUpdateURL |       if issueUpdateURL | ||||||
|         milestoneLinkTemplate = _.template( |         milestoneLinkTemplate = _.template( | ||||||
|           '<a href="/<%= namespace %>/<%= path %>/milestones/<%= iid %>"><%= title %></a>' |           '<a href="/<%= namespace %>/<%= path %>/milestones/<%= iid %>"><%= _.escape(title) %></a>' | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         milestoneLinkNoneTemplate = '<div class="light">None</div>' |         milestoneLinkNoneTemplate = '<div class="light">None</div>' | ||||||
|  | @ -71,7 +71,7 @@ class @MilestoneSelect | ||||||
|             defaultLabel |             defaultLabel | ||||||
|         fieldName: $dropdown.data('field-name') |         fieldName: $dropdown.data('field-name') | ||||||
|         text: (milestone) -> |         text: (milestone) -> | ||||||
|           milestone.title |           _.escape(milestone.title) | ||||||
|         id: (milestone) -> |         id: (milestone) -> | ||||||
|           if !useId |           if !useId | ||||||
|             milestone.name |             milestone.name | ||||||
|  | @ -97,7 +97,7 @@ class @MilestoneSelect | ||||||
|               selectedMilestone = selected.name |               selectedMilestone = selected.name | ||||||
|             else |             else | ||||||
|               selectedMilestone = '' |               selectedMilestone = '' | ||||||
|             Issues.filterResults $dropdown.closest('form') |             Issuable.filterResults $dropdown.closest('form') | ||||||
|           else if $dropdown.hasClass('js-filter-submit') |           else if $dropdown.hasClass('js-filter-submit') | ||||||
|             $dropdown.closest('form').submit() |             $dropdown.closest('form').submit() | ||||||
|           else |           else | ||||||
|  |  | ||||||
|  | @ -75,6 +75,9 @@ class @Notes | ||||||
|     # when issue status changes, we need to refresh data |     # when issue status changes, we need to refresh data | ||||||
|     $(document).on "issuable:change", @refresh |     $(document).on "issuable:change", @refresh | ||||||
| 
 | 
 | ||||||
|  |     # when a key is clicked on the notes | ||||||
|  |     $(document).on "keydown", ".js-note-text", @keydownNoteText | ||||||
|  | 
 | ||||||
|   cleanBinding: -> |   cleanBinding: -> | ||||||
|     $(document).off "ajax:success", ".js-main-target-form" |     $(document).off "ajax:success", ".js-main-target-form" | ||||||
|     $(document).off "ajax:success", ".js-discussion-note-form" |     $(document).off "ajax:success", ".js-discussion-note-form" | ||||||
|  | @ -92,10 +95,19 @@ class @Notes | ||||||
|     $(document).off "click", ".js-note-target-reopen" |     $(document).off "click", ".js-note-target-reopen" | ||||||
|     $(document).off "click", ".js-note-target-close" |     $(document).off "click", ".js-note-target-close" | ||||||
|     $(document).off "click", ".js-note-discard" |     $(document).off "click", ".js-note-discard" | ||||||
|  |     $(document).off "keydown", ".js-note-text" | ||||||
| 
 | 
 | ||||||
|     $('.note .js-task-list-container').taskList('disable') |     $('.note .js-task-list-container').taskList('disable') | ||||||
|     $(document).off 'tasklist:changed', '.note .js-task-list-container' |     $(document).off 'tasklist:changed', '.note .js-task-list-container' | ||||||
| 
 | 
 | ||||||
|  |   keydownNoteText: (e) -> | ||||||
|  |     $this = $(this) | ||||||
|  |     if $this.val() is '' and e.which is 38 #aka the up key | ||||||
|  |       myLastNote = $("li.note[data-author-id='#{gon.current_user_id}'][data-editable]:last") | ||||||
|  |       if myLastNote.length | ||||||
|  |         myLastNoteEditBtn = myLastNote.find('.js-note-edit') | ||||||
|  |         myLastNoteEditBtn.trigger('click', [true, myLastNote]) | ||||||
|  | 
 | ||||||
|   initRefresh: -> |   initRefresh: -> | ||||||
|     clearInterval(Notes.interval) |     clearInterval(Notes.interval) | ||||||
|     Notes.interval = setInterval => |     Notes.interval = setInterval => | ||||||
|  | @ -343,7 +355,7 @@ class @Notes | ||||||
|   Adds a hidden div with the original content of the note to fill the edit note form with |   Adds a hidden div with the original content of the note to fill the edit note form with | ||||||
|   if the user cancels |   if the user cancels | ||||||
|   ### |   ### | ||||||
|   showEditForm: (e) -> |   showEditForm: (e, scrollTo, myLastNote) -> | ||||||
|     e.preventDefault() |     e.preventDefault() | ||||||
|     note = $(this).closest(".note") |     note = $(this).closest(".note") | ||||||
|     note.addClass "is-editting" |     note.addClass "is-editting" | ||||||
|  | @ -354,9 +366,27 @@ class @Notes | ||||||
|     # Show the attachment delete link |     # Show the attachment delete link | ||||||
|     note.find(".js-note-attachment-delete").show() |     note.find(".js-note-attachment-delete").show() | ||||||
| 
 | 
 | ||||||
|     new GLForm form |     done = ($noteText) -> | ||||||
|  |       # Neat little trick to put the cursor at the end | ||||||
|  |       noteTextVal = $noteText.val() | ||||||
|  |       $noteText.val('').val(noteTextVal); | ||||||
| 
 | 
 | ||||||
|     form.find(".js-note-text").focus() |     new GLForm form | ||||||
|  |     if scrollTo? and myLastNote? | ||||||
|  |       # scroll to the bottom | ||||||
|  |       # so the open of the last element doesn't make a jump | ||||||
|  |       $('html, body').scrollTop($(document).height()); | ||||||
|  |       $('html, body').animate({ | ||||||
|  |         scrollTop: myLastNote.offset().top - 150 | ||||||
|  |       }, 500, -> | ||||||
|  |         $noteText = form.find(".js-note-text") | ||||||
|  |         $noteText.focus() | ||||||
|  |         done($noteText) | ||||||
|  |       ); | ||||||
|  |     else | ||||||
|  |       $noteText = form.find('.js-note-text') | ||||||
|  |       $noteText.focus() | ||||||
|  |       done($noteText) | ||||||
| 
 | 
 | ||||||
|   ### |   ### | ||||||
|   Called in response to clicking the edit note link |   Called in response to clicking the edit note link | ||||||
|  |  | ||||||
|  | @ -45,9 +45,10 @@ class @Profile | ||||||
| 
 | 
 | ||||||
|   saveForm: -> |   saveForm: -> | ||||||
|     self = @ |     self = @ | ||||||
| 
 |  | ||||||
|     formData = new FormData(@form[0]) |     formData = new FormData(@form[0]) | ||||||
|     formData.append('user[avatar]', @avatarGlCrop.getBlob(), 'avatar.png') | 
 | ||||||
|  |     avatarBlob = @avatarGlCrop.getBlob() | ||||||
|  |     formData.append('user[avatar]', avatarBlob, 'avatar.png') if avatarBlob? | ||||||
| 
 | 
 | ||||||
|     $.ajax |     $.ajax | ||||||
|       url: @form.attr('action') |       url: @form.attr('action') | ||||||
|  |  | ||||||
|  | @ -1,10 +1,12 @@ | ||||||
| class @Sidebar | class @Sidebar | ||||||
|   constructor: (currentUser) -> |   constructor: (currentUser) -> | ||||||
|  |     @sidebar = $('aside') | ||||||
|  | 
 | ||||||
|     @addEventListeners() |     @addEventListeners() | ||||||
| 
 | 
 | ||||||
|   addEventListeners: -> |   addEventListeners: -> | ||||||
|     $('aside').on('click', '.sidebar-collapsed-icon', @sidebarCollapseClicked) |     @sidebar.on('click', '.sidebar-collapsed-icon', @, @sidebarCollapseClicked) | ||||||
|     $('.dropdown').on('hidden.gl.dropdown', @sidebarDropdownHidden) |     $('.dropdown').on('hidden.gl.dropdown', @, @onSidebarDropdownHidden) | ||||||
|     $('.dropdown').on('loading.gl.dropdown', @sidebarDropdownLoading) |     $('.dropdown').on('loading.gl.dropdown', @sidebarDropdownLoading) | ||||||
|     $('.dropdown').on('loaded.gl.dropdown', @sidebarDropdownLoaded) |     $('.dropdown').on('loaded.gl.dropdown', @sidebarDropdownLoaded) | ||||||
| 
 | 
 | ||||||
|  | @ -30,26 +32,56 @@ class @Sidebar | ||||||
|     else |     else | ||||||
|       i.show() |       i.show() | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|   sidebarCollapseClicked: (e) -> |   sidebarCollapseClicked: (e) -> | ||||||
|  |     sidebar = e.data | ||||||
|     e.preventDefault() |     e.preventDefault() | ||||||
|     $block = $(@).closest('.block') |     $block = $(@).closest('.block') | ||||||
|  |     sidebar.openDropdown($block); | ||||||
| 
 | 
 | ||||||
|     $('aside') |   openDropdown: (blockOrName) -> | ||||||
|       .find('.gutter-toggle') |     $block = if _.isString(blockOrName) then @getBlock(blockOrName) else blockOrName | ||||||
|       .trigger('click') |  | ||||||
|     $editLink = $block.find('.edit-link') |  | ||||||
| 
 | 
 | ||||||
|     if $editLink.length |     $block.find('.edit-link').trigger('click') | ||||||
|       $editLink.trigger('click') |  | ||||||
|       $block.addClass('collapse-after-update') |  | ||||||
|       $('.page-with-sidebar').addClass('with-overlay') |  | ||||||
| 
 | 
 | ||||||
|   sidebarDropdownHidden: (e) -> |     if not @isOpen() | ||||||
|  |       @setCollapseAfterUpdate($block) | ||||||
|  |       @toggleSidebar('open') | ||||||
|  | 
 | ||||||
|  |   setCollapseAfterUpdate: ($block) -> | ||||||
|  |     $block.addClass('collapse-after-update') | ||||||
|  |     $('.page-with-sidebar').addClass('with-overlay') | ||||||
|  | 
 | ||||||
|  |   onSidebarDropdownHidden: (e) -> | ||||||
|  |     sidebar = e.data | ||||||
|  |     e.preventDefault() | ||||||
|     $block = $(@).closest('.block') |     $block = $(@).closest('.block') | ||||||
|  |     sidebar.sidebarDropdownHidden($block) | ||||||
|  | 
 | ||||||
|  |   sidebarDropdownHidden: ($block) -> | ||||||
|     if $block.hasClass('collapse-after-update') |     if $block.hasClass('collapse-after-update') | ||||||
|       $block.removeClass('collapse-after-update') |       $block.removeClass('collapse-after-update') | ||||||
|       $('.page-with-sidebar').removeClass('with-overlay') |       $('.page-with-sidebar').removeClass('with-overlay') | ||||||
|       $('aside') |       @toggleSidebar('hide') | ||||||
|         .find('.gutter-toggle') | 
 | ||||||
|         .trigger('click') |   triggerOpenSidebar: -> | ||||||
|  |     @sidebar | ||||||
|  |       .find('.js-sidebar-toggle') | ||||||
|  |       .trigger('click') | ||||||
|  | 
 | ||||||
|  |   toggleSidebar: (action = 'toggle') -> | ||||||
|  |     if action is 'toggle' | ||||||
|  |       @triggerOpenSidebar() | ||||||
|  | 
 | ||||||
|  |     if action is 'open' | ||||||
|  |       @triggerOpenSidebar() if not @isOpen() | ||||||
|  | 
 | ||||||
|  |     if action is 'hide' | ||||||
|  |       @triggerOpenSidebar() is @isOpen() | ||||||
|  | 
 | ||||||
|  |   isOpen: -> | ||||||
|  |     @sidebar.is('.right-sidebar-expanded') | ||||||
|  | 
 | ||||||
|  |   getBlock: (name) -> | ||||||
|  |     @sidebar.find(".block.#{name}") | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,75 @@ | ||||||
|  | class @Search | ||||||
|  |   constructor: -> | ||||||
|  |     $groupDropdown = $('.js-search-group-dropdown') | ||||||
|  |     $projectDropdown = $('.js-search-project-dropdown') | ||||||
|  |     @eventListeners() | ||||||
|  | 
 | ||||||
|  |     $groupDropdown.glDropdown( | ||||||
|  |       selectable: true | ||||||
|  |       filterable: true | ||||||
|  |       fieldName: 'group_id' | ||||||
|  |       data: (term, callback) -> | ||||||
|  |         Api.groups term, null, (data) -> | ||||||
|  |           data.unshift( | ||||||
|  |             name: 'Any' | ||||||
|  |           ) | ||||||
|  |           data.splice 1, 0, 'divider' | ||||||
|  | 
 | ||||||
|  |           callback(data) | ||||||
|  |       id: (obj) -> | ||||||
|  |         obj.id | ||||||
|  |       text: (obj) -> | ||||||
|  |         obj.name | ||||||
|  |       toggleLabel: (obj) -> | ||||||
|  |         "#{$groupDropdown.data('default-label')} #{obj.name}" | ||||||
|  |       clicked: => | ||||||
|  |         @submitSearch() | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     $projectDropdown.glDropdown( | ||||||
|  |       selectable: true | ||||||
|  |       filterable: true | ||||||
|  |       fieldName: 'project_id' | ||||||
|  |       data: (term, callback) -> | ||||||
|  |         Api.projects term, 'id', (data) -> | ||||||
|  |           data.unshift( | ||||||
|  |             name_with_namespace: 'Any' | ||||||
|  |           ) | ||||||
|  |           data.splice 1, 0, 'divider' | ||||||
|  | 
 | ||||||
|  |           callback(data) | ||||||
|  |       id: (obj) -> | ||||||
|  |         obj.id | ||||||
|  |       text: (obj) -> | ||||||
|  |         obj.name_with_namespace | ||||||
|  |       toggleLabel: (obj) -> | ||||||
|  |         "#{$projectDropdown.data('default-label')} #{obj.name_with_namespace}" | ||||||
|  |       clicked: => | ||||||
|  |         @submitSearch() | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |   eventListeners: -> | ||||||
|  |     $(document) | ||||||
|  |       .off 'keyup', '.js-search-input' | ||||||
|  |       .on 'keyup', '.js-search-input', @searchKeyUp | ||||||
|  | 
 | ||||||
|  |     $(document) | ||||||
|  |       .off 'click', '.js-search-clear' | ||||||
|  |       .on 'click', '.js-search-clear', @clearSearchField | ||||||
|  | 
 | ||||||
|  |   submitSearch: -> | ||||||
|  |     $('.js-search-form').submit() | ||||||
|  | 
 | ||||||
|  |   searchKeyUp: -> | ||||||
|  |     $input = $(@) | ||||||
|  | 
 | ||||||
|  |     if $input.val() is '' | ||||||
|  |       $('.js-search-clear').addClass 'hidden' | ||||||
|  |     else | ||||||
|  |       $('.js-search-clear').removeClass 'hidden' | ||||||
|  | 
 | ||||||
|  |   clearSearchField: -> | ||||||
|  |     $('.js-search-input') | ||||||
|  |       .val '' | ||||||
|  |       .trigger 'keyup' | ||||||
|  |       .focus() | ||||||
|  | @ -2,34 +2,35 @@ class @Shortcuts | ||||||
|   constructor: -> |   constructor: -> | ||||||
|     @enabledHelp = [] |     @enabledHelp = [] | ||||||
|     Mousetrap.reset() |     Mousetrap.reset() | ||||||
|     Mousetrap.bind('?', @selectiveHelp) |     Mousetrap.bind('?', @onToggleHelp) | ||||||
|     Mousetrap.bind('s', Shortcuts.focusSearch) |     Mousetrap.bind('s', Shortcuts.focusSearch) | ||||||
|     Mousetrap.bind(['ctrl+shift+p', 'command+shift+p'], @toggleMarkdownPreview) |     Mousetrap.bind(['ctrl+shift+p', 'command+shift+p'], @toggleMarkdownPreview) | ||||||
|     Mousetrap.bind('t', -> Turbolinks.visit(findFileURL)) if findFileURL? |     Mousetrap.bind('t', -> Turbolinks.visit(findFileURL)) if findFileURL? | ||||||
| 
 | 
 | ||||||
|   selectiveHelp: (e) => |   onToggleHelp: (e) => | ||||||
|     Shortcuts.showHelp(e, @enabledHelp) |     e.preventDefault() | ||||||
|  |     @toggleHelp(@enabledHelp) | ||||||
| 
 | 
 | ||||||
|   toggleMarkdownPreview: (e) => |   toggleMarkdownPreview: (e) => | ||||||
|     $(document).triggerHandler('markdown-preview:toggle', [e]) |     $(document).triggerHandler('markdown-preview:toggle', [e]) | ||||||
| 
 | 
 | ||||||
|   @showHelp: (e, location) -> |   toggleHelp: (location) -> | ||||||
|     if $('#modal-shortcuts').length > 0 |     $modal = $('#modal-shortcuts') | ||||||
|       $('#modal-shortcuts').modal('show') | 
 | ||||||
|     else |     if $modal.length | ||||||
|       url = '/help/shortcuts' |       $modal.modal('toggle') | ||||||
|       url = gon.relative_url_root + url if gon.relative_url_root? |       return | ||||||
|       $.ajax( | 
 | ||||||
|         url: url, |     $.ajax( | ||||||
|         dataType: 'script', |       url: gon.shortcuts_path, | ||||||
|         success: (e) -> |       dataType: 'script', | ||||||
|           if location and location.length > 0 |       success: (e) -> | ||||||
|             $(l).show() for l in location |         if location and location.length > 0 | ||||||
|           else |           $(l).show() for l in location | ||||||
|             $('.hidden-shortcut').show() |         else | ||||||
|             $('.js-more-help-button').remove() |           $('.hidden-shortcut').show() | ||||||
|       ) |           $('.js-more-help-button').remove() | ||||||
|       e.preventDefault() |     ) | ||||||
| 
 | 
 | ||||||
|   @focusSearch: (e) -> |   @focusSearch: (e) -> | ||||||
|     $('#search').focus() |     $('#search').focus() | ||||||
|  |  | ||||||
|  | @ -4,18 +4,8 @@ | ||||||
| class @ShortcutsIssuable extends ShortcutsNavigation | class @ShortcutsIssuable extends ShortcutsNavigation | ||||||
|   constructor: (isMergeRequest) -> |   constructor: (isMergeRequest) -> | ||||||
|     super() |     super() | ||||||
|     Mousetrap.bind('a', -> |     Mousetrap.bind('a', @openSidebarDropdown.bind(@, 'assignee')) | ||||||
|       $('.block.assignee .edit-link').trigger('click') |     Mousetrap.bind('m', @openSidebarDropdown.bind(@, 'milestone')) | ||||||
|       return false |  | ||||||
|     ) |  | ||||||
|     Mousetrap.bind('m', -> |  | ||||||
|       $('.block.milestone .edit-link').trigger('click') |  | ||||||
|       return false |  | ||||||
|     ) |  | ||||||
|     Mousetrap.bind('r', => |  | ||||||
|       @replyWithSelectedText() |  | ||||||
|       return false |  | ||||||
|     ) |  | ||||||
|     Mousetrap.bind('j', => |     Mousetrap.bind('j', => | ||||||
|       @prevIssue() |       @prevIssue() | ||||||
|       return false |       return false | ||||||
|  | @ -28,7 +18,7 @@ class @ShortcutsIssuable extends ShortcutsNavigation | ||||||
|       @editIssue() |       @editIssue() | ||||||
|       return false |       return false | ||||||
|     ) |     ) | ||||||
| 
 |     Mousetrap.bind('l', @openSidebarDropdown.bind(@, 'labels')) | ||||||
| 
 | 
 | ||||||
|     if isMergeRequest |     if isMergeRequest | ||||||
|       @enabledHelp.push('.hidden-shortcut.merge_requests') |       @enabledHelp.push('.hidden-shortcut.merge_requests') | ||||||
|  | @ -71,3 +61,7 @@ class @ShortcutsIssuable extends ShortcutsNavigation | ||||||
|   editIssue: -> |   editIssue: -> | ||||||
|     $editBtn = $('.issuable-edit') |     $editBtn = $('.issuable-edit') | ||||||
|     Turbolinks.visit($editBtn.attr('href')) |     Turbolinks.visit($editBtn.attr('href')) | ||||||
|  | 
 | ||||||
|  |   openSidebarDropdown: (name) -> | ||||||
|  |     sidebar.openDropdown(name) | ||||||
|  |     return false | ||||||
|  |  | ||||||
|  | @ -14,6 +14,7 @@ class @ShortcutsNavigation extends Shortcuts | ||||||
|     Mousetrap.bind('g m', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-merge_requests')) |     Mousetrap.bind('g m', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-merge_requests')) | ||||||
|     Mousetrap.bind('g w', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-wiki')) |     Mousetrap.bind('g w', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-wiki')) | ||||||
|     Mousetrap.bind('g s', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-snippets')) |     Mousetrap.bind('g s', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-snippets')) | ||||||
|  |     Mousetrap.bind('i', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-new-issue')) | ||||||
|     @enabledHelp.push('.hidden-shortcut.project') |     @enabledHelp.push('.hidden-shortcut.project') | ||||||
| 
 | 
 | ||||||
|   @findAndFollowLink: (selector) -> |   @findAndFollowLink: (selector) -> | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ toggleSidebar = -> | ||||||
|     niceScrollBars.updateScrollBar(); |     niceScrollBars.updateScrollBar(); | ||||||
|   ), 300 |   ), 300 | ||||||
| 
 | 
 | ||||||
| $(document).on("click", '.toggle-nav-collapse', (e) -> | $(document).on("click", '.toggle-nav-collapse, .side-nav-toggle', (e) -> | ||||||
|   e.preventDefault() |   e.preventDefault() | ||||||
| 
 | 
 | ||||||
|   toggleSidebar() |   toggleSidebar() | ||||||
|  |  | ||||||
|  | @ -1,5 +1,11 @@ | ||||||
| class @Todos | class @Todos | ||||||
|   constructor: (@name) -> |   constructor: (opts = {}) -> | ||||||
|  |     { | ||||||
|  |       @el = $('.js-todos-options') | ||||||
|  |     } = opts | ||||||
|  | 
 | ||||||
|  |     @perPage = @el.data('perPage') | ||||||
|  | 
 | ||||||
|     @clearListeners() |     @clearListeners() | ||||||
|     @initBtnListeners() |     @initBtnListeners() | ||||||
| 
 | 
 | ||||||
|  | @ -26,6 +32,7 @@ class @Todos | ||||||
|       dataType: 'json' |       dataType: 'json' | ||||||
|       data: '_method': 'delete' |       data: '_method': 'delete' | ||||||
|       success: (data) => |       success: (data) => | ||||||
|  |         @redirectIfNeeded data.count | ||||||
|         @clearDone $this.closest('li') |         @clearDone $this.closest('li') | ||||||
|         @updateBadges data |         @updateBadges data | ||||||
| 
 | 
 | ||||||
|  | @ -57,11 +64,46 @@ class @Todos | ||||||
|     $('.todos-pending .badge, .todos-pending-count').text data.count |     $('.todos-pending .badge, .todos-pending-count').text data.count | ||||||
|     $('.todos-done .badge').text data.done_count |     $('.todos-done .badge').text data.done_count | ||||||
| 
 | 
 | ||||||
|  |   getTotalPages: -> | ||||||
|  |     @el.data('totalPages') | ||||||
|  | 
 | ||||||
|  |   getCurrentPage: -> | ||||||
|  |     @el.data('currentPage') | ||||||
|  | 
 | ||||||
|  |   getTodosPerPage: -> | ||||||
|  |     @el.data('perPage') | ||||||
|  | 
 | ||||||
|  |   redirectIfNeeded: (total) -> | ||||||
|  |     currPages = @getTotalPages() | ||||||
|  |     currPage = @getCurrentPage() | ||||||
|  | 
 | ||||||
|  |     # Refresh if no remaining Todos | ||||||
|  |     if not total | ||||||
|  |       location.reload() | ||||||
|  |       return | ||||||
|  | 
 | ||||||
|  |     # Do nothing if no pagination | ||||||
|  |     return if not currPages | ||||||
|  | 
 | ||||||
|  |     newPages = Math.ceil(total / @getTodosPerPage()) | ||||||
|  |     url = location.href # Includes query strings | ||||||
|  | 
 | ||||||
|  |     # If new total of pages is different than we have now | ||||||
|  |     if newPages isnt currPages | ||||||
|  |       # Redirect to previous page if there's one available | ||||||
|  |       if currPages > 1 and currPage is currPages | ||||||
|  |         pageParams = | ||||||
|  |           page: currPages - 1 | ||||||
|  |         url = gl.utils.mergeUrlParams(pageParams, url) | ||||||
|  | 
 | ||||||
|  |       Turbolinks.visit(url) | ||||||
|  | 
 | ||||||
|   goToTodoUrl: (e)-> |   goToTodoUrl: (e)-> | ||||||
|     todoLink = $(this).data('url') |     todoLink = $(this).data('url') | ||||||
|     return unless todoLink |     return unless todoLink | ||||||
| 
 | 
 | ||||||
|     if e.metaKey |     # Allow Meta-Click or Mouse3-click to open in a new tab | ||||||
|  |     if e.metaKey or e.which is 2 | ||||||
|       e.preventDefault() |       e.preventDefault() | ||||||
|       window.open(todoLink,'_blank') |       window.open(todoLink,'_blank') | ||||||
|     else |     else | ||||||
|  |  | ||||||
|  | @ -92,7 +92,7 @@ class @UserTabs | ||||||
|     @setCurrentAction(action) |     @setCurrentAction(action) | ||||||
| 
 | 
 | ||||||
|   activateTab: (action) -> |   activateTab: (action) -> | ||||||
|     @parentEl.find(".nav-links .#{action}-tab a").tab('show') |     @parentEl.find(".nav-links .js-#{action}-tab a").tab('show') | ||||||
| 
 | 
 | ||||||
|   setTab: (source, action) -> |   setTab: (source, action) -> | ||||||
|     return if @loaded[action] is true |     return if @loaded[action] is true | ||||||
|  |  | ||||||
|  | @ -158,7 +158,7 @@ class @UsersSelect | ||||||
| 
 | 
 | ||||||
|           if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex) |           if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex) | ||||||
|             selectedId = user.id |             selectedId = user.id | ||||||
|             Issues.filterResults $dropdown.closest('form') |             Issuable.filterResults $dropdown.closest('form') | ||||||
|           else if $dropdown.hasClass 'js-filter-submit' |           else if $dropdown.hasClass 'js-filter-submit' | ||||||
|             $dropdown.closest('form').submit() |             $dropdown.closest('form').submit() | ||||||
|           else |           else | ||||||
|  |  | ||||||
|  | @ -25,6 +25,7 @@ | ||||||
| @import "framework/lists.scss"; | @import "framework/lists.scss"; | ||||||
| @import "framework/markdown_area.scss"; | @import "framework/markdown_area.scss"; | ||||||
| @import "framework/mobile.scss"; | @import "framework/mobile.scss"; | ||||||
|  | @import "framework/modal.scss"; | ||||||
| @import "framework/nav.scss"; | @import "framework/nav.scss"; | ||||||
| @import "framework/pagination.scss"; | @import "framework/pagination.scss"; | ||||||
| @import "framework/progress.scss"; | @import "framework/progress.scss"; | ||||||
|  |  | ||||||
|  | @ -28,6 +28,7 @@ | ||||||
|   &.s46 { width: 46px; height: 46px; margin-right: 15px; } |   &.s46 { width: 46px; height: 46px; margin-right: 15px; } | ||||||
|   &.s48 { width: 48px; height: 48px; margin-right: 10px; } |   &.s48 { width: 48px; height: 48px; margin-right: 10px; } | ||||||
|   &.s60 { width: 60px; height: 60px; margin-right: 12px; } |   &.s60 { width: 60px; height: 60px; margin-right: 12px; } | ||||||
|  |   &.s70 { width: 70px; height: 70px; margin-right: 14px; } | ||||||
|   &.s90 { width: 90px; height: 90px; margin-right: 15px; } |   &.s90 { width: 90px; height: 90px; margin-right: 15px; } | ||||||
|   &.s110 { width: 110px; height: 110px; margin-right: 15px; } |   &.s110 { width: 110px; height: 110px; margin-right: 15px; } | ||||||
|   &.s140 { width: 140px; height: 140px; margin-right: 20px; } |   &.s140 { width: 140px; height: 140px; margin-right: 20px; } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| .light-well { | .light-well { | ||||||
|   background-color: #f8fafc; |   background-color: $background-color; | ||||||
|   padding: 15px; |   padding: 15px; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -18,7 +18,7 @@ | ||||||
|   line-height: 36px; |   line-height: 36px; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .gray-content-block { | .row-content-block { | ||||||
|   margin-top: 0; |   margin-top: 0; | ||||||
|   margin-bottom: -$gl-padding; |   margin-bottom: -$gl-padding; | ||||||
|   background-color: $background-color; |   background-color: $background-color; | ||||||
|  | @ -81,6 +81,11 @@ | ||||||
|       margin-left: 10px; |       margin-left: 10px; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   &.build-content { | ||||||
|  |     background-color: $white-light; | ||||||
|  |     border-top: none; | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .cover-block { | .cover-block { | ||||||
|  | @ -113,7 +118,7 @@ | ||||||
|     line-height: 1.1; |     line-height: 1.1; | ||||||
| 
 | 
 | ||||||
|     h1 { |     h1 { | ||||||
|       color: #313236; |       color: $gl-gray-dark; | ||||||
|       margin-bottom: 6px; |       margin-bottom: 6px; | ||||||
|       font-size: 23px; |       font-size: 23px; | ||||||
|     } |     } | ||||||
|  | @ -150,6 +155,41 @@ | ||||||
|       right: auto; |       right: auto; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   &.groups-cover-block { | ||||||
|  |     background: $white-light; | ||||||
|  |     border-bottom: 1px solid $border-color; | ||||||
|  |     text-align: left; | ||||||
|  |     padding: 24px 0; | ||||||
|  | 
 | ||||||
|  |     .group-info { | ||||||
|  |       .cover-title { | ||||||
|  |         margin-top: 9px; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       p { | ||||||
|  |         margin-bottom: 0; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @media (max-width: $screen-xs-max) { | ||||||
|  |       text-align: center; | ||||||
|  | 
 | ||||||
|  |       .avatar { | ||||||
|  |         float: none; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .group-info { | ||||||
|  | 
 | ||||||
|  |     h1 { | ||||||
|  |       display: inline; | ||||||
|  |       font-weight: normal; | ||||||
|  |       font-size: 24px; | ||||||
|  |       color: $gl-title-color; | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .block-connector { | .block-connector { | ||||||
|  |  | ||||||
|  | @ -59,7 +59,7 @@ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @mixin btn-gray { | @mixin btn-gray { | ||||||
|   @include btn-color($gray-light, $border-gray-light, $gray-normal, $border-gray-light, $gray-dark, $border-gray-dark, #313236); |   @include btn-color($gray-light, $border-gray-light, $gray-normal, $border-gray-light, $gray-dark, $border-gray-dark, $gl-gray-dark); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @mixin btn-white { | @mixin btn-white { | ||||||
|  | @ -139,11 +139,19 @@ | ||||||
|     pointer-events: auto !important; |     pointer-events: auto !important; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   &[disabled] { | ||||||
|  |     pointer-events: none !important; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   .caret { |   .caret { | ||||||
|     margin-left: 5px; |     margin-left: 5px; | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .btn-lg { | ||||||
|  |   padding: 12px 20px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .btn-transparent { | .btn-transparent { | ||||||
|   color: $btn-transparent-color; |   color: $btn-transparent-color; | ||||||
|   background-color: transparent; |   background-color: transparent; | ||||||
|  | @ -243,3 +251,10 @@ | ||||||
| .btn-file-option { | .btn-file-option { | ||||||
|   background: linear-gradient(180deg, $white-light 25%, $gray-light 100%); |   background: linear-gradient(180deg, $white-light 25%, $gray-light 100%); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | .btn-build { | ||||||
|  |   margin-left: 10px; | ||||||
|  |   i { | ||||||
|  |     color: $gl-icon-color; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -54,6 +54,10 @@ | ||||||
|     fill: #254e77 !important; |     fill: #254e77 !important; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   .future { | ||||||
|  |     visibility: hidden; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   .domain-background { |   .domain-background { | ||||||
|     fill: none; |     fill: none; | ||||||
|     shape-rendering: crispedges; |     shape-rendering: crispedges; | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ | ||||||
| .prepend-top-10 { margin-top: 10px } | .prepend-top-10 { margin-top: 10px } | ||||||
| .prepend-top-default { margin-top: $gl-padding !important; } | .prepend-top-default { margin-top: $gl-padding !important; } | ||||||
| .prepend-top-20 { margin-top: 20px } | .prepend-top-20 { margin-top: 20px } | ||||||
|  | .prepend-left-5 { margin-left: 5px } | ||||||
| .prepend-left-10 { margin-left: 10px } | .prepend-left-10 { margin-left: 10px } | ||||||
| .prepend-left-default { margin-left: $gl-padding; } | .prepend-left-default { margin-left: $gl-padding; } | ||||||
| .prepend-left-20 { margin-left: 20px } | .prepend-left-20 { margin-left: 20px } | ||||||
|  |  | ||||||
|  | @ -42,7 +42,7 @@ | ||||||
|   font-size: 15px; |   font-size: 15px; | ||||||
|   text-align: left; |   text-align: left; | ||||||
|   border: 1px solid $dropdown-toggle-border-color; |   border: 1px solid $dropdown-toggle-border-color; | ||||||
|   border-radius: $dropdown-border-radius; |   border-radius: $border-radius-base; | ||||||
|   outline: 0; |   outline: 0; | ||||||
|   text-overflow: ellipsis; |   text-overflow: ellipsis; | ||||||
|   white-space: nowrap; |   white-space: nowrap; | ||||||
|  | @ -80,7 +80,7 @@ | ||||||
|   padding: 10px 0; |   padding: 10px 0; | ||||||
|   background-color: $dropdown-bg; |   background-color: $dropdown-bg; | ||||||
|   border: 1px solid $dropdown-border-color; |   border: 1px solid $dropdown-border-color; | ||||||
|   border-radius: $dropdown-border-radius; |   border-radius: $border-radius-base; | ||||||
|   box-shadow: 0 2px 4px $dropdown-shadow-color; |   box-shadow: 0 2px 4px $dropdown-shadow-color; | ||||||
| 
 | 
 | ||||||
|   &.is-loading { |   &.is-loading { | ||||||
|  | @ -248,7 +248,7 @@ | ||||||
| 
 | 
 | ||||||
| .dropdown-title { | .dropdown-title { | ||||||
|   position: relative; |   position: relative; | ||||||
|   padding: 0 25px 15px; |   padding: 0 25px 10px; | ||||||
|   margin: 0 10px 10px; |   margin: 0 10px 10px; | ||||||
|   font-weight: 600; |   font-weight: 600; | ||||||
|   line-height: 1; |   line-height: 1; | ||||||
|  | @ -278,7 +278,7 @@ | ||||||
|   right: 5px; |   right: 5px; | ||||||
|   width: 20px; |   width: 20px; | ||||||
|   height: 20px; |   height: 20px; | ||||||
|   top: -1px; |   top: -3px; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .dropdown-menu-back { | .dropdown-menu-back { | ||||||
|  | @ -320,7 +320,7 @@ | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .dropdown-input-field { | .dropdown-input-field, .default-dropdown-input { | ||||||
|   width: 100%; |   width: 100%; | ||||||
|   padding: 0 7px; |   padding: 0 7px; | ||||||
|   color: $dropdown-input-color; |   color: $dropdown-input-color; | ||||||
|  | @ -358,6 +358,13 @@ | ||||||
|   border-top: 1px solid $dropdown-divider-color; |   border-top: 1px solid $dropdown-divider-color; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .dropdown-due-date-footer { | ||||||
|  |   padding-top: 0; | ||||||
|  |   margin-left: 10px; | ||||||
|  |   margin-right: 10px; | ||||||
|  |   border-top: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .dropdown-footer-list { | .dropdown-footer-list { | ||||||
|   font-size: 14px; |   font-size: 14px; | ||||||
| 
 | 
 | ||||||
|  | @ -395,3 +402,122 @@ | ||||||
|   height: 15px; |   height: 15px; | ||||||
|   border-radius: $border-radius-base; |   border-radius: $border-radius-base; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | .dropdown-menu-due-date { | ||||||
|  |   .dropdown-content { | ||||||
|  |     max-height: 230px; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .ui-widget { | ||||||
|  |     table { | ||||||
|  |       margin: 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     &.ui-datepicker-inline { | ||||||
|  |       padding: 0 10px; | ||||||
|  |       border: 0; | ||||||
|  |       width: 100%; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .ui-datepicker-header { | ||||||
|  |       padding: 0 8px 10px; | ||||||
|  |       border: 0; | ||||||
|  | 
 | ||||||
|  |       .ui-icon { | ||||||
|  |         background: none; | ||||||
|  |         font-size: 20px; | ||||||
|  |         text-indent: 0; | ||||||
|  | 
 | ||||||
|  |         &:before { | ||||||
|  |           display: block; | ||||||
|  |           position: relative; | ||||||
|  |           top: -2px; | ||||||
|  |           color: $dropdown-title-btn-color; | ||||||
|  |           font: normal normal normal 14px/1 FontAwesome; | ||||||
|  |           font-size: inherit; | ||||||
|  |           text-rendering: auto; | ||||||
|  |           -webkit-font-smoothing: antialiased; | ||||||
|  |           -moz-osx-font-smoothing: grayscale; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .ui-state-active, | ||||||
|  |     .ui-state-hover { | ||||||
|  |       color: $md-link-color; | ||||||
|  |       background-color: $calendar-hover-bg; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .ui-datepicker-prev, | ||||||
|  |     .ui-datepicker-next { | ||||||
|  |       top: 0; | ||||||
|  |       height: 15px; | ||||||
|  |       cursor: pointer; | ||||||
|  | 
 | ||||||
|  |       &:hover { | ||||||
|  |         background-color: transparent; | ||||||
|  |         border: 0; | ||||||
|  | 
 | ||||||
|  |         .ui-icon:before { | ||||||
|  |           color: $md-link-color; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .ui-datepicker-prev { | ||||||
|  |       left: 0; | ||||||
|  | 
 | ||||||
|  |       .ui-icon:before { | ||||||
|  |         content: '\f104'; | ||||||
|  |         text-align: left; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .ui-datepicker-next { | ||||||
|  |       right: 0; | ||||||
|  | 
 | ||||||
|  |       .ui-icon:before { | ||||||
|  |         content: '\f105'; | ||||||
|  |         text-align: right; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     td { | ||||||
|  |       padding: 0; | ||||||
|  |       border: 1px solid $calendar-border-color; | ||||||
|  | 
 | ||||||
|  |       &:first-child { | ||||||
|  |         border-left: 0; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       &:last-child { | ||||||
|  |         border-right: 0; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       a { | ||||||
|  |         line-height: 17px; | ||||||
|  |         border: 0; | ||||||
|  |         border-radius: 0; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .ui-datepicker-title { | ||||||
|  |       color: $gl-gray; | ||||||
|  |       font-size: 15px; | ||||||
|  |       line-height: 1; | ||||||
|  |       font-weight: normal; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   th { | ||||||
|  |     padding: 2px 0; | ||||||
|  |     color: $calendar-header-color; | ||||||
|  |     font-weight: normal; | ||||||
|  |     text-transform: lowercase; | ||||||
|  |     border-top: 1px solid $calendar-border-color; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .ui-datepicker-unselectable { | ||||||
|  |     background-color: $calendar-unselectable-bg; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -38,12 +38,14 @@ | ||||||
| 
 | 
 | ||||||
|     .filename { |     .filename { | ||||||
|       &.old { |       &.old { | ||||||
|  |         display: inline-block; | ||||||
|         span.idiff { |         span.idiff { | ||||||
|           background-color: #f8cbcb; |           background-color: #f8cbcb; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       &.new { |       &.new { | ||||||
|  |         display: inline-block; | ||||||
|         span.idiff { |         span.idiff { | ||||||
|           background-color: #a6f3a6; |           background-color: #a6f3a6; | ||||||
|         } |         } | ||||||
|  | @ -82,10 +84,6 @@ | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     &.blob_file { |  | ||||||
| 
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     &.blob-no-preview { |     &.blob-no-preview { | ||||||
|       background: #eee; |       background: #eee; | ||||||
|       text-shadow: 0 1px 2px #fff; |       text-shadow: 0 1px 2px #fff; | ||||||
|  | @ -129,6 +127,11 @@ | ||||||
|       td.line-numbers { |       td.line-numbers { | ||||||
|         float: none; |         float: none; | ||||||
|         border-left: 1px solid #ddd; |         border-left: 1px solid #ddd; | ||||||
|  | 
 | ||||||
|  |         i { | ||||||
|  |           float: none; | ||||||
|  |           margin-right: 0; | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|       td.lines { |       td.lines { | ||||||
|         padding: 0; |         padding: 0; | ||||||
|  |  | ||||||
|  | @ -78,6 +78,24 @@ label { | ||||||
|   border-radius: 3px; |   border-radius: 3px; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .select-wrapper { | ||||||
|  |   position: relative; | ||||||
|  | 
 | ||||||
|  |   .caret { | ||||||
|  |     position: absolute; | ||||||
|  |     right: 10px; | ||||||
|  |     top: $gl-padding; | ||||||
|  |     color: $gray-darkest; | ||||||
|  |     pointer-events: none; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .select-control { | ||||||
|  |   padding-left: 10px; | ||||||
|  |   padding-right: 10px; | ||||||
|  |   -webkit-appearance: none; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .form-control-inline { | .form-control-inline { | ||||||
|   display: inline; |   display: inline; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -24,6 +24,10 @@ | ||||||
|         background-color: $color-darker; |         background-color: $color-darker; | ||||||
|         a { |         a { | ||||||
|           color: #fff; |           color: #fff; | ||||||
|  | 
 | ||||||
|  |           h3 { | ||||||
|  |             color: #fff; | ||||||
|  |           } | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ header { | ||||||
|   &.navbar-empty { |   &.navbar-empty { | ||||||
|     height: 58px; |     height: 58px; | ||||||
|     background: #fff; |     background: #fff; | ||||||
|     border-bottom: 1px solid #eee; |     border-bottom: 1px solid $btn-gray-hover; | ||||||
| 
 | 
 | ||||||
|     .center-logo { |     .center-logo { | ||||||
|       margin: 11px 0; |       margin: 11px 0; | ||||||
|  | @ -22,13 +22,21 @@ header { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   &.navbar-gitlab { |   &.navbar-gitlab { | ||||||
|     padding: 0 20px; |     padding: 0 16px; | ||||||
|     z-index: 100; |     z-index: 100; | ||||||
|     margin-bottom: 0; |     margin-bottom: 0; | ||||||
|     min-height: $header-height; |     height: $header-height; | ||||||
|     background-color: #fff; |     background-color: $background-color; | ||||||
|     border: none; |     border: none; | ||||||
|     border-bottom: 1px solid #eee; |     border-bottom: 1px solid $border-color; | ||||||
|  | 
 | ||||||
|  |     @media (max-width: $screen-xs-min) { | ||||||
|  |       padding: 0 16px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     &.with-horizontal-nav { | ||||||
|  |       border-bottom: none; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     .container-fluid { |     .container-fluid { | ||||||
|       width: 100% !important; |       width: 100% !important; | ||||||
|  | @ -47,7 +55,7 @@ header { | ||||||
|         text-align: center; |         text-align: center; | ||||||
| 
 | 
 | ||||||
|         &:hover, &:focus, &:active { |         &:hover, &:focus, &:active { | ||||||
|           background-color: #fff; |           background-color: $background-color; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|  | @ -56,22 +64,54 @@ header { | ||||||
|         margin: 6px 0; |         margin: 6px 0; | ||||||
|         border-radius: 0; |         border-radius: 0; | ||||||
|         position: absolute; |         position: absolute; | ||||||
|         right: 2px; |         right: -10px; | ||||||
|  |         padding: 6px 10px; | ||||||
| 
 | 
 | ||||||
|         &:hover { |         &:hover { | ||||||
|           background-color: #eee; |           background-color: $btn-gray-hover; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         &.active { |         &.active { | ||||||
|           color: $gl-icon-color; |           color: $gl-icon-color; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     &.header-collapsed { | ||||||
|  |       padding: 0 16px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .side-nav-toggle { | ||||||
|  |       display: none; | ||||||
|  |       position: absolute; | ||||||
|  |       left: -10px; | ||||||
|  |       margin: 6px 0; | ||||||
|  |       padding: 6px 10px; | ||||||
|  |       border: none; | ||||||
|  |       background-color: $background-color; | ||||||
|  | 
 | ||||||
|  |       &:hover { | ||||||
|  |         background-color: $btn-gray-hover; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       &:focus { | ||||||
|  |         outline: none; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       @media (max-width: $screen-xs-min) { | ||||||
|  |         display: block; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .header-content { |   .header-content { | ||||||
|     position: relative; |     position: relative; | ||||||
|     height: $header-height; |     height: $header-height; | ||||||
|     padding-right: 20px; |     padding-right: 40px; | ||||||
|  | 
 | ||||||
|  |     @media (max-width: $screen-xs-min) { | ||||||
|  |       padding-left: 40px; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     @media (min-width: $screen-sm-min) { |     @media (min-width: $screen-sm-min) { | ||||||
|       padding-right: 0; |       padding-right: 0; | ||||||
|  | @ -122,6 +162,10 @@ header { | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   .project-item-select-holder { | ||||||
|  |     display: inline; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   .impersonation i { |   .impersonation i { | ||||||
|     color: $red-normal; |     color: $red-normal; | ||||||
|   } |   } | ||||||
|  | @ -137,6 +181,10 @@ header { | ||||||
|   @media (min-width: $screen-md-min) { |   @media (min-width: $screen-md-min) { | ||||||
|     @include collapsed-header; |     @include collapsed-header; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   @media (max-width: $screen-xs-min) { | ||||||
|  |     margin-left: 0; | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .header-expanded { | .header-expanded { | ||||||
|  | @ -145,6 +193,10 @@ header { | ||||||
|   @media (min-width: $screen-md-min) { |   @media (min-width: $screen-md-min) { | ||||||
|     margin-left: $sidebar_width; |     margin-left: $sidebar_width; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   @media (max-width: $screen-xs-min) { | ||||||
|  |     margin-left: 0; | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @media (max-width: $screen-xs-max) { | @media (max-width: $screen-xs-max) { | ||||||
|  |  | ||||||
|  | @ -5,7 +5,7 @@ | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| .status-box { | .status-box { | ||||||
|    | 
 | ||||||
|   /* Extra small devices (phones, less than 768px) */ |   /* Extra small devices (phones, less than 768px) */ | ||||||
|   /* No media query since this is the default in Bootstrap */ |   /* No media query since this is the default in Bootstrap */ | ||||||
|   padding: 5px 11px; |   padding: 5px 11px; | ||||||
|  |  | ||||||
|  | @ -90,3 +90,12 @@ | ||||||
|   box-shadow: none; |   box-shadow: none; | ||||||
|   width: 100%; |   width: 100%; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | .md { | ||||||
|  |   &.md-preview-holder { | ||||||
|  |     code { | ||||||
|  |       white-space: pre-wrap; | ||||||
|  |       word-break: keep-all; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -30,7 +30,7 @@ | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .rss-btn { |   .rss-btn { | ||||||
|     display: none !important; |     display: none; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .project-home-links { |   .project-home-links { | ||||||
|  | @ -70,13 +70,6 @@ | ||||||
|     display: none; |     display: none; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .issue-details { |  | ||||||
|     .creator, |  | ||||||
|     .page-title .btn-close { |  | ||||||
|       display: none; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   %ul.notes .note-role, .note-actions { |   %ul.notes .note-role, .note-actions { | ||||||
|     display: none; |     display: none; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,22 @@ | ||||||
|  | .modal-body { | ||||||
|  |   position: relative; | ||||||
|  |   overflow-y: auto; | ||||||
|  |   padding: 15px; | ||||||
|  | 
 | ||||||
|  |   .form-actions { | ||||||
|  |     margin: -$gl-padding+1; | ||||||
|  |     margin-top: 15px; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .text-danger { | ||||||
|  |     font-weight: bold; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | body.modal-open { | ||||||
|  |   overflow: hidden; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .modal .modal-dialog { | ||||||
|  |   width: 860px; | ||||||
|  | } | ||||||
|  | @ -26,8 +26,8 @@ | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     &.active a { |     &.active a { | ||||||
|       color: #000; |       border-bottom: 2px solid $link-underline-blue; | ||||||
|       border-bottom: 2px solid #4688f1; |       color: $black; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .badge { |     .badge { | ||||||
|  | @ -140,6 +140,12 @@ | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     .project-filter-form { | ||||||
|  |       input { | ||||||
|  |         background-color: $background-color; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @media (max-width: $screen-xs-max) { |     @media (max-width: $screen-xs-max) { | ||||||
|       padding-bottom: 0; |       padding-bottom: 0; | ||||||
| 
 | 
 | ||||||
|  | @ -185,3 +191,73 @@ | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | .layout-nav { | ||||||
|  |   position: fixed; | ||||||
|  |   top: $header-height; | ||||||
|  |   width: 100%; | ||||||
|  |   z-index: 1; | ||||||
|  |   background: $background-color; | ||||||
|  |   border-bottom: 1px solid $border-color; | ||||||
|  |   transition-duration: .3s; | ||||||
|  | 
 | ||||||
|  |   .container-fluid { | ||||||
|  |     position: relative; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .controls { | ||||||
|  |     float: right; | ||||||
|  |     padding: 7px 0 0; | ||||||
|  | 
 | ||||||
|  |     i { | ||||||
|  |       color: $layout-link-gray; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .fa-rss, | ||||||
|  |     .fa-cog { | ||||||
|  |       font-size: 16px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .fa-caret-down { | ||||||
|  |       margin-left: 5px; | ||||||
|  |       color: $gl-icon-color; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .dropdown { | ||||||
|  |       margin-left: 7px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .nav-links { | ||||||
|  |     border-bottom: none; | ||||||
|  |     height: 51px; | ||||||
|  |     white-space: nowrap; | ||||||
|  |     overflow-x: auto; | ||||||
|  | 
 | ||||||
|  |     li { | ||||||
|  | 
 | ||||||
|  |       a { | ||||||
|  |         padding-top: 10px; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       a, i { | ||||||
|  |         color: $layout-link-gray; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       &.active { | ||||||
|  |         a, i { | ||||||
|  |           color: $black; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       .badge { | ||||||
|  |         color: $gl-icon-color; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .page-with-layout-nav { | ||||||
|  |   margin-top: 50px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -7,13 +7,11 @@ | ||||||
|   .select2-choice { |   .select2-choice { | ||||||
|     background: #fff; |     background: #fff; | ||||||
|     border-color: $input-border; |     border-color: $input-border; | ||||||
|     border-color: $border-white-light; |  | ||||||
|     height: 35px; |     height: 35px; | ||||||
|     padding: $gl-vert-padding $gl-btn-padding; |     padding: $gl-vert-padding $gl-btn-padding; | ||||||
|     font-size: $gl-font-size; |     font-size: $gl-font-size; | ||||||
|     line-height: 1.42857143; |     line-height: 1.42857143; | ||||||
| 
 |     border-radius: $border-radius-base; | ||||||
|     @include border-radius($border-radius-default); |  | ||||||
| 
 | 
 | ||||||
|     .select2-arrow { |     .select2-arrow { | ||||||
|       background-image: none; |       background-image: none; | ||||||
|  | @ -121,9 +119,6 @@ | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .select2-container-multi .select2-choices .select2-search-choice { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .select2-drop-active { | .select2-drop-active { | ||||||
|   margin-top: 6px; |   margin-top: 6px; | ||||||
|   font-size: 14px; |   font-size: 14px; | ||||||
|  | @ -202,6 +197,14 @@ | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .select2-highlighted { | ||||||
|  |   .group-result { | ||||||
|  |     .group-path { | ||||||
|  |       color: #fff; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .group-result { | .group-result { | ||||||
|   .group-image { |   .group-image { | ||||||
|     float: left; |     float: left; | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
|   position: absolute; |   position: absolute; | ||||||
|   width: 58px; |   width: 58px; | ||||||
|   cursor: pointer; |   cursor: pointer; | ||||||
|  |   margin-top: 8px; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .page-with-sidebar { | .page-with-sidebar { | ||||||
|  | @ -62,7 +63,7 @@ | ||||||
|       float: left; |       float: left; | ||||||
|       height: $header-height; |       height: $header-height; | ||||||
|       width: 100%; |       width: 100%; | ||||||
|       padding: 11px 0 11px 22px; |       padding-left: 22px; | ||||||
|       overflow: hidden; |       overflow: hidden; | ||||||
|       outline: none; |       outline: none; | ||||||
|       transition-duration: .3s; |       transition-duration: .3s; | ||||||
|  | @ -85,7 +86,7 @@ | ||||||
|           margin: 0; |           margin: 0; | ||||||
|           margin-left: 50px; |           margin-left: 50px; | ||||||
|           font-size: 19px; |           font-size: 19px; | ||||||
|           line-height: 41px; |           line-height: 50px; | ||||||
|           font-weight: normal; |           font-weight: normal; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  | @ -97,7 +98,7 @@ | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .sidebar-user { |   .sidebar-user { | ||||||
|     padding: 9px 22px; |     padding: 7px 22px; | ||||||
|     position: fixed; |     position: fixed; | ||||||
|     bottom: 40px; |     bottom: 40px; | ||||||
|     width: $sidebar_width; |     width: $sidebar_width; | ||||||
|  | @ -209,15 +210,33 @@ | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .sidebar-wrapper { | ||||||
|  |   &.hidden-nav { | ||||||
|  |     width: 0; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .page-sidebar-collapsed { | .page-sidebar-collapsed { | ||||||
|   padding-left: $sidebar_collapsed_width; |   padding-left: $sidebar_collapsed_width; | ||||||
| 
 | 
 | ||||||
|  |   @media (max-width: $screen-xs-min) { | ||||||
|  |     padding-left: 0; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   .sidebar-wrapper { |   .sidebar-wrapper { | ||||||
|     width: $sidebar_collapsed_width; |     width: $sidebar_collapsed_width; | ||||||
| 
 | 
 | ||||||
|  |     @media (max-width: $screen-xs-min) { | ||||||
|  |       width: 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     .header-logo { |     .header-logo { | ||||||
|       width: $sidebar_collapsed_width; |       width: $sidebar_collapsed_width; | ||||||
| 
 | 
 | ||||||
|  |       @media (max-width: $screen-xs-min) { | ||||||
|  |         width: 0; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|       a { |       a { | ||||||
|         padding-left: ($sidebar_collapsed_width - 36) / 2; |         padding-left: ($sidebar_collapsed_width - 36) / 2; | ||||||
| 
 | 
 | ||||||
|  | @ -243,17 +262,35 @@ | ||||||
| 
 | 
 | ||||||
|     .collapse-nav a { |     .collapse-nav a { | ||||||
|       width: $sidebar_collapsed_width; |       width: $sidebar_collapsed_width; | ||||||
|  | 
 | ||||||
|  |       @media (max-width: $screen-xs-min) { | ||||||
|  |         width: 0; | ||||||
|  |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .sidebar-user { |     .sidebar-user { | ||||||
|       padding-left: ($sidebar_collapsed_width - 36) / 2; |       padding-left: ($sidebar_collapsed_width - 36) / 2; | ||||||
|       width: $sidebar_collapsed_width; |       width: $sidebar_collapsed_width; | ||||||
| 
 | 
 | ||||||
|  |       @media (max-width: $screen-xs-min) { | ||||||
|  |         width: 0; | ||||||
|  |         padding-left: 0; | ||||||
|  |         padding-right: 0; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|       .username { |       .username { | ||||||
|         display: none; |         display: none; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   .layout-nav { | ||||||
|  |     padding-right: $sidebar_collapsed_width; | ||||||
|  | 
 | ||||||
|  |     @media (max-width: $screen-xs-min) { | ||||||
|  |       padding-right: 0;; | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .page-sidebar-expanded { | .page-sidebar-expanded { | ||||||
|  | @ -263,6 +300,10 @@ | ||||||
|     padding-left: $sidebar_width; |     padding-left: $sidebar_width; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   @media (max-width: $screen-xs-min) { | ||||||
|  |     padding-left: 0; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   .sidebar-wrapper { |   .sidebar-wrapper { | ||||||
|     width: $sidebar_width; |     width: $sidebar_width; | ||||||
| 
 | 
 | ||||||
|  | @ -280,6 +321,20 @@ | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   .layout-nav { | ||||||
|  |     @media (max-width: $screen-xs-min) { | ||||||
|  |       padding-right: 0;; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @media (min-width: $screen-xs-min) and (max-width: $screen-md-min) { | ||||||
|  |       padding-right: 62px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @media (min-width: $screen-md-min) { | ||||||
|  |       padding-right: $sidebar_width; | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .right-sidebar-collapsed { | .right-sidebar-collapsed { | ||||||
|  |  | ||||||
|  | @ -32,13 +32,11 @@ table { | ||||||
|       th { |       th { | ||||||
|         background-color: $background-color; |         background-color: $background-color; | ||||||
|         font-weight: normal; |         font-weight: normal; | ||||||
|         font-size: 15px; |         border-bottom: none; | ||||||
|         border-bottom: 1px solid $border-color; |  | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       td { |       td { | ||||||
|         border-color: $table-border-color; |         border-color: $table-border-color; | ||||||
|         border-bottom: 1px solid $border-color; |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -11,7 +11,7 @@ | ||||||
|     border-bottom: 1px solid $border-white-light; |     border-bottom: 1px solid $border-white-light; | ||||||
| 
 | 
 | ||||||
|     &:target { |     &:target { | ||||||
|       background: $row-hover; |       background: $line-target-blue; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .avatar { |     .avatar { | ||||||
|  | @ -39,8 +39,7 @@ | ||||||
|   .diff-file { |   .diff-file { | ||||||
|     border: 1px solid $border-color; |     border: 1px solid $border-color; | ||||||
|     border-bottom: none; |     border-bottom: none; | ||||||
|     margin-left: 0; |     margin: 0; | ||||||
|     margin-right: 0; |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -81,7 +81,7 @@ | ||||||
| 
 | 
 | ||||||
| // Labels | // Labels | ||||||
| .label { | .label { | ||||||
|   padding: 2px 4px; |   padding: 4px 5px; | ||||||
|   font-size: 13px; |   font-size: 13px; | ||||||
|   font-style: normal; |   font-style: normal; | ||||||
|   font-weight: normal; |   font-weight: normal; | ||||||
|  |  | ||||||
|  | @ -153,8 +153,8 @@ $nav-link-padding: 13px $gl-padding; | ||||||
| //== Code | //== Code | ||||||
| // | // | ||||||
| //## | //## | ||||||
| $pre-bg:           #f8fafc !default; | $pre-bg:           $background-color !default; | ||||||
| $pre-color:        $gl-gray !default; | $pre-color:        $gl-gray !default; | ||||||
| $pre-border-color: #e7e9ed; | $pre-border-color: $border-color; | ||||||
| 
 | 
 | ||||||
| $table-bg-accent: $background-color; | $table-bg-accent: $background-color; | ||||||
|  |  | ||||||
|  | @ -42,14 +42,14 @@ | ||||||
|     margin: 24px 0 12px; |     margin: 24px 0 12px; | ||||||
|     padding: 0 0 10px; |     padding: 0 0 10px; | ||||||
|     border-bottom: 1px solid #e7e9ed; |     border-bottom: 1px solid #e7e9ed; | ||||||
|     color: #313236; |     color: $gl-gray-dark; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   h2 { |   h2 { | ||||||
|     font-size: 1.2em; |     font-size: 1.2em; | ||||||
|     font-weight: 600; |     font-weight: 600; | ||||||
|     margin: 24px 0 12px; |     margin: 24px 0 12px; | ||||||
|     color: #313236; |     color: $gl-gray-dark; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   h3 { |   h3 { | ||||||
|  | @ -205,6 +205,10 @@ h1, h2, h3, h4, h5, h6 { | ||||||
|   font-weight: 600; |   font-weight: 600; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .light-header { | ||||||
|  |   font-weight: 600; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /** CODE **/ | /** CODE **/ | ||||||
| pre { | pre { | ||||||
|   font-family: $monospace_font; |   font-family: $monospace_font; | ||||||
|  | @ -259,3 +263,9 @@ h1, h2, h3, h4 { | ||||||
|     color: $gl-gray; |     color: $gl-gray; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | .text-right-lg { | ||||||
|  |   @media (min-width: $screen-lg-min) { | ||||||
|  |     text-align: right; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ $gutter_inner_width: 258px; | ||||||
|  */ |  */ | ||||||
| $border-color:       #e5e5e5; | $border-color:       #e5e5e5; | ||||||
| $focus-border-color: #3aabf0; | $focus-border-color: #3aabf0; | ||||||
| $table-border-color: #eef0f2; | $table-border-color: #ececec; | ||||||
| $background-color:   #fafafa; | $background-color:   #fafafa; | ||||||
| 
 | 
 | ||||||
| /* | /* | ||||||
|  | @ -20,7 +20,7 @@ $background-color:   #fafafa; | ||||||
|  */ |  */ | ||||||
| $gl-font-size:         15px; | $gl-font-size:         15px; | ||||||
| $gl-title-color:       #333; | $gl-title-color:       #333; | ||||||
| $gl-text-color:        #555; | $gl-text-color:        #5c5c5c; | ||||||
| $gl-text-green:        #4a2; | $gl-text-green:        #4a2; | ||||||
| $gl-text-red:          #d12f19; | $gl-text-red:          #d12f19; | ||||||
| $gl-text-orange:       #d90; | $gl-text-orange:       #d90; | ||||||
|  | @ -30,6 +30,7 @@ $gl-placeholder-color: #8f8f8f; | ||||||
| $gl-icon-color:        $gl-placeholder-color; | $gl-icon-color:        $gl-placeholder-color; | ||||||
| $gl-grayish-blue:      #7f8fa4; | $gl-grayish-blue:      #7f8fa4; | ||||||
| $gl-gray:              $gl-text-color; | $gl-gray:              $gl-text-color; | ||||||
|  | $gl-gray-dark:         #313236; | ||||||
| $gl-header-color:      $gl-title-color; | $gl-header-color:      $gl-title-color; | ||||||
| 
 | 
 | ||||||
| /* | /* | ||||||
|  | @ -65,16 +66,18 @@ $gl-padding-top: 10px; | ||||||
| $row-hover: #f4f8fe; | $row-hover: #f4f8fe; | ||||||
| $progress-color: #c0392b; | $progress-color: #c0392b; | ||||||
| $avatar_radius: 50%; | $avatar_radius: 50%; | ||||||
| $header-height: 58px; | $header-height: 50px; | ||||||
| $fixed-layout-width: 1280px; | $fixed-layout-width: 1280px; | ||||||
| $gl-avatar-size: 40px; | $gl-avatar-size: 40px; | ||||||
| $error-exclamation-point: #e62958; | $error-exclamation-point: #e62958; | ||||||
| $border-radius-default: 2px; | $border-radius-default: 2px; | ||||||
| $btn-transparent-color: #8f8f8f; | $btn-transparent-color: #8f8f8f; | ||||||
| $ssh-key-icon-color: #8f8f8f; | $settings-icon-size: 18px; | ||||||
| $ssh-key-icon-size: 18px; |  | ||||||
| $provider-btn-group-border: #e5e5e5; | $provider-btn-group-border: #e5e5e5; | ||||||
| $provider-btn-not-active-color: #4688f1; | $provider-btn-not-active-color: #4688f1; | ||||||
|  | $link-underline-blue: #4a8bee; | ||||||
|  | $layout-link-gray: #7e7c7c; | ||||||
|  | $todo-alert-blue: #428bca; | ||||||
| 
 | 
 | ||||||
| /* | /* | ||||||
|  * Color schema |  * Color schema | ||||||
|  | @ -109,6 +112,7 @@ $red-light: #e52c5a; | ||||||
| $red-normal: #d22852; | $red-normal: #d22852; | ||||||
| $red-dark: darken($red-normal, 5%); | $red-dark: darken($red-normal, 5%); | ||||||
| 
 | 
 | ||||||
|  | $black: #000; | ||||||
| $black-transparent: rgba(0, 0, 0, 0.3); | $black-transparent: rgba(0, 0, 0, 0.3); | ||||||
| 
 | 
 | ||||||
| $border-white-light: #f1f2f4; | $border-white-light: #f1f2f4; | ||||||
|  | @ -168,8 +172,12 @@ $line-removed: #fbe9eb; | ||||||
| $line-removed-dark: #fac5cd; | $line-removed-dark: #fac5cd; | ||||||
| $line-number-old: #f9d7dc; | $line-number-old: #f9d7dc; | ||||||
| $line-number-new: #ddfbe6; | $line-number-new: #ddfbe6; | ||||||
|  | $line-number-select: #fbf2da; | ||||||
| $match-line: #fafafa; | $match-line: #fafafa; | ||||||
| $table-border-gray: #f0f0f0; | $table-border-gray: #f0f0f0; | ||||||
|  | $line-target-blue: #eaf3fc; | ||||||
|  | $line-select-yellow: #fcf8e7; | ||||||
|  | $line-select-yellow-dark: #f0e2bd; | ||||||
| /* | /* | ||||||
|  * Fonts |  * Fonts | ||||||
|  */ |  */ | ||||||
|  | @ -179,7 +187,6 @@ $regular_font: 'Source Sans Pro', "Helvetica Neue", Helvetica, Arial, sans-serif | ||||||
| /* | /* | ||||||
| * Dropdowns | * Dropdowns | ||||||
| */ | */ | ||||||
| $dropdown-border-radius: 2px; |  | ||||||
| $dropdown-width: 300px; | $dropdown-width: 300px; | ||||||
| $dropdown-bg: #fff; | $dropdown-bg: #fff; | ||||||
| $dropdown-link-color: #555; | $dropdown-link-color: #555; | ||||||
|  | @ -208,6 +215,7 @@ $dropdown-toggle-hover-icon-color: $dropdown-toggle-hover-border-color; | ||||||
| $btn-active-gray: #ececec; | $btn-active-gray: #ececec; | ||||||
| $btn-placeholder-gray: #c7c7c7; | $btn-placeholder-gray: #c7c7c7; | ||||||
| $btn-white-active: #848484; | $btn-white-active: #848484; | ||||||
|  | $btn-gray-hover: #eee; | ||||||
| 
 | 
 | ||||||
| /* | /* | ||||||
|  *  Award emoji |  *  Award emoji | ||||||
|  | @ -241,3 +249,8 @@ $note-form-border-color: #e5e5e5; | ||||||
| $note-toolbar-color: #959494; | $note-toolbar-color: #959494; | ||||||
| 
 | 
 | ||||||
| $zen-control-hover-color: #111; | $zen-control-hover-color: #111; | ||||||
|  | 
 | ||||||
|  | $calendar-header-color: #b8b8b8; | ||||||
|  | $calendar-hover-bg: #ecf3fe; | ||||||
|  | $calendar-border-color: rgba(#000, .1); | ||||||
|  | $calendar-unselectable-bg: #faf9f9; | ||||||
|  |  | ||||||
|  | @ -111,8 +111,6 @@ | ||||||
|   .vg { color: #f8f8f2 } /* Name.Variable.Global */ |   .vg { color: #f8f8f2 } /* Name.Variable.Global */ | ||||||
|   .vi { color: #f8f8f2 } /* Name.Variable.Instance */ |   .vi { color: #f8f8f2 } /* Name.Variable.Instance */ | ||||||
|   .il { color: #ae81ff } /* Literal.Number.Integer.Long */ |   .il { color: #ae81ff } /* Literal.Number.Integer.Long */ | ||||||
| 
 |  | ||||||
|   .gh { } /* Generic Heading & Diff Header */ |  | ||||||
|   .gu { color: #75715e; } /* Generic.Subheading & Diff Unified/Comment? */ |   .gu { color: #75715e; } /* Generic.Subheading & Diff Unified/Comment? */ | ||||||
|   .gd { color: #f92672; } /* Generic.Deleted & Diff Deleted */ |   .gd { color: #f92672; } /* Generic.Deleted & Diff Deleted */ | ||||||
|   .gi { color: #a6e22e; } /* Generic.Inserted & Diff Inserted */ |   .gi { color: #a6e22e; } /* Generic.Inserted & Diff Inserted */ | ||||||
|  |  | ||||||
|  | @ -21,11 +21,6 @@ | ||||||
| 
 | 
 | ||||||
|   // Diff line |   // Diff line | ||||||
|   .line_holder { |   .line_holder { | ||||||
|     td.diff-line-num.hll:not(.empty-cell), |  | ||||||
|     td.line_content.hll:not(.empty-cell) { |  | ||||||
|       background-color: #f8eec7; |  | ||||||
|       border-color: darken(#f8eec7, 15%); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     .diff-line-num { |     .diff-line-num { | ||||||
|       &.old { |       &.old { | ||||||
|  | @ -37,11 +32,16 @@ | ||||||
|         background-color: $line-number-new; |         background-color: $line-number-new; | ||||||
|         border-color: $line-added-dark; |         border-color: $line-added-dark; | ||||||
|       } |       } | ||||||
|  | 
 | ||||||
|  |       &.hll:not(.empty-cell) { | ||||||
|  |         background-color: $line-number-select; | ||||||
|  |         border-color: $line-select-yellow-dark; | ||||||
|  |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .line_content { |     .line_content { | ||||||
|       &.old { |       &.old { | ||||||
|         background: $line-removed; |         background-color: $line-removed; | ||||||
| 
 | 
 | ||||||
|         span.idiff { |         span.idiff { | ||||||
|           background-color: $line-removed-dark; |           background-color: $line-removed-dark; | ||||||
|  | @ -58,7 +58,11 @@ | ||||||
| 
 | 
 | ||||||
|       &.match { |       &.match { | ||||||
|         color: $black-transparent; |         color: $black-transparent; | ||||||
|         background: $match-line; |         background-color: $match-line; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       &.hll:not(.empty-cell) { | ||||||
|  |         background-color: $line-select-yellow; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -83,3 +83,12 @@ | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | table.builds { | ||||||
|  | 
 | ||||||
|  |   .build-link { | ||||||
|  |     a { | ||||||
|  |       color: $gl-dark-link-color; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -31,9 +31,23 @@ | ||||||
|   } |   } | ||||||
|   .commit-committer-link, |   .commit-committer-link, | ||||||
|   .commit-author-link { |   .commit-author-link { | ||||||
|     color: #444; |     color: $gl-gray; | ||||||
|     font-weight: bold; |     font-weight: bold; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   .time_ago { | ||||||
|  |     margin-left: 8px; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .fa-clipboard { | ||||||
|  |     color: $dropdown-title-btn-color; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .commit-info { | ||||||
|  |     &.branches { | ||||||
|  |       margin-left: 8px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .commit-box { | .commit-box { | ||||||
|  | @ -42,7 +56,7 @@ | ||||||
|   .commit-title { |   .commit-title { | ||||||
|     margin: 0; |     margin: 0; | ||||||
|     font-size: 23px; |     font-size: 23px; | ||||||
|     color: #313236; |     color: $gl-gray-dark; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .commit-description { |   .commit-description { | ||||||
|  | @ -83,6 +97,14 @@ | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .commit-action-buttons { | ||||||
|  |   i { | ||||||
|  |     color: $gl-icon-color; | ||||||
|  |     font-size: 13px; | ||||||
|  |     margin-right: 3px; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* | /* | ||||||
|  * Commit message textarea for web editor and |  * Commit message textarea for web editor and | ||||||
|  * custom merge request message |  * custom merge request message | ||||||
|  |  | ||||||
|  | @ -0,0 +1,18 @@ | ||||||
|  | .well-confirmation { | ||||||
|  |   margin-bottom: 20px; | ||||||
|  |   border-bottom: 1px solid #eee; | ||||||
|  | 
 | ||||||
|  |   > h1 { | ||||||
|  |     font-weight: 400; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .lead { | ||||||
|  |     margin-bottom: 20px; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .confirmation-content { | ||||||
|  |   a { | ||||||
|  |     color: $md-link-color; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| .detail-page-header { | .detail-page-header { | ||||||
|   padding: 11px 0; |   padding: $gl-padding-top 0; | ||||||
|   border-bottom: 1px solid $border-color; |   border-bottom: 1px solid $border-color; | ||||||
|   color: #5c5d5e; |   color: #5c5d5e; | ||||||
|   font-size: 16px; |   font-size: 16px; | ||||||
|  | @ -16,18 +16,13 @@ | ||||||
|   .issue_created_ago, .author_link { |   .issue_created_ago, .author_link { | ||||||
|     white-space: nowrap; |     white-space: nowrap; | ||||||
|   } |   } | ||||||
| 
 |  | ||||||
|   .issue-meta { |  | ||||||
|     display: inline-block; |  | ||||||
|     line-height: 20px; |  | ||||||
|   } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .detail-page-description { | .detail-page-description { | ||||||
|   .title { |   .title { | ||||||
|     margin: 0; |     margin: 0; | ||||||
|     font-size: 23px; |     font-size: 23px; | ||||||
|     color: #313236; |     color: $gl-gray-dark; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .description { |   .description { | ||||||
|  | @ -41,4 +36,11 @@ | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   .wiki { | ||||||
|  |     code { | ||||||
|  |       white-space: pre-wrap; | ||||||
|  |       word-break: keep-all; | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -34,6 +34,7 @@ | ||||||
|     background: #fff; |     background: #fff; | ||||||
|     color: #333; |     color: #333; | ||||||
|     border-radius: 0 0 3px 3px; |     border-radius: 0 0 3px 3px; | ||||||
|  |     -webkit-overflow-scrolling: auto; | ||||||
| 
 | 
 | ||||||
|     .unfold { |     .unfold { | ||||||
|       cursor: pointer; |       cursor: pointer; | ||||||
|  | @ -86,7 +87,7 @@ | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         span { |         span { | ||||||
|           white-space: pre; |           white-space: pre-wrap; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  | @ -97,7 +98,11 @@ | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       td.line_content.parallel { |       td.line_content.parallel { | ||||||
|         width: 50%; |         width: 46%; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       .add-diff-note { | ||||||
|  |         margin-left: -65px; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -126,8 +131,13 @@ | ||||||
|       margin: 0; |       margin: 0; | ||||||
|       padding: 0 0.5em; |       padding: 0 0.5em; | ||||||
|       border: none; |       border: none; | ||||||
|  | 
 | ||||||
|       &.parallel { |       &.parallel { | ||||||
|         display: table-cell; |         display: table-cell; | ||||||
|  | 
 | ||||||
|  |         span { | ||||||
|  |           word-break: break-all; | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -335,7 +345,7 @@ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .diff-file .line_content { | .diff-file .line_content { | ||||||
|   white-space: pre; |   white-space: pre-wrap; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .diff-wrap-lines .line_content { | .diff-wrap-lines .line_content { | ||||||
|  |  | ||||||
|  | @ -26,6 +26,10 @@ | ||||||
|     line-height: 42px; |     line-height: 42px; | ||||||
|     padding-top: 7px; |     padding-top: 7px; | ||||||
|     padding-bottom: 7px; |     padding-bottom: 7px; | ||||||
|  | 
 | ||||||
|  |     .pull-right { | ||||||
|  |       height: 20px; | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .editor-ref { |   .editor-ref { | ||||||
|  | @ -53,4 +57,9 @@ | ||||||
|   .select2 { |   .select2 { | ||||||
|     float: right; |     float: right; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   .encoding-selector, | ||||||
|  |   .license-selector { | ||||||
|  |     display: inline-block; | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -18,9 +18,6 @@ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .graphs { | .graphs { | ||||||
|   .graph-author-commits-count { |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   .graph-author-email { |   .graph-author-email { | ||||||
|     float: right; |     float: right; | ||||||
|     color: #777; |     color: #777; | ||||||
|  |  | ||||||
|  | @ -55,23 +55,6 @@ | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .modal-body { |  | ||||||
|   position: relative; |  | ||||||
|   overflow-y: auto; |  | ||||||
|   padding: 15px; |  | ||||||
|   .form-actions { |  | ||||||
|     margin: -$gl-padding+1; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| body.modal-open { |  | ||||||
|   overflow: hidden; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .modal .modal-dialog { |  | ||||||
|   width: 860px; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .documentation { | .documentation { | ||||||
|   padding: 7px; |   padding: 7px; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -16,3 +16,24 @@ i.icon-gitorious-big { | ||||||
|   width: 18px; |   width: 18px; | ||||||
|   height: 18px; |   height: 18px; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | .import-jobs-from-col, | ||||||
|  | .import-jobs-to-col { | ||||||
|  |   width: 40%; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .import-jobs-status-col { | ||||||
|  |   width: 20%; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .btn-import { | ||||||
|  |   .loading-icon { | ||||||
|  |     display: none; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   &.is-loading { | ||||||
|  |     .loading-icon { | ||||||
|  |       display: inline-block; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -128,6 +128,7 @@ | ||||||
|   top: 58px; |   top: 58px; | ||||||
|   bottom: 0; |   bottom: 0; | ||||||
|   right: 0; |   right: 0; | ||||||
|  |   z-index: 10; | ||||||
|   transition: width .3s; |   transition: width .3s; | ||||||
|   background: $gray-light; |   background: $gray-light; | ||||||
|   padding: 10px 20px; |   padding: 10px 20px; | ||||||
|  | @ -241,16 +242,20 @@ | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .btn { |   .issuable-pager { | ||||||
|     background: $gray-normal; |     background: $gray-normal; | ||||||
|     border: 1px solid $border-gray-normal; |     border: 1px solid $border-gray-normal; | ||||||
|     &:hover { |     &:hover { | ||||||
|       background: $gray-dark; |       background: $gray-dark; | ||||||
|       border: 1px solid $border-gray-dark; |       border: 1px solid $border-gray-dark; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     &.btn-primary { | ||||||
|  |       @extend .btn-primary | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   a:not(.btn) { |   a:not(.issuable-pager) { | ||||||
|     &:hover { |     &:hover { | ||||||
|       color: $md-link-color; |       color: $md-link-color; | ||||||
|       text-decoration: none; |       text-decoration: none; | ||||||
|  | @ -273,10 +278,6 @@ | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .btn-default.gutter-toggle { |  | ||||||
|   margin-top: 4px; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .detail-page-description { | .detail-page-description { | ||||||
|   small { |   small { | ||||||
|     color: $gray-darkest; |     color: $gray-darkest; | ||||||
|  | @ -322,3 +323,50 @@ | ||||||
|     padding-top: 7px; |     padding-top: 7px; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | .issuable-status-box { | ||||||
|  |   float: none; | ||||||
|  |   display: inline-block; | ||||||
|  |   margin-top: 0; | ||||||
|  | 
 | ||||||
|  |   @media (max-width: $screen-xs-max) { | ||||||
|  |     position: absolute; | ||||||
|  |     top: 0; | ||||||
|  |     left: 0; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .issuable-header { | ||||||
|  |   position: relative; | ||||||
|  |   padding-left: 45px; | ||||||
|  |   padding-right: 45px; | ||||||
|  |   line-height: 35px; | ||||||
|  | 
 | ||||||
|  |   @media (min-width: $screen-sm-min) { | ||||||
|  |     float: left; | ||||||
|  |     padding-left: 0; | ||||||
|  |     padding-right: 0; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .issuable-actions { | ||||||
|  |   padding-top: 10px; | ||||||
|  | 
 | ||||||
|  |   @media (min-width: $screen-sm-min) { | ||||||
|  |     float: right; | ||||||
|  |     padding-top: 0; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .issuable-gutter-toggle { | ||||||
|  |   @media (max-width: $screen-sm-max) { | ||||||
|  |     position: absolute; | ||||||
|  |     top: 0; | ||||||
|  |     right: 0; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .issuable-meta { | ||||||
|  |   display: inline-block; | ||||||
|  |   line-height: 18px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -86,41 +86,9 @@ form.edit-issue { | ||||||
| @media (max-width: $screen-xs-max) { | @media (max-width: $screen-xs-max) { | ||||||
|   .issue-btn-group { |   .issue-btn-group { | ||||||
|     width: 100%; |     width: 100%; | ||||||
|     margin-top: 5px; |  | ||||||
| 
 |  | ||||||
|     .btn-group { |  | ||||||
|       width: 100%; |  | ||||||
| 
 |  | ||||||
|       ul { |  | ||||||
|         width: 100%; |  | ||||||
|         text-align: center; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     .btn { |     .btn { | ||||||
|       width: 100%; |       width: 100%; | ||||||
| 
 |  | ||||||
|       &:first-child:not(:last-child) { |  | ||||||
| 
 |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       &:not(:first-child):not(:last-child) { |  | ||||||
|         margin-top: 10px; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       &:last-child:not(:first-child) { |  | ||||||
|         margin-top: 10px; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   .issue { |  | ||||||
|     &:hover  .issue-actions { |  | ||||||
|       display: none !important; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     .issue-updated-at { |  | ||||||
|       display: none; |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | @ -133,11 +101,3 @@ form.edit-issue { | ||||||
|   color: $gl-text-color; |   color: $gl-text-color; | ||||||
|   margin-left: 52px; |   margin-left: 52px; | ||||||
| } | } | ||||||
| 
 |  | ||||||
| .editor-details { |  | ||||||
|   display: block; |  | ||||||
| 
 |  | ||||||
|   @media (min-width: $screen-sm-min) { |  | ||||||
|     display: inline-block; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -104,7 +104,7 @@ | ||||||
|       font-weight: 600; |       font-weight: 600; | ||||||
|       font-size: 17px; |       font-size: 17px; | ||||||
|       margin: 5px 0; |       margin: 5px 0; | ||||||
|       color: #313236; |       color: $gl-gray-dark; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     p:last-child { |     p:last-child { | ||||||
|  | @ -136,7 +136,7 @@ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .label-branch { | .label-branch { | ||||||
|   color: #313236; |   color: $gl-gray-dark; | ||||||
|   font-family: $monospace_font; |   font-family: $monospace_font; | ||||||
|   font-weight: bold; |   font-weight: bold; | ||||||
|   overflow: hidden; |   overflow: hidden; | ||||||
|  | @ -272,3 +272,19 @@ | ||||||
|   display: inline-block; |   display: inline-block; | ||||||
|   width: 250px; |   width: 250px; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | .table-holder { | ||||||
|  |   .builds { | ||||||
|  | 
 | ||||||
|  |     th { | ||||||
|  |       background-color: $white-light; | ||||||
|  |       color: $gl-placeholder-color; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     th, | ||||||
|  |     td { | ||||||
|  |       padding: 16px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | @ -28,7 +28,7 @@ li.milestone { | ||||||
| 
 | 
 | ||||||
|     // Issue title |     // Issue title | ||||||
|     span a { |     span a { | ||||||
|       color: rgba(0,0,0,0.64); |       color: $gl-text-color; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | @ -51,7 +51,7 @@ li.milestone { | ||||||
|     margin-top: 7px; |     margin-top: 7px; | ||||||
| 
 | 
 | ||||||
|     .issuable-number { |     .issuable-number { | ||||||
|       color: rgba(0,0,0,0.44); |       color: $gl-placeholder-color; | ||||||
|       margin-right: 5px; |       margin-right: 5px; | ||||||
|     } |     } | ||||||
|     .avatar { |     .avatar { | ||||||
|  |  | ||||||
|  | @ -42,6 +42,7 @@ | ||||||
| .note-textarea { | .note-textarea { | ||||||
|   display: block; |   display: block; | ||||||
|   padding: 10px 0; |   padding: 10px 0; | ||||||
|  |   color: $gl-gray; | ||||||
|   font-family: $regular_font; |   font-family: $regular_font; | ||||||
|   border: 0; |   border: 0; | ||||||
| 
 | 
 | ||||||
|  | @ -61,11 +62,11 @@ | ||||||
|     padding: $gl-padding-top $gl-padding; |     padding: $gl-padding-top $gl-padding; | ||||||
|     border: 1px solid $note-form-border-color; |     border: 1px solid $note-form-border-color; | ||||||
|     border-radius: $border-radius-base; |     border-radius: $border-radius-base; | ||||||
|  |     transition: border-color ease-in-out 0.15s, | ||||||
|  |                 box-shadow ease-in-out 0.15s; | ||||||
| 
 | 
 | ||||||
|     &.is-focused { |     &.is-focused { | ||||||
|       border-color: $focus-border-color; |       @extend .form-control:focus; | ||||||
|       box-shadow: 0 0 2px $black-transparent, |  | ||||||
|                   0 0 4px rgba($focus-border-color, .4); |  | ||||||
| 
 | 
 | ||||||
|       .comment-toolbar, |       .comment-toolbar, | ||||||
|       .nav-links { |       .nav-links { | ||||||
|  | @ -83,18 +84,6 @@ | ||||||
|         border-color: $gl-success; |         border-color: $gl-success; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     p { |  | ||||||
|       code { |  | ||||||
|         white-space: normal; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       pre { |  | ||||||
|         code { |  | ||||||
|           white-space: pre; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -80,16 +80,8 @@ ul.notes { | ||||||
|         @include md-typography; |         @include md-typography; | ||||||
| 
 | 
 | ||||||
|         // On diffs code should wrap nicely and not overflow |         // On diffs code should wrap nicely and not overflow | ||||||
|         p { |         code { | ||||||
|           code { |           white-space: pre-wrap; | ||||||
|             white-space: normal; |  | ||||||
|           } |  | ||||||
| 
 |  | ||||||
|           pre { |  | ||||||
|             code { |  | ||||||
|               white-space: pre; |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Reset ul style types since we're nested inside a ul already |         // Reset ul style types since we're nested inside a ul already | ||||||
|  | @ -116,10 +108,10 @@ ul.notes { | ||||||
|           border-color: darken(#f5f5f5, 8%); |           border-color: darken(#f5f5f5, 8%); | ||||||
|           margin: 10px 0; |           margin: 10px 0; | ||||||
|         } |         } | ||||||
|       } |  | ||||||
| 
 | 
 | ||||||
|       a { |         code { | ||||||
|         word-break: break-all; |           word-break: keep-all; | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -136,7 +128,7 @@ ul.notes { | ||||||
|     margin-right: 10px; |     margin-right: 10px; | ||||||
|   } |   } | ||||||
|   .line_content { |   .line_content { | ||||||
|     white-space: pre; |     white-space: pre-wrap; | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -175,6 +167,11 @@ ul.notes { | ||||||
|       .notes { |       .notes { | ||||||
|         background-color: $white-light; |         background-color: $white-light; | ||||||
|       } |       } | ||||||
|  | 
 | ||||||
|  |       a code { | ||||||
|  |         top: 0; | ||||||
|  |         margin-right: 0; | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | @ -190,6 +187,9 @@ ul.notes { | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   .author_link { | ||||||
|  |     color: $gl-gray; | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .note-headline-light, | .note-headline-light, | ||||||
|  | @ -197,6 +197,12 @@ ul.notes { | ||||||
|   color: $notes-light-color; |   color: $notes-light-color; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .discussion-headline-light { | ||||||
|  |   a { | ||||||
|  |     color: $gl-link-color; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * Actions for Discussions/Notes |  * Actions for Discussions/Notes | ||||||
|  */ |  */ | ||||||
|  | @ -208,6 +214,17 @@ ul.notes { | ||||||
|   color: $notes-action-color; |   color: $notes-action-color; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .discussion-actions { | ||||||
|  |   @media (max-width: $screen-md-max) { | ||||||
|  |     float: none; | ||||||
|  |     margin-left: 0; | ||||||
|  | 
 | ||||||
|  |     .note-action-button { | ||||||
|  |       margin-left: 0; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .note-action-button, | .note-action-button, | ||||||
| .discussion-action-button { | .discussion-action-button { | ||||||
|   display: inline-block; |   display: inline-block; | ||||||
|  | @ -285,7 +302,7 @@ ul.notes { | ||||||
|     padding: 4px; |     padding: 4px; | ||||||
|     font-size: 16px; |     font-size: 16px; | ||||||
|     color: $gl-link-color; |     color: $gl-link-color; | ||||||
|     margin-left: -60px; |     margin-left: -56px; | ||||||
|     position: absolute; |     position: absolute; | ||||||
|     z-index: 10; |     z-index: 10; | ||||||
|     width: 32px; |     width: 32px; | ||||||
|  |  | ||||||
|  | @ -18,7 +18,8 @@ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .account-btn-link, | .account-btn-link, | ||||||
| .profile-settings-sidebar a { | .profile-settings-sidebar a, | ||||||
|  | .settings-sidebar a { | ||||||
|   color: $md-link-color; |   color: $md-link-color; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -123,12 +124,6 @@ | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .key-icon { |  | ||||||
|   color: $ssh-key-icon-color; |  | ||||||
|   font-size: $ssh-key-icon-size; |  | ||||||
|   line-height: 42px; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .key-created-at { | .key-created-at { | ||||||
|   line-height: 42px; |   line-height: 42px; | ||||||
| } | } | ||||||
|  | @ -180,14 +175,6 @@ | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .profile-settings-message { |  | ||||||
|   line-height: 32px; |  | ||||||
|   color: $warning-message-color; |  | ||||||
|   background-color: $warning-message-bg; |  | ||||||
|   border: 1px solid $warning-message-border; |  | ||||||
|   border-radius: $border-radius-base; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .oauth-applications { | .oauth-applications { | ||||||
|   form { |   form { | ||||||
|     display: inline-block; |     display: inline-block; | ||||||
|  | @ -218,3 +205,21 @@ | ||||||
|     text-align: center; |     text-align: center; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | .user-profile { | ||||||
|  |   @media (max-width: $screen-xs-max) { | ||||||
|  |     .cover-block { | ||||||
|  |       padding-top: 20px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .cover-controls { | ||||||
|  |       position: static; | ||||||
|  |       margin-bottom: 20px; | ||||||
|  | 
 | ||||||
|  |       .btn { | ||||||
|  |         display: inline-block; | ||||||
|  |         width: 46%; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -178,7 +178,7 @@ | ||||||
|     .option-title { |     .option-title { | ||||||
|       font-weight: normal; |       font-weight: normal; | ||||||
|       display: inline-block; |       display: inline-block; | ||||||
|       color: #313236; |       color: $gl-gray-dark; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .option-descr { |     .option-descr { | ||||||
|  | @ -202,8 +202,31 @@ | ||||||
|   min-width: 200px; |   min-width: 200px; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .deploy-project-label { | .deploy-key-content { | ||||||
|   margin: 1px; |   @media (min-width: $screen-sm-min) { | ||||||
|  |     float: left; | ||||||
|  | 
 | ||||||
|  |     &:last-child { | ||||||
|  |       float: right; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .deploy-key-projects { | ||||||
|  |   @media (min-width: $screen-sm-min) { | ||||||
|  |     line-height: 42px; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | a.deploy-project-label { | ||||||
|  |   padding: 5px; | ||||||
|  |   margin-right: 5px; | ||||||
|  |   color: $gl-gray; | ||||||
|  |   background-color: $row-hover; | ||||||
|  | 
 | ||||||
|  |   &:hover { | ||||||
|  |     color: $gl-link-color; | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .vs-public { | .vs-public { | ||||||
|  | @ -256,12 +279,6 @@ | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| table.table.protected-branches-list tr.no-border { |  | ||||||
|   th, td { |  | ||||||
|     border: 0; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .project-import .btn { | .project-import .btn { | ||||||
|   float: left; |   float: left; | ||||||
|   margin-right: 10px; |   margin-right: 10px; | ||||||
|  | @ -474,3 +491,14 @@ pre.light-well { | ||||||
|     color: #fff; |     color: #fff; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | .protected-branches-list { | ||||||
|  |   a { | ||||||
|  |     color: $gl-gray; | ||||||
|  |     font-weight: 600; | ||||||
|  | 
 | ||||||
|  |     &:hover { | ||||||
|  |       color: $gl-link-color; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -10,17 +10,6 @@ | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .search-holder { |  | ||||||
|   max-width: 600px; |  | ||||||
|   margin: 0 auto; |  | ||||||
|   margin-bottom: 20px; |  | ||||||
| 
 |  | ||||||
|   input { |  | ||||||
|     border-color: #bbb; |  | ||||||
|     font-weight: bold; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .search { | .search { | ||||||
|   margin-right: 10px; |   margin-right: 10px; | ||||||
|   margin-left: 10px; |   margin-left: 10px; | ||||||
|  | @ -159,7 +148,85 @@ | ||||||
| 
 | 
 | ||||||
|   &.has-location-badge { |   &.has-location-badge { | ||||||
|     .search-input-wrap { |     .search-input-wrap { | ||||||
|       width: 78%; |       width: 68%; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | .search-holder { | ||||||
|  |   @media (min-width: $screen-sm-min) { | ||||||
|  |     display: -webkit-flex; | ||||||
|  |     display: -ms-flexbox; | ||||||
|  |     display: flex; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .search-field-holder { | ||||||
|  |     -webkit-flex: 1 0 auto; | ||||||
|  |     -ms-flex: 1 0 auto; | ||||||
|  |     flex: 1 0 auto; | ||||||
|  |     position: relative; | ||||||
|  |     margin-right: 0; | ||||||
|  | 
 | ||||||
|  |     @media (min-width: $screen-sm-min) { | ||||||
|  |       margin-right: 5px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .search-icon { | ||||||
|  |     position: absolute; | ||||||
|  |     left: 10px; | ||||||
|  |     top: 10px; | ||||||
|  |     color: $gray-darkest; | ||||||
|  |     pointer-events: none; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .search-text-input { | ||||||
|  |     padding-left: $gl-padding + 15px; | ||||||
|  |     padding-right: $gl-padding + 15px; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .btn-search { | ||||||
|  |     width: 100%; | ||||||
|  |     margin-top: 5px; | ||||||
|  | 
 | ||||||
|  |     @media (min-width: $screen-sm-min) { | ||||||
|  |       width: auto; | ||||||
|  |       margin-top: 0; | ||||||
|  |       margin-left: 5px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .dropdown { | ||||||
|  |     @media (min-width: $screen-sm-min) { | ||||||
|  |       margin-left: 5px; | ||||||
|  |       margin-right: 5px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .dropdown-menu-toggle { | ||||||
|  |     width: 100%; | ||||||
|  |     margin-top: 5px; | ||||||
|  | 
 | ||||||
|  |     @media (min-width: $screen-sm-min) { | ||||||
|  |       width: 160px; | ||||||
|  |       margin-top: 0; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .search-clear { | ||||||
|  |   position: absolute; | ||||||
|  |   right: 10px; | ||||||
|  |   top: 10px; | ||||||
|  |   padding: 0; | ||||||
|  |   color: $gray-darkest; | ||||||
|  |   line-height: 0; | ||||||
|  |   background: none; | ||||||
|  |   border: 0; | ||||||
|  | 
 | ||||||
|  |   &:hover, | ||||||
|  |   &:focus { | ||||||
|  |     color: $gl-link-color; | ||||||
|  |     outline: none; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,14 @@ | ||||||
|  | .settings-list-icon { | ||||||
|  |   color: $gl-placeholder-color; | ||||||
|  |   font-size: $settings-icon-size; | ||||||
|  |   line-height: 42px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .settings-message { | ||||||
|  |   padding: 5px; | ||||||
|  |   line-height: 1.3; | ||||||
|  |   color: $warning-message-color; | ||||||
|  |   background-color: $warning-message-bg; | ||||||
|  |   border: 1px solid $warning-message-border; | ||||||
|  |   border-radius: $border-radius-base; | ||||||
|  | } | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| .container-fluid { | .container-fluid { | ||||||
|   .ci-status { |   .ci-status { | ||||||
|     padding: 2px 7px; |     padding: 2px 7px; | ||||||
|     margin-right: 5px; |     margin-right: 10px; | ||||||
|     border: 1px solid #eee; |     border: 1px solid #eee; | ||||||
|     white-space: nowrap; |     white-space: nowrap; | ||||||
|     @include border-radius(4px); |     @include border-radius(4px); | ||||||
|  |  | ||||||
|  | @ -6,9 +6,16 @@ | ||||||
| .navbar-nav { | .navbar-nav { | ||||||
|   li { |   li { | ||||||
|     .badge.todos-pending-count { |     .badge.todos-pending-count { | ||||||
|       background-color: $gl-icon-color; |  | ||||||
|       margin-top: -5px; |       margin-top: -5px; | ||||||
|       font-weight: normal; |       font-weight: normal; | ||||||
|  |       background: $todo-alert-blue; | ||||||
|  |       margin-left: -17px; | ||||||
|  |       font-size: 11px; | ||||||
|  |       color: white; | ||||||
|  |       padding: 3px; | ||||||
|  |       padding-top: 1px; | ||||||
|  |       padding-bottom: 1px; | ||||||
|  |       border-radius: 3px; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -16,7 +16,7 @@ | ||||||
| 
 | 
 | ||||||
|     tr { |     tr { | ||||||
|       > td, > th { |       > td, > th { | ||||||
|         line-height: 26px; |         line-height: 23px; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       &:hover { |       &:hover { | ||||||
|  |  | ||||||
|  | @ -1,17 +1,37 @@ | ||||||
| /* Generic print styles */ |  | ||||||
| header, nav, nav.main-nav, nav.navbar-collapse, nav.navbar-collapse.collapse {display: none!important;} |  | ||||||
| .profiler-results {display: none;} |  | ||||||
| 
 |  | ||||||
| /* Styles targeted specifically at printing files */ |  | ||||||
| .tree-ref-holder, .tree-holder .breadcrumb, .blob-commit-info {display: none;} |  | ||||||
| .file-title {display: none;} |  | ||||||
| .file-holder {border: none;} |  | ||||||
| 
 |  | ||||||
| .wiki h1, .wiki h2, .wiki h3, .wiki h4, .wiki h5, .wiki h6 {margin-top: 17px; } | .wiki h1, .wiki h2, .wiki h3, .wiki h4, .wiki h5, .wiki h6 {margin-top: 17px; } | ||||||
| .wiki h1 {font-size: 30px;} | .wiki h1 {font-size: 30px;} | ||||||
| .wiki h2 {font-size: 22px;} | .wiki h2 {font-size: 22px;} | ||||||
| .wiki h3 {font-size: 18px; font-weight: bold; } | .wiki h3 {font-size: 18px; font-weight: bold; } | ||||||
| 
 | 
 | ||||||
| .sidebar-wrapper { display: none; } | header, | ||||||
| .nav { display: none; } | nav, | ||||||
| .btn { display: none; } | nav.main-nav, | ||||||
|  | nav.navbar-collapse, | ||||||
|  | nav.navbar-collapse.collapse, | ||||||
|  | .profiler-results, | ||||||
|  | .tree-ref-holder, | ||||||
|  | .tree-holder .breadcrumb, | ||||||
|  | .blob-commit-info, | ||||||
|  | .file-title, | ||||||
|  | .file-holder, | ||||||
|  | .sidebar-wrapper, | ||||||
|  | .nav, | ||||||
|  | .btn, | ||||||
|  | ul.notes-form, | ||||||
|  | .merge-request-ci-status .ci-status-link:after, | ||||||
|  | .issuable-gutter-toggle, | ||||||
|  | .gutter-toggle, | ||||||
|  | .issuable-details .content-block-small, | ||||||
|  | .edit-link, | ||||||
|  | .note-action-button { | ||||||
|  |   display: none!important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .page-gutter { | ||||||
|  |   padding-top: 0; | ||||||
|  |   padding-left: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .right-sidebar { | ||||||
|  |   top: 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -6,12 +6,6 @@ class Admin::ApplicationController < ApplicationController | ||||||
|   layout 'admin' |   layout 'admin' | ||||||
| 
 | 
 | ||||||
|   def authenticate_admin! |   def authenticate_admin! | ||||||
|     return render_404 unless current_user.is_admin? |     render_404 unless current_user.is_admin? | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def authorize_impersonator! |  | ||||||
|     if session[:impersonator_id] |  | ||||||
|       User.find_by!(username: session[:impersonator_id]).admin? |  | ||||||
|     end |  | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -75,6 +75,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController | ||||||
|       :admin_notification_email, |       :admin_notification_email, | ||||||
|       :user_oauth_applications, |       :user_oauth_applications, | ||||||
|       :shared_runners_enabled, |       :shared_runners_enabled, | ||||||
|  |       :shared_runners_text, | ||||||
|       :max_artifacts_size, |       :max_artifacts_size, | ||||||
|       :metrics_enabled, |       :metrics_enabled, | ||||||
|       :metrics_host, |       :metrics_host, | ||||||
|  | @ -92,6 +93,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController | ||||||
|       :akismet_api_key, |       :akismet_api_key, | ||||||
|       :email_author_in_body, |       :email_author_in_body, | ||||||
|       :repository_checks_enabled, |       :repository_checks_enabled, | ||||||
|  |       :metrics_packet_size, | ||||||
|       restricted_visibility_levels: [], |       restricted_visibility_levels: [], | ||||||
|       import_sources: [] |       import_sources: [] | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|  | @ -39,6 +39,12 @@ class Admin::HooksController < Admin::ApplicationController | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def hook_params |   def hook_params | ||||||
|     params.require(:hook).permit(:url, :enable_ssl_verification) |     params.require(:hook).permit( | ||||||
|  |       :enable_ssl_verification, | ||||||
|  |       :push_events, | ||||||
|  |       :tag_push_events, | ||||||
|  |       :token, | ||||||
|  |       :url | ||||||
|  |     ) | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -1,38 +0,0 @@ | ||||||
| class Admin::ImpersonationController < Admin::ApplicationController |  | ||||||
|   skip_before_action :authenticate_admin!, only: :destroy |  | ||||||
| 
 |  | ||||||
|   before_action :user |  | ||||||
|   before_action :authorize_impersonator! |  | ||||||
| 
 |  | ||||||
|   def create |  | ||||||
|     if @user.blocked? |  | ||||||
|       flash[:alert] = "You cannot impersonate a blocked user" |  | ||||||
| 
 |  | ||||||
|       redirect_to admin_user_path(@user) |  | ||||||
|     else |  | ||||||
|       session[:impersonator_id] = current_user.username |  | ||||||
|       session[:impersonator_return_to] = admin_user_path(@user) |  | ||||||
| 
 |  | ||||||
|       warden.set_user(user, scope: 'user') |  | ||||||
| 
 |  | ||||||
|       flash[:alert] = "You are impersonating #{user.username}." |  | ||||||
| 
 |  | ||||||
|       redirect_to root_path |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def destroy |  | ||||||
|     redirect = session[:impersonator_return_to] |  | ||||||
| 
 |  | ||||||
|     warden.set_user(user, scope: 'user') |  | ||||||
| 
 |  | ||||||
|     session[:impersonator_return_to] = nil |  | ||||||
|     session[:impersonator_id] = nil |  | ||||||
| 
 |  | ||||||
|     redirect_to redirect || root_path |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def user |  | ||||||
|     @user ||= User.find_by!(username: params[:id] || session[:impersonator_id]) |  | ||||||
|   end |  | ||||||
| end |  | ||||||
|  | @ -0,0 +1,26 @@ | ||||||
|  | class Admin::ImpersonationsController < Admin::ApplicationController | ||||||
|  |   skip_before_action :authenticate_admin! | ||||||
|  |   before_action :authenticate_impersonator! | ||||||
|  | 
 | ||||||
|  |   def destroy | ||||||
|  |     original_user = current_user | ||||||
|  | 
 | ||||||
|  |     warden.set_user(impersonator, scope: :user) | ||||||
|  | 
 | ||||||
|  |     Gitlab::AppLogger.info("User #{original_user.username} has stopped impersonating #{impersonator.username}") | ||||||
|  | 
 | ||||||
|  |     session[:impersonator_id] = nil | ||||||
|  | 
 | ||||||
|  |     redirect_to admin_user_path(original_user) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   private | ||||||
|  | 
 | ||||||
|  |   def impersonator | ||||||
|  |     @impersonator ||= User.find(session[:impersonator_id]) if session[:impersonator_id] | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def authenticate_impersonator! | ||||||
|  |     render_404 unless impersonator && impersonator.is_admin? && !impersonator.blocked? | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | @ -31,6 +31,24 @@ class Admin::UsersController < Admin::ApplicationController | ||||||
|     user |     user | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   def impersonate | ||||||
|  |     if user.blocked? | ||||||
|  |       flash[:alert] = "You cannot impersonate a blocked user" | ||||||
|  | 
 | ||||||
|  |       redirect_to admin_user_path(user) | ||||||
|  |     else | ||||||
|  |       session[:impersonator_id] = current_user.id | ||||||
|  | 
 | ||||||
|  |       warden.set_user(user, scope: :user) | ||||||
|  | 
 | ||||||
|  |       Gitlab::AppLogger.info("User #{current_user.username} has started impersonating #{user.username}") | ||||||
|  | 
 | ||||||
|  |       flash[:alert] = "You are now impersonating #{user.username}" | ||||||
|  | 
 | ||||||
|  |       redirect_to root_path | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   def block |   def block | ||||||
|     if user.block |     if user.block | ||||||
|       redirect_back_or_admin_user(notice: "Successfully blocked") |       redirect_back_or_admin_user(notice: "Successfully blocked") | ||||||
|  |  | ||||||
|  | @ -117,7 +117,7 @@ class ApplicationController < ActionController::Base | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def after_sign_out_path_for(resource) |   def after_sign_out_path_for(resource) | ||||||
|     current_application_settings.after_sign_out_path || new_user_session_path |     current_application_settings.after_sign_out_path.presence || new_user_session_path | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def abilities |   def abilities | ||||||
|  |  | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue