Update upstream source from tag 'upstream/11.7.5'

Update to upstream version '11.7.5'
with Debian dir 754b07a58f
This commit is contained in:
Sruthi Chandran 2019-02-13 22:34:19 +05:30
commit 65a2ae3b42
1768 changed files with 37598 additions and 15563 deletions

View file

@ -33,3 +33,4 @@ rules:
vue/no-unused-components: off
vue/no-use-v-if-with-v-for: off
vue/no-v-html: off
vue/use-v-on-exact: off

View file

@ -77,18 +77,6 @@ stages:
- mysql:5.7
- redis:alpine
.rails4: &rails4
allow_failure: false
except:
variables:
- $CI_COMMIT_REF_NAME =~ /(^docs[\/-].*|.*-docs$)/
- $CI_COMMIT_REF_NAME =~ /(^qa[\/-].*|.*-qa$)/
- $CI_COMMIT_REF_NAME =~ /norails4/
- $RAILS5_DISABLED
variables:
BUNDLE_GEMFILE: "Gemfile.rails4"
RAILS5: "false"
# Skip all jobs except the ones that begin with 'docs/'.
# Used for commits including ONLY documentation changes.
# https://docs.gitlab.com/ce/development/documentation/#testing
@ -180,18 +168,10 @@ stages:
<<: *rspec-metadata
<<: *use-pg
.rspec-metadata-pg-rails4: &rspec-metadata-pg-rails4
<<: *rspec-metadata-pg
<<: *rails4
.rspec-metadata-mysql: &rspec-metadata-mysql
<<: *rspec-metadata
<<: *use-mysql
.rspec-metadata-mysql-rails4: &rspec-metadata-mysql-rails4
<<: *rspec-metadata-mysql
<<: *rails4
.only-canonical-masters: &only-canonical-masters
only:
- master@gitlab-org/gitlab-ce
@ -251,10 +231,16 @@ package-and-qa:
<<: *single-script-job
variables:
<<: *single-script-job-variables
API_TOKEN: "${GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN}"
SCRIPT_NAME: trigger-build
retry: 0
script:
- gem install gitlab --no-document
- apk add --update openssl curl jq
- wget $CI_PROJECT_URL/raw/$CI_COMMIT_SHA/scripts/review_apps/review-apps.sh
- chmod 755 review-apps.sh
- source ./review-apps.sh
- wait_for_job_to_be_done "gitlab:assets:compile"
- ./$SCRIPT_NAME omnibus
when: manual
only:
@ -329,6 +315,7 @@ cloud-native-image:
variables:
GIT_DEPTH: "1"
cache: {}
when: always
script:
- gem install gitlab --no-document
- CNG_PROJECT_PATH="gitlab-org/build/CNG" BUILD_TRIGGER_TOKEN=$CI_JOB_TOKEN ./scripts/trigger-build cng
@ -432,7 +419,6 @@ setup-test-env:
script:
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
- scripts/gitaly-test-build # Do not use 'bundle exec' here
- BUNDLE_GEMFILE=Gemfile.rails4 bundle install $BUNDLE_INSTALL_FLAGS
artifacts:
expire_in: 7d
paths:
@ -513,14 +499,6 @@ rspec-mysql:
<<: *rspec-metadata-mysql
parallel: 50
rspec-pg-rails4:
<<: *rspec-metadata-pg-rails4
parallel: 50
rspec-mysql-rails4:
<<: *rspec-metadata-mysql-rails4
parallel: 50
static-analysis:
<<: *dedicated-no-docs-no-db-pull-cache-job
dependencies:
@ -554,8 +532,7 @@ docs lint:
# Build HTML from Markdown
- bundle exec nanoc
# Check the internal links
# Disabled until https://gitlab.com/gitlab-com/gitlab-docs/issues/305 is resolved
# - bundle exec nanoc check internal_links
- bundle exec nanoc check internal_links
downtime_check:
<<: *rake-exec
@ -566,12 +543,6 @@ downtime_check:
- /(^docs[\/-].*|.*-docs$)/
- /(^qa[\/-].*|.*-qa$)/
rails4_gemfile_lock_check:
<<: *dedicated-no-docs-no-db-pull-cache-job
<<: *except-docs-and-qa
script:
- scripts/rails4-gemfile-lock-check
ee_compat_check:
<<: *rake-exec
dependencies: []
@ -636,8 +607,8 @@ gitlab:setup-mysql:
# Frontend-related jobs
gitlab:assets:compile:
<<: *dedicated-no-docs-and-no-qa-pull-cache-job
image: dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.5.3-git-2.18-chrome-69.0-node-8.x-yarn-1.2-graphicsmagick-1.3.29-docker-18.06.1
<<: *dedicated-no-docs-pull-cache-job
image: dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.5.3-git-2.18-chrome-69.0-node-8.x-yarn-1.12-graphicsmagick-1.3.29-docker-18.06.1
dependencies: []
services:
- docker:stable-dind

View file

@ -1,6 +1,6 @@
# Backend Maintainers are the default for all ruby files
*.rb @ayufan @DouweM @dzaporozhets @grzesiek @nick.thomas @rspeicher @rymai @smcgivern
*.rake @ayufan @DouweM @dzaporozhets @grzesiek @nick.thomas @rspeicher @rymai @smcgivern
*.rb @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @nick.thomas @rspeicher @rymai @smcgivern
*.rake @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @nick.thomas @rspeicher @rymai @smcgivern
# Technical writing team are the default reviewers for everything in `doc/`
/doc/ @axil @marcia

View file

@ -4,7 +4,7 @@
### Target audience
<!--- For whom are we doing this? Include either a persona from https://design.gitlab.com/#/getting-started/personas or define a specific company role. e.a. "Release Manager" or "Security Analyst" -->
<!--- For whom are we doing this? Include either a persona from https://design.gitlab.com/getting-started/personas or define a specific company role. e.a. "Release Manager" or "Security Analyst" -->
### Further details

View file

@ -8,7 +8,7 @@ require:
- rubocop-rspec
AllCops:
TargetRailsVersion: 4.2
TargetRailsVersion: 5.0
Exclude:
- 'vendor/**/*'
- 'node_modules/**/*'
@ -174,3 +174,9 @@ GitlabSecurity/PublicSend:
- 'ee/db/**/*'
- 'ee/lib/**/*.rake'
- 'ee/spec/**/*'
Cop/InjectEnterpriseEditionModule:
Enabled: true
Exclude:
- 'spec/**/*'
- 'ee/spec/**/*'

View file

@ -107,12 +107,6 @@ Lint/UriEscapeUnescape:
Metrics/LineLength:
Max: 1310
# Offense count: 2
Naming/ConstantName:
Exclude:
- 'lib/gitlab/import_sources.rb'
- 'lib/gitlab/ssh_public_key.rb'
# Offense count: 11
# Configuration parameters: EnforcedStyle.
# SupportedStyles: lowercase, uppercase
@ -155,17 +149,6 @@ RSpec/ExpectChange:
RSpec/ExpectInHook:
Enabled: false
# Offense count: 7
# Configuration parameters: EnforcedStyle.
# SupportedStyles: implicit, each, example
RSpec/HookArgument:
Exclude:
- 'spec/spec_helper.rb'
- 'spec/support/carrierwave.rb'
- 'spec/support/db_cleaner.rb'
- 'spec/support/gitaly.rb'
- 'spec/support/setup_builds_storage.rb'
# Offense count: 19
# Configuration parameters: EnforcedStyle.
# SupportedStyles: it_behaves_like, it_should_behave_like

View file

@ -2,6 +2,300 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
## 11.7.5 (2019-02-06)
### Fixed (8 changes)
- Fix import handling errors in Bitbucket Server importer. !24499
- Adjusts suggestions unable to be applied. !24603
- Fix 500 errors with legacy appearance logos. !24615
- Fix form functionality for edit tag page. !24645
- Update Workhorse to v8.0.2. !24870
- Downcase aliased OAuth2 callback providers. !24877
- Fix Detect Host Keys not working. !24884
- Changed external wiki query method to prevent attribute caching. !24907
## 11.7.4 (2019-02-04)
### Security (1 change)
- Use sanitized user status message for user popover.
## 11.7.3 (2019-01-30)
- No changes.
## 11.7.2 (2019-01-29)
### Security (24 changes)
- Make potentially malicious links more visible in the UI and scrub RTLO chars from links. !2770
- Don't process MR refs for guests in the notes. !2771
- Sanitize user full name to clean up any URL to prevent mail clients from auto-linking URLs. !2828
- Fixed XSS content in KaTex links.
- Disallows unauthorized users from accessing the pipelines section.
- Verify that LFS upload requests are genuine.
- Extract GitLab Pages using RubyZip.
- Prevent awarding emojis to notes whose parent is not visible to user.
- Prevent unauthorized replies when discussion is locked or confidential.
- Disable git v2 protocol temporarily.
- Fix showing ci status for guest users when public pipline are not set.
- Fix contributed projects info still visible when user enable private profile.
- Add subresources removal to member destroy service.
- Add more LFS validations to prevent forgery.
- Use common error for unauthenticated users when creating issues.
- Fix slow regex in project reference pattern.
- Fix private user email being visible in push (and tag push) webhooks.
- Fix wiki access rights when external wiki is enabled.
- Group guests are no longer able to see merge requests they don't have access to at group level.
- Fix path disclosure on project import error.
- Restrict project import visibility based on its group.
- Expose CI/CD trigger token only to the trigger owner.
- Notify only users who can access the project on project move.
- Alias GitHub and BitBucket OAuth2 callback URLs.
### Fixed (1 change)
- Fix uninitialized constant with GitLab Pages.
## 11.7.1 (2019-01-28)
- Unreleased due to quality assurance failure.
## 11.7.0 (2019-01-22)
### Security (14 changes, 1 of them is from the community)
- Escape label and milestone titles to prevent XSS in GFM autocomplete. !2693
- Bump Ruby on Rails to 5.0.7.1. !23396 (@blackst0ne)
- Delete confidential todos for user when downgraded to Guest.
- Project guests no longer are able to see refs page.
- Set URL rel attribute for broken URLs.
- Prevent leaking protected variables for ambiguous refs.
- Authorize before reading job information via API.
- Allow changing group CI/CD settings only for owners.
- Fix SSRF with import_url and remote mirror url.
- Don't expose cross project repositories through diffs when creating merge reqeusts.
- Validate bundle files before unpacking them.
- Issuable no longer is visible to users when project can't be viewed.
- Escape html entities in LabelReferenceFilter when no label found.
- Prevent private snippets from being embeddable.
### Removed (3 changes, 1 of them is from the community)
- Removes all instances of deprecated Gitlab Upgrader calls. !23603 (@jwolen)
- Removed discard draft comment button form notes. !24185
- Remove migration to backfill project_repositories for legacy storage projects. !24299
### Fixed (42 changes, 7 of them are from the community)
- Prevent awards emoji being updated when updating status. !23470
- Allow merge after rebase without page refresh on FF repositories. !23572
- Prevent admins from attempting hashed storage migration on read only DB. !23597
- Correct the ordering of metrics on the performance dashboard. !23630
- Display empty files properly on MR diffs. !23671 (Sean Nichols)
- Allow GitHub imports via token even if OAuth2 provider not configured. !23703
- Update header navigation theme colors. !23734 (George Tsiolis)
- Fix login box bottom margins on signin page. !23739 (@gear54)
- Return an ApplicationSetting in CurrentSettings. !23766
- Fix bug commenting on LFS images. !23812
- Only prompt user once when navigating away from file editor. !23820 (Sam Bigelow)
- Display commit ID for discussions made on merge request commits. !23837
- Stop autofocusing on diff comment after initial mount. !23849
- Fix object storage not working properly with Google S3 compatibility. !23858
- Fix project calendar feed when sorted by priority. !23870
- Fix edit button disappearing in issue title. !23948 (Ruben Moya)
- Aligns build loader animation with the job log. !23959
- Allow 'rake gitlab:cleanup:remote_upload_files' to read bucket files without having permissions to see all buckets. !23981
- Correctly externalize pipeline tags. !24028
- Fix error when creating labels in a new issue in the boards page. !24039 (Ruben Moya)
- Use 'parsePikadayDate' to parse due date string. !24045
- Fix commit SHA not showing in merge request compare dropdown. !24084
- Remove top margin in modal header titles. !24108
- Drop Webhooks from project import/export config. !24121
- Only validate project visibility when it has changed. !24142
- Resolve About this feature link should open in new window. !24149
- Add syntax highlighting to suggestion diff. !24156
- Fix Bitbucket Server import only including first 25 pull requests. !24178
- Enable caching for records which primary key is not `id`. !24245
- Adjust applied suggestion reverting previous changes. !24250
- Fix unexpected exception by failure of finding an actual head pipeline. !24257
- Fix broken templated "Too many changes to show" text. !24282
- Fix requests profiler in admin page not rendering HTML properly. !24291
- Fix no avatar not showing in user selection box. !24346
- Upgrade to gitaly 1.12.1. !24361
- Fix runner eternal loop when update job result. !24481
- Fix notification email for image diff notes.
- Fixed merge request diffs empty states.
- Fixed diff suggestions removing dashes.
- Don't hide CI dropdown behind diff summary. (gfyoung)
- Fix spacing on discussions.
- Fixes missing margin in releases block.
### Changed (22 changes, 8 of them are from the community)
- Show clusters of ancestors in cluster list page. !22996
- Remove unnecessary line before reply holder. !23092 (George Tsiolis)
- Make the Pages permission setting more clear. !23146
- Disable merging of labels with same names. !23265
- Allow basic authentication on go get middleware. !23497 (Morty Choi @mortyccp)
- No longer require email subaddressing for issue creation by email. !23523
- Adjust padding of .dropdown-title to comply with design specs. !23546
- Make commit IDs in merge request discussion header monospace. !23562
- Update environments breadcrumb. !23751 (George Tsiolis)
- Add date range in milestone change email notifications. !23762
- Require Knative to be installed only on an RBAC kubernetes cluster. !23807 (Chris Baumbauer)
- Fix label and header styles in the job details sidebar. !23816 (Nathan Friend)
- Add % prefix to milestone reference links. !23928
- Reorder sidebar menu item for group clusters. !24001 (George Tsiolis)
- Support CURD operation for Links as one of the Release assets. !24056
- Upgrade Omniauth and JWT gems to switch away from Google+ API. !24068
- Renames Milestone sort into Milestone due date. !24080 (Jacopo Beschi @jacopo-beschi)
- Discussion filter only displayed in discussions tab for merge requests. !24082
- Make RBAC enabled default for new clusters. !24119
- Hashed Storage: Only set as `read_only` when starting the per-project migration. !24128
- Knative version bump 0.1.3 -> 0.2.2. (Chris Baumbauer)
- Show message on non-diff discussions.
### Performance (7 changes)
- Fix some N+1 queries related to Admin Dashboard, User Dashboards and Activity Stream. !23034
- Add indexes to speed up CI query. !23188
- Improve the loading time on merge request's discussion page by caching diff highlight. !23857
- Cache avatar URLs and paths within a request. !23950
- Improve snippet search performance by removing duplicate counts. !23952
- Skip per-commit validations already evaluated. !23984
- Fix timeout issues retrieving branches via API. !24034
### Added (29 changes, 6 of them are from the community)
- Handle ci.skip push option. !15643 (Jonathon Reinhart)
- Add NGINX 0.16.0 and above metrics. !22133
- Add project milestone link. !22552
- Support tls communication in gitaly. !22602
- Add option to make ci variables protected by default. !22744 (Alexis Reigel)
- Add project identifier as List-Id email Header to ease filtering. !22817 (Olivier Crête)
- Add markdown helper buttons to file editor. !23480
- Allow to include templates in gitlab-ci.yml. !23495
- Extend override check to also check arity. !23498 (Jacopo Beschi @jacopo-beschi)
- Add importing of issues from CSV file. !23532
- Add submit feedback link to help dropdown. !23547
- Send a notification email to project maintainers when a mirror update fails. !23595
- Restore Object Pools when restoring an object pool. !23682
- Creates component for release block. !23697
- Configure Auto DevOps deployed applications with secrets from prefixed CI variables. !23719
- Add name, author_id, and sha to releases table. !23763
- Display a list of Sentry Issues in GitLab. !23770
- Releases API. !23795
- Creates frontend app for releases. !23796
- Add new pipeline variable CI_COMMIT_SHORT_SHA. !23822
- Create system notes on issue / MR creation when labels, milestone, or due date is set. !23859
- Adds API documentation for releases. !23901
- Add API Support for Kubernetes integration. !23922
- Expose CI/CD predefined variable `CI_API_V4_URL`. !23936
- Add Knative metrics to Prometheus. !23972 (Chris Baumbauer)
- Use reports syntax for Dependency scanning in Auto DevOps. !24081
- Allow to include files from another projects in gitlab-ci.yml. !24101
- User Popovers for Commit Infos, Member Lists and Snippets. !24132
- Add no-color theme for syntax highlighting. (khm)
### Other (45 changes, 30 of them are from the community)
- Redesign project lists UI. !22682
- [Rails5.1] Update functional specs to use new keyword format. !23095 (@blackst0ne)
- Update a condition to visibility a merge request collaboration message. !23104 (Harry Kiselev)
- Remove framework/mobile.scss. !23301 (Takuya Noguchi)
- Passing the separator argument as a positional parameter is deprecated. !23334 (Jasper Maes)
- Clarifies docs about CI `allow_failure`. !23367 (C.J. Jameson)
- Refactor issuable sidebar to use serializer. !23379
- Refactor the logic of updating head pipelines for merge requests. !23502
- Allow user to add Kubernetes cluster for clusterable when there are ancestor clusters. !23569
- Adds explanatory text to input fields on user profile settings page. !23673
- Externalize strings from `/app/views/shared/notes`. !23696 (Tao Wang)
- Remove rails 4 support in CI, Gemfiles, bin/ and config/. !23717 (Jasper Maes)
- Fix calendar events fetching error on private profile page. !23718 (Harry Kiselev)
- Update GitLab Workhorse to v8.0.0. !23740
- Hide confidential events in the API. !23746
- Changed Userpopover Fixtures and shadow color. !23768
- Fix deprecation: Passing conditions to delete_all is deprecated. !23817 (Jasper Maes)
- Fix deprecation: Passing ActiveRecord::Base objects to sanitize_sql_hash_for_assignment. !23818 (Jasper Maes)
- Remove rails4 specific code. !23847 (Jasper Maes)
- Remove deprecated ActionDispatch::ParamsParser. !23848 (Jasper Maes)
- Fix deprecation: Comparing equality between ActionController::Parameters and a Hash is deprecated. !23855 (Jasper Maes)
- Fix deprecation: Directly inheriting from ActiveRecord::Migration is deprecated. !23884 (Jasper Maes)
- Fix deprecation: alias_method_chain is deprecated. Please, use Module#prepend instead. !23887 (Jasper Maes)
- Update specs to exclude possible false positive pass. !23893 (@blackst0ne)
- Passing an argument to force an association to reload is now deprecated. !23894 (Jasper Maes)
- ActiveRecord::Migration -> ActiveRecord::Migration[5.0]. !23910 (Jasper Maes)
- Split bio into individual line in extended user tooltips. !23940
- Fix deprecation: redirect_to :back is deprecated. !23943 (Jasper Maes)
- Fix deprecation: insert_sql is deprecated and will be removed. !23944 (Jasper Maes)
- Upgrade @gitlab/ui to 1.16.2. !23946
- convert specs in javascripts/ and support/ to new syntax. !23947 (Jasper Maes)
- Remove deprecated xhr from specs. !23949 (Jasper Maes)
- Remove app/views/shared/issuable/_filter.html.haml. !24008 (Takuya Noguchi)
- Fix deprecation: Using positional arguments in integration tests. !24009 (Jasper Maes)
- UI improvements for redesigned project lists. !24011
- Update cert-manager chart from v0.5.0 to v0.5.2. !24025 (Takuya Noguchi)
- Hide spinner on empty activites list on user profile overview. !24063
- Don't show Auto DevOps enabled banner for projects with CI file or CI disabled. !24067
- Update GitLab Runner Helm Chart to 0.1.43. !24083
- Fix navigation style in docs. !24090 (Takuya Noguchi)
- Remove gem install bundler from Docker-based Ruby environments. !24093 (Takuya Noguchi)
- Fix deprecation: Using positional arguments in integration tests. !24110 (Jasper Maes)
- Fix deprecation: returning false in Active Record and Active Model callbacks will not implicitly halt a callback chain. !24134 (Jasper Maes)
- ActiveRecord::Migration -> ActiveRecord::Migration[5.0] for AddIndexesToCiBuildsAndPipelines. !24167 (Jasper Maes)
- Update url placeholder for the sentry configuration page. !24338
## 11.6.3 (2019-01-04)
### Fixed (1 change)
- Fix clone URL not showing if protocol is HTTPS. !24131
## 11.6.2 (2019-01-02)
### Fixed (7 changes)
- Hide cluster features that don't work yet with Group Clusters. !23935
- Fix a 500 error that could occur until all migrations are done. !23939
- Fix missing Git clone button when protocol restriction setting enabled. !24015
- Fix clone dropdown parent inheritance issues in HAML. !24029
- Fix content-disposition in blobs and files API endpoint. !24078
- Fixed markdown toolbar buttons.
- Adjust line-height of blame view line numbers.
## 11.6.1 (2018-12-28)
### Security (15 changes)
- Escape label and milestone titles to prevent XSS in GFM autocomplete. !2740
- Prevent private snippets from being embeddable.
- Add subresources removal to member destroy service.
- Escape html entities in LabelReferenceFilter when no label found.
- Allow changing group CI/CD settings only for owners.
- Authorize before reading job information via API.
- Prevent leaking protected variables for ambiguous refs.
- Ensure that build token is only used when running.
- Issuable no longer is visible to users when project can't be viewed.
- Don't expose cross project repositories through diffs when creating merge reqeusts.
- Fix SSRF with import_url and remote mirror url.
- Fix persistent symlink in project import.
- Set URL rel attribute for broken URLs.
- Project guests no longer are able to see refs page.
- Delete confidential todos for user when downgraded to Guest.
### Other (1 change)
- Fix due date test. !23845
## 11.6.0 (2018-12-22)
### Security (24 changes, 1 of them is from the community)
@ -279,6 +573,13 @@ entry.
- Enable Rubocop on lib/gitlab. (gfyoung)
## 11.5.5 (2018-12-20)
### Security (1 change)
- Fix persistent symlink in project import.
## 11.5.3 (2018-12-06)
### Security (1 change)
@ -905,6 +1206,20 @@ entry.
- Check frozen string in style builds. (gfyoung)
## 11.3.14 (2018-12-20)
### Security (1 change)
- Fix persistent symlink in project import.
## 11.3.13 (2018-12-13)
### Security (1 change)
- Validate LFS hrefs before downloading them.
## 11.3.12 (2018-12-06)
### Security (1 change)

