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:
commit
65a2ae3b42
1768 changed files with 37598 additions and 15563 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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/**/*'
|
||||
|
|
|
@ -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
|
||||
|
|
315
CHANGELOG.md
315
CHANGELOG.md
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -1 +1 @@
|
|||
1.7.1
|
||||
1.12.2
|
||||
|
|
|
@ -1 +1 @@
|
|||
8.4.3
|
||||
8.4.4
|
||||
|
|
|
@ -1 +1 @@
|
|||
7.6.0
|
||||
8.0.2
|
||||
|
|
64
Gemfile
64
Gemfile
|
@ -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'
|
||||
|
|
151
Gemfile.lock
151
Gemfile.lock
|
@ -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
|
||||
|
|
|
@ -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)
|
1163
Gemfile.rails4.lock
1163
Gemfile.rails4.lock
File diff suppressed because it is too large
Load diff
101
PROCESS.md
101
PROCESS.md
|
@ -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
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
11.6.0
|
||||
11.7.5
|
||||
|
|
BIN
app/assets/images/none-scheme-preview.png
Normal file
BIN
app/assets/images/none-scheme-preview.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.8 KiB |
|
@ -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) {
|
||||
|
|
|
@ -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'));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}`);
|
||||
},
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:') }}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.'));
|
||||
});
|
||||
});
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
31
app/assets/javascripts/error_tracking/index.js
Normal file
31
app/assets/javascripts/error_tracking/index.js
Normal 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,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
7
app/assets/javascripts/error_tracking/services/index.js
Normal file
7
app/assets/javascripts/error_tracking/services/index.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import axios from '~/lib/utils/axios_utils';
|
||||
|
||||
export default {
|
||||
getErrorList({ endpoint }) {
|
||||
return axios.get(endpoint);
|
||||
},
|
||||
};
|
31
app/assets/javascripts/error_tracking/store/actions.js
Normal file
31
app/assets/javascripts/error_tracking/store/actions.js
Normal 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 () => {};
|
19
app/assets/javascripts/error_tracking/store/index.js
Normal file
19
app/assets/javascripts/error_tracking/store/index.js
Normal 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();
|
|
@ -0,0 +1,3 @@
|
|||
export const SET_ERRORS = 'SET_ERRORS';
|
||||
export const SET_EXTERNAL_URL = 'SET_EXTERNAL_URL';
|
||||
export const SET_LOADING = 'SET_LOADING';
|
14
app/assets/javascripts/error_tracking/store/mutations.js
Normal file
14
app/assets/javascripts/error_tracking/store/mutations.js
Normal 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;
|
||||
},
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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',
|
||||
}),
|
||||
);
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
};
|
||||
|
|
|
@ -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
|
||||
});
|
||||
|
|
|
@ -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
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import '~/commons/bootstrap';
|
||||
import { AwardsHandler } from '~/awards_handler';
|
||||
|
||||
class EmojiMenu extends AwardsHandler {
|
||||
|
|
|
@ -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
|
||||
});
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
import ErrorTracking from '~/error_tracking';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
ErrorTracking();
|
||||
});
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
import initReleases from '~/releases';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', initReleases);
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
});
|
5
app/assets/javascripts/pages/root/index.js
Normal file
5
app/assets/javascripts/pages/root/index.js
Normal 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';
|
|
@ -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');
|
||||
|
|
|
@ -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)
|
||||
|
|
34
app/assets/javascripts/persistent_user_callout.js
Normal file
34
app/assets/javascripts/persistent_user_callout.js
Normal 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.'));
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
82
app/assets/javascripts/releases/components/app.vue
Normal file
82
app/assets/javascripts/releases/components/app.vue
Normal 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>
|
129
app/assets/javascripts/releases/components/release_block.vue
Normal file
129
app/assets/javascripts/releases/components/release_block.vue
Normal 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">
|
||||
•
|
||||
<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>
|
24
app/assets/javascripts/releases/index.js
Normal file
24
app/assets/javascripts/releases/index.js
Normal 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,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
37
app/assets/javascripts/releases/store/actions.js
Normal file
37
app/assets/javascripts/releases/store/actions.js
Normal 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 () => {};
|
14
app/assets/javascripts/releases/store/index.js
Normal file
14
app/assets/javascripts/releases/store/index.js
Normal 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(),
|
||||
});
|
3
app/assets/javascripts/releases/store/mutation_types.js
Normal file
3
app/assets/javascripts/releases/store/mutation_types.js
Normal 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';
|
37
app/assets/javascripts/releases/store/mutations.js
Normal file
37
app/assets/javascripts/releases/store/mutations.js
Normal 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;
|
||||
},
|
||||
};
|
5
app/assets/javascripts/releases/store/state.js
Normal file
5
app/assets/javascripts/releases/store/state.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
export default () => ({
|
||||
isLoading: false,
|
||||
hasError: false,
|
||||
releases: [],
|
||||
});
|
|
@ -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
Loading…
Reference in a new issue