View file

@ -15,48 +15,6 @@ repository is licensed under Creative Commons:
_This notice should stay as the first item in the CONTRIBUTING.md file._
---
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Contributing Documentation has been moved](#contributing-documentation-has-been-moved)
- [Contribute to GitLab](#contribute-to-gitlab)
- [Security vulnerability disclosure](#security-vulnerability-disclosure)
- [Code of conduct](#code-of-conduct)
- [Closing policy for issues and merge requests](#closing-policy-for-issues-and-merge-requests)
- [Helping others](#helping-others)
- [I want to contribute!](#i-want-to-contribute)
- [Contribution Flow](#contribution-flow)
- [Workflow labels](#workflow-labels)
- [Type labels](#type-labels)
- [Subject labels](#subject-labels)
- [Team labels](#team-labels)
- [Release Scoping labels](#release-scoping-labels)
- [Priority labels](#priority-labels)
- [Severity labels](#severity-labels)
- [Severity impact guidance](#severity-impact-guidance)
- [Label for community contributors](#label-for-community-contributors)
- [Implement design & UI elements](#implement-design--ui-elements)
- [Issue tracker](#issue-tracker)
- [Issue triaging](#issue-triaging)
- [Feature proposals](#feature-proposals)
- [Issue tracker guidelines](#issue-tracker-guidelines)
- [Issue weight](#issue-weight)
- [Regression issues](#regression-issues)
- [Technical and UX debt](#technical-and-ux-debt)
- [Stewardship](#stewardship)
- [Merge requests](#merge-requests)
- [Merge request guidelines](#merge-request-guidelines)
- [Contribution acceptance criteria](#contribution-acceptance-criteria)
- [Definition of done](#definition-of-done)
- [Style guides](#style-guides)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
---
## Contributing Documentation has been moved
As of July 2018, all the documentation for contributing to the GitLab project has been moved to a new location.
@ -92,7 +50,7 @@ This [documentation](doc/development/contributing/index.md) has been moved.
## Workflow labels
This [documentation](doc/development/contributing/issue_workflow.md) has been moved.
This [documentation](doc/development/contributing/issue_workflow.md) has been moved.
### Type labels
@ -170,7 +128,6 @@ This [documentation](doc/development/contributing/merge_request_workflow.md) has
This [documentation](doc/development/contributing/merge_request_workflow.md) has been moved.
### Contribution acceptance criteria
This [documentation](doc/development/contributing/merge_request_workflow.md) has been moved.

View file

@ -8,5 +8,6 @@ danger.import_dangerfile(path: 'danger/database')
danger.import_dangerfile(path: 'danger/documentation')
danger.import_dangerfile(path: 'danger/frozen_string')
danger.import_dangerfile(path: 'danger/commit_messages')
danger.import_dangerfile(path: 'danger/duplicate_yarn_dependencies')
danger.import_dangerfile(path: 'danger/prettier')
danger.import_dangerfile(path: 'danger/eslint')

View file

@ -1 +1 @@
1.7.1
1.12.2

View file

@ -1 +1 @@
8.4.3
8.4.4

View file

@ -1 +1 @@
7.6.0
8.0.2

64
Gemfile
View file

@ -1,22 +1,6 @@
# --- Special code for migrating to Rails 5.0 ---
def rails5?
!%w[0 false].include?(ENV["RAILS5"])
end
gem_versions = {}
gem_versions['activerecord_sane_schema_dumper'] = rails5? ? '1.0' : '0.2'
gem_versions['rails'] = rails5? ? '5.0.7' : '4.2.11'
gem_versions['rails-i18n'] = rails5? ? '~> 5.1' : '~> 4.0.9'
# The 2.0.6 version of rack requires monkeypatch to be present in
# `config.ru`. This can be removed once a new update for Rack
# is available that contains https://github.com/rack/rack/pull/1201.
gem_versions['rack'] = rails5? ? '2.0.6' : '1.6.11'
# --- The end of special code for migrating to Rails 5.0 ---
source 'https://rubygems.org'
gem 'rails', gem_versions['rails']
gem 'rails', '5.0.7.1'
gem 'rails-deprecated_sanitizer', '~> 1.0.3'
# Improves copy-on-write performance for MRI
@ -28,11 +12,7 @@ gem 'responders', '~> 2.0'
gem 'sprockets', '~> 3.7.0'
# Default values for AR models
if rails5?
gem 'gitlab-default_value_for', '~> 3.1.1', require: 'default_value_for'
else
gem 'default_value_for', '~> 3.0.0'
end
gem 'gitlab-default_value_for', '~> 3.1.1', require: 'default_value_for'
# Supported DBs
gem 'mysql2', '~> 0.4.10', group: :mysql
@ -54,7 +34,7 @@ gem 'omniauth-cas3', '~> 1.1.4'
gem 'omniauth-facebook', '~> 4.0.0'
gem 'omniauth-github', '~> 1.3'
gem 'omniauth-gitlab', '~> 1.0.2'
gem 'omniauth-google-oauth2', '~> 0.5.3'
gem 'omniauth-google-oauth2', '~> 0.6.0'
gem 'omniauth-kerberos', '~> 0.3.0', group: :kerberos
gem 'omniauth-oauth2-generic', '~> 0.2.2'
gem 'omniauth-saml', '~> 1.10'
@ -63,7 +43,7 @@ gem 'omniauth-twitter', '~> 1.4'
gem 'omniauth_crowd', '~> 2.2.0'
gem 'omniauth-authentiq', '~> 0.3.3'
gem 'rack-oauth2', '~> 1.2.1'
gem 'jwt', '~> 1.5.6'
gem 'jwt', '~> 2.1.0'
# Spam and anti-bot protection
gem 'recaptcha', '~> 3.0', require: 'recaptcha/rails'
@ -77,6 +57,7 @@ gem 'u2f', '~> 0.2.1'
# GitLab Pages
gem 'validates_hostname', '~> 1.0.6'
gem 'rubyzip', '~> 1.2.2', require: 'zip'
# Browser detection
gem 'browser', '~> 2.5'
@ -109,9 +90,7 @@ gem 'kaminari', '~> 1.0'
gem 'hamlit', '~> 2.8.8'
# Files attachments
# Locked until https://github.com/carrierwaveuploader/carrierwave/pull/2332/files is merged.
# config/initializers/carrierwave_patch.rb can be removed once that change is released.
gem 'carrierwave', '= 1.2.3'
gem 'carrierwave', '~> 1.3'
gem 'mini_magick'
# for backups
@ -149,7 +128,7 @@ gem 'asciidoctor-plantuml', '0.0.8'
gem 'rouge', '~> 3.1'
gem 'truncato', '~> 0.7.9'
gem 'bootstrap_form', '~> 2.7.0'
gem 'nokogiri', '~> 1.8.2'
gem 'nokogiri', '~> 1.8.5'
gem 'escape_utils', '~> 1.1'
# Calendar rendering
@ -159,7 +138,10 @@ gem 'icalendar'
gem 'diffy', '~> 3.1.0'
# Application server
gem 'rack', gem_versions['rack']
# The 2.0.6 version of rack requires monkeypatch to be present in
# `config.ru`. This can be removed once a new update for Rack
# is available that contains https://github.com/rack/rack/pull/1201.
gem 'rack', '2.0.6'
group :unicorn do
gem 'unicorn', '~> 5.1.0'
@ -181,7 +163,7 @@ gem 'acts-as-taggable-on', '~> 5.0'
gem 'sidekiq', '~> 5.2.1'
gem 'sidekiq-cron', '~> 0.6.0'
gem 'redis-namespace', '~> 1.6.0'
gem 'gitlab-sidekiq-fetcher', '~> 0.1.0', require: 'sidekiq-reliable-fetch'
gem 'gitlab-sidekiq-fetcher', '~> 0.4.0', require: 'sidekiq-reliable-fetch'
# Cron Parser
gem 'rufus-scheduler', '~> 3.4'
@ -278,6 +260,7 @@ gem 'webpack-rails', '~> 0.9.10'
gem 'rack-proxy', '~> 0.6.0'
gem 'sass-rails', '~> 5.0.6'
gem 'sass', '~> 3.5'
gem 'uglifier', '~> 2.7.2'
gem 'addressable', '~> 2.5.2'
@ -297,7 +280,7 @@ gem 'premailer-rails', '~> 1.9.7'
# I18n
gem 'ruby_parser', '~> 3.8', require: false
gem 'rails-i18n', gem_versions['rails-i18n']
gem 'rails-i18n', '~> 5.1'
gem 'gettext_i18n_rails', '~> 1.8.0'
gem 'gettext_i18n_rails_js', '~> 1.3'
gem 'gettext', '~> 3.2.2', require: false, group: :development
@ -307,7 +290,7 @@ gem 'batch-loader', '~> 1.2.2'
# Perf bar
gem 'peek', '~> 1.0.1'
gem 'peek-gc', '~> 0.0.2'
gem 'peek-mysql2', '~> 1.1.0', group: :mysql
gem 'peek-mysql2', '~> 1.2.0', group: :mysql
gem 'peek-pg', '~> 1.3.0', group: :postgres
gem 'peek-rblineprof', '~> 0.2.0'
gem 'peek-redis', '~> 1.2.0'
@ -340,13 +323,13 @@ end
group :development, :test do
gem 'bootsnap', '~> 1.3'
gem 'bullet', '~> 5.5.0', require: !!ENV['ENABLE_BULLET']
gem 'pry-byebug', '~> 3.4.1', platform: :mri
gem 'pry-byebug', '~> 3.5.1', platform: :mri
gem 'pry-rails', '~> 0.3.4'
gem 'awesome_print', require: false
gem 'fuubar', '~> 2.2.0'
gem 'database_cleaner', '~> 1.5.0'
gem 'database_cleaner', '~> 1.7.0'
gem 'factory_bot_rails', '~> 4.8.2'
gem 'rspec-rails', '~> 3.7.0'
gem 'rspec-retry', '~> 0.4.5'
@ -355,13 +338,13 @@ group :development, :test do
gem 'rspec-parameterized', require: false
# Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826)
gem 'minitest', '~> 5.7.0'
gem 'minitest', '~> 5.11.0'
# Generate Fake data
gem 'ffaker', '~> 2.10'
gem 'capybara', '~> 2.15'
gem 'capybara-screenshot', '~> 1.0.0'
gem 'capybara', '~> 2.16.1'
gem 'capybara-screenshot', '~> 1.0.18'
gem 'selenium-webdriver', '~> 3.12'
gem 'spring', '~> 2.0.0'
@ -382,7 +365,7 @@ group :development, :test do
gem 'license_finder', '~> 5.4', require: false
gem 'knapsack', '~> 1.17'
gem 'activerecord_sane_schema_dumper', gem_versions['activerecord_sane_schema_dumper']
gem 'activerecord_sane_schema_dumper', '1.0'
gem 'stackprof', '~> 0.2.10', require: false
@ -396,8 +379,7 @@ group :test do
gem 'email_spec', '~> 2.2.0'
gem 'json-schema', '~> 2.8.0'
gem 'webmock', '~> 2.3.2'
gem 'rails-controller-testing' if rails5? # Rails5 only gem.
gem 'test_after_commit', '~> 1.1' unless rails5? # Remove this gem when migrated to rails 5.0. It's been integrated to rails 5.0.
gem 'rails-controller-testing'
gem 'sham_rack', '~> 1.3.6'
gem 'concurrent-ruby', '~> 1.1'
gem 'test-prof', '~> 0.2.5'
@ -435,7 +417,7 @@ group :ed25519 do
end
# Gitaly GRPC client
gem 'gitaly-proto', '~> 1.3.0', require: 'gitaly'
gem 'gitaly-proto', '~> 1.5.0', require: 'gitaly'
gem 'grpc', '~> 1.15.0'
gem 'google-protobuf', '~> 3.6'

View file

@ -4,41 +4,41 @@ GEM
RedCloth (4.3.2)
abstract_type (0.0.7)
ace-rails-ap (4.1.2)
actioncable (5.0.7)
actionpack (= 5.0.7)
actioncable (5.0.7.1)
actionpack (= 5.0.7.1)
nio4r (>= 1.2, < 3.0)
websocket-driver (~> 0.6.1)
actionmailer (5.0.7)
actionpack (= 5.0.7)
actionview (= 5.0.7)
activejob (= 5.0.7)
actionmailer (5.0.7.1)
actionpack (= 5.0.7.1)
actionview (= 5.0.7.1)
activejob (= 5.0.7.1)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (5.0.7)
actionview (= 5.0.7)
activesupport (= 5.0.7)
actionpack (5.0.7.1)
actionview (= 5.0.7.1)
activesupport (= 5.0.7.1)
rack (~> 2.0)
rack-test (~> 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.0.7)
activesupport (= 5.0.7)
actionview (5.0.7.1)
activesupport (= 5.0.7.1)
builder (~> 3.1)
erubis (~> 2.7.0)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (5.0.7)
activesupport (= 5.0.7)
activejob (5.0.7.1)
activesupport (= 5.0.7.1)
globalid (>= 0.3.6)
activemodel (5.0.7)
activesupport (= 5.0.7)
activerecord (5.0.7)
activemodel (= 5.0.7)
activesupport (= 5.0.7)
activemodel (5.0.7.1)
activesupport (= 5.0.7.1)
activerecord (5.0.7.1)
activemodel (= 5.0.7.1)
activesupport (= 5.0.7.1)
arel (~> 7.0)
activerecord_sane_schema_dumper (1.0)
rails (>= 5, < 6)
activesupport (5.0.7)
activesupport (5.0.7.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
@ -97,18 +97,18 @@ GEM
bundler-audit (0.5.0)
bundler (~> 1.2)
thor (~> 0.18)
byebug (9.0.6)
capybara (2.15.1)
byebug (9.1.0)
capybara (2.16.1)
addressable
mini_mime (>= 0.1.3)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
capybara-screenshot (1.0.14)
capybara (>= 1.0, < 3)
capybara-screenshot (1.0.22)
capybara (>= 1.0, < 4)
launchy
carrierwave (1.2.3)
carrierwave (1.3.1)
activemodel (>= 4.0.0)
activesupport (>= 4.0.0)
mime-types (>= 1.16)
@ -140,7 +140,7 @@ GEM
css_parser (1.5.0)
addressable
daemons (1.2.6)
database_cleaner (1.5.3)
database_cleaner (1.7.0)
debug_inspector (0.0.3)
debugger-ruby_core_source (1.3.8)
deckar01-task_list (2.0.0)
@ -274,13 +274,13 @@ GEM
gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gitaly-proto (1.3.0)
gitaly-proto (1.5.0)
grpc (~> 1.0)
github-markup (1.7.0)
gitlab-default_value_for (3.1.1)
activerecord (>= 3.2.0, < 6.0)
gitlab-markup (1.6.5)
gitlab-sidekiq-fetcher (0.1.0)
gitlab-sidekiq-fetcher (0.4.0)
sidekiq (~> 5)
gitlab-styles (2.4.1)
rubocop (~> 0.54.0)
@ -381,7 +381,7 @@ GEM
json (~> 1.8)
multi_xml (>= 0.5.2)
httpclient (2.8.3)
i18n (1.1.1)
i18n (1.2.0)
concurrent-ruby (~> 1.0)
icalendar (2.4.1)
ice_nine (0.11.2)
@ -403,7 +403,7 @@ GEM
bindata
json-schema (2.8.0)
addressable (>= 2.4)
jwt (1.5.6)
jwt (2.1.0)
kaminari (1.0.1)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.0.1)
@ -449,7 +449,7 @@ GEM
loofah (2.2.3)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.0)
mail (2.7.1)
mini_mime (>= 0.1.1)
mail_room (0.9.1)
memoist (0.16.0)
@ -463,7 +463,7 @@ GEM
mini_magick (4.8.0)
mini_mime (1.0.1)
mini_portile2 (2.3.0)
minitest (5.7.0)
minitest (5.11.3)
msgpack (1.2.4)
multi_json (1.13.1)
multi_xml (0.6.0)
@ -483,24 +483,24 @@ GEM
nokogiri
numerizer (0.1.1)
oauth (0.5.4)
oauth2 (1.4.0)
faraday (>= 0.8, < 0.13)
jwt (~> 1.0)
oauth2 (1.4.1)
faraday (>= 0.8, < 0.16.0)
jwt (>= 1.0, < 3.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
octokit (4.9.0)
sawyer (~> 0.8.0, >= 0.5.3)
omniauth (1.8.1)
hashie (>= 3.4.6, < 3.6.0)
omniauth (1.9.0)
hashie (>= 3.4.6, < 3.7.0)
rack (>= 1.6.2, < 3)
omniauth-auth0 (2.0.0)
omniauth-oauth2 (~> 1.4)
omniauth-authentiq (0.3.3)
jwt (>= 1.5)
omniauth-oauth2 (>= 1.5)
omniauth-azure-oauth2 (0.0.9)
jwt (~> 1.0)
omniauth-azure-oauth2 (0.0.10)
jwt (>= 1.0, < 3.0)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.4)
omniauth-cas3 (1.1.4)
@ -515,8 +515,8 @@ GEM
omniauth-gitlab (1.0.3)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.0)
omniauth-google-oauth2 (0.5.3)
jwt (>= 1.5)
omniauth-google-oauth2 (0.6.0)
jwt (>= 2.0)
omniauth (>= 1.1.1)
omniauth-oauth2 (>= 1.5)
omniauth-kerberos (0.3.0)
@ -527,9 +527,9 @@ GEM
omniauth-oauth (1.1.0)
oauth
omniauth (~> 1.0)
omniauth-oauth2 (1.5.0)
omniauth-oauth2 (1.6.0)
oauth2 (~> 1.1)
omniauth (~> 1.2)
omniauth (~> 1.9)
omniauth-oauth2-generic (0.2.2)
omniauth-oauth2 (~> 1.0)
omniauth-saml (1.10.0)
@ -558,8 +558,9 @@ GEM
railties (>= 4.0.0)
peek-gc (0.0.2)
peek
peek-mysql2 (1.1.0)
atomic (>= 1.0.0)
peek-mysql2 (1.2.0)
concurrent-ruby
concurrent-ruby-ext
mysql2
peek
peek-pg (1.3.0)
@ -594,8 +595,8 @@ GEM
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
pry-byebug (3.4.3)
byebug (>= 9.0, < 9.1)
pry-byebug (3.5.1)
byebug (~> 9.1)
pry (~> 0.10)
pry-rails (0.3.6)
pry (>= 0.10.4)
@ -623,17 +624,17 @@ GEM
rack
rack-test (0.6.3)
rack (>= 1.0)
rails (5.0.7)
actioncable (= 5.0.7)
actionmailer (= 5.0.7)
actionpack (= 5.0.7)
actionview (= 5.0.7)
activejob (= 5.0.7)
activemodel (= 5.0.7)
activerecord (= 5.0.7)
activesupport (= 5.0.7)
rails (5.0.7.1)
actioncable (= 5.0.7.1)
actionmailer (= 5.0.7.1)
actionpack (= 5.0.7.1)
actionview (= 5.0.7.1)
activejob (= 5.0.7.1)
activemodel (= 5.0.7.1)
activerecord (= 5.0.7.1)
activesupport (= 5.0.7.1)
bundler (>= 1.3.0)
railties (= 5.0.7)
railties (= 5.0.7.1)
sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.2)
actionpack (~> 5.x, >= 5.0.1)
@ -649,15 +650,15 @@ GEM
rails-i18n (5.1.1)
i18n (>= 0.7, < 2)
railties (>= 5.0, < 6)
railties (5.0.7)
actionpack (= 5.0.7)
activesupport (= 5.0.7)
railties (5.0.7.1)
actionpack (= 5.0.7.1)
activesupport (= 5.0.7.1)
method_source
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rainbow (3.0.0)
raindrops (0.18.0)
rake (12.3.1)
rake (12.3.2)
rb-fsevent (0.10.2)
rb-inotify (0.9.10)
ffi (>= 0.5.0, < 2)
@ -962,9 +963,9 @@ DEPENDENCIES
browser (~> 2.5)
bullet (~> 5.5.0)
bundler-audit (~> 0.5.0)
capybara (~> 2.15)
capybara-screenshot (~> 1.0.0)
carrierwave (= 1.2.3)
capybara (~> 2.16.1)
capybara-screenshot (~> 1.0.18)
carrierwave (~> 1.3)
charlock_holmes (~> 0.7.5)
chronic (~> 0.10.2)
chronic_duration (~> 0.10.6)
@ -972,7 +973,7 @@ DEPENDENCIES
concurrent-ruby (~> 1.1)
connection_pool (~> 2.0)
creole (~> 0.5.0)
database_cleaner (~> 1.5.0)
database_cleaner (~> 1.7.0)
deckar01-task_list (= 2.0.0)
device_detector
devise (~> 4.4)
@ -1007,11 +1008,11 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)
gitaly-proto (~> 1.3.0)
gitaly-proto (~> 1.5.0)
github-markup (~> 1.7.0)
gitlab-default_value_for (~> 3.1.1)
gitlab-markup (~> 1.6.5)
gitlab-sidekiq-fetcher (~> 0.1.0)
gitlab-sidekiq-fetcher (~> 0.4.0)
gitlab-styles (~> 2.4)
gitlab_omniauth-ldap (~> 2.0.4)
gon (~> 6.2)
@ -1040,7 +1041,7 @@ DEPENDENCIES
jquery-atwho-rails (~> 1.3.2)
js_regex (~> 2.2.1)
json-schema (~> 2.8.0)
jwt (~> 1.5.6)
jwt (~> 2.1.0)
kaminari (~> 1.0)
knapsack (~> 1.17)
kubeclient (~> 4.0.0)
@ -1053,12 +1054,12 @@ DEPENDENCIES
method_source (~> 0.8)
mimemagic (~> 0.3.2)
mini_magick
minitest (~> 5.7.0)
minitest (~> 5.11.0)
mysql2 (~> 0.4.10)
nakayoshi_fork (~> 0.0.4)
net-ldap
net-ssh (~> 5.0)
nokogiri (~> 1.8.2)
nokogiri (~> 1.8.5)
oauth2 (~> 1.4)
octokit (~> 4.9)
omniauth (~> 1.8)
@ -1069,7 +1070,7 @@ DEPENDENCIES
omniauth-facebook (~> 4.0.0)
omniauth-github (~> 1.3)
omniauth-gitlab (~> 1.0.2)
omniauth-google-oauth2 (~> 0.5.3)
omniauth-google-oauth2 (~> 0.6.0)
omniauth-kerberos (~> 0.3.0)
omniauth-oauth2-generic (~> 0.2.2)
omniauth-saml (~> 1.10)
@ -1079,14 +1080,14 @@ DEPENDENCIES
org-ruby (~> 0.9.12)
peek (~> 1.0.1)
peek-gc (~> 0.0.2)
peek-mysql2 (~> 1.1.0)
peek-mysql2 (~> 1.2.0)
peek-pg (~> 1.3.0)
peek-rblineprof (~> 0.2.0)
peek-redis (~> 1.2.0)
pg (~> 0.18.2)
premailer-rails (~> 1.9.7)
prometheus-client-mmap (~> 0.9.4)
pry-byebug (~> 3.4.1)
pry-byebug (~> 3.5.1)
pry-rails (~> 0.3.4)
puma (~> 3.12)
puma_worker_killer
@ -1095,7 +1096,7 @@ DEPENDENCIES
rack-cors (~> 1.0.0)
rack-oauth2 (~> 1.2.1)
rack-proxy (~> 0.6.0)
rails (= 5.0.7)
rails (= 5.0.7.1)
rails-controller-testing
rails-deprecated_sanitizer (~> 1.0.3)
rails-i18n (~> 5.1)
@ -1126,9 +1127,11 @@ DEPENDENCIES
ruby-prof (~> 0.17.0)
ruby-progressbar
ruby_parser (~> 3.8)
rubyzip (~> 1.2.2)
rufus-scheduler (~> 3.4)
rugged (~> 0.27)
sanitize (~> 4.6)
sass (~> 3.5)
sass-rails (~> 5.0.6)
scss_lint (~> 0.56.0)
seed-fu (~> 2.3.7)
@ -1169,4 +1172,4 @@ DEPENDENCIES
wikicloth (= 0.8.1)
BUNDLED WITH
1.17.1
1.17.3

View file

@ -1,7 +0,0 @@
# BUNDLE_GEMFILE=Gemfile.rails4 bundle install
ENV["RAILS5"] = "false"
gemfile = File.expand_path("../Gemfile", __FILE__)
eval(File.read(gemfile), nil, gemfile)

File diff suppressed because it is too large Load diff

View file

@ -12,15 +12,18 @@
- [Assigning issues](#assigning-issues)
- [Be kind](#be-kind)
- [Feature freeze on the 7th for the release on the 22nd](#feature-freeze-on-the-7th-for-the-release-on-the-22nd)
- [Feature flags](#feature-flags)
- [Between the 1st and the 7th](#between-the-1st-and-the-7th)
- [What happens if these deadlines are missed?](#what-happens-if-these-deadlines-are-missed)
- [On the 7th](#on-the-7th)
- [Feature merge requests](#feature-merge-requests)
- [Documentation merge requests](#documentation-merge-requests)
- [After the 7th](#after-the-7th)
- [Asking for an exception](#asking-for-an-exception)
- [Bugs](#bugs)
- [Regressions](#regressions)
- [Managing bugs](#managing-bugs)
- [Release retrospective and kickoff](#release-retrospective-and-kickoff)
- [Retrospective](#retrospective)
- [Kickoff](#kickoff)
- [Copy & paste responses](#copy--paste-responses)
- [Improperly formatted issue](#improperly-formatted-issue)
- [Issue report for old version](#issue-report-for-old-version)
@ -28,11 +31,8 @@
- [Code format](#code-format)
- [Issue fixed in newer version](#issue-fixed-in-newer-version)
- [Improperly formatted merge request](#improperly-formatted-merge-request)
- [Inactivity close of an issue](#inactivity-close-of-an-issue)
- [Inactivity close of a merge request](#inactivity-close-of-a-merge-request)
- [Accepting merge requests](#accepting-merge-requests)
- [Only accepting merge requests with green tests](#only-accepting-merge-requests-with-green-tests)
- [Closing down the issue tracker on GitHub](#closing-down-the-issue-tracker-on-github)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
@ -58,6 +58,18 @@ their contributions accepted by meeting our [Definition of done][done].
What you can expect from them is described at https://about.gitlab.com/roles/merge-request-coach/.
### Milestones on community contribution issues
The milestone of an issue that is currently being worked on by a community contributor
should not be set to a named GitLab milestone (e.g. 11.7, 11.8), until the associated
merge request is very close to being merged, and we will likely know in which named
GitLab milestone the issue will land. There are many factors that influence when
a community contributor finishes an issue, or even at all. So we should set this
milestone only when we have more certainty.
Note this only applies to issues currently assigned to community contributors. For
issues assigned to GitLabbers, we are [ambitious in assigning milestones to issues](https://about.gitlab.com/direction/#how-we-plan-releases).
## Assigning issues
If an issue is complex and needs the attention of a specific person, assignment is a good option but assigning issues might discourage other people from contributing to that issue. We need all the contributions we can get so this should never be discouraged. Also, an assigned person might not have time for a few weeks, so others should feel free to takeover.
@ -74,10 +86,13 @@ star, smile, etc.). Some good tips about code reviews can be found in our
## Feature freeze on the 7th for the release on the 22nd
After 7th at 23:59 (Pacific Time Zone) of each month, RC1 of the upcoming
release (to be shipped on the 22nd) is created and deployed to GitLab.com and
the stable branch for this release is frozen, which means master is no longer
merged into it. Merge requests may still be merged into master during this
After 7th at 23:59 (Pacific Time Zone) of each month, stable branch and RC1
of the upcoming release (to be shipped on the 22nd) is created and deployed to GitLab.com.
The stable branch is frozen at the most recent "qualifying commit" on master.
A "qualifying commit" is one that is pushed before the feature freeze cutoff time
and that passes all CI jobs (green pipeline).
Merge requests may still be merged into master during this
period, but they will go into the _next_ release, unless they are manually
cherry-picked into the stable branch.
@ -249,7 +264,7 @@ A ~bug is a defect, error, failure which causes the system to behave incorrectly
The level of impact of a ~bug can vary from blocking a whole functionality
or a feature usability bug. A bug should always be linked to a severity level.
Refer to our [severity levels](../CONTRIBUTING.md#severity-labels)
Refer to our [severity levels](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html#severity-labels)
Whether the bug is also a regression or not, the triage process should start as soon as possible.
Ensure that the Engineering Manager and/or the Product Manager for the relative area is involved to prioritize the work as needed.
@ -281,10 +296,10 @@ The two scenarios below can [bypass the exception request in the release process
When a bug is found:
1. Create an issue describing the problem in the most detailed way possible.
1. If possible, provide links to real examples and how to reproduce the problem.
1. Label the issue properly, using the [team label](../CONTRIBUTING.md#team-labels),
the [subject label](../CONTRIBUTING.md#subject-labels)
1. Label the issue properly, using the [team label](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html#team-labels),
the [subject label](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html#subject-labels)
and any other label that may apply in the specific case
1. Notify the respective Engineering Manager to evaluate and apply the [Severity label](../CONTRIBUTING.md#bug-severity-labels) and [Priority label](../CONTRIBUTING.md#bug-priority-labels).
1. Notify the respective Engineering Manager to evaluate and apply the [Severity label](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html#severity-labels) and [Priority label](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html#priority-labels).
The counterpart Product Manager is included to weigh-in on prioritization as needed.
1. If the ~bug is **NOT** a regression:
1. The Engineering Manager decides which milestone the bug will be fixed. The appropriate milestone is applied.
@ -306,67 +321,77 @@ The counterpart Product Manager is included to weigh-in on prioritization as nee
### Improperly formatted issue
Thanks for the issue report. Please reformat your issue to conform to the [contributing guidelines](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker-guidelines).
```
Thanks for the issue report. Please reformat your issue to conform to the
[contributing guidelines](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html#issue-tracker-guidelines).
```
### Issue report for old version
Thanks for the issue report but we only support issues for the latest stable version of GitLab. I'm closing this issue but if you still experience this problem in the latest stable version, please open a new issue (but also reference the old issue(s)). Make sure to also include the necessary debugging information conforming to the issue tracker guidelines found in our [contributing guidelines](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker-guidelines).
```
Thanks for the issue report but we only support issues for the latest stable version of GitLab.
I'm closing this issue but if you still experience this problem in the latest stable version,
please open a new issue (but also reference the old issue(s)).
Make sure to also include the necessary debugging information conforming to the issue tracker
guidelines found in our [contributing guidelines](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html#issue-tracker-guidelines).
```
### Support requests and configuration questions
```
Thanks for your interest in GitLab. We don't use the issue tracker for support
requests and configuration questions. Please check our
[getting help](https://about.gitlab.com/getting-help/) page to see all of the available
support options. Also, have a look at the [contribution guidelines](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md)
support options. Also, have a look at the [contribution guidelines](https://docs.gitlab.com/ee/development/contributing/index.html)
for more information.
```
### Code format
```
Please use \`\`\` to format console output, logs, and code as it's very hard to read otherwise.
```
### Issue fixed in newer version
Thanks for the issue report. This issue has already been fixed in newer versions of GitLab. Due to the size of this project and our limited resources we are only able to support the latest stable release as outlined in our [contributing guidelines](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker). In order to get this bug fix and enjoy many new features please [upgrade](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/update). If you still experience issues at that time please open a new issue following our issue tracker guidelines found in the [contributing guidelines](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker-guidelines).
```
Thanks for the issue report. This issue has already been fixed in newer versions of GitLab.
Due to the size of this project and our limited resources we are only able to support the
latest stable release as outlined in our [contributing guidelines](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html).
In order to get this bug fix and enjoy many new features please
[upgrade](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/update).
If you still experience issues at that time please open a new issue following our issue
tracker guidelines found in the [contributing guidelines](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html#issue-tracker-guidelines).
```
### Improperly formatted merge request
Thanks for your interest in improving the GitLab codebase! Please update your merge request according to the [contributing guidelines](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#pull-request-guidelines).
### Inactivity close of an issue
It's been at least 2 weeks (and a new release) since we heard from you. I'm closing this issue but if you still experience this problem, please open a new issue (but also reference the old issue(s)). Make sure to also include the necessary debugging information conforming to the issue tracker guidelines found in our [contributing guidelines](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker-guidelines).
### Inactivity close of a merge request
This merge request has been closed because a request for more information has not been reacted to for more than 2 weeks. If you respond and conform to the merge request guidelines in our [contributing guidelines](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#pull-requests) we will reopen this merge request.
```
Thanks for your interest in improving the GitLab codebase!
Please update your merge request according to the [contributing guidelines](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/contributing/merge_request_workflow.md#merge-request-guidelines).
```
### Accepting merge requests
```
Is there an issue on the
[issue tracker](https://gitlab.com/gitlab-org/gitlab-ce/issues) that is
similar to this? Could you please link it here?
Please be aware that new functionality that is not marked
[accepting merge requests](https://gitlab.com/gitlab-org/gitlab-ce/issues?milestone_id=&scope=all&sort=created_desc&state=opened&utf8=%E2%9C%93&assignee_id=&author_id=&milestone_title=&label_name=Accepting+Merge+Requests)
[`Accepting merge requests`](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html#label-for-community-contributors)
might not make it into GitLab.
```
### Only accepting merge requests with green tests
```
We can only accept a merge request if all the tests are green. I've just
restarted the build. When the tests are still not passing after this restart and
you're sure that is does not have anything to do with your code changes, please
rebase with master to see if that solves the issue.
### Closing down the issue tracker on GitHub
We are currently in the process of closing down the issue tracker on GitHub, to
prevent duplication with the GitLab.com issue tracker.
Since this is an older issue I'll be closing this for now. If you think this is
still an issue I encourage you to open it on the [GitLab.com issue tracker](https://gitlab.com/gitlab-org/gitlab-ce/issues).
```
[team]: https://about.gitlab.com/team/
[contribution acceptance criteria]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#contribution-acceptance-criteria
["Implement design & UI elements" guidelines]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#implement-design-ui-elements
[Thoughtbot code review guide]: https://github.com/thoughtbot/guides/tree/master/code-review
[done]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#definition-of-done
[done]: https://docs.gitlab.com/ee/development/contributing/merge_request_workflow.html#definition-of-done
[automatic_ce_ee_merge]: https://docs.gitlab.com/ce/development/automatic_ce_ee_merge.html
[ee_features]: https://docs.gitlab.com/ce/development/ee_features.html

View file

@ -1 +1 @@
11.6.0
11.7.5

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View file

@ -29,6 +29,7 @@ const Api = {
commitPipelinesPath: '/:project_id/commit/:sha/pipelines',
branchSinglePath: '/api/:version/projects/:id/repository/branches/:branch',
createBranchPath: '/api/:version/projects/:id/repository/branches',
releasesPath: '/api/:version/projects/:id/releases',
group(groupId, callback) {
const url = Api.buildUrl(Api.groupPath).replace(':id', groupId);
@ -307,6 +308,12 @@ const Api = {
});
},
releases(id) {
const url = Api.buildUrl(this.releasesPath).replace(':id', encodeURIComponent(id));
return axios.get(url);
},
buildUrl(url) {
let urlRoot = '';
if (gon.relative_url_root != null) {

View file

@ -8,6 +8,7 @@ export default class ShortcutsNavigation extends Shortcuts {
Mousetrap.bind('g p', () => findAndFollowLink('.shortcuts-project'));
Mousetrap.bind('g v', () => findAndFollowLink('.shortcuts-project-activity'));
Mousetrap.bind('g r', () => findAndFollowLink('.shortcuts-project-releases'));
Mousetrap.bind('g f', () => findAndFollowLink('.shortcuts-tree'));
Mousetrap.bind('g c', () => findAndFollowLink('.shortcuts-commits'));
Mousetrap.bind('g j', () => findAndFollowLink('.shortcuts-builds'));

View file

@ -16,13 +16,25 @@ export default () => {
const filePath = editBlobForm.data('blobFilename');
const currentAction = $('.js-file-title').data('currentAction');
const projectId = editBlobForm.data('project-id');
const isMarkdown = editBlobForm.data('is-markdown');
const commitButton = $('.js-commit-button');
const cancelLink = $('.btn.btn-cancel');
cancelLink.on('click', () => {
window.onbeforeunload = null;
});
commitButton.on('click', () => {
window.onbeforeunload = null;
});
new EditBlob(`${urlRoot}${assetsPath}`, filePath, currentAction, projectId);
new EditBlob({
assetsPath: `${urlRoot}${assetsPath}`,
filePath,
currentAction,
projectId,
isMarkdown,
});
new NewCommitForm(editBlobForm);
// returning here blocks page navigation

View file

@ -6,22 +6,31 @@ import createFlash from '~/flash';
import { __ } from '~/locale';
import TemplateSelectorMediator from '../blob/file_template_mediator';
import getModeByFileExtension from '~/lib/utils/ace_utils';
import { addEditorMarkdownListeners } from '~/lib/utils/text_markdown';
export default class EditBlob {
constructor(assetsPath, aceMode, currentAction, projectId) {
this.configureAceEditor(aceMode, assetsPath);
// The options object has:
// assetsPath, filePath, currentAction, projectId, isMarkdown
constructor(options) {
this.options = options;
this.configureAceEditor();
this.initModePanesAndLinks();
this.initSoftWrap();
this.initFileSelectors(currentAction, projectId);
this.initFileSelectors();
}
configureAceEditor(filePath, assetsPath) {
configureAceEditor() {
const { filePath, assetsPath, isMarkdown } = this.options;
ace.config.set('modePath', `${assetsPath}/ace`);
ace.config.loadModule('ace/ext/searchbox');
ace.config.loadModule('ace/ext/modelist');
this.editor = ace.edit('editor');
if (isMarkdown) {
addEditorMarkdownListeners(this.editor);
}
// This prevents warnings re: automatic scrolling being logged
this.editor.$blockScrolling = Infinity;
@ -32,7 +41,8 @@ export default class EditBlob {
}
}
initFileSelectors(currentAction, projectId) {
initFileSelectors() {
const { currentAction, projectId } = this.options;
this.fileTemplateMediator = new TemplateSelectorMediator({
currentAction,
editor: this.editor,

View file

@ -3,7 +3,12 @@ import dateFormat from 'dateformat';
import { GlTooltip } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import { __ } from '~/locale';
import { getDayDifference, getTimeago, dateInWords } from '~/lib/utils/datetime_utility';
import {
getDayDifference,
getTimeago,
dateInWords,
parsePikadayDate,
} from '~/lib/utils/datetime_utility';
export default {
components: {
@ -54,7 +59,7 @@ export default {
return standardDateFormat;
},
issueDueDate() {
return new Date(this.date);
return parsePikadayDate(this.date);
},
timeDifference() {
const today = new Date();

View file

@ -45,7 +45,7 @@ export default {
<section class="empty-state">
<div class="row">
<div class="col-12 col-md-6 order-md-last">
<aside class="svg-content"><img :src="emptyStateSvg" /></aside>
<aside class="svg-content d-none d-md-block"><img :src="emptyStateSvg" /></aside>
</div>
<div class="col-12 col-md-6 order-md-first">
<div class="text-content">

View file

@ -37,7 +37,7 @@ export default function initNewListDropdown() {
});
},
renderRow(label) {
const active = boardsStore.findList('title', label.title);
const active = boardsStore.findListByLabelId(label.id);
const $li = $('<li />');
const $a = $('<a />', {
class: active ? `is-active js-board-list-${active.id}` : '',
@ -63,7 +63,7 @@ export default function initNewListDropdown() {
const label = options.selectedObj;
e.preventDefault();
if (!boardsStore.findList('title', label.title)) {
if (!boardsStore.findListByLabelId(label.id)) {
boardsStore.new({
title: label.title,
position: boardsStore.state.lists.length - 2,

View file

@ -55,12 +55,12 @@ class ListIssue {
}
findLabel(findLabel) {
return this.labels.filter(label => label.title === findLabel.title)[0];
return this.labels.find(label => label.id === findLabel.id);
}
removeLabel(removeLabel) {
if (removeLabel) {
this.labels = this.labels.filter(label => removeLabel.title !== label.title);
this.labels = this.labels.filter(label => removeLabel.id !== label.id);
}
}
@ -75,7 +75,7 @@ class ListIssue {
}
findAssignee(findAssignee) {
return this.assignees.filter(assignee => assignee.id === findAssignee.id)[0];
return this.assignees.find(assignee => assignee.id === findAssignee.id);
}
removeAssignee(removeAssignee) {

View file

@ -244,6 +244,7 @@ class List {
issue.project = data.project;
issue.path = data.real_path;
issue.referencePath = data.reference_path;
issue.assignableLabelsEndpoint = data.assignable_labels_endpoint;
if (this.issuesSize > 1) {
const moveBeforeId = this.issues[1].id;

View file

@ -166,6 +166,9 @@ const boardsStore = {
});
return filteredList[0];
},
findListByLabelId(id) {
return this.state.lists.find(list => list.type === 'label' && list.label.id === id);
},
updateFiltersUrl() {
window.history.pushState(null, null, `?${this.filter.path}`);
},

View file

@ -36,7 +36,9 @@ export default class VariableList {
},
protected: {
selector: '.js-ci-variable-input-protected',
default: 'false',
// use `attr` instead of `data` as we don't want the value to be
// converted. we need the value as a string.
default: $('.js-ci-variable-input-protected').attr('data-default'),
},
environment_scope: {
// We can't use a `.js-` class here because

View file

@ -1,6 +1,6 @@
import Visibility from 'visibilityjs';
import Vue from 'vue';
import initDismissableCallout from '~/dismissable_callout';
import PersistentUserCallout from '../persistent_user_callout';
import { s__, sprintf } from '../locale';
import Flash from '../flash';
import Poll from '../lib/utils/poll';
@ -32,6 +32,7 @@ export default class Clusters {
installKnativePath,
installPrometheusPath,
managePrometheusPath,
hasRbac,
clusterType,
clusterStatus,
clusterStatusReason,
@ -45,6 +46,7 @@ export default class Clusters {
this.store.setManagePrometheusPath(managePrometheusPath);
this.store.updateStatus(clusterStatus);
this.store.updateStatusReason(clusterStatusReason);
this.store.updateRbac(hasRbac);
this.service = new ClustersService({
endpoint: statusPath,
installHelmEndpoint: installHelmPath,
@ -67,7 +69,7 @@ export default class Clusters {
this.showTokenButton = document.querySelector('.js-show-cluster-token');
this.tokenField = document.querySelector('.js-cluster-token');
initDismissableCallout('.js-cluster-security-warning');
Clusters.initDismissableCallout();
initSettingsPanels();
setupToggleButtons(document.querySelector('.js-cluster-enable-toggle-area'));
this.initApplications(clusterType);
@ -102,12 +104,19 @@ export default class Clusters {
ingressHelpPath: this.state.ingressHelpPath,
managePrometheusPath: this.state.managePrometheusPath,
ingressDnsHelpPath: this.state.ingressDnsHelpPath,
rbac: this.state.rbac,
},
});
},
});
}
static initDismissableCallout() {
const callout = document.querySelector('.js-cluster-security-warning');
if (callout) new PersistentUserCallout(callout); // eslint-disable-line no-new
}
addListeners() {
if (this.showTokenButton) this.showTokenButton.addEventListener('click', this.showToken);
eventHub.$on('installApplication', this.installApplication);

View file

@ -52,6 +52,11 @@ export default {
required: false,
default: '',
},
rbac: {
type: Boolean,
required: false,
default: false,
},
},
data: () => ({
elasticsearchLogo,
@ -442,6 +447,18 @@ export default {
title-link="https://github.com/knative/docs"
>
<div slot="description">
<span v-if="!rbac">
<p v-if="!rbac" class="bs-callout bs-callout-info append-bottom-0">
{{
s__(`ClusterIntegration|You must have an RBAC-enabled cluster
to install Knative.`)
}}
<a :href="helpPath" target="_blank" rel="noopener noreferrer">
{{ __('More information') }}
</a>
</p>
<br />
</span>
<p>
{{
s__(`ClusterIntegration|Knative extends Kubernetes to provide
@ -465,7 +482,7 @@ export default {
/>
</div>
</template>
<template v-else-if="helmInstalled">
<template v-else-if="helmInstalled && rbac">
<div class="form-group">
<label for="knative-domainname">
{{ s__('ClusterIntegration|Knative Domain Name:') }}

View file

@ -1,4 +1,5 @@
import { s__ } from '../../locale';
import { parseBoolean } from '../../lib/utils/common_utils';
import { INGRESS, JUPYTER, KNATIVE, CERT_MANAGER } from '../constants';
export default class ClusterStore {
@ -7,6 +8,7 @@ export default class ClusterStore {
helpPath: null,
ingressHelpPath: null,
status: null,
rbac: false,
statusReason: null,
applications: {
helm: {
@ -81,6 +83,10 @@ export default class ClusterStore {
this.state.status = status;
}
updateRbac(rbac) {
this.state.rbac = parseBoolean(rbac);
}
updateStatusReason(reason) {
this.state.statusReason = reason;
}

View file

@ -73,7 +73,7 @@ export default {
plainDiffPath: state => state.diffs.plainDiffPath,
emailPatchPath: state => state.diffs.emailPatchPath,
}),
...mapState('diffs', ['showTreeList', 'isLoading']),
...mapState('diffs', ['showTreeList', 'isLoading', 'startVersion']),
...mapGetters('diffs', ['isParallelView']),
...mapGetters(['isNotesFetched', 'getNoteableData']),
targetBranch() {
@ -89,6 +89,13 @@ export default {
showCompareVersions() {
return this.mergeRequestDiffs && this.mergeRequestDiff;
},
renderDiffFiles() {
return (
this.diffFiles.length > 0 ||
(this.startVersion &&
this.startVersion.version_index === this.mergeRequestDiff.version_index)
);
},
},
watch: {
diffViewType() {
@ -201,7 +208,7 @@ export default {
<div v-show="showTreeList" class="diff-tree-list"><tree-list /></div>
<div class="diff-files-holder">
<commit-widget v-if="commit" :commit="commit" />
<template v-if="diffFiles.length > 0">
<template v-if="renderDiffFiles">
<diff-file
v-for="file in diffFiles"
:key="file.newPath"
@ -210,7 +217,7 @@ export default {
:can-current-user-fork="canCurrentUserFork"
/>
</template>
<no-changes v-else />
<no-changes v-else :changes-empty-state-illustration="changesEmptyStateIllustration" />
</div>
</div>
</div>

View file

@ -5,6 +5,7 @@ import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import CIIcon from '~/vue_shared/components/ci_icon.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import CommitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue';
import initUserPopovers from '../../user_popovers';
/**
* CommitItem
@ -35,20 +36,30 @@ export default {
},
},
computed: {
author() {
return this.commit.author || {};
},
authorName() {
return (this.commit.author && this.commit.author.name) || this.commit.author_name;
return this.author.name || this.commit.author_name;
},
authorClass() {
return this.author.name ? 'js-user-link' : '';
},
authorId() {
return this.author.id ? this.author.id : '';
},
authorUrl() {
return (
(this.commit.author && this.commit.author.web_url) || `mailto:${this.commit.author_email}`
);
return this.author.web_url || `mailto:${this.commit.author_email}`;
},
authorAvatar() {
return (
(this.commit.author && this.commit.author.avatar_url) || this.commit.author_gravatar_url
);
return this.author.avatar_url || this.commit.author_gravatar_url;
},
},
created() {
this.$nextTick(() => {
initUserPopovers(this.$el.querySelectorAll('.js-user-link'));
});
},
};
</script>
@ -81,7 +92,13 @@ export default {
</button>
<div class="commiter">
<a :href="authorUrl" v-text="authorName"></a> {{ s__('CommitWidget|authored') }}
<a
:href="authorUrl"
:class="authorClass"
:data-user-id="authorId"
v-text="authorName"
></a>
{{ s__('CommitWidget|authored') }}
<time-ago-tooltip :time="commit.authored_date" />
</div>

View file

@ -129,7 +129,7 @@ export default {
</strong>
</div>
<div>
<small class="commit-sha"> {{ version.truncated_commit_sha }} </small>
<small class="commit-sha"> {{ version.short_commit_sha }} </small>
</div>
<div>
<small>

View file

@ -1,6 +1,7 @@
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue';
import EmptyFileViewer from '~/vue_shared/components/diff_viewer/viewers/empty_file.vue';
import InlineDiffView from './inline_diff_view.vue';
import ParallelDiffView from './parallel_diff_view.vue';
import NoteForm from '../../notes/components/note_form.vue';
@ -17,6 +18,7 @@ export default {
NoteForm,
DiffDiscussions,
ImageDiffOverlay,
EmptyFileViewer,
},
props: {
diffFile: {
@ -43,6 +45,9 @@ export default {
isTextFile() {
return this.diffFile.viewer.name === 'text';
},
errorMessage() {
return this.diffFile.viewer.error;
},
diffFileCommentForm() {
return this.getCommentFormForDiffFile(this.diffFile.file_hash);
},
@ -73,16 +78,17 @@ export default {
<template>
<div class="diff-content">
<div class="diff-viewer">
<div v-if="!errorMessage" class="diff-viewer">
<template v-if="isTextFile">
<empty-file-viewer v-if="diffFile.empty" />
<inline-diff-view
v-if="isInlineView"
v-else-if="isInlineView"
:diff-file="diffFile"
:diff-lines="diffFile.highlighted_diff_lines || []"
:help-page-path="helpPagePath"
/>
<parallel-diff-view
v-if="isParallelView"
v-else-if="isParallelView"
:diff-file="diffFile"
:diff-lines="diffFile.parallel_diff_lines || []"
:help-page-path="helpPagePath"
@ -126,5 +132,8 @@ export default {
</div>
</diff-viewer>
</div>
<div v-else class="diff-viewer">
<div class="nothing-here-block" v-html="errorMessage"></div>
</div>
</div>
</template>

View file

@ -49,7 +49,7 @@ export default {
:is-bottom="index + 1 === diffLinesLength"
/>
<inline-diff-comment-row
:key="`icr-${index}`"
:key="`icr-${line.line_code || index}`"
:diff-file-hash="diffFile.file_hash"
:line="line"
:help-page-path="helpPagePath"

View file

@ -1,34 +1,51 @@
<script>
import { mapState } from 'vuex';
import emptyImage from '~/../../views/shared/icons/_mr_widget_empty_state.svg';
import { mapGetters } from 'vuex';
import _ from 'underscore';
import { GlButton } from '@gitlab/ui';
import { __, sprintf } from '~/locale';
export default {
data() {
return {
emptyImage,
};
components: {
GlButton,
},
props: {
changesEmptyStateIllustration: {
type: String,
required: true,
},
},
computed: {
...mapState({
sourceBranch: state => state.notes.noteableData.source_branch,
targetBranch: state => state.notes.noteableData.target_branch,
newBlobPath: state => state.notes.noteableData.new_blob_path,
}),
...mapGetters(['getNoteableData']),
emptyStateText() {
return sprintf(
__(
'No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}',
),
{
ref_start: '<span class="ref-name">',
ref_end: '</span>',
source_branch: _.escape(this.getNoteableData.source_branch),
target_branch: _.escape(this.getNoteableData.target_branch),
},
false,
);
},
},
};
</script>
<template>
<div class="row empty-state nothing-here-block">
<div class="col-xs-12">
<div class="svg-content"><span v-html="emptyImage"></span></div>
<div class="row empty-state">
<div class="col-12">
<div class="svg-content svg-250"><img :src="changesEmptyStateIllustration" /></div>
</div>
<div class="col-xs-12">
<div class="col-12">
<div class="text-content text-center">
No changes between <span class="ref-name">{{ sourceBranch }}</span> and
<span class="ref-name">{{ targetBranch }}</span>
<span v-html="emptyStateText"></span>
<div class="text-center">
<a :href="newBlobPath" class="btn btn-success"> {{ __('Create commit') }} </a>
<gl-button :href="getNoteableData.new_blob_path" variant="success">{{
__('Create commit')
}}</gl-button>
</div>
</div>
</div>

View file

@ -43,14 +43,14 @@ export default {
<tbody>
<template v-for="(line, index) in diffLines">
<parallel-diff-table-row
:key="index"
:key="line.line_code"
:file-hash="diffFile.file_hash"
:context-lines-path="diffFile.context_lines_path"
:line="line"
:is-bottom="index + 1 === diffLinesLength"
/>
<parallel-diff-comment-row
:key="`dcr-${index}`"
:key="`dcr-${line.line_code || index}`"
:line="line"
:diff-file-hash="diffFile.file_hash"
:line-index="index"

View file

@ -18,6 +18,7 @@ export default function initDiffsApp(store) {
projectPath: dataset.projectPath,
helpPagePath: dataset.helpPagePath,
currentUser: JSON.parse(dataset.currentUserData) || {},
changesEmptyStateIllustration: dataset.changesEmptyStateIllustration,
};
},
computed: {
@ -33,6 +34,7 @@ export default function initDiffsApp(store) {
projectPath: this.projectPath,
helpPagePath: this.helpPagePath,
shouldShow: this.activeTab === 'diffs',
changesEmptyStateIllustration: this.changesEmptyStateIllustration,
},
});
},

View file

@ -196,6 +196,15 @@ export function trimFirstCharOfLineContent(line = {}) {
return parsedLine;
}
function getLineCode({ left, right }, index) {
if (left && left.line_code) {
return left.line_code;
} else if (right && right.line_code) {
return right.line_code;
}
return index;
}
// This prepares and optimizes the incoming diff data from the server
// by setting up incremental rendering and removing unneeded data
export function prepareDiffData(diffData) {
@ -208,6 +217,8 @@ export function prepareDiffData(diffData) {
const linesLength = file.parallel_diff_lines.length;
for (let u = 0; u < linesLength; u += 1) {
const line = file.parallel_diff_lines[u];
line.line_code = getLineCode(line, u);
if (line.left) {
line.left = trimFirstCharOfLineContent(line.left);
line.left.hasForm = false;

View file

@ -1,27 +0,0 @@
import $ from 'jquery';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import Flash from '~/flash';
export default function initDismissableCallout(alertSelector) {
const alertEl = document.querySelector(alertSelector);
if (!alertEl) {
return;
}
const closeButtonEl = alertEl.getElementsByClassName('close')[0];
const { dismissEndpoint, featureId } = closeButtonEl.dataset;
closeButtonEl.addEventListener('click', () => {
axios
.post(dismissEndpoint, {
feature_name: featureId,
})
.then(() => {
$(alertEl).alert('close');
})
.catch(() => {
Flash(__('An error occurred while dismissing the alert. Refresh the page and try again.'));
});
});
}

View file

@ -14,6 +14,7 @@ import MonitoringButtonComponent from './environment_monitoring.vue';
import CommitComponent from '../../vue_shared/components/commit.vue';
import eventHub from '../event_hub';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { CLUSTER_TYPE } from '~/clusters/constants';
/**
* Environment Item Component
@ -84,6 +85,15 @@ export default {
return this.model && this.model.is_protected;
},
/**
* Hide group cluster features which are not currently implemented.
*
* @returns {Boolean}
*/
disableGroupClusterFeatures() {
return this.model && this.model.cluster_type === CLUSTER_TYPE.GROUP;
},
/**
* Returns whether the environment can be stopped.
*
@ -547,6 +557,7 @@ export default {
<terminal-button-component
v-if="model && model.terminal_path"
:terminal-path="model.terminal_path"
:disabled="disableGroupClusterFeatures"
/>
<rollback-component

View file

@ -19,6 +19,11 @@ export default {
required: false,
default: '',
},
disabled: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
title() {
@ -33,6 +38,7 @@ export default {
:title="title"
:aria-label="title"
:href="terminalPath"
:class="{ disabled: disabled }"
class="btn terminal-button d-none d-sm-none d-md-block"
>
<icon name="terminal" />

View file

@ -0,0 +1,118 @@
<script>
import { mapActions, mapState } from 'vuex';
import { GlEmptyState, GlButton, GlLink, GlLoadingIcon, GlTable } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import { __ } from '~/locale';
export default {
fields: [
{ key: 'error', label: __('Open errors') },
{ key: 'events', label: __('Events') },
{ key: 'users', label: __('Users') },
{ key: 'lastSeen', label: __('Last seen') },
],
components: {
GlEmptyState,
GlButton,
GlLink,
GlLoadingIcon,
GlTable,
Icon,
TimeAgo,
},
props: {
indexPath: {
type: String,
required: true,
},
enableErrorTrackingLink: {
type: String,
required: true,
},
errorTrackingEnabled: {
type: Boolean,
required: true,
},
illustrationPath: {
type: String,
required: true,
},
},
computed: {
...mapState(['errors', 'externalUrl', 'loading']),
},
created() {
if (this.errorTrackingEnabled) {
this.startPolling(this.indexPath);
}
},
methods: {
...mapActions(['startPolling']),
},
};
</script>
<template>
<div>
<div v-if="errorTrackingEnabled">
<div v-if="loading" class="py-3"><gl-loading-icon :size="3" /></div>
<div v-else>
<div class="d-flex justify-content-end">
<gl-button class="my-3 ml-auto" variant="primary" :href="externalUrl" target="_blank"
>View in Sentry <icon name="external-link" />
</gl-button>
</div>
<gl-table
:items="errors"
:fields="$options.fields"
:show-empty="true"
:empty-text="__('No errors to display')"
>
<template slot="HEAD_events" slot-scope="data">
<div class="text-right">{{ data.label }}</div>
</template>
<template slot="HEAD_users" slot-scope="data">
<div class="text-right">{{ data.label }}</div>
</template>
<template slot="error" slot-scope="errors">
<div class="d-flex flex-column">
<div class="d-flex">
<gl-link :href="errors.item.externalUrl" class="d-flex text-dark" target="_blank">
<strong>{{ errors.item.title.trim() }}</strong>
<icon name="external-link" class="ml-1" />
</gl-link>
<span class="text-secondary ml-2">{{ errors.item.culprit }}</span>
</div>
{{ errors.item.message || __('No details available') }}
</div>
</template>
<template slot="events" slot-scope="errors">
<div class="text-right">{{ errors.item.count }}</div>
</template>
<template slot="users" slot-scope="errors">
<div class="text-right">{{ errors.item.userCount }}</div>
</template>
<template slot="lastSeen" slot-scope="errors">
<div class="d-flex align-items-center">
<icon name="calendar" css-classes="text-secondary mr-1" />
<time-ago :time="errors.item.lastSeen" class="text-secondary" />
</div>
</template>
</gl-table>
</div>
</div>
<div v-else>
<gl-empty-state
:title="__('Get started with error tracking')"
:description="__('Monitor your errors by integrating with Sentry')"
:primary-button-text="__('Enable error tracking')"
:primary-button-link="enableErrorTrackingLink"
:svg-path="illustrationPath"
/>
</div>
</div>
</template>

View file

@ -0,0 +1,31 @@
import Vue from 'vue';
import { parseBoolean } from '~/lib/utils/common_utils';
import store from './store';
import ErrorTrackingList from './components/error_tracking_list.vue';
export default () => {
// eslint-disable-next-line no-new
new Vue({
el: '#js-error_tracking',
components: {
ErrorTrackingList,
},
store,
render(createElement) {
const domEl = document.querySelector(this.$options.el);
const { indexPath, enableErrorTrackingLink, illustrationPath } = domEl.dataset;
let { errorTrackingEnabled } = domEl.dataset;
errorTrackingEnabled = parseBoolean(errorTrackingEnabled);
return createElement('error-tracking-list', {
props: {
indexPath,
enableErrorTrackingLink,
errorTrackingEnabled,
illustrationPath,
},
});
},
});
};

View file

@ -0,0 +1,7 @@
import axios from '~/lib/utils/axios_utils';
export default {
getErrorList({ endpoint }) {
return axios.get(endpoint);
},
};

View file

@ -0,0 +1,31 @@
import Service from '../services';
import * as types from './mutation_types';
import createFlash from '~/flash';
import Poll from '~/lib/utils/poll';
import { __ } from '~/locale';
let eTagPoll;
export function startPolling({ commit }, endpoint) {
eTagPoll = new Poll({
resource: Service,
method: 'getErrorList',
data: { endpoint },
successCallback: ({ data }) => {
if (!data) {
return;
}
commit(types.SET_ERRORS, data.errors);
commit(types.SET_EXTERNAL_URL, data.external_url);
commit(types.SET_LOADING, false);
},
errorCallback: () => {
commit(types.SET_LOADING, false);
createFlash(__('Failed to load errors from Sentry'));
},
});
eTagPoll.makeRequest();
}
export default () => {};

View file

@ -0,0 +1,19 @@
import Vue from 'vue';
import Vuex from 'vuex';
import * as actions from './actions';
import mutations from './mutations';
Vue.use(Vuex);
export const createStore = () =>
new Vuex.Store({
state: {
errors: [],
externalUrl: '',
loading: true,
},
actions,
mutations,
});
export default createStore();

View file

@ -0,0 +1,3 @@
export const SET_ERRORS = 'SET_ERRORS';
export const SET_EXTERNAL_URL = 'SET_EXTERNAL_URL';
export const SET_LOADING = 'SET_LOADING';

View file

@ -0,0 +1,14 @@
import * as types from './mutation_types';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
export default {
[types.SET_ERRORS](state, data) {
state.errors = convertObjectPropsToCamelCase(data, { deep: true });
},
[types.SET_EXTERNAL_URL](state, url) {
state.externalUrl = url;
},
[types.SET_LOADING](state, loading) {
state.loading = loading;
},
};

View file

@ -54,67 +54,6 @@ export default class DropdownUtils {
return updatedItem;
}
static mergeDuplicateLabels(dataMap, newLabel) {
const updatedMap = dataMap;
const key = newLabel.title;
const hasKeyProperty = Object.prototype.hasOwnProperty.call(updatedMap, key);
if (!hasKeyProperty) {
updatedMap[key] = newLabel;
} else {
const existing = updatedMap[key];
if (!existing.multipleColors) {
existing.multipleColors = [existing.color];
}
existing.multipleColors.push(newLabel.color);
}
return updatedMap;
}
static duplicateLabelColor(labelColors) {
const colors = labelColors;
const spacing = 100 / colors.length;
// Reduce the colors to 4
colors.length = Math.min(colors.length, 4);
const color = colors
.map((c, i) => {
const percentFirst = Math.floor(spacing * i);
const percentSecond = Math.floor(spacing * (i + 1));
return `${c} ${percentFirst}%, ${c} ${percentSecond}%`;
})
.join(', ');
return `linear-gradient(${color})`;
}
static duplicateLabelPreprocessing(data) {
const results = [];
const dataMap = {};
data.forEach(DropdownUtils.mergeDuplicateLabels.bind(null, dataMap));
Object.keys(dataMap).forEach(key => {
const label = dataMap[key];
if (label.multipleColors) {
label.color = DropdownUtils.duplicateLabelColor(label.multipleColors);
label.text_color = '#000000';
}
results.push(label);
});
results.preprocessed = true;
return results;
}
static filterHint(config, item) {
const { input, allowedKeys } = config;
const updatedItem = item;

View file

@ -79,11 +79,7 @@ export default class FilteredSearchVisualTokens {
static setTokenStyle(tokenContainer, backgroundColor, textColor) {
const token = tokenContainer;
// Labels with linear gradient should not override default background color
if (backgroundColor.indexOf('linear-gradient') === -1) {
token.style.backgroundColor = backgroundColor;
}
token.style.backgroundColor = backgroundColor;
token.style.color = textColor;
if (textColor === '#FFFFFF') {
@ -94,18 +90,6 @@ export default class FilteredSearchVisualTokens {
return token;
}
static preprocessLabel(labelsEndpoint, labels) {
let processed = labels;
if (!labels.preprocessed) {
processed = DropdownUtils.duplicateLabelPreprocessing(labels);
AjaxCache.override(labelsEndpoint, processed);
processed.preprocessed = true;
}
return processed;
}
static updateLabelTokenColor(tokenValueContainer, tokenValue) {
const filteredSearchInput = FilteredSearchContainer.container.querySelector('.filtered-search');
const { baseEndpoint } = filteredSearchInput.dataset;
@ -115,7 +99,6 @@ export default class FilteredSearchVisualTokens {
);
return AjaxCache.retrieve(labelsEndpoint)
.then(FilteredSearchVisualTokens.preprocessLabel.bind(null, labelsEndpoint))
.then(labels => {
const matchingLabel = (labels || []).find(
label => `~${DropdownUtils.getEscapedText(label.title)}` === tokenValue,

View file

@ -221,13 +221,13 @@ class GfmAutoComplete {
displayTpl(value) {
let tmpl = GfmAutoComplete.Loading.template;
if (value.title != null) {
tmpl = GfmAutoComplete.Issues.templateFunction(value.id, value.title);
tmpl = GfmAutoComplete.Issues.templateFunction(value);
}
return tmpl;
},
data: GfmAutoComplete.defaultLoadingData,
// eslint-disable-next-line no-template-curly-in-string
insertTpl: '${atwho-at}${id}',
insertTpl: GfmAutoComplete.Issues.insertTemplateFunction,
skipSpecialCharacterTest: true,
callbacks: {
...this.getDefaultCallbacks(),
beforeSave(issues) {
@ -238,6 +238,7 @@ class GfmAutoComplete {
return {
id: i.iid,
title: sanitize(i.title),
reference: i.reference,
search: `${i.iid} ${i.title}`,
};
});
@ -256,7 +257,7 @@ class GfmAutoComplete {
displayTpl(value) {
let tmpl = GfmAutoComplete.Loading.template;
if (value.title != null) {
tmpl = GfmAutoComplete.Milestones.template;
tmpl = GfmAutoComplete.Milestones.templateFunction(value.title);
}
return tmpl;
},
@ -287,13 +288,13 @@ class GfmAutoComplete {
displayTpl(value) {
let tmpl = GfmAutoComplete.Loading.template;
if (value.title != null) {
tmpl = GfmAutoComplete.Issues.templateFunction(value.id, value.title);
tmpl = GfmAutoComplete.Issues.templateFunction(value);
}
return tmpl;
},
data: GfmAutoComplete.defaultLoadingData,
// eslint-disable-next-line no-template-curly-in-string
insertTpl: '${atwho-at}${id}',
insertTpl: GfmAutoComplete.Issues.insertTemplateFunction,
skipSpecialCharacterTest: true,
callbacks: {
...this.getDefaultCallbacks(),
beforeSave(merges) {
@ -304,6 +305,7 @@ class GfmAutoComplete {
return {
id: m.iid,
title: sanitize(m.title),
reference: m.reference,
search: `${m.iid} ${m.title}`,
};
});
@ -323,7 +325,7 @@ class GfmAutoComplete {
searchKey: 'search',
data: GfmAutoComplete.defaultLoadingData,
displayTpl(value) {
let tmpl = GfmAutoComplete.Labels.template;
let tmpl = GfmAutoComplete.Labels.templateFunction(value.color, value.title);
if (GfmAutoComplete.isLoading(value)) {
tmpl = GfmAutoComplete.Loading.template;
}
@ -397,7 +399,7 @@ class GfmAutoComplete {
displayTpl(value) {
let tmpl = GfmAutoComplete.Loading.template;
if (value.title != null) {
tmpl = GfmAutoComplete.Issues.templateFunction(value.id, value.title);
tmpl = GfmAutoComplete.Issues.templateFunction(value);
}
return tmpl;
},
@ -588,20 +590,27 @@ GfmAutoComplete.Members = {
},
};
GfmAutoComplete.Labels = {
template:
// eslint-disable-next-line no-template-curly-in-string
'<li><span class="dropdown-label-box" style="background: ${color}"></span> ${title}</li>',
templateFunction(color, title) {
return `<li><span class="dropdown-label-box" style="background: ${_.escape(
color,
)}"></span> ${_.escape(title)}</li>`;
},
};
// Issues, MergeRequests and Snippets
GfmAutoComplete.Issues = {
templateFunction(id, title) {
return `<li><small>${id}</small> ${_.escape(title)}</li>`;
insertTemplateFunction(value) {
// eslint-disable-next-line no-template-curly-in-string
return value.reference || '${atwho-at}${id}';
},
templateFunction({ id, title, reference }) {
return `<li><small>${reference || id}</small> ${_.escape(title)}</li>`;
},
};
// Milestones
GfmAutoComplete.Milestones = {
// eslint-disable-next-line no-template-curly-in-string
template: '<li>${title}</li>',
templateFunction(title) {
return `<li>${_.escape(title)}</li>`;
},
};
GfmAutoComplete.Loading = {
template:

View file

@ -51,8 +51,6 @@ export default class GLForm {
// form and textarea event listeners
this.addEventListeners();
addMarkdownListeners(this.form);
// hide discard button
this.form.find('.js-note-discard').hide();
this.form.show();
if (this.isAutosizeable) this.setupAutosize();
}

View file

@ -28,27 +28,29 @@ export default {
</script>
<template>
<div class="block">
<div class="title">{{ s__('Job|Job artifacts') }}</div>
<div class="title font-weight-bold">{{ s__('Job|Job artifacts') }}</div>
<p v-if="isExpired" class="js-artifacts-removed build-detail-row">
{{ s__('Job|The artifacts were removed') }}
<p
v-if="isExpired || willExpire"
:class="{
'js-artifacts-removed': isExpired,
'js-artifacts-will-be-removed': willExpire,
}"
class="build-detail-row"
>
<span v-if="isExpired">{{ s__('Job|The artifacts were removed') }}</span>
<span v-if="willExpire">{{ s__('Job|The artifacts will be removed') }}</span>
<timeago-tooltip v-if="artifact.expire_at" :time="artifact.expire_at" />
</p>
<p v-else-if="willExpire" class="js-artifacts-will-be-removed build-detail-row">
{{ s__('Job|The artifacts will be removed in') }}
</p>
<timeago-tooltip v-if="artifact.expire_at" :time="artifact.expire_at" />
<div class="btn-group d-flex" role="group">
<div class="btn-group d-flex prepend-top-10" role="group">
<gl-link
v-if="artifact.keep_path"
:href="artifact.keep_path"
class="js-keep-artifacts btn btn-sm btn-default"
data-method="post"
>{{ s__('Job|Keep') }}</gl-link
>
{{ s__('Job|Keep') }}
</gl-link>
<gl-link
v-if="artifact.download_path"
@ -56,17 +58,15 @@ export default {
class="js-download-artifacts btn btn-sm btn-default"
download
rel="nofollow"
>{{ s__('Job|Download') }}</gl-link
>
{{ s__('Job|Download') }}
</gl-link>
<gl-link
v-if="artifact.browse_path"
:href="artifact.browse_path"
class="js-browse-artifacts btn btn-sm btn-default"
>{{ s__('Job|Browse') }}</gl-link
>
{{ s__('Job|Browse') }}
</gl-link>
</div>
</div>
</template>

View file

@ -31,12 +31,12 @@ export default {
block: !isLastBlock,
}"
>
<p>
{{ __('Commit') }}
<p class="append-bottom-5">
<span class="font-weight-bold">{{ __('Commit') }}</span>
<gl-link :href="commit.commit_path" class="js-commit-sha commit-sha link-commit">{{
commit.short_id
}}</gl-link>
<gl-link :href="commit.commit_path" class="js-commit-sha commit-sha link-commit">
{{ commit.short_id }}
</gl-link>
<clipboard-button
:text="commit.short_id"
@ -44,11 +44,14 @@ export default {
css-class="btn btn-clipboard btn-transparent"
/>
<gl-link v-if="mergeRequest" :href="mergeRequest.path" class="js-link-commit link-commit"
>!{{ mergeRequest.iid }}</gl-link
>
<span v-if="mergeRequest">
{{ __('in') }}
<gl-link :href="mergeRequest.path" class="js-link-commit link-commit"
>!{{ mergeRequest.iid }}</gl-link
>
</span>
</p>
<p class="build-light-text append-bottom-0">{{ commit.title }}</p>
<p class="append-bottom-0">{{ commit.title }}</p>
</div>
</template>

View file

@ -110,22 +110,20 @@ export default {
<aside class="right-sidebar build-sidebar" data-offset-top="101" data-spy="affix">
<div class="sidebar-container">
<div class="blocks-container">
<div class="block">
<strong class="inline prepend-top-8"> {{ job.name }} </strong>
<div class="block d-flex align-items-center">
<h4 class="flex-grow-1 prepend-top-8 m-0">{{ job.name }}</h4>
<gl-link
v-if="job.retry_path"
:class="retryButtonClass"
:href="job.retry_path"
data-method="post"
rel="nofollow"
>{{ __('Retry') }}</gl-link
>
{{ __('Retry') }}
</gl-link>
<gl-link
v-if="job.terminal_path"
:href="job.terminal_path"
class="js-terminal-link pull-right btn btn-primary
btn-inverted visible-md-block visible-lg-block"
class="js-terminal-link pull-right btn btn-primary btn-inverted visible-md-block visible-lg-block"
target="_blank"
>
{{ __('Debug') }} <icon name="external-link" />
@ -133,8 +131,7 @@ export default {
<gl-button
:aria-label="__('Toggle Sidebar')"
type="button"
class="btn btn-blank gutter-toggle
float-right d-block d-md-none js-sidebar-build-toggle"
class="btn btn-blank gutter-toggle float-right d-block d-md-none js-sidebar-build-toggle"
@click="toggleSidebar"
>
<i aria-hidden="true" data-hidden="true" class="fa fa-angle-double-right"></i>
@ -145,25 +142,18 @@ export default {
v-if="job.new_issue_path"
:href="job.new_issue_path"
class="js-new-issue btn btn-success btn-inverted"
>{{ __('New issue') }}</gl-link
>
{{ __('New issue') }}
</gl-link>
<gl-link
v-if="job.retry_path"
:href="job.retry_path"
class="js-retry-job btn btn-inverted-secondary"
data-method="post"
rel="nofollow"
>{{ __('Retry') }}</gl-link
>
{{ __('Retry') }}
</gl-link>
</div>
<div :class="{ block: renderBlock }">
<p v-if="job.merge_request" class="build-detail-row js-job-mr">
<span class="build-light-text"> {{ __('Merge Request:') }} </span>
<gl-link :href="job.merge_request.path"> !{{ job.merge_request.iid }} </gl-link>
</p>
<detail-row
v-if="job.duration"
:value="duration"
@ -198,10 +188,10 @@ export default {
title="Coverage"
/>
<p v-if="job.tags.length" class="build-detail-row js-job-tags">
<span class="build-light-text"> {{ __('Tags:') }} </span>
<span v-for="(tag, i) in job.tags" :key="i" class="badge badge-primary">
{{ tag }}
</span>
<span class="font-weight-bold">{{ __('Tags:') }}</span>
<span v-for="(tag, i) in job.tags" :key="i" class="badge badge-primary mr-1">{{
tag
}}</span>
</p>
<div v-if="job.cancel_path" class="btn-group prepend-top-5" role="group">
@ -210,9 +200,8 @@ export default {
class="js-cancel-job btn btn-sm btn-default"
data-method="post"
rel="nofollow"
>{{ __('Cancel') }}</gl-link
>
{{ __('Cancel') }}
</gl-link>
</div>
</div>

View file

@ -34,8 +34,7 @@ export default {
</script>
<template>
<p class="build-detail-row">
<span v-if="hasTitle" class="build-light-text"> {{ title }}: </span> {{ value }}
<span v-if="hasTitle" class="font-weight-bold">{{ title }}:</span> {{ value }}
<span v-if="hasHelpURL" class="help-button float-right">
<gl-link :href="helpUrl" target="_blank" rel="noopener noreferrer nofollow">
<i class="fa fa-question-circle" aria-hidden="true"></i>

View file

@ -38,11 +38,11 @@ export default {
<div class="block-last dropdown">
<ci-icon :status="pipeline.details.status" class="vertical-align-middle" />
{{ __('Pipeline') }}
<a :href="pipeline.path" class="js-pipeline-path link-commit"> #{{ pipeline.id }} </a>
<span class="font-weight-bold">{{ __('Pipeline') }}</span>
<a :href="pipeline.path" class="js-pipeline-path link-commit">#{{ pipeline.id }}</a>
<template v-if="hasRef">
{{ __('from') }}
<a :href="pipeline.ref.path" class="link-commit ref-name"> {{ pipeline.ref.name }} </a>
<a :href="pipeline.ref.path" class="link-commit ref-name">{{ pipeline.ref.name }}</a>
</template>
<button

View file

@ -43,23 +43,24 @@ export default {
<template>
<div class="build-widget block">
<h4 class="title">{{ __('Trigger') }}</h4>
<p
v-if="trigger.short_token"
class="js-short-token"
:class="{ 'append-bottom-0': !hasVariables }"
:class="{ 'append-bottom-5': hasVariables, 'append-bottom-0': !hasVariables }"
>
<span class="build-light-text"> {{ __('Token') }} </span> {{ trigger.short_token }}
<span class="font-weight-bold">{{ __('Trigger token:') }}</span> {{ trigger.short_token }}
</p>
<template v-if="hasVariables">
<p class="trigger-variables-btn-container">
<span class="build-light-text"> {{ __('Variables:') }} </span>
<span class="font-weight-bold">{{ __('Trigger variables:') }}</span>
<gl-button v-if="hasValues" class="group js-reveal-variables" @click="toggleValues">
{{ getToggleButtonText }}
</gl-button>
<gl-button
v-if="hasValues"
class="btn-sm group js-reveal-variables trigger-variables-btn"
@click="toggleValues"
>{{ getToggleButtonText }}</gl-button
>
</p>
<table class="js-build-variables trigger-build-variables">

View file

@ -7,7 +7,6 @@ import _ from 'underscore';
import { sprintf, __ } from './locale';
import axios from './lib/utils/axios_utils';
import IssuableBulkUpdateActions from './issuable_bulk_update_actions';
import DropdownUtils from './filtered_search/dropdown_utils';
import CreateLabelDropdown from './create_label';
import flash from './flash';
import ModalStore from './boards/stores/modal_store';
@ -171,23 +170,7 @@ export default class LabelsSelect {
axios
.get(labelUrl)
.then(res => {
let data = _.chain(res.data)
.groupBy(function(label) {
return label.title;
})
.map(function(label) {
var color;
color = _.map(label, function(dup) {
return dup.color;
});
return {
id: label[0].id,
title: label[0].title,
color: color,
duplicate: color.length > 1,
};
})
.value();
let { data } = res;
if ($dropdown.hasClass('js-extra-options')) {
var extraData = [];
if (showNo) {
@ -272,15 +255,9 @@ export default class LabelsSelect {
selectedClass.push('dropdown-clear-active');
}
}
if (label.duplicate) {
color = DropdownUtils.duplicateLabelColor(label.color);
} else {
if (label.color != null) {
[color] = label.color;
}
}
if (color) {
colorEl = "<span class='dropdown-label-box' style='background: " + color + "'></span>";
if (label.color) {
colorEl =
"<span class='dropdown-label-box' style='background: " + label.color + "'></span>";
} else {
colorEl = '';
}
@ -435,7 +412,7 @@ export default class LabelsSelect {
new ListLabel({
id: label.id,
title: label.title,
color: label.color[0],
color: label.color,
textColor: '#fff',
}),
);

View file

@ -8,6 +8,10 @@ function selectedText(text, textarea) {
return text.substring(textarea.selectionStart, textarea.selectionEnd);
}
function addBlockTags(blockTag, selected) {
return `${blockTag}\n${selected}\n${blockTag}`;
}
function lineBefore(text, textarea) {
var split;
split = text
@ -24,19 +28,45 @@ function lineAfter(text, textarea) {
.split('\n')[0];
}
function editorBlockTagText(text, blockTag, selected, editor) {
const lines = text.split('\n');
const selectionRange = editor.getSelectionRange();
const shouldRemoveBlock =
lines[selectionRange.start.row - 1] === blockTag &&
lines[selectionRange.end.row + 1] === blockTag;
if (shouldRemoveBlock) {
if (blockTag !== null) {
// ace is globally defined
// eslint-disable-next-line no-undef
const { Range } = ace.require('ace/range');
const lastLine = lines[selectionRange.end.row + 1];
const rangeWithBlockTags = new Range(
lines[selectionRange.start.row - 1],
0,
selectionRange.end.row + 1,
lastLine.length,
);
editor.getSelection().setSelectionRange(rangeWithBlockTags);
}
return selected;
}
return addBlockTags(blockTag, selected);
}
function blockTagText(text, textArea, blockTag, selected) {
const before = lineBefore(text, textArea);
const after = lineAfter(text, textArea);
if (before === blockTag && after === blockTag) {
const shouldRemoveBlock =
lineBefore(text, textArea) === blockTag && lineAfter(text, textArea) === blockTag;
if (shouldRemoveBlock) {
// To remove the block tag we have to select the line before & after
if (blockTag != null) {
textArea.selectionStart = textArea.selectionStart - (blockTag.length + 1);
textArea.selectionEnd = textArea.selectionEnd + (blockTag.length + 1);
}
return selected;
} else {
return blockTag + '\n' + selected + '\n' + blockTag;
}
return addBlockTags(blockTag, selected);
}
function moveCursor({
@ -46,33 +76,48 @@ function moveCursor({
positionBetweenTags,
removedLastNewLine,
select,
editor,
editorSelectionStart,
editorSelectionEnd,
}) {
var pos;
if (!textArea.setSelectionRange) {
if (textArea && !textArea.setSelectionRange) {
return;
}
if (select && select.length > 0) {
// calculate the part of the text to be selected
const startPosition = textArea.selectionStart - (tag.length - tag.indexOf(select));
const endPosition = startPosition + select.length;
return textArea.setSelectionRange(startPosition, endPosition);
if (textArea) {
// calculate the part of the text to be selected
const startPosition = textArea.selectionStart - (tag.length - tag.indexOf(select));
const endPosition = startPosition + select.length;
return textArea.setSelectionRange(startPosition, endPosition);
} else if (editor) {
editor.navigateLeft(tag.length - tag.indexOf(select));
editor.getSelection().selectAWord();
return;
}
}
if (textArea.selectionStart === textArea.selectionEnd) {
if (textArea) {
if (textArea.selectionStart === textArea.selectionEnd) {
if (positionBetweenTags) {
pos = textArea.selectionStart - tag.length;
} else {
pos = textArea.selectionStart;
}
if (removedLastNewLine) {
pos -= 1;
}
if (cursorOffset) {
pos -= cursorOffset;
}
return textArea.setSelectionRange(pos, pos);
}
} else if (editor && editorSelectionStart.row === editorSelectionEnd.row) {
if (positionBetweenTags) {
pos = textArea.selectionStart - tag.length;
} else {
pos = textArea.selectionStart;
editor.navigateLeft(tag.length);
}
if (removedLastNewLine) {
pos -= 1;
}
if (cursorOffset) {
pos -= cursorOffset;
}
return textArea.setSelectionRange(pos, pos);
}
}
@ -82,9 +127,10 @@ export function insertMarkdownText({
tag,
cursorOffset,
blockTag,
selected,
selected = '',
wrap,
select,
editor,
}) {
var textToInsert,
selectedSplit,
@ -92,11 +138,20 @@ export function insertMarkdownText({
removedLastNewLine,
removedFirstNewLine,
currentLineEmpty,
lastNewLine;
lastNewLine,
editorSelectionStart,
editorSelectionEnd;
removedLastNewLine = false;
removedFirstNewLine = false;
currentLineEmpty = false;
if (editor) {
const selectionRange = editor.getSelectionRange();
editorSelectionStart = selectionRange.start;
editorSelectionEnd = selectionRange.end;
}
// check for link pattern and selected text is an URL
// if so fill in the url part instead of the text part of the pattern.
if (tag === LINK_TAG_PATTERN) {
@ -119,14 +174,27 @@ export function insertMarkdownText({
}
// Remove the last newline
if (textArea.selectionEnd - textArea.selectionStart > selected.replace(/\n$/, '').length) {
removedLastNewLine = true;
selected = selected.replace(/\n$/, '');
if (textArea) {
if (textArea.selectionEnd - textArea.selectionStart > selected.replace(/\n$/, '').length) {
removedLastNewLine = true;
selected = selected.replace(/\n$/, '');
}
} else if (editor) {
if (editorSelectionStart.row !== editorSelectionEnd.row) {
removedLastNewLine = true;
selected = selected.replace(/\n$/, '');
}
}
selectedSplit = selected.split('\n');
if (!wrap) {
if (editor && !wrap) {
lastNewLine = editor.getValue().split('\n')[editorSelectionStart.row];
if (/^\s*$/.test(lastNewLine)) {
currentLineEmpty = true;
}
} else if (textArea && !wrap) {
lastNewLine = textArea.value.substr(0, textArea.selectionStart).lastIndexOf('\n');
// Check whether the current line is empty or consists only of spaces(=handle as empty)
@ -135,13 +203,19 @@ export function insertMarkdownText({
}
}
startChar = !wrap && !currentLineEmpty && textArea.selectionStart > 0 ? '\n' : '';
const isBeginning =
(textArea && textArea.selectionStart === 0) ||
(editor && editorSelectionStart.column === 0 && editorSelectionStart.row === 0);
startChar = !wrap && !currentLineEmpty && !isBeginning ? '\n' : '';
const textPlaceholder = '{text}';
if (selectedSplit.length > 1 && (!wrap || (blockTag != null && blockTag !== ''))) {
if (blockTag != null && blockTag !== '') {
textToInsert = blockTagText(text, textArea, blockTag, selected);
textToInsert = editor
? editorBlockTagText(text, blockTag, selected, editor)
: blockTagText(text, textArea, blockTag, selected);
} else {
textToInsert = selectedSplit
.map(function(val) {
@ -170,7 +244,11 @@ export function insertMarkdownText({
textToInsert += '\n';
}
insertText(textArea, textToInsert);
if (editor) {
editor.insert(textToInsert);
} else {
insertText(textArea, textToInsert);
}
return moveCursor({
textArea,
tag: tag.replace(textPlaceholder, selected),
@ -178,6 +256,9 @@ export function insertMarkdownText({
positionBetweenTags: wrap && selected.length === 0,
removedLastNewLine,
select,
editor,
editorSelectionStart,
editorSelectionEnd,
});
}
@ -212,11 +293,30 @@ export function addMarkdownListeners(form) {
blockTag: $this.data('mdBlock'),
wrap: !$this.data('mdPrepend'),
select: $this.data('mdSelect'),
tagContent: $this.data('mdTagContent').toString(),
tagContent: $this.data('mdTagContent'),
});
});
}
export function addEditorMarkdownListeners(editor) {
$('.js-md')
.off('click')
.on('click', function(e) {
const { mdTag, mdBlock, mdPrepend, mdSelect } = $(e.currentTarget).data();
insertMarkdownText({
tag: mdTag,
blockTag: mdBlock,
wrap: !mdPrepend,
select: mdSelect,
selected: editor.getSelectedText(),
text: editor.getValue(),
editor,
});
editor.focus();
});
}
export function removeMarkdownListeners(form) {
return $('.js-md', form).off('click');
}

View file

@ -6,6 +6,7 @@ export default {
components: {
GlAreaChart,
},
inheritAttrs: false,
props: {
graphData: {
type: Object,
@ -25,6 +26,11 @@ export default {
);
},
},
alertData: {
type: Object,
required: false,
default: () => ({}),
},
},
computed: {
chartData() {
@ -74,9 +80,6 @@ export default {
const [date, value] = params;
return [dateFormat(date, 'dd mmm yyyy, h:MMtt'), value.toFixed(3)];
},
onCreated(chart) {
this.$emit('created', chart);
},
},
};
</script>
@ -88,10 +91,11 @@ export default {
<div class="prometheus-graph-widgets"><slot></slot></div>
</div>
<gl-area-chart
v-bind="$attrs"
:data="chartData"
:option="chartOptions"
:format-tooltip-text="formatTooltipText"
@created="onCreated"
:thresholds="alertData"
/>
</div>
</template>

View file

@ -144,6 +144,9 @@ export default {
}
},
methods: {
getGraphAlerts(graphId) {
return this.alertData ? this.alertData[graphId] || {} : {};
},
getGraphsData() {
this.state = 'loading';
Promise.all([
@ -223,6 +226,8 @@ export default {
:tags-path="tagsPath"
:show-legend="showLegend"
:small-graph="forceSmallGraph"
:alert-data="getGraphAlerts(graphData.id)"
group-id="monitor-area-chart"
>
<!-- EE content -->
{{ null }}

View file

@ -92,7 +92,11 @@ function queryTimeSeries(query, graphDrawData, lineStyle) {
if (seriesCustomizationData) {
metricTag = seriesCustomizationData.value || timeSeriesMetricLabel;
[lineColor, areaColor] = pickColor(seriesCustomizationData.color);
shouldRenderLegend = false;
if (timeSeriesParsed.length > 0) {
shouldRenderLegend = false;
} else {
shouldRenderLegend = true;
}
} else {
metricTag = timeSeriesMetricLabel || query.label || `series ${timeSeriesNumber + 1}`;
[lineColor, areaColor] = pickColor();
@ -101,19 +105,6 @@ function queryTimeSeries(query, graphDrawData, lineStyle) {
}
}
if (!shouldRenderLegend) {
if (!timeSeriesParsed[0].tracksLegend) {
timeSeriesParsed[0].tracksLegend = [];
}
timeSeriesParsed[0].tracksLegend.push({
max: maximumValue,
average: accum / timeSeries.values.length,
lineStyle,
lineColor,
metricTag,
});
}
const values = datesWithoutGaps.map(time => ({
time,
value: findByDate(timeSeries.values, time),
@ -135,6 +126,19 @@ function queryTimeSeries(query, graphDrawData, lineStyle) {
shouldRenderLegend,
renderCanary,
});
if (!shouldRenderLegend) {
if (!timeSeriesParsed[0].tracksLegend) {
timeSeriesParsed[0].tracksLegend = [];
}
timeSeriesParsed[0].tracksLegend.push({
max: maximumValue,
average: accum / timeSeries.values.length,
lineStyle,
lineColor,
metricTag,
});
}
});
return timeSeriesParsed;

View file

@ -138,8 +138,6 @@ export default class Notes {
this.$wrapperEl.on('click', '.js-note-delete', this.removeNote);
// delete note attachment
this.$wrapperEl.on('click', '.js-note-attachment-delete', this.removeAttachment);
// reset main target form when clicking discard
this.$wrapperEl.on('click', '.js-note-discard', this.resetMainTargetForm);
// update the file name when an attachment is selected
this.$wrapperEl.on('change', '.js-note-attachment-input', this.updateFormAttachment);
// reply to diff/discussion notes
@ -191,7 +189,6 @@ export default class Notes {
this.$wrapperEl.off('keyup input', '.js-note-text');
this.$wrapperEl.off('click', '.js-note-target-reopen');
this.$wrapperEl.off('click', '.js-note-target-close');
this.$wrapperEl.off('click', '.js-note-discard');
this.$wrapperEl.off('keydown', '.js-note-text');
this.$wrapperEl.off('click', '.js-comment-resolve-button');
this.$wrapperEl.off('click', '.system-note-commit-list-toggler');
@ -986,11 +983,9 @@ export default class Notes {
form.find('#note_position').val(dataHolder.attr('data-position'));
form
.find('.js-note-discard')
.find('.js-close-discussion-note-form')
.show()
.removeClass('js-note-discard')
.addClass('js-close-discussion-note-form')
.text(form.find('.js-close-discussion-note-form').data('cancelText'));
.removeClass('hide');
form.find('.js-note-target-close').remove();
form.find('.js-note-new-discussion').remove();
this.setupNoteForm(form);
@ -1194,12 +1189,11 @@ export default class Notes {
}
updateTargetButtons(e) {
var closebtn, closetext, discardbtn, form, reopenbtn, reopentext, textarea;
var closebtn, closetext, form, reopenbtn, reopentext, textarea;
textarea = $(e.target);
form = textarea.parents('form');
reopenbtn = form.find('.js-note-target-reopen');
closebtn = form.find('.js-note-target-close');
discardbtn = form.find('.js-note-discard');
if (textarea.val().trim().length > 0) {
reopentext = reopenbtn.attr('data-alternative-text');
@ -1216,9 +1210,6 @@ export default class Notes {
if (closebtn.is(':not(.btn-comment-and-close)')) {
closebtn.addClass('btn-comment-and-close');
}
if (discardbtn.is(':hidden')) {
return discardbtn.show();
}
} else {
reopentext = reopenbtn.data('originalText');
closetext = closebtn.data('originalText');
@ -1234,9 +1225,6 @@ export default class Notes {
if (closebtn.is('.btn-comment-and-close')) {
closebtn.removeClass('btn-comment-and-close');
}
if (discardbtn.is(':visible')) {
return discardbtn.hide();
}
}
}

View file

@ -431,15 +431,6 @@ append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown"
:label="issueActionButtonTitle"
@click="handleSave(true);"
/>
<button
v-if="note.length"
type="button"
class="btn btn-cancel js-note-discard"
@click="discard"
>
Discard draft
</button>
</div>
</form>
</div>

View file

@ -2,7 +2,11 @@
import $ from 'jquery';
import { mapGetters, mapActions } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue';
import { DISCUSSION_FILTERS_DEFAULT_VALUE, HISTORY_ONLY_FILTER_VALUE } from '../constants';
import {
DISCUSSION_FILTERS_DEFAULT_VALUE,
HISTORY_ONLY_FILTER_VALUE,
DISCUSSION_TAB_LABEL,
} from '../constants';
export default {
components: {
@ -23,6 +27,7 @@ export default {
return {
currentValue: this.selectedValue,
defaultValue: DISCUSSION_FILTERS_DEFAULT_VALUE,
displayFilters: true,
};
},
computed: {
@ -32,6 +37,14 @@ export default {
return this.filters.find(filter => filter.value === this.currentValue);
},
},
created() {
if (window.mrTabs) {
const { eventHub, currentTab } = window.mrTabs;
eventHub.$on('MergeRequestTabChange', this.toggleFilters);
this.toggleFilters(currentTab);
}
},
mounted() {
this.toggleCommentsForm();
},
@ -51,12 +64,15 @@ export default {
toggleCommentsForm() {
this.setCommentsDisabled(this.currentValue === HISTORY_ONLY_FILTER_VALUE);
},
toggleFilters(tab) {
this.displayFilters = tab === DISCUSSION_TAB_LABEL;
},
},
};
</script>
<template>
<div class="discussion-filter-container d-inline-block align-bottom">
<div v-if="displayFilters" class="discussion-filter-container d-inline-block align-bottom">
<button
id="discussion-filter-dropdown"
ref="dropdownToggle"

View file

@ -149,6 +149,9 @@ export default {
return shouldResolve || shouldToggleState;
},
handleKeySubmit() {
this.handleUpdate();
},
handleUpdate(shouldResolve) {
const beforeSubmitDiscussionState = this.discussionResolved;
this.isSubmitting = true;
@ -216,8 +219,8 @@ export default {
class="note-textarea js-gfm-input js-note-text js-autosize markdown-area js-vue-issue-note-form js-vue-textarea qa-reply-input"
aria-label="Description"
placeholder="Write a comment or drag your files here…"
@keydown.meta.enter="handleUpdate();"
@keydown.ctrl.enter="handleUpdate();"
@keydown.meta.enter="handleKeySubmit();"
@keydown.ctrl.enter="handleKeySubmit();"
@keydown.up="editMyLastNote();"
@keydown.esc="cancelHandler(true);"
></textarea>
@ -226,7 +229,7 @@ export default {
<button
:disabled="isDisabled"
type="button"
class="js-vue-issue-save btn btn-success js-comment-button"
class="js-vue-issue-save btn btn-success js-comment-button qa-reply-comment-button"
@click="handleUpdate();"
>
{{ saveButtonTitle }}

View file

@ -170,35 +170,40 @@ export default {
return expanded || this.alwaysExpanded || isResolvedNonDiffDiscussion;
},
actionText() {
const commitId = this.discussion.commit_id ? truncateSha(this.discussion.commit_id) : '';
const linkStart = `<a href="${_.escape(this.discussion.discussion_path)}">`;
const linkEnd = '</a>';
let text = s__('MergeRequests|started a discussion');
let { commit_id: commitId } = this.discussion;
if (commitId) {
commitId = `<span class="commit-sha">${truncateSha(commitId)}</span>`;
}
if (this.discussion.for_commit) {
const {
for_commit: isForCommit,
diff_discussion: isDiffDiscussion,
active: isActive,
} = this.discussion;
let text = s__('MergeRequests|started a discussion');
if (isForCommit) {
text = s__(
'MergeRequests|started a discussion on commit %{linkStart}%{commitId}%{linkEnd}',
);
} else if (this.discussion.diff_discussion) {
if (this.discussion.active) {
text = s__('MergeRequests|started a discussion on %{linkStart}the diff%{linkEnd}');
} else {
text = s__(
'MergeRequests|started a discussion on %{linkStart}an old version of the diff%{linkEnd}',
);
}
} else if (isDiffDiscussion && commitId) {
text = isActive
? s__('MergeRequests|started a discussion on commit %{linkStart}%{commitId}%{linkEnd}')
: s__(
'MergeRequests|started a discussion on an outdated change in commit %{linkStart}%{commitId}%{linkEnd}',
);
} else if (isDiffDiscussion) {
text = isActive
? s__('MergeRequests|started a discussion on %{linkStart}the diff%{linkEnd}')
: s__(
'MergeRequests|started a discussion on %{linkStart}an old version of the diff%{linkEnd}',
);
}
return sprintf(
text,
{
commitId,
linkStart,
linkEnd,
},
false,
);
return sprintf(text, { commitId, linkStart, linkEnd }, false);
},
diffLine() {
if (this.discussion.diff_discussion && this.discussion.truncated_diff_lines) {
@ -374,6 +379,14 @@ Please check your network connection and try again.`;
:help-page-path="helpPagePath"
@handleDeleteNote="deleteNoteHandler"
>
<note-edited-text
v-if="discussion.resolved"
slot="discussion-resolved-text"
:edited-at="discussion.resolved_at"
:edited-by="discussion.resolved_by"
:action-text="resolvedText"
class-name="discussion-headline-light js-discussion-headline discussion-resolved-text"
/>
<slot slot="avatar-badge" name="avatar-badge"></slot>
</component>
<toggle-replies-widget
@ -417,7 +430,7 @@ Please check your network connection and try again.`;
<div class="discussion-with-resolve-btn">
<button
type="button"
class="js-vue-discussion-reply btn btn-text-field mr-sm-2 qa-discussion-reply"
class="js-vue-discussion-reply btn btn-text-field qa-discussion-reply"
title="Add a reply"
@click="showReplyForm"
>
@ -426,7 +439,7 @@ Please check your network connection and try again.`;
<div v-if="discussion.resolvable">
<button
type="button"
class="btn btn-default mr-sm-2"
class="btn btn-default ml-sm-2"
@click="resolveHandler();"
>
<i v-if="isResolving" aria-hidden="true" class="fa fa-spinner fa-spin"></i>

View file

@ -195,7 +195,7 @@ export default {
:img-alt="author.name"
:img-size="40"
>
<slot slot="avatar-badge" name="avatar-badge"> </slot>
<slot slot="avatar-badge" name="avatar-badge"></slot>
</user-avatar-link>
</div>
<div class="timeline-content">
@ -227,16 +227,19 @@ export default {
@handleResolve="resolveHandler"
/>
</div>
<note-body
ref="noteBody"
:note="note"
:line="line"
:can-edit="note.current_user.can_edit"
:is-editing="isEditing"
:help-page-path="helpPagePath"
@handleFormUpdate="formUpdateHandler"
@cancelForm="formCancelHandler"
/>
<div class="timeline-discussion-body">
<slot name="discussion-resolved-text"></slot>
<note-body
ref="noteBody"
:note="note"
:line="line"
:can-edit="note.current_user.can_edit"
:is-editing="isEditing"
:help-page-path="helpPagePath"
@handleFormUpdate="formUpdateHandler"
@cancelForm="formCancelHandler"
/>
</div>
</div>
</timeline-entry-item>
</template>

View file

@ -57,7 +57,7 @@ export default {
tooltip-placement="bottom"
/>
</div>
<button class="btn btn-link js-replies-text" type="button" @click="toggle">
<button class="btn btn-link js-replies-text qa-expand-replies" type="button" @click="toggle">
{{ replies.length }} {{ n__('reply', 'replies', replies.length) }}
</button>
{{ __('Last reply by') }}
@ -66,7 +66,11 @@ export default {
</a>
<time-ago-tooltip :time="lastReply.created_at" tooltip-placement="bottom" />
</template>
<span v-else class="collapse-replies-btn js-collapse-replies" @click="toggle">
<span
v-else
class="collapse-replies-btn js-collapse-replies qa-collapse-replies"
@click="toggle"
>
<icon name="chevron-down" /> {{ s__('Notes|Collapse replies') }}
</span>
</li>

View file

@ -17,6 +17,7 @@ export const RESOLVE_NOTE_METHOD_NAME = 'post';
export const DESCRIPTION_TYPE = 'changed the description';
export const HISTORY_ONLY_FILTER_VALUE = 2;
export const DISCUSSION_FILTERS_DEFAULT_VALUE = 0;
export const DISCUSSION_TAB_LABEL = 'show';
export const NOTEABLE_TYPE_MAPPING = {
Issue: ISSUE_NOTEABLE_TYPE,

View file

@ -415,12 +415,13 @@ export const submitSuggestion = (
commit(types.APPLY_SUGGESTION, { discussionId, noteId, suggestionId });
callback();
})
.catch(() => {
Flash(
__('Something went wrong while applying the suggestion. Please try again.'),
'alert',
flashContainer,
.catch(err => {
const defaultMessage = __(
'Something went wrong while applying the suggestion. Please try again.',
);
const flashMessage = err.response.data ? `${err.response.data.message}.` : defaultMessage;
Flash(__(flashMessage), 'alert', flashContainer);
callback();
});
};

View file

@ -1,3 +1,7 @@
import ProjectsList from '~/projects_list';
import Star from '../../../star';
document.addEventListener('DOMContentLoaded', () => new ProjectsList());
document.addEventListener('DOMContentLoaded', () => {
new ProjectsList(); // eslint-disable-line no-new
new Star('.project-row'); // eslint-disable-line no-new
});

View file

@ -1,5 +1,7 @@
import initDismissableCallout from '~/dismissable_callout';
import PersistentUserCallout from '~/persistent_user_callout';
document.addEventListener('DOMContentLoaded', () => {
initDismissableCallout('.gcp-signup-offer');
const callout = document.querySelector('.gcp-signup-offer');
if (callout) new PersistentUserCallout(callout); // eslint-disable-line no-new
});

View file

@ -1,6 +1,12 @@
import initDismissableCallout from '~/dismissable_callout';
import PersistentUserCallout from '~/persistent_user_callout';
import initGkeDropdowns from '~/projects/gke_cluster_dropdowns';
function initGcpSignupCallout() {
const callout = document.querySelector('.gcp-signup-offer');
if (callout) new PersistentUserCallout(callout); // eslint-disable-line no-new
}
document.addEventListener('DOMContentLoaded', () => {
const { page } = document.body.dataset;
const newClusterViews = [
@ -10,7 +16,7 @@ document.addEventListener('DOMContentLoaded', () => {
];
if (newClusterViews.indexOf(page) > -1) {
initDismissableCallout('.gcp-signup-offer');
initGcpSignupCallout();
initGkeDropdowns();
}
});

View file

@ -1,3 +1,4 @@
import '~/commons/bootstrap';
import { AwardsHandler } from '~/awards_handler';
class EmojiMenu extends AwardsHandler {

View file

@ -1,5 +1,7 @@
import initDismissableCallout from '~/dismissable_callout';
import PersistentUserCallout from '~/persistent_user_callout';
document.addEventListener('DOMContentLoaded', () => {
initDismissableCallout('.gcp-signup-offer');
const callout = document.querySelector('.gcp-signup-offer');
if (callout) new PersistentUserCallout(callout); // eslint-disable-line no-new
});

View file

@ -0,0 +1,5 @@
import ErrorTracking from '~/error_tracking';
document.addEventListener('DOMContentLoaded', () => {
ErrorTracking();
});

View file

@ -1,5 +1,5 @@
import initDismissableCallout from '~/dismissable_callout';
import initGkeDropdowns from '~/projects/gke_cluster_dropdowns';
import PersistentUserCallout from '../../persistent_user_callout';
import Project from './project';
import ShortcutsNavigation from '../../behaviors/shortcuts/shortcuts_navigation';
@ -12,7 +12,9 @@ document.addEventListener('DOMContentLoaded', () => {
];
if (newClusterViews.indexOf(page) > -1) {
initDismissableCallout('.gcp-signup-offer');
const callout = document.querySelector('.gcp-signup-offer');
if (callout) new PersistentUserCallout(callout); // eslint-disable-line no-new
initGkeDropdowns();
}

View file

@ -0,0 +1,3 @@
import initReleases from '~/releases';
document.addEventListener('DOMContentLoaded', initReleases);

View file

@ -325,8 +325,8 @@ export default {
<project-setting-row
v-if="pagesAvailable && pagesAccessControlEnabled"
:help-path="pagesHelpPath"
label="Pages"
help-text="Static website for the project."
label="Pages access control"
help-text="Access control for the project's static website"
>
<project-feature-setting
v-model="pagesAccessLevel"

View file

@ -0,0 +1,8 @@
import $ from 'jquery';
import ZenMode from '~/zen_mode';
import GLForm from '~/gl_form';
document.addEventListener('DOMContentLoaded', () => {
new ZenMode(); // eslint-disable-line no-new
new GLForm($('.release-form')); // eslint-disable-line no-new
});

View file

@ -0,0 +1,5 @@
// if the "projects dashboard" is a user's default dashboard, when they visit the
// instance root index, the dashboard will be served by the root controller instead
// of a dashboard controller. The root index redirects for all other default dashboards.
import '../dashboard/projects/index';

View file

@ -29,18 +29,21 @@ export default class UserOverviewBlock {
render(data) {
const { html, count } = data;
const contentList = document.querySelector(`${this.container} .overview-content-list`);
const containerEl = document.querySelector(this.container);
const contentList = containerEl.querySelector('.overview-content-list');
contentList.innerHTML += html;
const loadingEl = document.querySelector(`${this.container} .loading`);
const loadingEl = containerEl.querySelector('.loading');
if (count && count > 0) {
document.querySelector(`${this.container} .js-view-all`).classList.remove('hide');
containerEl.querySelector('.js-view-all').classList.remove('hide');
} else {
document
.querySelector(`${this.container} .nothing-here-block`)
.classList.add('text-left', 'p-0');
const nothingHereBlock = containerEl.querySelector('.nothing-here-block');
if (nothingHereBlock) {
nothingHereBlock.classList.add('text-left', 'p-0');
}
}
loadingEl.classList.add('hide');

View file

@ -151,8 +151,10 @@ export default class UserTabs {
loadTab(action, endpoint) {
this.toggleLoading(true);
const params = action === 'projects' ? { skip_namespace: true } : {};
return axios
.get(endpoint)
.get(endpoint, { params })
.then(({ data }) => {
const tabSelector = `div#${action}`;
this.$parentEl.find(tabSelector).html(data.html);
@ -188,7 +190,7 @@ export default class UserTabs {
requestParams: { limit: 10 },
});
UserTabs.renderMostRecentBlocks('#js-overview .projects-block', {
requestParams: { limit: 10, skip_pagination: true },
requestParams: { limit: 10, skip_pagination: true, skip_namespace: true, compact_mode: true },
});
this.loaded.overview = true;
@ -206,6 +208,8 @@ export default class UserTabs {
loadActivityCalendar() {
const $calendarWrap = this.$parentEl.find('.tab-pane.active .user-calendar');
if (!$calendarWrap.length) return;
const calendarPath = $calendarWrap.data('calendarPath');
AjaxCache.retrieve(calendarPath)

View file

@ -0,0 +1,34 @@
import axios from './lib/utils/axios_utils';
import { __ } from './locale';
import Flash from './flash';
export default class PersistentUserCallout {
constructor(container) {
const { dismissEndpoint, featureId } = container.dataset;
this.container = container;
this.dismissEndpoint = dismissEndpoint;
this.featureId = featureId;
this.init();
}
init() {
const closeButton = this.container.querySelector('.js-close');
closeButton.addEventListener('click', event => this.dismiss(event));
}
dismiss(event) {
event.preventDefault();
axios
.post(this.dismissEndpoint, {
feature_name: this.featureId,
})
.then(() => {
this.container.remove();
})
.catch(() => {
Flash(__('An error occurred while dismissing the alert. Refresh the page and try again.'));
});
}
}

View file

@ -1,8 +1,20 @@
<script>
import { GlLink, GlTooltipDirective } from '@gitlab/ui';
import _ from 'underscore';
import { __, sprintf } from '~/locale';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import popover from '~/vue_shared/directives/popover';
const popoverTitle = sprintf(
_.escape(
__(
`This pipeline makes use of a predefined CI/CD configuration enabled by %{strongStart}Auto DevOps.%{strongEnd}`,
),
),
{ strongStart: '<b>', strongEnd: '</b>' },
false,
);
export default {
components: {
UserAvatarLink,
@ -32,14 +44,14 @@ export default {
trigger: 'focus',
placement: 'top',
title: `<div class="autodevops-title">
This pipeline makes use of a predefined CI/CD configuration enabled by <b>Auto DevOps.</b>
${popoverTitle}
</div>`,
content: `<a
class="autodevops-link"
href="${this.autoDevopsHelpPath}"
target="_blank"
rel="noopener noreferrer nofollow">
Learn more about Auto DevOps
${_.escape(__('Learn more about Auto DevOps'))}
</a>`,
};
},
@ -54,9 +66,9 @@ export default {
<span>by</span>
<user-avatar-link
v-if="user"
:link-href="pipeline.user.path"
:img-src="pipeline.user.avatar_url"
:tooltip-text="pipeline.user.name"
:link-href="user.path"
:img-src="user.avatar_url"
:tooltip-text="user.name"
class="js-pipeline-url-user"
/>
<span v-if="!user" class="js-pipeline-url-api api"> API </span>
@ -64,10 +76,10 @@ export default {
<span
v-if="pipeline.flags.latest"
v-gl-tooltip
:title="__('Latest pipeline for this branch')"
class="js-pipeline-url-latest badge badge-success"
title="__('Latest pipeline for this branch')"
>
latest
{{ __('latest') }}
</span>
<span
v-if="pipeline.flags.yaml_errors"
@ -75,7 +87,7 @@ export default {
:title="pipeline.yaml_errors"
class="js-pipeline-url-yaml badge badge-danger"
>
yaml invalid
{{ __('yaml invalid') }}
</span>
<span
v-if="pipeline.flags.failure_reason"
@ -83,7 +95,7 @@ export default {
:title="pipeline.failure_reason"
class="js-pipeline-url-failure badge badge-danger"
>
error
{{ __('error') }}
</span>
<gl-link
v-if="pipeline.flags.auto_devops"
@ -95,15 +107,15 @@ export default {
Auto DevOps
</gl-link>
<span v-if="pipeline.flags.stuck" class="js-pipeline-url-stuck badge badge-warning">
stuck
{{ __('stuck') }}
</span>
<span
v-if="pipeline.flags.merge_request"
v-gl-tooltip
title="__('This pipeline is run in a merge request context')"
:title="__('This pipeline is run in a merge request context')"
class="js-pipeline-url-mergerequest badge badge-info"
>
merge request
{{ __('merge request') }}
</span>
</div>
</div>

View file

@ -0,0 +1,82 @@
<script>
import { mapState, mapActions } from 'vuex';
import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui';
import ReleaseBlock from './release_block.vue';
export default {
name: 'ReleasesApp',
components: {
GlLoadingIcon,
GlEmptyState,
ReleaseBlock,
},
props: {
projectId: {
type: String,
required: true,
},
documentationLink: {
type: String,
required: true,
},
illustrationPath: {
type: String,
required: true,
},
},
computed: {
...mapState(['isLoading', 'releases', 'hasError']),
shouldRenderEmptyState() {
return !this.releases.length && !this.hasError && !this.isLoading;
},
shouldRenderSuccessState() {
return this.releases.length && !this.isLoading && !this.hasError;
},
},
created() {
this.fetchReleases(this.projectId);
},
methods: {
...mapActions(['fetchReleases']),
},
};
</script>
<template>
<div class="prepend-top-default">
<gl-loading-icon v-if="isLoading" :size="2" class="js-loading prepend-top-20" />
<gl-empty-state
v-else-if="shouldRenderEmptyState"
class="js-empty-state"
:title="__('Getting started with releases')"
:svg-path="illustrationPath"
:description="
__(
'Releases mark specific points in a project\'s development history, communicate information about the type of change, and deliver on prepared, often compiled, versions of the software to be reused elsewhere. Currently, releases can only be created through the API.',
)
"
:primary-button-link="documentationLink"
:primary-button-text="__('Open Documentation')"
/>
<div v-else-if="shouldRenderSuccessState" class="js-success-state">
<release-block
v-for="(release, index) in releases"
:key="release.tag_name"
:release="release"
:class="{ 'linked-card': releases.length > 1 && index !== releases.length - 1 }"
/>
</div>
</div>
</template>
<style>
.linked-card::after {
width: 1px;
content: ' ';
border: 1px solid #e5e5e5;
height: 17px;
top: 100%;
position: absolute;
left: 32px;
}
</style>

View file

@ -0,0 +1,129 @@
<script>
import _ from 'underscore';
import { GlTooltipDirective, GlLink } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import { sprintf } from '../../locale';
export default {
name: 'ReleaseBlock',
components: {
GlLink,
Icon,
UserAvatarLink,
},
directives: {
GlTooltip: GlTooltipDirective,
},
mixins: [timeagoMixin],
props: {
release: {
type: Object,
required: true,
default: () => ({}),
},
},
computed: {
releasedTimeAgo() {
return sprintf('released %{time}', {
time: this.timeFormated(this.release.created_at),
});
},
userImageAltDescription() {
return this.author && this.author.username
? sprintf("%{username}'s avatar", { username: this.author.username })
: null;
},
commit() {
return this.release.commit || {};
},
assets() {
return this.release.assets || {};
},
author() {
return this.release.author || {};
},
hasAuthor() {
return !_.isEmpty(this.author);
},
},
};
</script>
<template>
<div class="card">
<div class="card-body">
<h2 class="card-title mt-0">{{ release.name }}</h2>
<div class="card-subtitle d-flex flex-wrap text-secondary">
<div class="append-right-8">
<icon name="commit" class="align-middle" />
<span v-gl-tooltip.bottom :title="commit.title">{{ commit.short_id }}</span>
</div>
<div class="append-right-8">
<icon name="tag" class="align-middle" />
<span v-gl-tooltip.bottom :title="__('Tag')">{{ release.tag_name }}</span>
</div>
<div class="append-right-4">
&bull;
<span v-gl-tooltip.bottom :title="tooltipTitle(release.created_at)">{{
releasedTimeAgo
}}</span>
</div>
<div v-if="hasAuthor" class="d-flex">
by
<user-avatar-link
class="prepend-left-4"
:link-href="author.path"
:img-src="author.avatar_url"
:img-alt="userImageAltDescription"
:tooltip-text="author.username"
/>
</div>
</div>
<div
v-if="assets.links.length || assets.sources.length"
class="card-text prepend-top-default"
>
<b>
{{ __('Assets') }}
<span class="js-assets-count badge badge-pill">{{ assets.count }}</span>
</b>
<ul v-if="assets.links.length" class="pl-0 mb-0 prepend-top-8 list-unstyled js-assets-list">
<li v-for="link in assets.links" :key="link.name" class="append-bottom-8">
<gl-link v-gl-tooltip.bottom :title="__('Download asset')" :href="link.url">
<icon name="package" class="align-middle append-right-4 align-text-bottom" />
{{ link.name }}
</gl-link>
</li>
</ul>
<div v-if="assets.sources.length" class="dropdown">
<button
type="button"
class="btn btn-link"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
<icon name="doc-code" class="align-top append-right-4" /> {{ __('Source code') }}
<icon name="arrow-down" />
</button>
<div class="js-sources-dropdown dropdown-menu">
<li v-for="asset in assets.sources" :key="asset.url">
<gl-link :href="asset.url">{{ __('Download') }} {{ asset.format }}</gl-link>
</li>
</div>
</div>
</div>
<div class="card-text prepend-top-default"><div v-html="release.description_html"></div></div>
</div>
</div>
</template>

View file

@ -0,0 +1,24 @@
import Vue from 'vue';
import App from './components/app.vue';
import createStore from './store';
export default () => {
const element = document.getElementById('js-releases-page');
return new Vue({
el: element,
store: createStore(),
components: {
App,
},
render(createElement) {
return createElement('app', {
props: {
projectId: element.dataset.projectId,
documentationLink: element.dataset.documentationPath,
illustrationPath: element.dataset.illustrationPath,
},
});
},
});
};

View file

@ -0,0 +1,37 @@
import * as types from './mutation_types';
import createFlash from '~/flash';
import { __ } from '~/locale';
import api from '~/api';
/**
* Commits a mutation to update the state while the main endpoint is being requested.
*/
export const requestReleases = ({ commit }) => commit(types.REQUEST_RELEASES);
/**
* Fetches the main endpoint.
* Will dispatch requestNamespace action before starting the request.
* Will dispatch receiveNamespaceSuccess if the request is successfull
* Will dispatch receiveNamesapceError if the request returns an error
*
* @param {String} projectId
*/
export const fetchReleases = ({ dispatch }, projectId) => {
dispatch('requestReleases');
api
.releases(projectId)
.then(({ data }) => dispatch('receiveReleasesSuccess', data))
.catch(() => dispatch('receiveReleasesError'));
};
export const receiveReleasesSuccess = ({ commit }, data) =>
commit(types.RECEIVE_RELEASES_SUCCESS, data);
export const receiveReleasesError = ({ commit }) => {
commit(types.RECEIVE_RELEASES_ERROR);
createFlash(__('An error occured while fetching the releases. Please try again.'));
};
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};

View file

@ -0,0 +1,14 @@
import Vue from 'vue';
import Vuex from 'vuex';
import state from './state';
import * as actions from './actions';
import mutations from './mutations';
Vue.use(Vuex);
export default () =>
new Vuex.Store({
actions,
mutations,
state: state(),
});

View file

@ -0,0 +1,3 @@
export const REQUEST_RELEASES = 'REQUEST_RELEASES';
export const RECEIVE_RELEASES_SUCCESS = 'RECEIVE_RELEASES_SUCCESS';
export const RECEIVE_RELEASES_ERROR = 'RECEIVE_RELEASES_ERROR';

View file

@ -0,0 +1,37 @@
import * as types from './mutation_types';
export default {
/**
* Sets isLoading to true while the request is being made.
* @param {Object} state
*/
[types.REQUEST_RELEASES](state) {
state.isLoading = true;
},
/**
* Sets isLoading to false.
* Sets hasError to false.
* Sets the received data
* @param {Object} state
* @param {Object} data
*/
[types.RECEIVE_RELEASES_SUCCESS](state, data) {
state.hasError = false;
state.isLoading = false;
state.releases = data;
},
/**
* Sets isLoading to false.
* Sets hasError to true.
* Resets the data
* @param {Object} state
* @param {Object} data
*/
[types.RECEIVE_RELEASES_ERROR](state) {
state.isLoading = false;
state.releases = [];
state.hasError = true;
},
};

View file

@ -0,0 +1,5 @@
export default () => ({
isLoading: false,
hasError: false,
releases: [],
});

View file

@ -79,11 +79,12 @@ Sidebar.prototype.sidebarToggleClicked = function(e, triggered) {
Sidebar.prototype.toggleTodo = function(e) {
var $btnText, $this, $todoLoading, ajaxType, url;
$this = $(e.currentTarget);
ajaxType = $this.attr('data-delete-path') ? 'delete' : 'post';
if ($this.attr('data-delete-path')) {
url = '' + $this.attr('data-delete-path');
ajaxType = $this.data('deletePath') ? 'delete' : 'post';
if ($this.data('deletePath')) {
url = '' + $this.data('deletePath');
} else {
url = '' + $this.data('url');
url = '' + $this.data('createPath');
}
$this.tooltip('hide');
@ -119,14 +120,14 @@ Sidebar.prototype.todoUpdateDone = function(data) {
.removeClass('is-loading')
.enable()
.attr('aria-label', $el.data(`${attrPrefix}Text`))
.attr('data-delete-path', deletePath)
.attr('title', $el.data(`${attrPrefix}Text`));
.attr('title', $el.data(`${attrPrefix}Text`))
.data('deletePath', deletePath);
if ($el.hasClass('has-tooltip')) {
$el.tooltip('_fixTitle');
}
if ($el.data(`${attrPrefix}Icon`)) {
if (typeof $el.data('isCollapsed') !== 'undefined') {
$elText.html($el.data(`${attrPrefix}Icon`));
} else {
$elText.text($el.data(`${attrPrefix}Text`));

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