Merge branch 'master' into 'zj-wiki-page-versions'
# Conflicts: # Gemfile # Gemfile.lock
|
@ -1,7 +1,5 @@
|
|||
---
|
||||
engines:
|
||||
brakeman:
|
||||
enabled: true
|
||||
bundler-audit:
|
||||
enabled: true
|
||||
duplication:
|
||||
|
|
|
@ -6,3 +6,5 @@ app/models/concerns/relative_positioning.rb
|
|||
app/workers/stuck_merge_jobs_worker.rb
|
||||
lib/gitlab/redis/*.rb
|
||||
lib/gitlab/gitaly_client/operation_service.rb
|
||||
lib/gitlab/background_migration/*
|
||||
app/models/project_services/kubernetes_service.rb
|
||||
|
|
157
.gitlab-ci.yml
|
@ -6,7 +6,7 @@ image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.6-golang-1.9-git
|
|||
- gitlab-org
|
||||
|
||||
.default-cache: &default-cache
|
||||
key: "ruby-235-with-yarn"
|
||||
key: "ruby-2.3.6-with-yarn"
|
||||
paths:
|
||||
- vendor/ruby
|
||||
- .yarn-cache/
|
||||
|
@ -290,7 +290,7 @@ flaky-examples-check:
|
|||
- scripts/merge-reports ${NEW_FLAKY_SPECS_REPORT} rspec_flaky/new_*_*.json
|
||||
- scripts/detect-new-flaky-examples $NEW_FLAKY_SPECS_REPORT
|
||||
|
||||
setup-test-env:
|
||||
compile-assets:
|
||||
<<: *dedicated-runner
|
||||
<<: *except-docs
|
||||
<<: *use-pg
|
||||
|
@ -301,82 +301,94 @@ setup-test-env:
|
|||
- node --version
|
||||
- yarn install --frozen-lockfile --cache-folder .yarn-cache
|
||||
- bundle exec rake gitlab:assets:compile
|
||||
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
|
||||
- scripts/gitaly-test-build # Do not use 'bundle exec' here
|
||||
artifacts:
|
||||
expire_in: 7d
|
||||
paths:
|
||||
- node_modules
|
||||
- public/assets
|
||||
|
||||
setup-test-env:
|
||||
<<: *dedicated-runner
|
||||
<<: *except-docs
|
||||
<<: *use-pg
|
||||
stage: prepare
|
||||
cache:
|
||||
<<: *default-cache
|
||||
script:
|
||||
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
|
||||
- scripts/gitaly-test-build # Do not use 'bundle exec' here
|
||||
artifacts:
|
||||
expire_in: 7d
|
||||
paths:
|
||||
- tmp/tests
|
||||
- config/secrets.yml
|
||||
|
||||
rspec-pg 0 26: *rspec-metadata-pg
|
||||
rspec-pg 1 26: *rspec-metadata-pg
|
||||
rspec-pg 2 26: *rspec-metadata-pg
|
||||
rspec-pg 3 26: *rspec-metadata-pg
|
||||
rspec-pg 4 26: *rspec-metadata-pg
|
||||
rspec-pg 5 26: *rspec-metadata-pg
|
||||
rspec-pg 6 26: *rspec-metadata-pg
|
||||
rspec-pg 7 26: *rspec-metadata-pg
|
||||
rspec-pg 8 26: *rspec-metadata-pg
|
||||
rspec-pg 9 26: *rspec-metadata-pg
|
||||
rspec-pg 10 26: *rspec-metadata-pg
|
||||
rspec-pg 11 26: *rspec-metadata-pg
|
||||
rspec-pg 12 26: *rspec-metadata-pg
|
||||
rspec-pg 13 26: *rspec-metadata-pg
|
||||
rspec-pg 14 26: *rspec-metadata-pg
|
||||
rspec-pg 15 26: *rspec-metadata-pg
|
||||
rspec-pg 16 26: *rspec-metadata-pg
|
||||
rspec-pg 17 26: *rspec-metadata-pg
|
||||
rspec-pg 18 26: *rspec-metadata-pg
|
||||
rspec-pg 19 26: *rspec-metadata-pg
|
||||
rspec-pg 20 26: *rspec-metadata-pg
|
||||
rspec-pg 21 26: *rspec-metadata-pg
|
||||
rspec-pg 22 26: *rspec-metadata-pg
|
||||
rspec-pg 23 26: *rspec-metadata-pg
|
||||
rspec-pg 24 26: *rspec-metadata-pg
|
||||
rspec-pg 25 26: *rspec-metadata-pg
|
||||
rspec-pg 0 27: *rspec-metadata-pg
|
||||
rspec-pg 1 27: *rspec-metadata-pg
|
||||
rspec-pg 2 27: *rspec-metadata-pg
|
||||
rspec-pg 3 27: *rspec-metadata-pg
|
||||
rspec-pg 4 27: *rspec-metadata-pg
|
||||
rspec-pg 5 27: *rspec-metadata-pg
|
||||
rspec-pg 6 27: *rspec-metadata-pg
|
||||
rspec-pg 7 27: *rspec-metadata-pg
|
||||
rspec-pg 8 27: *rspec-metadata-pg
|
||||
rspec-pg 9 27: *rspec-metadata-pg
|
||||
rspec-pg 10 27: *rspec-metadata-pg
|
||||
rspec-pg 11 27: *rspec-metadata-pg
|
||||
rspec-pg 12 27: *rspec-metadata-pg
|
||||
rspec-pg 13 27: *rspec-metadata-pg
|
||||
rspec-pg 14 27: *rspec-metadata-pg
|
||||
rspec-pg 15 27: *rspec-metadata-pg
|
||||
rspec-pg 16 27: *rspec-metadata-pg
|
||||
rspec-pg 17 27: *rspec-metadata-pg
|
||||
rspec-pg 18 27: *rspec-metadata-pg
|
||||
rspec-pg 19 27: *rspec-metadata-pg
|
||||
rspec-pg 20 27: *rspec-metadata-pg
|
||||
rspec-pg 21 27: *rspec-metadata-pg
|
||||
rspec-pg 22 27: *rspec-metadata-pg
|
||||
rspec-pg 23 27: *rspec-metadata-pg
|
||||
rspec-pg 24 27: *rspec-metadata-pg
|
||||
rspec-pg 25 27: *rspec-metadata-pg
|
||||
rspec-pg 26 27: *rspec-metadata-pg
|
||||
|
||||
rspec-mysql 0 26: *rspec-metadata-mysql
|
||||
rspec-mysql 1 26: *rspec-metadata-mysql
|
||||
rspec-mysql 2 26: *rspec-metadata-mysql
|
||||
rspec-mysql 3 26: *rspec-metadata-mysql
|
||||
rspec-mysql 4 26: *rspec-metadata-mysql
|
||||
rspec-mysql 5 26: *rspec-metadata-mysql
|
||||
rspec-mysql 6 26: *rspec-metadata-mysql
|
||||
rspec-mysql 7 26: *rspec-metadata-mysql
|
||||
rspec-mysql 8 26: *rspec-metadata-mysql
|
||||
rspec-mysql 9 26: *rspec-metadata-mysql
|
||||
rspec-mysql 10 26: *rspec-metadata-mysql
|
||||
rspec-mysql 11 26: *rspec-metadata-mysql
|
||||
rspec-mysql 12 26: *rspec-metadata-mysql
|
||||
rspec-mysql 13 26: *rspec-metadata-mysql
|
||||
rspec-mysql 14 26: *rspec-metadata-mysql
|
||||
rspec-mysql 15 26: *rspec-metadata-mysql
|
||||
rspec-mysql 16 26: *rspec-metadata-mysql
|
||||
rspec-mysql 17 26: *rspec-metadata-mysql
|
||||
rspec-mysql 18 26: *rspec-metadata-mysql
|
||||
rspec-mysql 19 26: *rspec-metadata-mysql
|
||||
rspec-mysql 20 26: *rspec-metadata-mysql
|
||||
rspec-mysql 21 26: *rspec-metadata-mysql
|
||||
rspec-mysql 22 26: *rspec-metadata-mysql
|
||||
rspec-mysql 23 26: *rspec-metadata-mysql
|
||||
rspec-mysql 24 26: *rspec-metadata-mysql
|
||||
rspec-mysql 25 26: *rspec-metadata-mysql
|
||||
rspec-mysql 0 27: *rspec-metadata-mysql
|
||||
rspec-mysql 1 27: *rspec-metadata-mysql
|
||||
rspec-mysql 2 27: *rspec-metadata-mysql
|
||||
rspec-mysql 3 27: *rspec-metadata-mysql
|
||||
rspec-mysql 4 27: *rspec-metadata-mysql
|
||||
rspec-mysql 5 27: *rspec-metadata-mysql
|
||||
rspec-mysql 6 27: *rspec-metadata-mysql
|
||||
rspec-mysql 7 27: *rspec-metadata-mysql
|
||||
rspec-mysql 8 27: *rspec-metadata-mysql
|
||||
rspec-mysql 9 27: *rspec-metadata-mysql
|
||||
rspec-mysql 10 27: *rspec-metadata-mysql
|
||||
rspec-mysql 11 27: *rspec-metadata-mysql
|
||||
rspec-mysql 12 27: *rspec-metadata-mysql
|
||||
rspec-mysql 13 27: *rspec-metadata-mysql
|
||||
rspec-mysql 14 27: *rspec-metadata-mysql
|
||||
rspec-mysql 15 27: *rspec-metadata-mysql
|
||||
rspec-mysql 16 27: *rspec-metadata-mysql
|
||||
rspec-mysql 17 27: *rspec-metadata-mysql
|
||||
rspec-mysql 18 27: *rspec-metadata-mysql
|
||||
rspec-mysql 19 27: *rspec-metadata-mysql
|
||||
rspec-mysql 20 27: *rspec-metadata-mysql
|
||||
rspec-mysql 21 27: *rspec-metadata-mysql
|
||||
rspec-mysql 22 27: *rspec-metadata-mysql
|
||||
rspec-mysql 23 27: *rspec-metadata-mysql
|
||||
rspec-mysql 24 27: *rspec-metadata-mysql
|
||||
rspec-mysql 25 27: *rspec-metadata-mysql
|
||||
rspec-mysql 26 27: *rspec-metadata-mysql
|
||||
|
||||
spinach-pg 0 4: *spinach-metadata-pg
|
||||
spinach-pg 1 4: *spinach-metadata-pg
|
||||
spinach-pg 2 4: *spinach-metadata-pg
|
||||
spinach-pg 3 4: *spinach-metadata-pg
|
||||
spinach-pg 0 3: *spinach-metadata-pg
|
||||
spinach-pg 1 3: *spinach-metadata-pg
|
||||
spinach-pg 2 3: *spinach-metadata-pg
|
||||
|
||||
spinach-mysql 0 4: *spinach-metadata-mysql
|
||||
spinach-mysql 1 4: *spinach-metadata-mysql
|
||||
spinach-mysql 2 4: *spinach-metadata-mysql
|
||||
spinach-mysql 3 4: *spinach-metadata-mysql
|
||||
spinach-mysql 0 3: *spinach-metadata-mysql
|
||||
spinach-mysql 1 3: *spinach-metadata-mysql
|
||||
spinach-mysql 2 3: *spinach-metadata-mysql
|
||||
|
||||
# Static analysis jobs
|
||||
.ruby-static-analysis: &ruby-static-analysis
|
||||
<<: *pull-cache
|
||||
variables:
|
||||
SIMPLECOV: "false"
|
||||
SETUP_DB: "false"
|
||||
|
@ -397,6 +409,12 @@ static-analysis:
|
|||
stage: test
|
||||
script:
|
||||
- scripts/static-analysis
|
||||
cache:
|
||||
key: "ruby-2.3.6-with-yarn-and-rubocop"
|
||||
paths:
|
||||
- vendor/ruby
|
||||
- .yarn-cache/
|
||||
- tmp/rubocop_cache
|
||||
|
||||
# Documentation checks:
|
||||
# - Check validity of relative links
|
||||
|
@ -609,6 +627,8 @@ codequality:
|
|||
sast:
|
||||
<<: *except-docs
|
||||
image: registry.gitlab.com/gitlab-org/gl-sast:latest
|
||||
variables:
|
||||
CONFIDENCE_LEVEL: 2
|
||||
before_script: []
|
||||
script:
|
||||
- /app/bin/run .
|
||||
|
@ -664,6 +684,7 @@ lint:javascript:report:
|
|||
<<: *pull-cache
|
||||
stage: post-test
|
||||
dependencies:
|
||||
- compile-assets
|
||||
- setup-test-env
|
||||
before_script: []
|
||||
script:
|
||||
|
@ -704,8 +725,6 @@ pages:
|
|||
cache gems:
|
||||
<<: *dedicated-runner
|
||||
<<: *pull-cache
|
||||
only:
|
||||
- tags
|
||||
variables:
|
||||
SETUP_DB: "false"
|
||||
script:
|
||||
|
@ -716,12 +735,14 @@ cache gems:
|
|||
only:
|
||||
- master@gitlab-org/gitlab-ce
|
||||
- master@gitlab-org/gitlab-ee
|
||||
- tags
|
||||
|
||||
gitlab_git_test:
|
||||
<<: *dedicated-runner
|
||||
<<: *except-docs-and-qa
|
||||
<<: *pull-cache
|
||||
variables:
|
||||
SETUP_DB: "false"
|
||||
before_script: []
|
||||
cache: {}
|
||||
script:
|
||||
- spec/support/prepare-gitlab-git-test-for-commit --check-for-changes
|
||||
|
|
|
@ -17,6 +17,7 @@ AllCops:
|
|||
- 'bin/**/*'
|
||||
- 'generator_templates/**/*'
|
||||
- 'builds/**/*'
|
||||
CacheRootDirectory: tmp
|
||||
|
||||
# Gitlab ###################################################################
|
||||
|
||||
|
|
|
@ -342,10 +342,6 @@ RSpec/SharedContext:
|
|||
Exclude:
|
||||
- 'spec/features/admin/admin_groups_spec.rb'
|
||||
|
||||
# Offense count: 90
|
||||
RSpec/SingleLineHook:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 5
|
||||
RSpec/VoidExpect:
|
||||
Exclude:
|
||||
|
@ -708,7 +704,9 @@ Style/RedundantSelf:
|
|||
# Configuration parameters: EnforcedStyle, AllowInnerSlashes.
|
||||
# SupportedStyles: slashes, percent_r, mixed
|
||||
Style/RegexpLiteral:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
EnforcedStyle: mixed
|
||||
AllowInnerSlashes: false
|
||||
|
||||
# Offense count: 36
|
||||
# Cop supports --auto-correct.
|
||||
|
|
3470
CHANGELOG.md
|
@ -50,6 +50,9 @@ _This notice should stay as the first item in the CONTRIBUTING.md file._
|
|||
|
||||
## Contribute to GitLab
|
||||
|
||||
For a first-time step-by-step guide to the contribution process, see
|
||||
["Contributing to GitLab"](https://about.gitlab.com/contributing/).
|
||||
|
||||
Thank you for your interest in contributing to GitLab. This guide details how
|
||||
to contribute to GitLab in a way that is efficient for everyone.
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.70.0
|
||||
0.78.0
|
||||
|
|
|
@ -1 +1 @@
|
|||
5.11.0
|
||||
6.0.2
|
||||
|
|
|
@ -1 +1 @@
|
|||
3.5.0
|
||||
3.6.0
|
||||
|
|
12
Gemfile
|
@ -69,6 +69,10 @@ gem 'net-ldap'
|
|||
|
||||
# Git Wiki
|
||||
# Required manually in config/initializers/gollum.rb to control load order
|
||||
# Before updating this gem, check if
|
||||
# https://github.com/gollum/gollum-lib/pull/292 has been merged.
|
||||
# If it has, then remove the monkey patch for update_page, rename_page and raw_data_in_committer
|
||||
# in config/initializers/gollum.rb
|
||||
gem 'gollum-lib', '~> 4.2', require: false
|
||||
|
||||
# Before updating this gem, check if
|
||||
|
@ -132,7 +136,7 @@ gem 'asciidoctor-plantuml', '0.0.7'
|
|||
gem 'rouge', '~> 2.0'
|
||||
gem 'truncato', '~> 0.7.9'
|
||||
gem 'bootstrap_form', '~> 2.7.0'
|
||||
gem 'nokogiri', '~> 1.8.1'
|
||||
gem 'nokogiri', '~> 1.8.2'
|
||||
|
||||
# Diffs
|
||||
gem 'diffy', '~> 3.1.0'
|
||||
|
@ -325,7 +329,7 @@ group :development, :test do
|
|||
gem 'spinach-rerun-reporter', '~> 0.0.2'
|
||||
gem 'rspec_profiling', '~> 0.0.5'
|
||||
gem 'rspec-set', '~> 0.1.3'
|
||||
gem 'rspec-parameterized'
|
||||
gem 'rspec-parameterized', require: false
|
||||
|
||||
# Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826)
|
||||
gem 'minitest', '~> 5.7.0'
|
||||
|
@ -349,7 +353,7 @@ group :development, :test do
|
|||
gem 'scss_lint', '~> 0.56.0', require: false
|
||||
gem 'haml_lint', '~> 0.26.0', require: false
|
||||
gem 'simplecov', '~> 0.14.0', require: false
|
||||
gem 'flay', '~> 2.8.0', require: false
|
||||
gem 'flay', '~> 2.10.0', require: false
|
||||
gem 'bundler-audit', '~> 0.5.0', require: false
|
||||
|
||||
gem 'benchmark-ips', '~> 2.3.0', require: false
|
||||
|
@ -406,7 +410,7 @@ group :ed25519 do
|
|||
end
|
||||
|
||||
# Gitaly GRPC client
|
||||
gem 'gitaly-proto', '~> 0.74.0', require: 'gitaly'
|
||||
gem 'gitaly-proto', '~> 0.83.0', require: 'gitaly'
|
||||
|
||||
gem 'toml-rb', '~> 0.3.15', require: false
|
||||
|
||||
|
|
18
Gemfile.lock
|
@ -211,7 +211,7 @@ GEM
|
|||
fast_gettext (1.4.0)
|
||||
ffaker (2.4.0)
|
||||
ffi (1.9.18)
|
||||
flay (2.8.1)
|
||||
flay (2.10.0)
|
||||
erubis (~> 2.7.0)
|
||||
path_expander (~> 1.0)
|
||||
ruby_parser (~> 3.0)
|
||||
|
@ -285,7 +285,7 @@ GEM
|
|||
po_to_json (>= 1.0.0)
|
||||
rails (>= 3.2.0)
|
||||
gherkin-ruby (0.3.2)
|
||||
gitaly-proto (0.74.0)
|
||||
gitaly-proto (0.83.0)
|
||||
google-protobuf (~> 3.1)
|
||||
grpc (~> 1.0)
|
||||
github-linguist (4.7.6)
|
||||
|
@ -304,7 +304,7 @@ GEM
|
|||
mime-types (>= 1.16)
|
||||
posix-spawn (~> 0.3)
|
||||
gitlab-markup (1.6.3)
|
||||
gitlab-styles (2.3.0)
|
||||
gitlab-styles (2.3.2)
|
||||
rubocop (~> 0.51)
|
||||
rubocop-gitlab-security (~> 0.1.0)
|
||||
rubocop-rspec (~> 1.19)
|
||||
|
@ -340,7 +340,7 @@ GEM
|
|||
mime-types (~> 3.0)
|
||||
representable (~> 3.0)
|
||||
retriable (>= 2.0, < 4.0)
|
||||
google-protobuf (3.4.1.1)
|
||||
google-protobuf (3.5.1.1)
|
||||
googleapis-common-protos-types (1.0.1)
|
||||
google-protobuf (~> 3.0)
|
||||
googleauth (0.5.3)
|
||||
|
@ -513,7 +513,7 @@ GEM
|
|||
net-ldap (0.16.0)
|
||||
net-ssh (4.1.0)
|
||||
netrc (0.11.0)
|
||||
nokogiri (1.8.1)
|
||||
nokogiri (1.8.2)
|
||||
mini_portile2 (~> 2.3.0)
|
||||
numerizer (0.1.1)
|
||||
oauth (0.5.1)
|
||||
|
@ -588,7 +588,7 @@ GEM
|
|||
ast (~> 2.3)
|
||||
parslet (1.5.0)
|
||||
blankslate (~> 2.0)
|
||||
path_expander (1.0.1)
|
||||
path_expander (1.0.2)
|
||||
peek (1.0.1)
|
||||
concurrent-ruby (>= 0.9.0)
|
||||
concurrent-ruby-ext (>= 0.9.0)
|
||||
|
@ -1037,7 +1037,7 @@ DEPENDENCIES
|
|||
faraday (~> 0.12)
|
||||
fast_blank
|
||||
ffaker (~> 2.4)
|
||||
flay (~> 2.8.0)
|
||||
flay (~> 2.10.0)
|
||||
flipper (~> 0.11.0)
|
||||
flipper-active_record (~> 0.11.0)
|
||||
flipper-active_support_cache_store (~> 0.11.0)
|
||||
|
@ -1056,7 +1056,7 @@ DEPENDENCIES
|
|||
gettext (~> 3.2.2)
|
||||
gettext_i18n_rails (~> 1.8.0)
|
||||
gettext_i18n_rails_js (~> 1.2.0)
|
||||
gitaly-proto (~> 0.74.0)
|
||||
gitaly-proto (~> 0.83.0)
|
||||
github-linguist (~> 4.7.0)
|
||||
gitlab-flowdock-git-hook (~> 1.0.1)
|
||||
gitlab-markup (~> 1.6.2)
|
||||
|
@ -1100,7 +1100,7 @@ DEPENDENCIES
|
|||
mysql2 (~> 0.4.10)
|
||||
net-ldap
|
||||
net-ssh (~> 4.1.0)
|
||||
nokogiri (~> 1.8.1)
|
||||
nokogiri (~> 1.8.2)
|
||||
oauth2 (~> 1.4)
|
||||
octokit (~> 4.6.2)
|
||||
oj (~> 2.17.4)
|
||||
|
|
30
PROCESS.md
|
@ -85,7 +85,8 @@ These types of merge requests for the upcoming release need special consideratio
|
|||
and a dedicated team with front-end, back-end, and UX.
|
||||
* **Small features**: any other feature request.
|
||||
|
||||
**Large features** must be with a maintainer **by the 1st**. This means that:
|
||||
It is strongly recommended that **large features** be with a maintainer **by the
|
||||
1st**. This means that:
|
||||
|
||||
* There is a merge request (even if it's WIP).
|
||||
* The person (or people, if it needs a frontend and backend maintainer) who will
|
||||
|
@ -100,14 +101,37 @@ The maintainer can also choose to assign a reviewer to perform an initial
|
|||
review, but this way the maintainer is unlikely to be surprised by receiving an
|
||||
MR later in the cycle.
|
||||
|
||||
**Small features** must be with a reviewer (not necessarily maintainer) **by the
|
||||
3rd**.
|
||||
It is strongly recommended that **small features** be with a reviewer (not
|
||||
necessarily a maintainer) **by the 3rd**.
|
||||
|
||||
Most merge requests from the community do not have a specific release
|
||||
target. However, if one does and falls into either of the above categories, it's
|
||||
the reviewer's responsibility to manage the above communication and assignment
|
||||
on behalf of the community member.
|
||||
|
||||
#### What happens if these deadlines are missed?
|
||||
|
||||
If a small or large feature is _not_ with a maintainer or reviewer by the
|
||||
recommended date, this does _not_ mean that maintainers or reviewers will refuse
|
||||
to review or merge it, or that the feature will definitely not make it in before
|
||||
the feature freeze.
|
||||
|
||||
However, with every day that passes without review, it will become more likely
|
||||
that the feature will slip, because maintainers and reviewers may not have
|
||||
enough time to do a thorough review, and developers may not have enough time to
|
||||
adequately address any feedback that may come back.
|
||||
|
||||
A maintainer or reviewer may also determine that it will not be possible to
|
||||
finish the current scope of the feature in time, but that it is possible to
|
||||
reduce the scope so that something can still ship this month, with the remaining
|
||||
scope moving to the next release. The sooner this decision is made, in
|
||||
conversation with the Product Manager and developer, the more time there is to
|
||||
extract that which is now out of scope, and to finish that which remains in scope.
|
||||
|
||||
For these reasons, it is strongly recommended to follow the guidelines above,
|
||||
to maximize the chances of your feature making it in before the feature freeze,
|
||||
and to prevent any last minute surprises.
|
||||
|
||||
### On the 7th
|
||||
|
||||
Merge requests should still be complete, following the
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"iconCount":189,"spriteSize":85766,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","bookmark","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder-o-open","folder-o","folder-open","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","image-comment-light","import","issue-block","issue-child","issue-close","issue-duplicate","issue-external","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","podcast","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","staged","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","unstaged","user","users","volume-up","warning","work"]}
|
||||
{"iconCount":191,"spriteSize":86607,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","bookmark","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder-o","folder-open","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","image-comment-light","import","issue-block","issue-child","issue-close","issue-duplicate","issue-external","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","podcast","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","soft-unwrap","soft-wrap","spam","spinner","staged","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_notfound","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","unstaged","user","users","volume-up","warning","work"]}
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 85 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="142" height="104" viewBox="0 0 142 104"><g fill="none" fill-rule="evenodd"><g transform="translate(112 4)"><path fill="#FFF" d="M8 4a4 4 0 0 0-4 4v14a4 4 0 0 0 4 4h14a4 4 0 0 0 4-4V8a4 4 0 0 0-4-4H8z"/><path fill="#FDC4A8" fill-rule="nonzero" d="M8 4a4 4 0 0 0-4 4v14a4 4 0 0 0 4 4h14a4 4 0 0 0 4-4V8a4 4 0 0 0-4-4H8zm0-4h14a8 8 0 0 1 8 8v14a8 8 0 0 1-8 8H8a8 8 0 0 1-8-8V8a8 8 0 0 1 8-8z"/><rect width="10" height="10" x="10" y="10" fill="#FC6D26" rx="5"/></g><g transform="translate(5 74)"><rect width="30" height="30" fill="#FFF" rx="8"/><path fill="#E1DBF1" fill-rule="nonzero" d="M8 4a4 4 0 0 0-4 4v14a4 4 0 0 0 4 4h14a4 4 0 0 0 4-4V8a4 4 0 0 0-4-4H8zm0-4h14a8 8 0 0 1 8 8v14a8 8 0 0 1-8 8H8a8 8 0 0 1-8-8V8a8 8 0 0 1 8-8z"/><rect width="10" height="10" x="10" y="10" fill="#6B4FBB" rx="5"/></g><path fill="#FFF" d="M6 4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H6z"/><path fill="#FDC4A8" fill-rule="nonzero" d="M6 4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H6zm0-4h12a6 6 0 0 1 6 6v12a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V6a6 6 0 0 1 6-6z"/><rect width="8" height="8" x="8" y="8" fill="#FC6D26" rx="4"/><g transform="translate(112 77)"><rect width="24" height="24" fill="#FFF" rx="6"/><path fill="#E1DBF1" fill-rule="nonzero" d="M6 4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H6zm0-4h12a6 6 0 0 1 6 6v12a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V6a6 6 0 0 1 6-6z"/><rect width="8" height="8" x="8" y="8" fill="#6B4FBB" rx="4"/></g><g transform="translate(46 29)"><rect width="46" height="46" y="2" fill="#E1DBF1" rx="10"/><rect width="46" height="46" fill="#E1DBF1" rx="10"/><path fill="#C3B8E3" fill-rule="nonzero" d="M10 4a6 6 0 0 0-6 6v26a6 6 0 0 0 6 6h26a6 6 0 0 0 6-6V10a6 6 0 0 0-6-6H10zm0-4h26c5.523 0 10 4.477 10 10v26c0 5.523-4.477 10-10 10H10C4.477 46 0 41.523 0 36V10C0 4.477 4.477 0 10 0z"/><rect width="14" height="14" x="16" y="16" fill="#6B4FBB" rx="2"/></g><path fill="#E1DBF1" fill-rule="nonzero" d="M98.413 35.682a2 2 0 1 1-2.826-2.83l2.122-2.12a2 2 0 1 1 2.827 2.83l-2.123 2.12z"/><path fill="#C3B8E3" d="M104.78 29.32a2 2 0 0 1-2.826-2.829l2.122-2.12a2 2 0 0 1 2.827 2.83l-2.122 2.12z"/><path fill="#C3B8E3" fill-rule="nonzero" d="M42.413 89.682a2 2 0 1 1-2.826-2.83l2.122-2.12a2 2 0 1 1 2.827 2.83l-2.123 2.12z"/><path fill="#E1DBF1" d="M48.78 83.32a2 2 0 1 1-2.826-2.829l2.122-2.12a2 2 0 1 1 2.827 2.83l-2.122 2.12z"/><path fill="#E1DBF1" fill-rule="nonzero" d="M27.713 26.531a2 2 0 1 1 2.574-3.062l2.296 1.93a2 2 0 1 1-2.573 3.062l-2.297-1.93z"/><path fill="#C3B8E3" d="M34.604 32.321a2 2 0 1 1 2.573-3.062l2.297 1.93A2 2 0 0 1 36.9 34.25l-2.297-1.93z"/><path fill="#C3B8E3" fill-rule="nonzero" d="M93.74 74.553a2 2 0 0 1 2.52-3.106l2.33 1.891a2 2 0 1 1-2.521 3.106l-2.33-1.891z"/><path fill="#E1DBF1" d="M100.727 80.225a2 2 0 1 1 2.521-3.105l2.33 1.89a2 2 0 1 1-2.522 3.106l-2.33-1.89z"/></g></svg>
|
After Width: | Height: | Size: 2.9 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><g fill="none" fill-rule="evenodd"><path fill="#EEE" d="M44.242 59.348c-3.7 1.576-7.3 1.994-10.902.84a7.002 7.002 0 0 1-9.085-.699l-4.243-4.243a7 7 0 0 1-.238-9.649c-.701-3.024-.419-6.083.646-9.206l-6.287-2.426a5.6 5.6 0 0 1-2.274-8.824l8.233-9.811a5.6 5.6 0 0 1 6.306-1.625l8.045 3.105c.772-.797 1.564-1.6 2.374-2.41C44.841 6.376 55.265 2.135 68.09 1.677a10 10 0 0 1 1.119.023c5.507.42 9.63 5.226 9.209 10.733-.935 12.225-5.373 22.309-13.315 30.25a410.76 410.76 0 0 1-1.661 1.653l3.247 8.412a5.6 5.6 0 0 1-1.625 6.306l-9.81 8.233a5.6 5.6 0 0 1-8.825-2.274l-2.186-5.665zm-22.92-26.923l10.406-12.402-6.822-2.633a1.6 1.6 0 0 0-1.801.464l-8.233 9.811a1.6 1.6 0 0 0 .65 2.521l5.8 2.239zm26.646 25.4l2.239 5.8a1.6 1.6 0 0 0 2.521.649l9.81-8.232a1.6 1.6 0 0 0 .465-1.802l-2.633-6.822-12.402 10.406zm-19.69-5.627c8.751 8.752 16.065 5.587 33.995-12.343 7.25-7.25 11.292-16.433 12.155-27.727a6 6 0 0 0-6.196-6.454c-11.846.423-21.303 4.271-28.586 11.554-17.03 17.03-20.414 25.924-11.368 34.97z"/><path fill="#FDC4A8" fill-rule="nonzero" d="M52.54 28.376a4 4 0 1 0 5.656-5.657 4 4 0 0 0-5.657 5.657zm-2.83 2.829A8 8 0 1 1 61.025 19.89a8 8 0 0 1-11.313 11.314z"/><path fill="#FEE1D3" d="M15.063 54.54a2 2 0 0 1 0 2.828L3.749 68.68A2 2 0 1 1 .92 65.853l11.314-11.314a2 2 0 0 1 2.829 0zm9.899 9.899a2 2 0 0 1 0 2.828l-8.485 8.485a2 2 0 1 1-2.829-2.828l8.486-8.485a2 2 0 0 1 2.828 0z"/><path fill="#FDC4A8" d="M20.012 59.489a2 2 0 0 1 0 2.828L4.456 77.874a2 2 0 0 1-2.829-2.829L17.184 59.49a2 2 0 0 1 2.828 0z"/></g></svg>
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><g fill="none" fill-rule="evenodd" transform="translate(7 3)"><path fill="#EEE" fill-rule="nonzero" d="M54 18a2 2 0 1 1 0-4h4c.843 0 1.675.105 2.48.31a2 2 0 1 1-.99 3.876A6.015 6.015 0 0 0 58 18h-4zm9.735 4.228a2 2 0 0 1 3.822-1.18A10 10 0 0 1 68 24v3.513a2 2 0 1 1-4 0V24c0-.61-.09-1.204-.265-1.772zM64 35.513a2 2 0 1 1 4 0v6a2 2 0 1 1-4 0v-6zm0 14a2 2 0 1 1 4 0v6a2 2 0 1 1-4 0v-6zm0 14a2 2 0 1 1 4 0V66a9.97 9.97 0 0 1-.963 4.286 2 2 0 1 1-3.613-1.716A5.969 5.969 0 0 0 64 66v-2.487zm-5.255 8.441a2 2 0 1 1 .49 3.97c-.401.05-.806.075-1.218.076h-5.042a2 2 0 1 1 0-4h5.038c.246 0 .49-.016.732-.046zM44.975 72a2 2 0 1 1 0 4h-6a2 2 0 1 1 0-4h6zm-14 0a2 2 0 1 1 0 4H26c-.429 0-.855-.027-1.276-.08a2 2 0 0 1 .506-3.969c.254.033.51.049.77.049h4.975zm-10.438-3.514a2 2 0 1 1-3.64 1.66A9.97 9.97 0 0 1 16 66v-2.538a2 2 0 1 1 4 0V66c0 .871.185 1.713.537 2.486zM8 2a6 6 0 0 0-6 6v42a6 6 0 0 0 6 6h32a6 6 0 0 0 6-6V8a6 6 0 0 0-6-6H8zm0-4h32c5.523 0 10 4.477 10 10v42c0 5.523-4.477 10-10 10H8C2.477 60-2 55.523-2 50V8C-2 2.477 2.477-2 8-2z"/><rect width="10" height="4" x="8" y="16" fill="#EFEDF8" rx="2"/><rect width="10" height="4" x="21" y="16" fill="#6B4FBB" rx="2"/><rect width="10" height="4" x="8" y="32" fill="#E1DBF1" rx="2"/><rect width="6" height="4" x="34" y="16" fill="#EFEDF8" rx="2"/><rect width="6" height="4" x="8" y="24" fill="#6B4FBB" rx="2"/><rect width="6" height="4" x="17" y="24" fill="#EFEDF8" rx="2"/><rect width="6" height="4" x="21" y="32" fill="#6B4FBB" rx="2"/><rect width="6" height="4" x="8" y="40" fill="#6B4FBB" rx="2"/><rect width="6" height="4" x="17" y="40" fill="#EFEDF8" rx="2"/><rect width="6" height="4" x="26" y="40" fill="#C3B8E3" rx="2"/><rect width="10" height="4" x="26" y="24" fill="#C3B8E3" rx="2"/></g></svg>
|
After Width: | Height: | Size: 1.8 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><g fill="none" fill-rule="evenodd" transform="translate(0 3)"><path fill="#EEE" fill-rule="nonzero" d="M40.843 5.864a2 2 0 1 1 .348-3.985l5.977.523a2 2 0 1 1-.348 3.985l-5.977-.523zm13.946 1.22a2 2 0 1 1 .349-3.985l5.977.523a2 2 0 1 1-.348 3.985l-5.978-.523zm13.947 1.22a2 2 0 1 1 .349-3.984 11.952 11.952 0 0 1 6.655 2.75 2 2 0 1 1-2.569 3.066 7.953 7.953 0 0 0-4.435-1.832zm7.28 7.357a2 2 0 1 1 3.99-.301c.048.639.045 1.283-.01 1.934l-.385 4.4a2 2 0 1 1-3.985-.349l.384-4.395c.037-.433.039-.863.007-1.29zm-1.088 13.654a2 2 0 0 1 3.985.348l-.523 5.978a2 2 0 1 1-3.984-.349l.522-5.977zm-1.22 13.947a2 2 0 1 1 3.985.348l-.523 5.977a2 2 0 1 1-3.985-.348l.523-5.977zM72.305 56.7a2 2 0 0 1 3.79 1.282 11.995 11.995 0 0 1-4.253 5.81 2 2 0 0 1-2.373-3.22 7.996 7.996 0 0 0 2.836-3.872zm-9.054 5.33a2 2 0 1 1-.349 3.985l-5.977-.522a2 2 0 1 1 .349-3.985l5.977.523zM32.793 10.675a2 2 0 1 1-3.675-1.579 12.02 12.02 0 0 1 4.696-5.456 2 2 0 0 1 2.112 3.397 8.02 8.02 0 0 0-3.133 3.638z"/><rect width="48" height="58" x="2" y="14" fill="#FAFAFA" rx="10"/><path fill="#EEE" fill-rule="nonzero" d="M12 16a8 8 0 0 0-8 8v38a8 8 0 0 0 8 8h28a8 8 0 0 0 8-8V24a8 8 0 0 0-8-8H12zm0-4h28c6.627 0 12 5.373 12 12v38c0 6.627-5.373 12-12 12H12C5.373 74 0 68.627 0 62V24c0-6.627 5.373-12 12-12z"/><rect width="24" height="4" x="11" y="30" fill="#E5E5E5" rx="2"/><rect width="30" height="4" x="11" y="41" fill="#E5E5E5" rx="2"/><rect width="20" height="4" x="11" y="52" fill="#E5E5E5" rx="2"/></g></svg>
|
After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="430" height="200" viewBox="0 0 430 200"><g fill="none" fill-rule="evenodd"><g transform="translate(138 65)"><path fill="#E5E5E5" fill-rule="nonzero" d="M35 70a2 2 0 1 1 0-4c2.542 0 5.042-.305 7.463-.904a2 2 0 1 1 .96 3.884A35.075 35.075 0 0 1 35 70zm18.21-5.105a2 2 0 1 1-2.083-3.414 31.143 31.143 0 0 0 5.896-4.664 2 2 0 1 1 2.842 2.815 35.143 35.143 0 0 1-6.654 5.263zM66.106 51.06a2 2 0 0 1-3.552-1.838 30.77 30.77 0 0 0 2.612-7.042 2 2 0 1 1 3.892.922 34.77 34.77 0 0 1-2.952 7.958zm3.816-18.433a2 2 0 1 1-3.991.268 30.873 30.873 0 0 0-1.407-7.38 2 2 0 0 1 3.808-1.223 34.873 34.873 0 0 1 1.59 8.335zm-6.346-17.842a2 2 0 0 1-3.264 2.312 31.188 31.188 0 0 0-5.054-5.564 2 2 0 0 1 2.615-3.027 35.188 35.188 0 0 1 5.703 6.279zM48.895 2.867a2 2 0 0 1-1.59 3.67 30.758 30.758 0 0 0-7.206-2.12 2 2 0 1 1 .653-3.946 34.758 34.758 0 0 1 8.143 2.396zM30.263.318a2 2 0 0 1 .537 3.964c-2.505.339-4.94.98-7.266 1.907a2 2 0 1 1-1.48-3.716A34.774 34.774 0 0 1 30.263.318zM12.907 7.853a2 2 0 0 1 2.527 3.1 31.196 31.196 0 0 0-5.213 5.416 2 2 0 0 1-3.196-2.406 35.196 35.196 0 0 1 5.882-6.11zM1.99 23.343a2 2 0 0 1 3.772 1.331 30.82 30.82 0 0 0-1.619 7.337 2 2 0 1 1-3.982-.38 34.82 34.82 0 0 1 1.829-8.289zM.719 42.086a2 2 0 1 1 3.917-.806 30.757 30.757 0 0 0 2.4 7.118 2 2 0 1 1-3.605 1.73 34.757 34.757 0 0 1-2.713-8.042zM9.393 58.86a2 2 0 0 1 2.926-2.728 31.167 31.167 0 0 0 5.751 4.841 2 2 0 1 1-2.187 3.349 35.167 35.167 0 0 1-6.49-5.462zm16.245 9.873a2 2 0 1 1 1.067-3.855 30.979 30.979 0 0 0 7.434 1.11 2 2 0 1 1-.11 3.998 34.979 34.979 0 0 1-8.391-1.253z"/><circle cx="35" cy="35" r="16" stroke="#E1DBF1" stroke-width="4"/><path fill="#6B4FBB" d="M37 33h5a2 2 0 1 1 0 4h-7a2 2 0 0 1-2-2v-8a2 2 0 1 1 4 0v6z"/></g><g transform="translate(247 30)"><rect width="116" height="135" y="5" fill="#F9F9F9" rx="10"/><rect width="116" height="134" x="5" fill="#FFF" stroke="#EEE" stroke-width="4" stroke-linecap="round" rx="10"/><g transform="translate(23 23)"><rect width="16" height="4" fill="#E1DBF1" rx="2"/><rect width="16" height="4" x="32" y="12" fill="#E1DBF1" rx="2"/><rect width="16" height="4" x="44" fill="#EEE" rx="2"/><rect width="16" height="4" x="12" y="24" fill="#E1DBF1" rx="2"/><rect width="16" height="4" x="64" y="36" fill="#FEF0E8" rx="2"/><rect width="8" height="4" x="20" fill="#FEE1D3" rx="2"/><rect width="8" height="4" x="32" y="36" fill="#FC6D26" rx="2"/><rect width="8" height="4" x="52" y="12" fill="#FEF0E8" rx="2"/><rect width="8" height="4" x="64" fill="#FEF0E8" rx="2"/><rect width="12" height="4" x="16" y="48" fill="#E1DBF1" rx="2"/><rect width="8" height="4" x="44" y="36" fill="#FC6D26" rx="2"/><rect width="4" height="4" x="56" y="36" fill="#E1DBF1" rx="2"/><rect width="4" height="4" x="64" y="60" fill="#E1DBF1" rx="2"/><rect width="4" height="4" x="72" y="60" fill="#FC6D26" rx="2"/><rect width="8" height="4" x="32" fill="#FC6D26" rx="2"/><rect width="28" height="4" y="36" fill="#EEE" rx="2"/><rect width="28" height="4" x="44" y="48" fill="#EEE" rx="2"/><rect width="28" height="4" x="32" y="60" fill="#EFEDF8" rx="2"/><rect width="28" height="4" y="12" fill="#6B4FBB" rx="2"/><rect width="28" height="4" x="32" y="24" fill="#C3B8E3" rx="2"/><rect width="8" height="4" y="24" fill="#FEF0E8" rx="2"/><rect width="8" height="4" x="32" y="48" fill="#6B4FBB" rx="2"/><rect width="12" height="4" y="48" fill="#FC6D26" rx="2"/><rect width="12" height="4" y="60" fill="#FEF0E8" rx="2"/><rect width="12" height="4" x="16" y="60" fill="#FEF0E8" rx="2"/></g><g transform="translate(23 95)"><rect width="16" height="4" fill="#EFEDF8" rx="2"/><rect width="16" height="4" x="18" y="12" fill="#FC6D26" rx="2"/><rect width="16" height="4" x="44" fill="#6B4FBB" rx="2"/><rect width="8" height="4" x="20" fill="#FEE1D3" rx="2"/><rect width="8" height="4" x="38" y="12" fill="#FEF0E8" rx="2"/><rect width="8" height="4" x="64" fill="#FEF0E8" rx="2"/><rect width="8" height="4" x="32" fill="#FC6D26" rx="2"/><rect width="14" height="4" y="12" fill="#EEE" rx="2"/></g></g><path fill="#FC6D26" fill-rule="nonzero" d="M81 119c-10.493 0-19-8.507-19-19s8.507-19 19-19 19 8.507 19 19-8.507 19-19 19zm0-4c8.284 0 15-6.716 15-15 0-8.284-6.716-15-15-15-8.284 0-15 6.716-15 15 0 8.284 6.716 15 15 15zm-5-20a2 2 0 0 1 2 2v6a2 2 0 1 1-4 0v-6a2 2 0 0 1 2-2zm10 0a2 2 0 0 1 2 2v6a2 2 0 1 1-4 0v-6a2 2 0 0 1 2-2z"/><path fill="#E5E5E5" fill-rule="nonzero" d="M108 102c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004a1.994 1.994 0 0 1-1.998-2zm14 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004a1.994 1.994 0 0 1-1.998-2zm93 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004a1.994 1.994 0 0 1-1.998-2zm14 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004a1.994 1.994 0 0 1-1.998-2z"/></g></svg>
|
After Width: | Height: | Size: 4.8 KiB |
|
@ -1,9 +1,9 @@
|
|||
import $ from 'jquery';
|
||||
import _ from 'underscore';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
|
||||
const Api = {
|
||||
groupsPath: '/api/:version/groups.json',
|
||||
groupPath: '/api/:version/groups/:id.json',
|
||||
groupPath: '/api/:version/groups/:id',
|
||||
namespacesPath: '/api/:version/namespaces.json',
|
||||
groupProjectsPath: '/api/:version/groups/:id/projects.json',
|
||||
projectsPath: '/api/:version/projects.json',
|
||||
|
@ -23,42 +23,44 @@ const Api = {
|
|||
group(groupId, callback) {
|
||||
const url = Api.buildUrl(Api.groupPath)
|
||||
.replace(':id', groupId);
|
||||
return $.ajax({
|
||||
url,
|
||||
dataType: 'json',
|
||||
})
|
||||
.done(group => callback(group));
|
||||
return axios.get(url)
|
||||
.then(({ data }) => {
|
||||
callback(data);
|
||||
|
||||
return data;
|
||||
});
|
||||
},
|
||||
|
||||
// Return groups list. Filtered by query
|
||||
groups(query, options, callback) {
|
||||
const url = Api.buildUrl(Api.groupsPath);
|
||||
return $.ajax({
|
||||
url,
|
||||
data: Object.assign({
|
||||
return axios.get(url, {
|
||||
params: Object.assign({
|
||||
search: query,
|
||||
per_page: 20,
|
||||
}, options),
|
||||
dataType: 'json',
|
||||
})
|
||||
.done(groups => callback(groups));
|
||||
.then(({ data }) => {
|
||||
callback(data);
|
||||
|
||||
return data;
|
||||
});
|
||||
},
|
||||
|
||||
// Return namespaces list. Filtered by query
|
||||
namespaces(query, callback) {
|
||||
const url = Api.buildUrl(Api.namespacesPath);
|
||||
return $.ajax({
|
||||
url,
|
||||
data: {
|
||||
return axios.get(url, {
|
||||
params: {
|
||||
search: query,
|
||||
per_page: 20,
|
||||
},
|
||||
dataType: 'json',
|
||||
}).done(namespaces => callback(namespaces));
|
||||
})
|
||||
.then(({ data }) => callback(data));
|
||||
},
|
||||
|
||||
// Return projects list. Filtered by query
|
||||
projects(query, options, callback) {
|
||||
projects(query, options, callback = _.noop) {
|
||||
const url = Api.buildUrl(Api.projectsPath);
|
||||
const defaults = {
|
||||
search: query,
|
||||
|
@ -70,12 +72,14 @@ const Api = {
|
|||
defaults.membership = true;
|
||||
}
|
||||
|
||||
return $.ajax({
|
||||
url,
|
||||
data: Object.assign(defaults, options),
|
||||
dataType: 'json',
|
||||
return axios.get(url, {
|
||||
params: Object.assign(defaults, options),
|
||||
})
|
||||
.done(projects => callback(projects));
|
||||
.then(({ data }) => {
|
||||
callback(data);
|
||||
|
||||
return data;
|
||||
});
|
||||
},
|
||||
|
||||
// Return single project
|
||||
|
@ -97,41 +101,34 @@ const Api = {
|
|||
url = Api.buildUrl(Api.groupLabelsPath).replace(':namespace_path', namespacePath);
|
||||
}
|
||||
|
||||
return $.ajax({
|
||||
url,
|
||||
type: 'POST',
|
||||
data: { label: data },
|
||||
dataType: 'json',
|
||||
return axios.post(url, {
|
||||
label: data,
|
||||
})
|
||||
.done(label => callback(label))
|
||||
.fail(message => callback(message.responseJSON));
|
||||
.then(res => callback(res.data))
|
||||
.catch(e => callback(e.response.data));
|
||||
},
|
||||
|
||||
// Return group projects list. Filtered by query
|
||||
groupProjects(groupId, query, callback) {
|
||||
const url = Api.buildUrl(Api.groupProjectsPath)
|
||||
.replace(':id', groupId);
|
||||
return $.ajax({
|
||||
url,
|
||||
data: {
|
||||
return axios.get(url, {
|
||||
params: {
|
||||
search: query,
|
||||
per_page: 20,
|
||||
},
|
||||
dataType: 'json',
|
||||
})
|
||||
.done(projects => callback(projects));
|
||||
.then(({ data }) => callback(data));
|
||||
},
|
||||
|
||||
commitMultiple(id, data) {
|
||||
// see https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions
|
||||
const url = Api.buildUrl(Api.commitPath)
|
||||
.replace(':id', encodeURIComponent(id));
|
||||
return this.wrapAjaxCall({
|
||||
url,
|
||||
type: 'POST',
|
||||
contentType: 'application/json; charset=utf-8',
|
||||
data: JSON.stringify(data),
|
||||
dataType: 'json',
|
||||
return axios.post(url, JSON.stringify(data), {
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -140,65 +137,57 @@ const Api = {
|
|||
.replace(':id', encodeURIComponent(id))
|
||||
.replace(':branch', branch);
|
||||
|
||||
return this.wrapAjaxCall({
|
||||
url,
|
||||
type: 'GET',
|
||||
contentType: 'application/json; charset=utf-8',
|
||||
dataType: 'json',
|
||||
});
|
||||
return axios.get(url);
|
||||
},
|
||||
|
||||
// Return text for a specific license
|
||||
licenseText(key, data, callback) {
|
||||
const url = Api.buildUrl(Api.licensePath)
|
||||
.replace(':key', key);
|
||||
return $.ajax({
|
||||
url,
|
||||
data,
|
||||
return axios.get(url, {
|
||||
params: data,
|
||||
})
|
||||
.done(license => callback(license));
|
||||
.then(res => callback(res.data));
|
||||
},
|
||||
|
||||
gitignoreText(key, callback) {
|
||||
const url = Api.buildUrl(Api.gitignorePath)
|
||||
.replace(':key', key);
|
||||
return $.get(url, gitignore => callback(gitignore));
|
||||
return axios.get(url)
|
||||
.then(({ data }) => callback(data));
|
||||
},
|
||||
|
||||
gitlabCiYml(key, callback) {
|
||||
const url = Api.buildUrl(Api.gitlabCiYmlPath)
|
||||
.replace(':key', key);
|
||||
return $.get(url, file => callback(file));
|
||||
return axios.get(url)
|
||||
.then(({ data }) => callback(data));
|
||||
},
|
||||
|
||||
dockerfileYml(key, callback) {
|
||||
const url = Api.buildUrl(Api.dockerfilePath).replace(':key', key);
|
||||
$.get(url, callback);
|
||||
return axios.get(url)
|
||||
.then(({ data }) => callback(data));
|
||||
},
|
||||
|
||||
issueTemplate(namespacePath, projectPath, key, type, callback) {
|
||||
const url = Api.buildUrl(Api.issuableTemplatePath)
|
||||
.replace(':key', key)
|
||||
.replace(':key', encodeURIComponent(key))
|
||||
.replace(':type', type)
|
||||
.replace(':project_path', projectPath)
|
||||
.replace(':namespace_path', namespacePath);
|
||||
$.ajax({
|
||||
url,
|
||||
dataType: 'json',
|
||||
})
|
||||
.done(file => callback(null, file))
|
||||
.fail(callback);
|
||||
return axios.get(url)
|
||||
.then(({ data }) => callback(null, data))
|
||||
.catch(callback);
|
||||
},
|
||||
|
||||
users(query, options) {
|
||||
const url = Api.buildUrl(this.usersPath);
|
||||
return Api.wrapAjaxCall({
|
||||
url,
|
||||
data: Object.assign({
|
||||
return axios.get(url, {
|
||||
params: Object.assign({
|
||||
search: query,
|
||||
per_page: 20,
|
||||
}, options),
|
||||
dataType: 'json',
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -209,21 +198,6 @@ const Api = {
|
|||
}
|
||||
return urlRoot + url.replace(':version', gon.api_version);
|
||||
},
|
||||
|
||||
wrapAjaxCall(options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// jQuery 2 is not Promises/A+ compatible (missing catch)
|
||||
$.ajax(options) // eslint-disable-line promise/catch-or-return
|
||||
.then(data => resolve(data),
|
||||
(jqXHR, textStatus, errorThrown) => {
|
||||
const error = new Error(`${options.url}: ${errorThrown}`);
|
||||
error.textStatus = textStatus;
|
||||
if (jqXHR && jqXHR.responseJSON) error.responseJSON = jqXHR.responseJSON;
|
||||
reject(error);
|
||||
},
|
||||
);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default Api;
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/* eslint-disable class-methods-use-this */
|
||||
import _ from 'underscore';
|
||||
import Cookies from 'js-cookie';
|
||||
import { __ } from './locale';
|
||||
import { isInIssuePage, updateTooltipTitle } from './lib/utils/common_utils';
|
||||
import Flash from './flash';
|
||||
import flash from './flash';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
|
||||
const animationEndEventString = 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd';
|
||||
const transitionEndEventString = 'transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd';
|
||||
|
@ -441,13 +443,15 @@ class AwardsHandler {
|
|||
if (this.isUserAuthored($emojiButton)) {
|
||||
this.userAuthored($emojiButton);
|
||||
} else {
|
||||
$.post(awardUrl, {
|
||||
axios.post(awardUrl, {
|
||||
name: emoji,
|
||||
}, (data) => {
|
||||
})
|
||||
.then(({ data }) => {
|
||||
if (data.ok) {
|
||||
callback();
|
||||
}
|
||||
}).fail(() => new Flash('Something went wrong on our end.'));
|
||||
})
|
||||
.catch(() => flash(__('Something went wrong on our end.')));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -299,6 +299,13 @@ const gfmRules = {
|
|||
|
||||
export class CopyAsGFM {
|
||||
constructor() {
|
||||
// iOS currently does not support clipboardData.setData(). This bug should
|
||||
// be fixed in iOS 12, but for now we'll disable this for all iOS browsers
|
||||
// ref: https://trac.webkit.org/changeset/222228/webkit
|
||||
const userAgent = (typeof navigator !== 'undefined' && navigator.userAgent) || '';
|
||||
const isIOS = /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent);
|
||||
if (isIOS) return;
|
||||
|
||||
$(document).on('copy', '.md, .wiki', (e) => { CopyAsGFM.copyAsGFM(e, CopyAsGFM.transformGFMSelection); });
|
||||
$(document).on('copy', 'pre.code.highlight, .diff-content .line_content', (e) => { CopyAsGFM.copyAsGFM(e, CopyAsGFM.transformCodeSelection); });
|
||||
$(document).on('paste', '.js-gfm-input', CopyAsGFM.pasteGFM);
|
||||
|
|
|
@ -2,22 +2,25 @@ import { n__ } from '../locale';
|
|||
import { convertPermissionToBoolean } from '../lib/utils/common_utils';
|
||||
|
||||
export default class SecretValues {
|
||||
constructor(container) {
|
||||
constructor({
|
||||
container,
|
||||
valueSelector = '.js-secret-value',
|
||||
placeholderSelector = '.js-secret-value-placeholder',
|
||||
}) {
|
||||
this.container = container;
|
||||
this.valueSelector = valueSelector;
|
||||
this.placeholderSelector = placeholderSelector;
|
||||
}
|
||||
|
||||
init() {
|
||||
this.values = this.container.querySelectorAll('.js-secret-value');
|
||||
this.placeholders = this.container.querySelectorAll('.js-secret-value-placeholder');
|
||||
this.revealButton = this.container.querySelector('.js-secret-value-reveal-button');
|
||||
|
||||
this.revealText = n__('Reveal value', 'Reveal values', this.values.length);
|
||||
this.hideText = n__('Hide value', 'Hide values', this.values.length);
|
||||
if (this.revealButton) {
|
||||
const isRevealed = convertPermissionToBoolean(this.revealButton.dataset.secretRevealStatus);
|
||||
this.updateDom(isRevealed);
|
||||
|
||||
const isRevealed = convertPermissionToBoolean(this.revealButton.dataset.secretRevealStatus);
|
||||
this.updateDom(isRevealed);
|
||||
|
||||
this.revealButton.addEventListener('click', this.onRevealButtonClicked.bind(this));
|
||||
this.revealButton.addEventListener('click', this.onRevealButtonClicked.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
onRevealButtonClicked() {
|
||||
|
@ -28,15 +31,17 @@ export default class SecretValues {
|
|||
}
|
||||
|
||||
updateDom(isRevealed) {
|
||||
this.values.forEach((value) => {
|
||||
const values = this.container.querySelectorAll(this.valueSelector);
|
||||
values.forEach((value) => {
|
||||
value.classList.toggle('hide', !isRevealed);
|
||||
});
|
||||
|
||||
this.placeholders.forEach((placeholder) => {
|
||||
const placeholders = this.container.querySelectorAll(this.placeholderSelector);
|
||||
placeholders.forEach((placeholder) => {
|
||||
placeholder.classList.toggle('hide', isRevealed);
|
||||
});
|
||||
|
||||
this.revealButton.textContent = isRevealed ? this.hideText : this.revealText;
|
||||
this.revealButton.textContent = isRevealed ? n__('Hide value', 'Hide values', values.length) : n__('Reveal value', 'Reveal values', values.length);
|
||||
this.revealButton.dataset.secretRevealStatus = isRevealed;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -235,7 +235,7 @@ export default class FileTemplateMediator {
|
|||
}
|
||||
|
||||
setFilename(name) {
|
||||
this.$filenameInput.val(name);
|
||||
this.$filenameInput.val(name).trigger('change');
|
||||
}
|
||||
|
||||
getSelected() {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Flash from '../../flash';
|
||||
import { handleLocationHash } from '../../lib/utils/common_utils';
|
||||
import axios from '../../lib/utils/axios_utils';
|
||||
|
||||
export default class BlobViewer {
|
||||
constructor() {
|
||||
|
@ -127,25 +128,18 @@ export default class BlobViewer {
|
|||
const viewer = viewerParam;
|
||||
const url = viewer.getAttribute('data-url');
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!url || viewer.getAttribute('data-loaded') || viewer.getAttribute('data-loading')) {
|
||||
resolve(viewer);
|
||||
return;
|
||||
}
|
||||
if (!url || viewer.getAttribute('data-loaded') || viewer.getAttribute('data-loading')) {
|
||||
return Promise.resolve(viewer);
|
||||
}
|
||||
|
||||
viewer.setAttribute('data-loading', 'true');
|
||||
viewer.setAttribute('data-loading', 'true');
|
||||
|
||||
$.ajax({
|
||||
url,
|
||||
dataType: 'JSON',
|
||||
})
|
||||
.fail(reject)
|
||||
.done((data) => {
|
||||
return axios.get(url)
|
||||
.then(({ data }) => {
|
||||
viewer.innerHTML = data.html;
|
||||
viewer.setAttribute('data-loaded', 'true');
|
||||
|
||||
resolve(viewer);
|
||||
return viewer;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
/* global ace */
|
||||
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import createFlash from '~/flash';
|
||||
import { __ } from '~/locale';
|
||||
import TemplateSelectorMediator from '../blob/file_template_mediator';
|
||||
|
||||
export default class EditBlob {
|
||||
|
@ -56,12 +59,14 @@ export default class EditBlob {
|
|||
|
||||
if (paneId === '#preview') {
|
||||
this.$toggleButton.hide();
|
||||
return $.post(currentLink.data('preview-url'), {
|
||||
axios.post(currentLink.data('preview-url'), {
|
||||
content: this.editor.getValue(),
|
||||
}, (response) => {
|
||||
currentPane.empty().append(response);
|
||||
return currentPane.renderGFM();
|
||||
});
|
||||
})
|
||||
.then(({ data }) => {
|
||||
currentPane.empty().append(data);
|
||||
currentPane.renderGFM();
|
||||
})
|
||||
.catch(() => createFlash(__('An error occurred previewing the blob')));
|
||||
}
|
||||
|
||||
this.$toggleButton.show();
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
import $ from 'jquery';
|
||||
import { convertPermissionToBoolean } from '../lib/utils/common_utils';
|
||||
import { s__ } from '../locale';
|
||||
import setupToggleButtons from '../toggle_buttons';
|
||||
import CreateItemDropdown from '../create_item_dropdown';
|
||||
import SecretValues from '../behaviors/secret_values';
|
||||
|
||||
const ALL_ENVIRONMENTS_STRING = s__('CiVariable|All environments');
|
||||
|
||||
function createEnvironmentItem(value) {
|
||||
return {
|
||||
title: value === '*' ? ALL_ENVIRONMENTS_STRING : value,
|
||||
id: value,
|
||||
text: value,
|
||||
};
|
||||
}
|
||||
|
||||
export default class VariableList {
|
||||
constructor({
|
||||
container,
|
||||
formField,
|
||||
}) {
|
||||
this.$container = $(container);
|
||||
this.formField = formField;
|
||||
this.environmentDropdownMap = new WeakMap();
|
||||
|
||||
this.inputMap = {
|
||||
id: {
|
||||
selector: '.js-ci-variable-input-id',
|
||||
default: '',
|
||||
},
|
||||
key: {
|
||||
selector: '.js-ci-variable-input-key',
|
||||
default: '',
|
||||
},
|
||||
value: {
|
||||
selector: '.js-ci-variable-input-value',
|
||||
default: '',
|
||||
},
|
||||
protected: {
|
||||
selector: '.js-ci-variable-input-protected',
|
||||
default: 'true',
|
||||
},
|
||||
environment: {
|
||||
// We can't use a `.js-` class here because
|
||||
// gl_dropdown replaces the <input> and doesn't copy over the class
|
||||
// See https://gitlab.com/gitlab-org/gitlab-ce/issues/42458
|
||||
selector: `input[name="${this.formField}[variables_attributes][][environment]"]`,
|
||||
default: '*',
|
||||
},
|
||||
_destroy: {
|
||||
selector: '.js-ci-variable-input-destroy',
|
||||
default: '',
|
||||
},
|
||||
};
|
||||
|
||||
this.secretValues = new SecretValues({
|
||||
container: this.$container[0],
|
||||
valueSelector: '.js-row:not(:last-child) .js-secret-value',
|
||||
placeholderSelector: '.js-row:not(:last-child) .js-secret-value-placeholder',
|
||||
});
|
||||
}
|
||||
|
||||
init() {
|
||||
this.bindEvents();
|
||||
this.secretValues.init();
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.$container.find('.js-row').each((index, rowEl) => {
|
||||
this.initRow(rowEl);
|
||||
});
|
||||
|
||||
this.$container.on('click', '.js-row-remove-button', (e) => {
|
||||
e.preventDefault();
|
||||
this.removeRow($(e.currentTarget).closest('.js-row'));
|
||||
});
|
||||
|
||||
const inputSelector = Object.keys(this.inputMap)
|
||||
.map(name => this.inputMap[name].selector)
|
||||
.join(',');
|
||||
|
||||
// Remove any empty rows except the last row
|
||||
this.$container.on('blur', inputSelector, (e) => {
|
||||
const $row = $(e.currentTarget).closest('.js-row');
|
||||
|
||||
if ($row.is(':not(:last-child)') && !this.checkIfRowTouched($row)) {
|
||||
this.removeRow($row);
|
||||
}
|
||||
});
|
||||
|
||||
// Always make sure there is an empty last row
|
||||
this.$container.on('input trigger-change', inputSelector, () => {
|
||||
const $lastRow = this.$container.find('.js-row').last();
|
||||
|
||||
if (this.checkIfRowTouched($lastRow)) {
|
||||
this.insertRow($lastRow);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
initRow(rowEl) {
|
||||
const $row = $(rowEl);
|
||||
|
||||
setupToggleButtons($row[0]);
|
||||
|
||||
const $environmentSelect = $row.find('.js-variable-environment-toggle');
|
||||
if ($environmentSelect.length) {
|
||||
const createItemDropdown = new CreateItemDropdown({
|
||||
$dropdown: $environmentSelect,
|
||||
defaultToggleLabel: ALL_ENVIRONMENTS_STRING,
|
||||
fieldName: `${this.formField}[variables_attributes][][environment]`,
|
||||
getData: (term, callback) => callback(this.getEnvironmentValues()),
|
||||
createNewItemFromValue: createEnvironmentItem,
|
||||
onSelect: () => {
|
||||
// Refresh the other dropdowns in the variable list
|
||||
// so they have the new value we just picked
|
||||
this.refreshDropdownData();
|
||||
|
||||
$row.find(this.inputMap.environment.selector).trigger('trigger-change');
|
||||
},
|
||||
});
|
||||
|
||||
// Clear out any data that might have been left-over from the row clone
|
||||
createItemDropdown.clearDropdown();
|
||||
|
||||
this.environmentDropdownMap.set($row[0], createItemDropdown);
|
||||
}
|
||||
}
|
||||
|
||||
insertRow($row) {
|
||||
const $rowClone = $row.clone();
|
||||
$rowClone.removeAttr('data-is-persisted');
|
||||
|
||||
// Reset the inputs to their defaults
|
||||
Object.keys(this.inputMap).forEach((name) => {
|
||||
const entry = this.inputMap[name];
|
||||
$rowClone.find(entry.selector).val(entry.default);
|
||||
});
|
||||
|
||||
this.initRow($rowClone);
|
||||
|
||||
$row.after($rowClone);
|
||||
}
|
||||
|
||||
removeRow($row) {
|
||||
const isPersisted = convertPermissionToBoolean($row.attr('data-is-persisted'));
|
||||
|
||||
if (isPersisted) {
|
||||
$row.hide();
|
||||
$row
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
.find(this.inputMap._destroy.selector)
|
||||
.val(true);
|
||||
} else {
|
||||
$row.remove();
|
||||
}
|
||||
}
|
||||
|
||||
checkIfRowTouched($row) {
|
||||
return Object.keys(this.inputMap).some((name) => {
|
||||
const entry = this.inputMap[name];
|
||||
const $el = $row.find(entry.selector);
|
||||
return $el.length && $el.val() !== entry.default;
|
||||
});
|
||||
}
|
||||
|
||||
getAllData() {
|
||||
// Ignore the last empty row because we don't want to try persist
|
||||
// a blank variable and run into validation problems.
|
||||
const validRows = this.$container.find('.js-row').toArray().slice(0, -1);
|
||||
|
||||
return validRows.map((rowEl) => {
|
||||
const resultant = {};
|
||||
Object.keys(this.inputMap).forEach((name) => {
|
||||
const entry = this.inputMap[name];
|
||||
const $input = $(rowEl).find(entry.selector);
|
||||
if ($input.length) {
|
||||
resultant[name] = $input.val();
|
||||
}
|
||||
});
|
||||
|
||||
return resultant;
|
||||
});
|
||||
}
|
||||
|
||||
getEnvironmentValues() {
|
||||
const valueMap = this.$container.find(this.inputMap.environment.selector).toArray()
|
||||
.reduce((prevValueMap, envInput) => ({
|
||||
...prevValueMap,
|
||||
[envInput.value]: envInput.value,
|
||||
}), {});
|
||||
|
||||
return Object.keys(valueMap).map(createEnvironmentItem);
|
||||
}
|
||||
|
||||
refreshDropdownData() {
|
||||
this.$container.find('.js-row').each((index, rowEl) => {
|
||||
const environmentDropdown = this.environmentDropdownMap.get(rowEl);
|
||||
if (environmentDropdown) {
|
||||
environmentDropdown.refreshData();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import VariableList from './ci_variable_list';
|
||||
|
||||
// Used for the variable list on scheduled pipeline edit page
|
||||
export default function setupNativeFormVariableList({
|
||||
container,
|
||||
formField = 'variables',
|
||||
}) {
|
||||
const $container = $(container);
|
||||
|
||||
const variableList = new VariableList({
|
||||
container: $container,
|
||||
formField,
|
||||
});
|
||||
variableList.init();
|
||||
|
||||
// Clear out the names in the empty last row so it
|
||||
// doesn't get submitted and throw validation errors
|
||||
$container.closest('form').on('submit trigger-submit', () => {
|
||||
const $lastRow = $container.find('.js-row').last();
|
||||
|
||||
const isTouched = variableList.checkIfRowTouched($lastRow);
|
||||
if (!isTouched) {
|
||||
$lastRow.find('input, textarea').attr('name', '');
|
||||
}
|
||||
});
|
||||
}
|
|
@ -14,6 +14,7 @@ import {
|
|||
import ClustersService from './services/clusters_service';
|
||||
import ClustersStore from './stores/clusters_store';
|
||||
import applications from './components/applications.vue';
|
||||
import setupToggleButtons from '../toggle_buttons';
|
||||
|
||||
/**
|
||||
* Cluster page has 2 separate parts:
|
||||
|
@ -34,10 +35,11 @@ export default class Clusters {
|
|||
clusterStatus,
|
||||
clusterStatusReason,
|
||||
helpPath,
|
||||
ingressHelpPath,
|
||||
} = document.querySelector('.js-edit-cluster-form').dataset;
|
||||
|
||||
this.store = new ClustersStore();
|
||||
this.store.setHelpPath(helpPath);
|
||||
this.store.setHelpPaths(helpPath, ingressHelpPath);
|
||||
this.store.updateStatus(clusterStatus);
|
||||
this.store.updateStatusReason(clusterStatusReason);
|
||||
this.service = new ClustersService({
|
||||
|
@ -48,12 +50,9 @@ export default class Clusters {
|
|||
installPrometheusEndpoint: installPrometheusPath,
|
||||
});
|
||||
|
||||
this.toggle = this.toggle.bind(this);
|
||||
this.installApplication = this.installApplication.bind(this);
|
||||
this.showToken = this.showToken.bind(this);
|
||||
|
||||
this.toggleButton = document.querySelector('.js-toggle-cluster');
|
||||
this.toggleInput = document.querySelector('.js-toggle-input');
|
||||
this.errorContainer = document.querySelector('.js-cluster-error');
|
||||
this.successContainer = document.querySelector('.js-cluster-success');
|
||||
this.creatingContainer = document.querySelector('.js-cluster-creating');
|
||||
|
@ -63,6 +62,7 @@ export default class Clusters {
|
|||
this.tokenField = document.querySelector('.js-cluster-token');
|
||||
|
||||
initSettingsPanels();
|
||||
setupToggleButtons(document.querySelector('.js-cluster-enable-toggle-area'));
|
||||
this.initApplications();
|
||||
|
||||
if (this.store.state.status !== 'created') {
|
||||
|
@ -94,6 +94,7 @@ export default class Clusters {
|
|||
props: {
|
||||
applications: this.state.applications,
|
||||
helpPath: this.state.helpPath,
|
||||
ingressHelpPath: this.state.ingressHelpPath,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
@ -101,13 +102,11 @@ export default class Clusters {
|
|||
}
|
||||
|
||||
addListeners() {
|
||||
this.toggleButton.addEventListener('click', this.toggle);
|
||||
if (this.showTokenButton) this.showTokenButton.addEventListener('click', this.showToken);
|
||||
eventHub.$on('installApplication', this.installApplication);
|
||||
}
|
||||
|
||||
removeListeners() {
|
||||
this.toggleButton.removeEventListener('click', this.toggle);
|
||||
if (this.showTokenButton) this.showTokenButton.removeEventListener('click', this.showToken);
|
||||
eventHub.$off('installApplication', this.installApplication);
|
||||
}
|
||||
|
@ -151,11 +150,6 @@ export default class Clusters {
|
|||
this.updateContainer(prevStatus, this.store.state.status, this.store.state.statusReason);
|
||||
}
|
||||
|
||||
toggle() {
|
||||
this.toggleButton.classList.toggle('is-checked');
|
||||
this.toggleInput.setAttribute('value', this.toggleButton.classList.contains('is-checked').toString());
|
||||
}
|
||||
|
||||
showToken() {
|
||||
const type = this.tokenField.getAttribute('type');
|
||||
|
||||
|
@ -180,7 +174,7 @@ export default class Clusters {
|
|||
.map(appId => newApplicationMap[appId].title);
|
||||
|
||||
if (appTitles.length > 0) {
|
||||
const text = sprintf(s__('ClusterIntegration|%{appList} was successfully installed on your cluster'), {
|
||||
const text = sprintf(s__('ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster'), {
|
||||
appList: appTitles.join(', '),
|
||||
});
|
||||
Flash(text, 'notice', this.successApplicationContainer);
|
||||
|
|
|
@ -1,58 +1,20 @@
|
|||
import Flash from '../flash';
|
||||
import { s__ } from '../locale';
|
||||
import setupToggleButtons from '../toggle_buttons';
|
||||
import ClustersService from './services/clusters_service';
|
||||
/**
|
||||
* Toggles loading and disabled classes.
|
||||
* @param {HTMLElement} button
|
||||
*/
|
||||
const toggleLoadingButton = (button) => {
|
||||
if (button.getAttribute('disabled')) {
|
||||
button.removeAttribute('disabled');
|
||||
} else {
|
||||
button.setAttribute('disabled', true);
|
||||
|
||||
export default () => {
|
||||
const clusterList = document.querySelector('.js-clusters-list');
|
||||
// The empty state won't have a clusterList
|
||||
if (clusterList) {
|
||||
setupToggleButtons(
|
||||
document.querySelector('.js-clusters-list'),
|
||||
(value, toggle) =>
|
||||
ClustersService.updateCluster(toggle.dataset.endpoint, { cluster: { enabled: value } })
|
||||
.catch((err) => {
|
||||
Flash(s__('ClusterIntegration|Something went wrong on our end.'));
|
||||
throw err;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
button.classList.toggle('is-loading');
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggles checked class for the given button
|
||||
* @param {HTMLElement} button
|
||||
*/
|
||||
const toggleValue = (button) => {
|
||||
button.classList.toggle('is-checked');
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles toggle buttons in the cluster's table.
|
||||
*
|
||||
* When the user clicks the toggle button for each cluster, it:
|
||||
* - toggles the button
|
||||
* - shows a loading and disables button
|
||||
* - Makes a put request to the given endpoint
|
||||
* Once we receive the response, either:
|
||||
* 1) Show updated status in case of successfull response
|
||||
* 2) Show initial status in case of failed response
|
||||
*/
|
||||
export default function setClusterTableToggles() {
|
||||
document.querySelectorAll('.js-toggle-cluster-list')
|
||||
.forEach(button => button.addEventListener('click', (e) => {
|
||||
const toggleButton = e.currentTarget;
|
||||
const endpoint = toggleButton.getAttribute('data-endpoint');
|
||||
|
||||
toggleValue(toggleButton);
|
||||
toggleLoadingButton(toggleButton);
|
||||
|
||||
const value = toggleButton.classList.contains('is-checked');
|
||||
|
||||
ClustersService.updateCluster(endpoint, { cluster: { enabled: value } })
|
||||
.then(() => {
|
||||
toggleLoadingButton(toggleButton);
|
||||
})
|
||||
.catch(() => {
|
||||
toggleLoadingButton(toggleButton);
|
||||
toggleValue(toggleButton);
|
||||
Flash(s__('ClusterIntegration|Something went wrong on our end.'));
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -18,11 +18,16 @@
|
|||
required: false,
|
||||
default: '',
|
||||
},
|
||||
ingressHelpPath: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
generalApplicationDescription() {
|
||||
return sprintf(
|
||||
_.escape(s__(`ClusterIntegration|Install applications on your cluster.
|
||||
_.escape(s__(`ClusterIntegration|Install applications on your Kubernetes cluster.
|
||||
Read more about %{helpLink}`)),
|
||||
{
|
||||
helpLink: `<a href="${this.helpPath}">
|
||||
|
@ -34,7 +39,7 @@
|
|||
},
|
||||
helmTillerDescription() {
|
||||
return _.escape(s__(
|
||||
`ClusterIntegration|Helm streamlines installing and managing Kubernets applications.
|
||||
`ClusterIntegration|Helm streamlines installing and managing Kubernetes applications.
|
||||
Tiller runs inside of your Kubernetes Cluster, and manages
|
||||
releases of your charts.`,
|
||||
));
|
||||
|
@ -49,7 +54,7 @@
|
|||
_.escape(s__(
|
||||
`ClusterIntegration|%{boldNotice} This will add some extra resources
|
||||
like a load balancer, which may incur additional costs depending on
|
||||
the hosting provider Kubernetes is installed on. If you are using GKE,
|
||||
the hosting provider your Kubernetes cluster is installed on. If you are using GKE,
|
||||
you can %{pricingLink}.`,
|
||||
)), {
|
||||
boldNotice: `<strong>${_.escape(s__('ClusterIntegration|Note:'))}</strong>`,
|
||||
|
@ -59,13 +64,28 @@
|
|||
false,
|
||||
);
|
||||
|
||||
const externalIpParagraph = sprintf(
|
||||
_.escape(s__(
|
||||
`ClusterIntegration|After installing Ingress, you will need to point your wildcard DNS
|
||||
at the generated external IP address in order to view your app after it is deployed. %{ingressHelpLink}`,
|
||||
)), {
|
||||
ingressHelpLink: `<a href="${this.ingressHelpPath}">
|
||||
${_.escape(s__('ClusterIntegration|More information'))}
|
||||
</a>`,
|
||||
},
|
||||
false,
|
||||
);
|
||||
|
||||
return `
|
||||
<p>
|
||||
${descriptionParagraph}
|
||||
</p>
|
||||
<p class="append-bottom-0">
|
||||
<p>
|
||||
${extraCostParagraph}
|
||||
</p>
|
||||
<p class="settings-message append-bottom-0">
|
||||
${externalIpParagraph}
|
||||
</p>
|
||||
`;
|
||||
},
|
||||
gitlabRunnerDescription() {
|
||||
|
|
|
@ -4,6 +4,7 @@ export default class ClusterStore {
|
|||
constructor() {
|
||||
this.state = {
|
||||
helpPath: null,
|
||||
ingressHelpPath: null,
|
||||
status: null,
|
||||
statusReason: null,
|
||||
applications: {
|
||||
|
@ -39,8 +40,9 @@ export default class ClusterStore {
|
|||
};
|
||||
}
|
||||
|
||||
setHelpPath(helpPath) {
|
||||
setHelpPaths(helpPath, ingressHelpPath) {
|
||||
this.state.helpPath = helpPath;
|
||||
this.state.ingressHelpPath = ingressHelpPath;
|
||||
}
|
||||
|
||||
updateStatus(status) {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
import { pluralize } from './lib/utils/text_utility';
|
||||
import { localTimeAgo } from './lib/utils/datetime_utility';
|
||||
import Pager from './pager';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
|
||||
export default (function () {
|
||||
const CommitsList = {};
|
||||
|
@ -43,29 +44,30 @@ export default (function () {
|
|||
CommitsList.filterResults = function () {
|
||||
const form = $('.commits-search-form');
|
||||
const search = CommitsList.searchField.val();
|
||||
if (search === CommitsList.lastSearch) return;
|
||||
if (search === CommitsList.lastSearch) return Promise.resolve();
|
||||
const commitsUrl = form.attr('action') + '?' + form.serialize();
|
||||
CommitsList.content.fadeTo('fast', 0.5);
|
||||
return $.ajax({
|
||||
type: 'GET',
|
||||
url: form.attr('action'),
|
||||
data: form.serialize(),
|
||||
complete: function () {
|
||||
return CommitsList.content.fadeTo('fast', 1.0);
|
||||
},
|
||||
success: function (data) {
|
||||
const params = form.serializeArray().reduce((acc, obj) => Object.assign(acc, {
|
||||
[obj.name]: obj.value,
|
||||
}), {});
|
||||
|
||||
return axios.get(form.attr('action'), {
|
||||
params,
|
||||
})
|
||||
.then(({ data }) => {
|
||||
CommitsList.lastSearch = search;
|
||||
CommitsList.content.html(data.html);
|
||||
return history.replaceState({
|
||||
page: commitsUrl,
|
||||
CommitsList.content.fadeTo('fast', 1.0);
|
||||
|
||||
// Change url so if user reload a page - search results are saved
|
||||
history.replaceState({
|
||||
page: commitsUrl,
|
||||
}, document.title, commitsUrl);
|
||||
},
|
||||
error: function () {
|
||||
})
|
||||
.catch(() => {
|
||||
CommitsList.content.fadeTo('fast', 1.0);
|
||||
CommitsList.lastSearch = null;
|
||||
},
|
||||
dataType: 'json',
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Prepare loaded data.
|
||||
|
|
|
@ -8,6 +8,8 @@ import 'core-js/fn/promise';
|
|||
import 'core-js/fn/string/code-point-at';
|
||||
import 'core-js/fn/string/from-code-point';
|
||||
import 'core-js/fn/symbol';
|
||||
import 'core-js/es6/map';
|
||||
import 'core-js/es6/weak-map';
|
||||
|
||||
// Browser polyfills
|
||||
import 'classlist-polyfill';
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, wrap-iife, quotes, no-var, object-shorthand, consistent-return, no-unused-vars, comma-dangle, vars-on-top, prefer-template, max-len */
|
||||
import { localTimeAgo } from './lib/utils/datetime_utility';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
|
||||
export default class Compare {
|
||||
constructor(opts) {
|
||||
|
@ -41,17 +42,14 @@ export default class Compare {
|
|||
}
|
||||
|
||||
getTargetProject() {
|
||||
return $.ajax({
|
||||
url: this.opts.targetProjectUrl,
|
||||
data: {
|
||||
target_project_id: $("input[name='merge_request[target_project_id]']").val()
|
||||
$('.mr_target_commit').empty();
|
||||
|
||||
return axios.get(this.opts.targetProjectUrl, {
|
||||
params: {
|
||||
target_project_id: $("input[name='merge_request[target_project_id]']").val(),
|
||||
},
|
||||
beforeSend: function() {
|
||||
return $('.mr_target_commit').empty();
|
||||
},
|
||||
success: function(html) {
|
||||
return $('.js-target-branch-dropdown .dropdown-content').html(html);
|
||||
}
|
||||
}).then(({ data }) => {
|
||||
$('.js-target-branch-dropdown .dropdown-content').html(data);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -68,22 +66,19 @@ export default class Compare {
|
|||
});
|
||||
}
|
||||
|
||||
static sendAjax(url, loading, target, data) {
|
||||
var $target;
|
||||
$target = $(target);
|
||||
return $.ajax({
|
||||
url: url,
|
||||
data: data,
|
||||
beforeSend: function() {
|
||||
loading.show();
|
||||
return $target.empty();
|
||||
},
|
||||
success: function(html) {
|
||||
loading.hide();
|
||||
$target.html(html);
|
||||
var className = '.' + $target[0].className.replace(' ', '.');
|
||||
localTimeAgo($('.js-timeago', className));
|
||||
}
|
||||
static sendAjax(url, loading, target, params) {
|
||||
const $target = $(target);
|
||||
|
||||
loading.show();
|
||||
$target.empty();
|
||||
|
||||
return axios.get(url, {
|
||||
params,
|
||||
}).then(({ data }) => {
|
||||
loading.hide();
|
||||
$target.html(data);
|
||||
const className = '.' + $target[0].className.replace(' ', '.');
|
||||
localTimeAgo($('.js-timeago', className));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, one-var, no-var, one-var-declaration-per-line, object-shorthand, comma-dangle, prefer-arrow-callback, no-else-return, newline-per-chained-call, wrap-iife, max-len */
|
||||
import { __ } from './locale';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import flash from './flash';
|
||||
|
||||
export default function initCompareAutocomplete() {
|
||||
$('.js-compare-dropdown').each(function() {
|
||||
|
@ -10,15 +13,14 @@ export default function initCompareAutocomplete() {
|
|||
const $filterInput = $('input[type="search"]', $dropdownContainer);
|
||||
$dropdown.glDropdown({
|
||||
data: function(term, callback) {
|
||||
return $.ajax({
|
||||
url: $dropdown.data('refs-url'),
|
||||
data: {
|
||||
axios.get($dropdown.data('refsUrl'), {
|
||||
params: {
|
||||
ref: $dropdown.data('ref'),
|
||||
search: term,
|
||||
}
|
||||
}).done(function(refs) {
|
||||
return callback(refs);
|
||||
});
|
||||
},
|
||||
}).then(({ data }) => {
|
||||
callback(data);
|
||||
}).catch(() => flash(__('Error fetching refs')));
|
||||
},
|
||||
selectable: true,
|
||||
filterable: true,
|
||||
|
|
|
@ -12,6 +12,7 @@ export default class CreateItemDropdown {
|
|||
this.fieldName = options.fieldName;
|
||||
this.onSelect = options.onSelect || (() => {});
|
||||
this.getDataOption = options.getData;
|
||||
this.createNewItemFromValueOption = options.createNewItemFromValue;
|
||||
this.$dropdown = options.$dropdown;
|
||||
this.$dropdownContainer = this.$dropdown.parent();
|
||||
this.$dropdownFooter = this.$dropdownContainer.find('.dropdown-footer');
|
||||
|
@ -30,15 +31,15 @@ export default class CreateItemDropdown {
|
|||
filterable: true,
|
||||
remote: false,
|
||||
search: {
|
||||
fields: ['title'],
|
||||
fields: ['text'],
|
||||
},
|
||||
selectable: true,
|
||||
toggleLabel(selected) {
|
||||
return (selected && 'id' in selected) ? selected.title : this.defaultToggleLabel;
|
||||
return (selected && 'id' in selected) ? _.escape(selected.title) : this.defaultToggleLabel;
|
||||
},
|
||||
fieldName: this.fieldName,
|
||||
text(item) {
|
||||
return _.escape(item.title);
|
||||
return _.escape(item.text);
|
||||
},
|
||||
id(item) {
|
||||
return _.escape(item.id);
|
||||
|
@ -51,6 +52,11 @@ export default class CreateItemDropdown {
|
|||
});
|
||||
}
|
||||
|
||||
clearDropdown() {
|
||||
this.$dropdownContainer.find('.dropdown-content').html('');
|
||||
this.$dropdownContainer.find('.dropdown-input-field').val('');
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.$createButton.on('click', this.onClickCreateWildcard.bind(this));
|
||||
}
|
||||
|
@ -58,9 +64,13 @@ export default class CreateItemDropdown {
|
|||
onClickCreateWildcard(e) {
|
||||
e.preventDefault();
|
||||
|
||||
this.refreshData();
|
||||
this.$dropdown.data('glDropdown').selectRowAtIndex();
|
||||
}
|
||||
|
||||
refreshData() {
|
||||
// Refresh the dropdown's data, which ends up calling `getData`
|
||||
this.$dropdown.data('glDropdown').remote.execute();
|
||||
this.$dropdown.data('glDropdown').selectRowAtIndex();
|
||||
}
|
||||
|
||||
getData(term, callback) {
|
||||
|
@ -79,20 +89,28 @@ export default class CreateItemDropdown {
|
|||
});
|
||||
}
|
||||
|
||||
toggleCreateNewButton(item) {
|
||||
if (item) {
|
||||
this.selectedItem = {
|
||||
title: item,
|
||||
id: item,
|
||||
text: item,
|
||||
};
|
||||
createNewItemFromValue(newValue) {
|
||||
if (this.createNewItemFromValueOption) {
|
||||
return this.createNewItemFromValueOption(newValue);
|
||||
}
|
||||
|
||||
return {
|
||||
title: newValue,
|
||||
id: newValue,
|
||||
text: newValue,
|
||||
};
|
||||
}
|
||||
|
||||
toggleCreateNewButton(newValue) {
|
||||
if (newValue) {
|
||||
this.selectedItem = this.createNewItemFromValue(newValue);
|
||||
|
||||
this.$dropdownContainer
|
||||
.find('.js-dropdown-create-new-item code')
|
||||
.text(item);
|
||||
.text(newValue);
|
||||
}
|
||||
|
||||
this.toggleFooter(!item);
|
||||
this.toggleFooter(!newValue);
|
||||
}
|
||||
|
||||
toggleFooter(toggleState) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* eslint-disable no-new */
|
||||
import _ from 'underscore';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import Flash from './flash';
|
||||
import DropLab from './droplab/drop_lab';
|
||||
import ISetter from './droplab/plugins/input_setter';
|
||||
|
@ -74,60 +75,52 @@ export default class CreateMergeRequestDropdown {
|
|||
}
|
||||
|
||||
checkAbilityToCreateBranch() {
|
||||
return $.ajax({
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
url: this.canCreatePath,
|
||||
beforeSend: () => this.setUnavailableButtonState(),
|
||||
})
|
||||
.done((data) => {
|
||||
this.setUnavailableButtonState(false);
|
||||
this.setUnavailableButtonState();
|
||||
|
||||
if (data.can_create_branch) {
|
||||
this.available();
|
||||
this.enable();
|
||||
axios.get(this.canCreatePath)
|
||||
.then(({ data }) => {
|
||||
this.setUnavailableButtonState(false);
|
||||
|
||||
if (!this.droplabInitialized) {
|
||||
this.droplabInitialized = true;
|
||||
this.initDroplab();
|
||||
this.bindEvents();
|
||||
if (data.can_create_branch) {
|
||||
this.available();
|
||||
this.enable();
|
||||
|
||||
if (!this.droplabInitialized) {
|
||||
this.droplabInitialized = true;
|
||||
this.initDroplab();
|
||||
this.bindEvents();
|
||||
}
|
||||
} else if (data.has_related_branch) {
|
||||
this.hide();
|
||||
}
|
||||
} else if (data.has_related_branch) {
|
||||
this.hide();
|
||||
}
|
||||
}).fail(() => {
|
||||
this.unavailable();
|
||||
this.disable();
|
||||
new Flash('Failed to check if a new branch can be created.');
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
this.unavailable();
|
||||
this.disable();
|
||||
Flash('Failed to check if a new branch can be created.');
|
||||
});
|
||||
}
|
||||
|
||||
createBranch() {
|
||||
return $.ajax({
|
||||
method: 'POST',
|
||||
dataType: 'json',
|
||||
url: this.createBranchPath,
|
||||
beforeSend: () => (this.isCreatingBranch = true),
|
||||
})
|
||||
.done((data) => {
|
||||
this.branchCreated = true;
|
||||
window.location.href = data.url;
|
||||
})
|
||||
.fail(() => new Flash('Failed to create a branch for this issue. Please try again.'));
|
||||
this.isCreatingBranch = true;
|
||||
|
||||
return axios.post(this.createBranchPath)
|
||||
.then(({ data }) => {
|
||||
this.branchCreated = true;
|
||||
window.location.href = data.url;
|
||||
})
|
||||
.catch(() => Flash('Failed to create a branch for this issue. Please try again.'));
|
||||
}
|
||||
|
||||
createMergeRequest() {
|
||||
return $.ajax({
|
||||
method: 'POST',
|
||||
dataType: 'json',
|
||||
url: this.createMrPath,
|
||||
beforeSend: () => (this.isCreatingMergeRequest = true),
|
||||
})
|
||||
.done((data) => {
|
||||
this.mergeRequestCreated = true;
|
||||
window.location.href = data.url;
|
||||
})
|
||||
.fail(() => new Flash('Failed to create Merge Request. Please try again.'));
|
||||
this.isCreatingMergeRequest = true;
|
||||
|
||||
return axios.post(this.createMrPath)
|
||||
.then(({ data }) => {
|
||||
this.mergeRequestCreated = true;
|
||||
window.location.href = data.url;
|
||||
})
|
||||
.catch(() => Flash('Failed to create Merge Request. Please try again.'));
|
||||
}
|
||||
|
||||
disable() {
|
||||
|
@ -200,39 +193,33 @@ export default class CreateMergeRequestDropdown {
|
|||
getRef(ref, target = 'all') {
|
||||
if (!ref) return false;
|
||||
|
||||
return $.ajax({
|
||||
method: 'GET',
|
||||
dataType: 'json',
|
||||
url: this.refsPath + ref,
|
||||
beforeSend: () => {
|
||||
this.isGettingRef = true;
|
||||
},
|
||||
})
|
||||
.always(() => {
|
||||
this.isGettingRef = false;
|
||||
})
|
||||
.done((data) => {
|
||||
const branches = data[Object.keys(data)[0]];
|
||||
const tags = data[Object.keys(data)[1]];
|
||||
let result;
|
||||
return axios.get(this.refsPath + ref)
|
||||
.then(({ data }) => {
|
||||
const branches = data[Object.keys(data)[0]];
|
||||
const tags = data[Object.keys(data)[1]];
|
||||
let result;
|
||||
|
||||
if (target === 'branch') {
|
||||
result = CreateMergeRequestDropdown.findByValue(branches, ref);
|
||||
} else {
|
||||
result = CreateMergeRequestDropdown.findByValue(branches, ref, true) ||
|
||||
CreateMergeRequestDropdown.findByValue(tags, ref, true);
|
||||
this.suggestedRef = result;
|
||||
}
|
||||
if (target === 'branch') {
|
||||
result = CreateMergeRequestDropdown.findByValue(branches, ref);
|
||||
} else {
|
||||
result = CreateMergeRequestDropdown.findByValue(branches, ref, true) ||
|
||||
CreateMergeRequestDropdown.findByValue(tags, ref, true);
|
||||
this.suggestedRef = result;
|
||||
}
|
||||
|
||||
return this.updateInputState(target, ref, result);
|
||||
})
|
||||
.fail(() => {
|
||||
this.unavailable();
|
||||
this.disable();
|
||||
new Flash('Failed to get ref.');
|
||||
this.isGettingRef = false;
|
||||
|
||||
return false;
|
||||
});
|
||||
return this.updateInputState(target, ref, result);
|
||||
})
|
||||
.catch(() => {
|
||||
this.unavailable();
|
||||
this.disable();
|
||||
new Flash('Failed to get ref.');
|
||||
|
||||
this.isGettingRef = false;
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
getTargetData(target) {
|
||||
|
@ -332,12 +319,12 @@ export default class CreateMergeRequestDropdown {
|
|||
xhr = this.createBranch();
|
||||
}
|
||||
|
||||
xhr.fail(() => {
|
||||
xhr.catch(() => {
|
||||
this.isCreatingMergeRequest = false;
|
||||
this.isCreatingBranch = false;
|
||||
});
|
||||
|
||||
xhr.always(() => this.enable());
|
||||
this.enable();
|
||||
});
|
||||
|
||||
this.disable();
|
||||
}
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
<div v-else-if="hasKeys">
|
||||
<keys-panel
|
||||
title="Enabled deploy keys for this project"
|
||||
class="qa-project-deploy-keys"
|
||||
:keys="keys.enabled_keys"
|
||||
:store="store"
|
||||
:endpoint="endpoint"
|
||||
|
|
|
@ -53,10 +53,10 @@
|
|||
</i>
|
||||
</div>
|
||||
<div class="deploy-key-content key-list-item-info">
|
||||
<strong class="title">
|
||||
<strong class="title qa-key-title">
|
||||
{{ deployKey.title }}
|
||||
</strong>
|
||||
<div class="description">
|
||||
<div class="description qa-key-fingerprint">
|
||||
{{ deployKey.fingerprint }}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,36 +1,20 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, wrap-iife, no-shadow, consistent-return, one-var, one-var-declaration-per-line, camelcase, default-case, no-new, quotes, no-duplicate-case, no-case-declarations, no-fallthrough, max-len */
|
||||
import Milestone from './milestone';
|
||||
import NotificationsForm from './notifications_form';
|
||||
import notificationsDropdown from './notifications_dropdown';
|
||||
import LineHighlighter from './line_highlighter';
|
||||
import MergeRequest from './merge_request';
|
||||
import Sidebar from './right_sidebar';
|
||||
import Flash from './flash';
|
||||
import SecretValues from './behaviors/secret_values';
|
||||
import UserCallout from './user_callout';
|
||||
import BlobViewer from './blob/viewer/index';
|
||||
import GfmAutoComplete from './gfm_auto_complete';
|
||||
import Star from './star';
|
||||
import TreeView from './tree';
|
||||
import ZenMode from './zen_mode';
|
||||
import initSettingsPanels from './settings_panels';
|
||||
import PerformanceBar from './performance_bar';
|
||||
import initNotes from './init_notes';
|
||||
import initIssuableSidebar from './init_issuable_sidebar';
|
||||
import { ajaxGet, convertPermissionToBoolean } from './lib/utils/common_utils';
|
||||
import { convertPermissionToBoolean } from './lib/utils/common_utils';
|
||||
import GlFieldErrors from './gl_field_errors';
|
||||
import GLForm from './gl_form';
|
||||
import Shortcuts from './shortcuts';
|
||||
import ShortcutsNavigation from './shortcuts_navigation';
|
||||
import ShortcutsIssuable from './shortcuts_issuable';
|
||||
import U2FAuthenticate from './u2f/authenticate';
|
||||
import Diff from './diff';
|
||||
import SearchAutocomplete from './search_autocomplete';
|
||||
import Activities from './activities';
|
||||
|
||||
var Dispatcher;
|
||||
|
||||
(function() {
|
||||
var Dispatcher;
|
||||
|
||||
Dispatcher = (function() {
|
||||
function Dispatcher() {
|
||||
this.initSearch();
|
||||
|
@ -65,45 +49,30 @@ import Activities from './activities';
|
|||
});
|
||||
|
||||
switch (page) {
|
||||
case 'sessions:new':
|
||||
import('./pages/sessions/new')
|
||||
case 'projects:environments:metrics':
|
||||
import('./pages/projects/environments/metrics')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'projects:boards:show':
|
||||
case 'projects:boards:index':
|
||||
import('./pages/projects/boards/index')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
shortcut_handler = true;
|
||||
break;
|
||||
case 'projects:merge_requests:index':
|
||||
import('./pages/projects/merge_requests/index')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
shortcut_handler = true;
|
||||
break;
|
||||
case 'projects:issues:index':
|
||||
import('./pages/projects/issues/index')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
shortcut_handler = true;
|
||||
break;
|
||||
case 'projects:issues:show':
|
||||
import('./pages/projects/issues/show')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
shortcut_handler = true;
|
||||
break;
|
||||
case 'dashboard:milestones:index':
|
||||
import('./pages/dashboard/milestones/index')
|
||||
case 'projects:milestones:index':
|
||||
import('./pages/projects/milestones/index')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'projects:milestones:show':
|
||||
import('./pages/projects/milestones/show')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'groups:milestones:show':
|
||||
new Milestone();
|
||||
new Sidebar();
|
||||
import('./pages/groups/milestones/show')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'dashboard:milestones:show':
|
||||
import('./pages/dashboard/milestones/show')
|
||||
|
@ -131,7 +100,9 @@ import Activities from './activities';
|
|||
.catch(fail);
|
||||
break;
|
||||
case 'dashboard:todos:index':
|
||||
import('./pages/dashboard/todos/index').then(callDefault).catch(fail);
|
||||
import('./pages/dashboard/todos/index')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'admin:jobs:index':
|
||||
import('./pages/admin/jobs/index')
|
||||
|
@ -234,15 +205,21 @@ import Activities from './activities';
|
|||
.catch(fail);
|
||||
break;
|
||||
case 'projects:snippets:show':
|
||||
initNotes();
|
||||
new ZenMode();
|
||||
import('./pages/projects/snippets/show')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'projects:snippets:new':
|
||||
case 'projects:snippets:edit':
|
||||
case 'projects:snippets:create':
|
||||
import('./pages/projects/snippets/new')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'projects:snippets:edit':
|
||||
case 'projects:snippets:update':
|
||||
new GLForm($('.snippet-form'), true);
|
||||
new ZenMode();
|
||||
import('./pages/projects/snippets/edit')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'snippets:new':
|
||||
import('./pages/snippets/new')
|
||||
|
@ -265,8 +242,9 @@ import Activities from './activities';
|
|||
.catch(fail);
|
||||
break;
|
||||
case 'projects:releases:edit':
|
||||
new ZenMode();
|
||||
new GLForm($('.release-form'), true);
|
||||
import('./pages/projects/releases/edit')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'projects:merge_requests:show':
|
||||
new Diff();
|
||||
|
@ -310,19 +288,7 @@ import Activities from './activities';
|
|||
shortcut_handler = true;
|
||||
break;
|
||||
case 'projects:show':
|
||||
shortcut_handler = new ShortcutsNavigation();
|
||||
new NotificationsForm();
|
||||
new UserCallout({
|
||||
setCalloutPerProject: true,
|
||||
className: 'js-autodevops-banner',
|
||||
});
|
||||
|
||||
if ($('#tree-slider').length) new TreeView();
|
||||
if ($('.blob-viewer').length) new BlobViewer();
|
||||
if ($('.project-show-activity').length) new Activities();
|
||||
$('#tree-slider').waitForImages(function() {
|
||||
ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
|
||||
});
|
||||
shortcut_handler = true;
|
||||
break;
|
||||
case 'projects:edit':
|
||||
import('./pages/projects/edit')
|
||||
|
@ -353,9 +319,6 @@ import Activities from './activities';
|
|||
.catch(fail);
|
||||
break;
|
||||
case 'groups:show':
|
||||
import('./pages/groups/show')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
shortcut_handler = true;
|
||||
break;
|
||||
case 'groups:group_members:index':
|
||||
|
@ -364,7 +327,7 @@ import Activities from './activities';
|
|||
.catch(fail);
|
||||
break;
|
||||
case 'projects:project_members:index':
|
||||
import('./pages/projects/project_members/')
|
||||
import('./pages/projects/project_members')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
|
@ -477,18 +440,15 @@ import Activities from './activities';
|
|||
.catch(fail);
|
||||
break;
|
||||
case 'projects:settings:repository:show':
|
||||
// Initialize expandable settings panels
|
||||
initSettingsPanels();
|
||||
import('./pages/projects/settings/repository/show')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'projects:settings:ci_cd:show':
|
||||
// Initialize expandable settings panels
|
||||
initSettingsPanels();
|
||||
|
||||
const runnerToken = document.querySelector('.js-secret-runner-token');
|
||||
if (runnerToken) {
|
||||
const runnerTokenSecretValue = new SecretValues(runnerToken);
|
||||
runnerTokenSecretValue.init();
|
||||
}
|
||||
import('./pages/projects/settings/ci_cd/show')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'groups:settings:ci_cd:show':
|
||||
import('./pages/groups/settings/ci_cd/show')
|
||||
.then(callDefault)
|
||||
|
@ -496,13 +456,19 @@ import Activities from './activities';
|
|||
break;
|
||||
case 'ci:lints:create':
|
||||
case 'ci:lints:show':
|
||||
import('./pages/ci/lints').then(m => m.default()).catch(fail);
|
||||
import('./pages/ci/lints')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'users:show':
|
||||
import('./pages/users/show').then(callDefault).catch(fail);
|
||||
import('./pages/users/show')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'admin:conversational_development_index:show':
|
||||
import('./pages/admin/conversational_development_index/show').then(m => m.default()).catch(fail);
|
||||
import('./pages/admin/conversational_development_index/show')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'snippets:show':
|
||||
import('./pages/snippets/show')
|
||||
|
@ -510,7 +476,9 @@ import Activities from './activities';
|
|||
.catch(fail);
|
||||
break;
|
||||
case 'import:fogbugz:new_user_map':
|
||||
import('./pages/import/fogbugz/new_user_map').then(m => m.default()).catch(fail);
|
||||
import('./pages/import/fogbugz/new_user_map')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'profiles:personal_access_tokens:index':
|
||||
import('./pages/profiles/personal_access_tokens')
|
||||
|
@ -534,21 +502,23 @@ import Activities from './activities';
|
|||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'dashboard:groups:index':
|
||||
import('./pages/dashboard/groups/index')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
}
|
||||
switch (path[0]) {
|
||||
case 'sessions':
|
||||
import('./pages/sessions')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'omniauth_callbacks':
|
||||
if (!gon.u2f) break;
|
||||
const u2fAuthenticate = new U2FAuthenticate(
|
||||
$('#js-authenticate-u2f'),
|
||||
'#js-login-u2f-form',
|
||||
gon.u2f,
|
||||
document.querySelector('#js-login-2fa-device'),
|
||||
document.querySelector('.js-2fa-form'),
|
||||
);
|
||||
u2fAuthenticate.start();
|
||||
// needed in rspec
|
||||
gl.u2fAuthenticate = u2fAuthenticate;
|
||||
import('./pages/omniauth_callbacks')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'admin':
|
||||
import('./pages/admin')
|
||||
.then(callDefault)
|
||||
|
@ -598,12 +568,8 @@ import Activities from './activities';
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case 'dashboard':
|
||||
case 'root':
|
||||
new UserCallout();
|
||||
break;
|
||||
case 'profiles':
|
||||
import('./pages/profiles/index/')
|
||||
import('./pages/profiles/index')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
|
@ -624,23 +590,12 @@ import Activities from './activities';
|
|||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'show':
|
||||
new Star();
|
||||
notificationsDropdown();
|
||||
break;
|
||||
case 'wikis':
|
||||
import('./pages/projects/wikis')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
shortcut_handler = true;
|
||||
break;
|
||||
case 'snippets':
|
||||
if (path[2] === 'show') {
|
||||
new ZenMode();
|
||||
new LineHighlighter();
|
||||
new BlobViewer();
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -650,7 +605,9 @@ import Activities from './activities';
|
|||
}
|
||||
|
||||
if (document.querySelector('#peek')) {
|
||||
new PerformanceBar({ container: '#peek' });
|
||||
import('./performance_bar')
|
||||
.then(m => new m.default({ container: '#peek' })) // eslint-disable-line new-cap
|
||||
.catch(fail);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -669,8 +626,8 @@ import Activities from './activities';
|
|||
|
||||
return Dispatcher;
|
||||
})();
|
||||
})();
|
||||
|
||||
$(window).on('load', function() {
|
||||
new Dispatcher();
|
||||
});
|
||||
}).call(window);
|
||||
export default function initDispatcher() {
|
||||
return new Dispatcher();
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import Dropzone from 'dropzone';
|
|||
import _ from 'underscore';
|
||||
import './preview_markdown';
|
||||
import csrf from './lib/utils/csrf';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
|
||||
Dropzone.autoDiscover = false;
|
||||
|
||||
|
@ -235,25 +236,21 @@ export default function dropzoneInput(form) {
|
|||
uploadFile = (item, filename) => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', item, filename);
|
||||
return $.ajax({
|
||||
url: uploadsPath,
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
dataType: 'json',
|
||||
processData: false,
|
||||
contentType: false,
|
||||
headers: csrf.headers,
|
||||
beforeSend: () => {
|
||||
showSpinner();
|
||||
return closeAlertMessage();
|
||||
},
|
||||
success: (e, text, response) => {
|
||||
const md = response.responseJSON.link.markdown;
|
||||
|
||||
showSpinner();
|
||||
closeAlertMessage();
|
||||
|
||||
axios.post(uploadsPath, formData)
|
||||
.then(({ data }) => {
|
||||
const md = data.link.markdown;
|
||||
|
||||
insertToTextArea(filename, md);
|
||||
},
|
||||
error: response => showError(response.responseJSON.message),
|
||||
complete: () => closeSpinner(),
|
||||
});
|
||||
closeSpinner();
|
||||
})
|
||||
.catch((e) => {
|
||||
showError(e.response.data.message);
|
||||
closeSpinner();
|
||||
});
|
||||
};
|
||||
|
||||
updateAttachingMessage = (files, messageContainer) => {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* global dateFormat */
|
||||
|
||||
import Pikaday from 'pikaday';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import { parsePikadayDate, pikadayToString } from './lib/utils/datefix';
|
||||
|
||||
class DueDateSelect {
|
||||
|
@ -125,37 +126,30 @@ class DueDateSelect {
|
|||
}
|
||||
|
||||
submitSelectedDate(isDropdown) {
|
||||
return $.ajax({
|
||||
type: 'PUT',
|
||||
url: this.issueUpdateURL,
|
||||
data: this.datePayload,
|
||||
dataType: 'json',
|
||||
beforeSend: () => {
|
||||
const selectedDateValue = this.datePayload[this.abilityName].due_date;
|
||||
const displayedDateStyle = this.displayedDate !== 'No due date' ? 'bold' : 'no-value';
|
||||
const selectedDateValue = this.datePayload[this.abilityName].due_date;
|
||||
const displayedDateStyle = this.displayedDate !== 'No due date' ? 'bold' : 'no-value';
|
||||
|
||||
this.$loading.removeClass('hidden').fadeIn();
|
||||
this.$loading.removeClass('hidden').fadeIn();
|
||||
|
||||
if (isDropdown) {
|
||||
this.$dropdown.trigger('loading.gl.dropdown');
|
||||
this.$selectbox.hide();
|
||||
}
|
||||
|
||||
this.$value.css('display', '');
|
||||
this.$valueContent.html(`<span class='${displayedDateStyle}'>${this.displayedDate}</span>`);
|
||||
this.$sidebarValue.html(this.displayedDate);
|
||||
|
||||
$('.js-remove-due-date-holder').toggleClass('hidden', selectedDateValue.length);
|
||||
|
||||
return axios.put(this.issueUpdateURL, this.datePayload)
|
||||
.then(() => {
|
||||
if (isDropdown) {
|
||||
this.$dropdown.trigger('loading.gl.dropdown');
|
||||
this.$selectbox.hide();
|
||||
this.$dropdown.trigger('loaded.gl.dropdown');
|
||||
this.$dropdown.dropdown('toggle');
|
||||
}
|
||||
|
||||
this.$value.css('display', '');
|
||||
this.$valueContent.html(`<span class='${displayedDateStyle}'>${this.displayedDate}</span>`);
|
||||
this.$sidebarValue.html(this.displayedDate);
|
||||
|
||||
return selectedDateValue.length ?
|
||||
$('.js-remove-due-date-holder').removeClass('hidden') :
|
||||
$('.js-remove-due-date-holder').addClass('hidden');
|
||||
},
|
||||
}).done(() => {
|
||||
if (isDropdown) {
|
||||
this.$dropdown.trigger('loaded.gl.dropdown');
|
||||
this.$dropdown.dropdown('toggle');
|
||||
}
|
||||
return this.$loading.fadeOut();
|
||||
});
|
||||
return this.$loading.fadeOut();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ export default {
|
|||
>
|
||||
<div
|
||||
v-if="model.isLoadingFolderContent"
|
||||
:key="i">
|
||||
:key="`loading-item-${i}`">
|
||||
<loading-icon size="2" />
|
||||
</div>
|
||||
|
||||
|
@ -110,10 +110,10 @@ export default {
|
|||
:model="children"
|
||||
:can-create-deployment="canCreateDeployment"
|
||||
:can-read-environment="canReadEnvironment"
|
||||
:key="index"
|
||||
:key="`env-item-${i}-${index}`"
|
||||
/>
|
||||
|
||||
<div :key="i">
|
||||
<div :key="`sub-div-${i}`">
|
||||
<div class="text-center prepend-top-10">
|
||||
<a
|
||||
:href="folderUrl(model)"
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
import _ from 'underscore';
|
||||
import {
|
||||
getSelector,
|
||||
togglePopover,
|
||||
inserted,
|
||||
mouseenter,
|
||||
mouseleave,
|
||||
} from './feature_highlight_helper';
|
||||
|
||||
export function setupFeatureHighlightPopover(id, debounceTimeout = 300) {
|
||||
const $selector = $(getSelector(id));
|
||||
const $parent = $selector.parent();
|
||||
const $popoverContent = $parent.siblings('.feature-highlight-popover-content');
|
||||
const hideOnScroll = togglePopover.bind($selector, false);
|
||||
const debouncedMouseleave = _.debounce(mouseleave, debounceTimeout);
|
||||
|
||||
$selector
|
||||
// Setup popover
|
||||
.data('content', $popoverContent.prop('outerHTML'))
|
||||
.popover({
|
||||
html: true,
|
||||
// Override the existing template to add custom CSS classes
|
||||
template: `
|
||||
<div class="popover feature-highlight-popover" role="tooltip">
|
||||
<div class="arrow"></div>
|
||||
<div class="popover-content"></div>
|
||||
</div>
|
||||
`,
|
||||
})
|
||||
.on('mouseenter', mouseenter)
|
||||
.on('mouseleave', debouncedMouseleave)
|
||||
.on('inserted.bs.popover', inserted)
|
||||
.on('show.bs.popover', () => {
|
||||
window.addEventListener('scroll', hideOnScroll);
|
||||
})
|
||||
.on('hide.bs.popover', () => {
|
||||
window.removeEventListener('scroll', hideOnScroll);
|
||||
})
|
||||
// Display feature highlight
|
||||
.removeAttr('disabled');
|
||||
}
|
||||
|
||||
export function findHighestPriorityFeature() {
|
||||
let priorityFeature;
|
||||
|
||||
const sortedFeatureEls = [].slice.call(document.querySelectorAll('.js-feature-highlight')).sort((a, b) =>
|
||||
(a.dataset.highlightPriority || 0) < (b.dataset.highlightPriority || 0));
|
||||
|
||||
const [priorityFeatureEl] = sortedFeatureEls;
|
||||
if (priorityFeatureEl) {
|
||||
priorityFeature = priorityFeatureEl.dataset.highlight;
|
||||
}
|
||||
|
||||
return priorityFeature;
|
||||
}
|
||||
|
||||
export function highlightFeatures() {
|
||||
const priorityFeature = findHighestPriorityFeature();
|
||||
|
||||
if (priorityFeature) {
|
||||
setupFeatureHighlightPopover(priorityFeature);
|
||||
}
|
||||
|
||||
return priorityFeature;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
import axios from '../lib/utils/axios_utils';
|
||||
import { __ } from '../locale';
|
||||
import Flash from '../flash';
|
||||
import LazyLoader from '../lazy_loader';
|
||||
|
||||
export const getSelector = highlightId => `.js-feature-highlight[data-highlight=${highlightId}]`;
|
||||
|
||||
export function togglePopover(show) {
|
||||
const isAlreadyShown = this.hasClass('js-popover-show');
|
||||
if ((show && isAlreadyShown) || (!show && !isAlreadyShown)) {
|
||||
return false;
|
||||
}
|
||||
this.popover(show ? 'show' : 'hide');
|
||||
this.toggleClass('disable-animation js-popover-show', show);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function dismiss(highlightId) {
|
||||
axios.post(this.attr('data-dismiss-endpoint'), {
|
||||
feature_name: highlightId,
|
||||
})
|
||||
.catch(() => Flash(__('An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again.')));
|
||||
|
||||
togglePopover.call(this, false);
|
||||
this.hide();
|
||||
}
|
||||
|
||||
export function mouseleave() {
|
||||
if (!$('.popover:hover').length > 0) {
|
||||
const $featureHighlight = $(this);
|
||||
togglePopover.call($featureHighlight, false);
|
||||
}
|
||||
}
|
||||
|
||||
export function mouseenter() {
|
||||
const $featureHighlight = $(this);
|
||||
|
||||
const showedPopover = togglePopover.call($featureHighlight, true);
|
||||
if (showedPopover) {
|
||||
$('.popover')
|
||||
.on('mouseleave', mouseleave.bind($featureHighlight));
|
||||
}
|
||||
}
|
||||
|
||||
export function inserted() {
|
||||
const popoverId = this.getAttribute('aria-describedby');
|
||||
const highlightId = this.dataset.highlight;
|
||||
const $popover = $(this);
|
||||
const dismissWrapper = dismiss.bind($popover, highlightId);
|
||||
|
||||
$(`#${popoverId} .dismiss-feature-highlight`)
|
||||
.on('click', dismissWrapper);
|
||||
|
||||
const lazyImg = $(`#${popoverId} .feature-highlight-illustration`)[0];
|
||||
if (lazyImg) {
|
||||
LazyLoader.loadImage(lazyImg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import { highlightFeatures } from './feature_highlight';
|
||||
import bp from '../breakpoints';
|
||||
|
||||
export default function domContentLoaded() {
|
||||
if (bp.getBreakpointSize() === 'lg') {
|
||||
highlightFeatures();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', domContentLoaded);
|
|
@ -1,4 +1,5 @@
|
|||
import _ from 'underscore';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
|
||||
/**
|
||||
* Makes search request for content when user types a value in the search input.
|
||||
|
@ -54,32 +55,26 @@ export default class FilterableList {
|
|||
this.listFilterElement.removeEventListener('input', this.debounceFilter);
|
||||
}
|
||||
|
||||
filterResults(queryData) {
|
||||
filterResults(params) {
|
||||
if (this.isBusy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$(this.listHolderElement).fadeTo(250, 0.5);
|
||||
|
||||
return $.ajax({
|
||||
url: this.getFilterEndpoint(),
|
||||
data: queryData,
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
context: this,
|
||||
complete: this.onFilterComplete,
|
||||
beforeSend: () => {
|
||||
this.isBusy = true;
|
||||
},
|
||||
success: (response, textStatus, xhr) => {
|
||||
this.onFilterSuccess(response, xhr, queryData);
|
||||
},
|
||||
});
|
||||
this.isBusy = true;
|
||||
|
||||
return axios.get(this.getFilterEndpoint(), {
|
||||
params,
|
||||
}).then((res) => {
|
||||
this.onFilterSuccess(res, params);
|
||||
this.onFilterComplete();
|
||||
}).catch(() => this.onFilterComplete());
|
||||
}
|
||||
|
||||
onFilterSuccess(response, xhr, queryData) {
|
||||
if (response.html) {
|
||||
this.listHolderElement.innerHTML = response.html;
|
||||
onFilterSuccess(response, queryData) {
|
||||
if (response.data.html) {
|
||||
this.listHolderElement.innerHTML = response.data.html;
|
||||
}
|
||||
|
||||
// Change url so if user reload a page - search results are saved
|
||||
|
|
|
@ -118,14 +118,14 @@ export const showSubLevelItems = (el) => {
|
|||
moveSubItemsToPosition(el, subItems);
|
||||
};
|
||||
|
||||
export const mouseEnterTopItems = (el) => {
|
||||
export const mouseEnterTopItems = (el, timeout = getHideSubItemsInterval()) => {
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
timeoutId = setTimeout(() => {
|
||||
if (currentOpenMenu) hideMenu(currentOpenMenu);
|
||||
|
||||
showSubLevelItems(el);
|
||||
}, getHideSubItemsInterval());
|
||||
}, timeout);
|
||||
};
|
||||
|
||||
export const mouseLeaveTopItem = (el) => {
|
||||
|
|
|
@ -461,7 +461,7 @@ class GfmAutoComplete {
|
|||
const accentAChar = decodeURI('%C3%80');
|
||||
const accentYChar = decodeURI('%C3%BF');
|
||||
|
||||
const regexp = new RegExp(`^(?:\\B|[^a-zA-Z0-9_${atSymbolsWithoutBar}]|\\s)${resultantFlag}(?!${atSymbolsWithBar})((?:[A-Za-z${accentAChar}-${accentYChar}0-9_'.+-]|[^\\x00-\\x7a])*)$`, 'gi');
|
||||
const regexp = new RegExp(`^(?:\\B|[^a-zA-Z0-9_\`${atSymbolsWithoutBar}]|\\s)${resultantFlag}(?!${atSymbolsWithBar})((?:[A-Za-z${accentAChar}-${accentYChar}0-9_'.+-]|[^\\x00-\\x7a])*)$`, 'gi');
|
||||
|
||||
return regexp.exec(targetSubtext);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
/* global fuzzaldrinPlus */
|
||||
import _ from 'underscore';
|
||||
import fuzzaldrinPlus from 'fuzzaldrin-plus';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import { visitUrl } from './lib/utils/url_utility';
|
||||
import { isObject } from './lib/utils/type_utility';
|
||||
|
||||
|
@ -212,25 +213,17 @@ GitLabDropdownRemote = (function() {
|
|||
};
|
||||
|
||||
GitLabDropdownRemote.prototype.fetchData = function() {
|
||||
return $.ajax({
|
||||
url: this.dataEndpoint,
|
||||
dataType: this.options.dataType,
|
||||
beforeSend: (function(_this) {
|
||||
return function() {
|
||||
if (_this.options.beforeSend) {
|
||||
return _this.options.beforeSend();
|
||||
}
|
||||
};
|
||||
})(this),
|
||||
success: (function(_this) {
|
||||
return function(data) {
|
||||
if (_this.options.success) {
|
||||
return _this.options.success(data);
|
||||
}
|
||||
};
|
||||
})(this)
|
||||
});
|
||||
// Fetch the data through ajax if the data is a string
|
||||
if (this.options.beforeSend) {
|
||||
this.options.beforeSend();
|
||||
}
|
||||
|
||||
// Fetch the data through ajax if the data is a string
|
||||
return axios.get(this.dataEndpoint)
|
||||
.then(({ data }) => {
|
||||
if (this.options.success) {
|
||||
return this.options.success(data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return GitLabDropdownRemote;
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import flash from '../flash';
|
||||
import { __ } from '../locale';
|
||||
import axios from '../lib/utils/axios_utils';
|
||||
import ContributorsStatGraph from './stat_graph_contributors';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: document.querySelector('.js-graphs-show').dataset.projectGraphPath,
|
||||
dataType: 'json',
|
||||
success(data) {
|
||||
const url = document.querySelector('.js-graphs-show').dataset.projectGraphPath;
|
||||
|
||||
axios.get(url)
|
||||
.then(({ data }) => {
|
||||
const graph = new ContributorsStatGraph();
|
||||
graph.init(data);
|
||||
|
||||
|
@ -16,6 +18,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
|
||||
$('.stat-graph').fadeIn();
|
||||
$('.loading-graph').hide();
|
||||
},
|
||||
});
|
||||
})
|
||||
.catch(() => flash(__('Error fetching contributors data.')));
|
||||
});
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
import axios from './lib/utils/axios_utils';
|
||||
import flash from './flash';
|
||||
import { __ } from './locale';
|
||||
|
||||
export default class GroupLabelSubscription {
|
||||
constructor(container) {
|
||||
const $container = $(container);
|
||||
|
@ -13,14 +17,12 @@ export default class GroupLabelSubscription {
|
|||
event.preventDefault();
|
||||
|
||||
const url = this.$unsubscribeButtons.attr('data-url');
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url,
|
||||
}).done(() => {
|
||||
this.toggleSubscriptionButtons();
|
||||
this.$unsubscribeButtons.removeAttr('data-url');
|
||||
});
|
||||
axios.post(url)
|
||||
.then(() => {
|
||||
this.toggleSubscriptionButtons();
|
||||
this.$unsubscribeButtons.removeAttr('data-url');
|
||||
})
|
||||
.catch(() => flash(__('There was an error when unsubscribing from this label.')));
|
||||
}
|
||||
|
||||
subscribe(event) {
|
||||
|
@ -31,12 +33,9 @@ export default class GroupLabelSubscription {
|
|||
|
||||
this.$unsubscribeButtons.attr('data-url', url);
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url,
|
||||
}).done(() => {
|
||||
this.toggleSubscriptionButtons();
|
||||
});
|
||||
axios.post(url)
|
||||
.then(() => this.toggleSubscriptionButtons())
|
||||
.catch(() => flash(__('There was an error when subscribing to this label.')));
|
||||
}
|
||||
|
||||
toggleSubscriptionButtons() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import FilterableList from '~/filterable_list';
|
||||
import eventHub from './event_hub';
|
||||
import { getParameterByName } from '../lib/utils/common_utils';
|
||||
import { normalizeHeaders, getParameterByName } from '../lib/utils/common_utils';
|
||||
|
||||
export default class GroupFilterableList extends FilterableList {
|
||||
constructor({ form, filter, holder, filterEndpoint, pagePath, dropdownSel, filterInputField }) {
|
||||
|
@ -94,23 +94,14 @@ export default class GroupFilterableList extends FilterableList {
|
|||
this.form.querySelector(`[name="${this.filterInputField}"]`).value = '';
|
||||
}
|
||||
|
||||
onFilterSuccess(data, xhr, queryData) {
|
||||
onFilterSuccess(res, queryData) {
|
||||
const currentPath = this.getPagePath(queryData);
|
||||
|
||||
const paginationData = {
|
||||
'X-Per-Page': xhr.getResponseHeader('X-Per-Page'),
|
||||
'X-Page': xhr.getResponseHeader('X-Page'),
|
||||
'X-Total': xhr.getResponseHeader('X-Total'),
|
||||
'X-Total-Pages': xhr.getResponseHeader('X-Total-Pages'),
|
||||
'X-Next-Page': xhr.getResponseHeader('X-Next-Page'),
|
||||
'X-Prev-Page': xhr.getResponseHeader('X-Prev-Page'),
|
||||
};
|
||||
|
||||
window.history.replaceState({
|
||||
page: currentPath,
|
||||
}, document.title, currentPath);
|
||||
|
||||
eventHub.$emit('updateGroups', data, Object.prototype.hasOwnProperty.call(queryData, this.filterInputField));
|
||||
eventHub.$emit('updatePagination', paginationData);
|
||||
eventHub.$emit('updateGroups', res.data, Object.prototype.hasOwnProperty.call(queryData, this.filterInputField));
|
||||
eventHub.$emit('updatePagination', normalizeHeaders(res.headers));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import groupItemComponent from './components/group_item.vue';
|
|||
|
||||
Vue.use(Translate);
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
export default () => {
|
||||
const el = document.getElementById('js-groups-tree');
|
||||
|
||||
// Don't do anything if element doesn't exist (No groups)
|
||||
|
@ -71,4 +71,4 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import Vue from 'vue';
|
||||
import VueResource from 'vue-resource';
|
||||
|
||||
Vue.use(VueResource);
|
||||
import '../../vue_shared/vue_resource_interceptor';
|
||||
|
||||
export default class GroupsService {
|
||||
constructor(endpoint) {
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
export default class TransferDropdown {
|
||||
constructor() {
|
||||
this.groupDropdown = $('.js-groups-dropdown');
|
||||
this.parentInput = $('#new_parent_group_id');
|
||||
this.data = this.groupDropdown.data('data');
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.buildDropdown();
|
||||
}
|
||||
|
||||
buildDropdown() {
|
||||
const extraOptions = [{ id: '', text: 'No parent group' }, 'divider'];
|
||||
|
||||
this.groupDropdown.glDropdown({
|
||||
selectable: true,
|
||||
filterable: true,
|
||||
toggleLabel: item => item.text,
|
||||
search: { fields: ['text'] },
|
||||
data: extraOptions.concat(this.data),
|
||||
text: item => item.text,
|
||||
clicked: (options) => {
|
||||
const { e } = options;
|
||||
e.preventDefault();
|
||||
this.assignSelected(options.selectedObj);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
assignSelected(selected) {
|
||||
this.parentInput.val(selected.id);
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@
|
|||
>
|
||||
<repo-tab
|
||||
v-for="tab in openFiles"
|
||||
:key="tab.id"
|
||||
:key="tab.key"
|
||||
:tab="tab"
|
||||
/>
|
||||
</ul>
|
||||
|
|
|
@ -71,7 +71,7 @@ export const setResizingStatus = ({ commit }, resizing) => {
|
|||
export const checkCommitStatus = ({ state }) =>
|
||||
service
|
||||
.getBranchData(state.currentProjectId, state.currentBranchId)
|
||||
.then((data) => {
|
||||
.then(({ data }) => {
|
||||
const { id } = data.commit;
|
||||
const selectedBranch =
|
||||
state.projects[state.currentProjectId].branches[state.currentBranchId];
|
||||
|
@ -90,7 +90,7 @@ export const commitChanges = (
|
|||
) =>
|
||||
service
|
||||
.commit(state.currentProjectId, payload)
|
||||
.then((data) => {
|
||||
.then(({ data }) => {
|
||||
const { branch } = payload;
|
||||
if (!data.short_id) {
|
||||
flash(data.message, 'alert', document, null, false, true);
|
||||
|
@ -147,8 +147,8 @@ export const commitChanges = (
|
|||
})
|
||||
.catch((err) => {
|
||||
let errMsg = 'Error committing changes. Please try again.';
|
||||
if (err.responseJSON && err.responseJSON.message) {
|
||||
errMsg += ` (${stripHtml(err.responseJSON.message)})`;
|
||||
if (err.response.data && err.response.data.message) {
|
||||
errMsg += ` (${stripHtml(err.response.data.message)})`;
|
||||
}
|
||||
flash(errMsg, 'alert', document, null, false, true);
|
||||
window.dispatchEvent(new Event('resize'));
|
||||
|
|
|
@ -10,7 +10,7 @@ export const getBranchData = (
|
|||
!state.projects[`${projectId}`].branches[branchId])
|
||||
|| force) {
|
||||
service.getBranchData(`${projectId}`, branchId)
|
||||
.then((data) => {
|
||||
.then(({ data }) => {
|
||||
const { id } = data.commit;
|
||||
commit(types.SET_BRANCH, { projectPath: `${projectId}`, branchName: branchId, branch: data });
|
||||
commit(types.SET_BRANCH_WORKING_REFERENCE, { projectId, branchId, reference: id });
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Flash from '../flash';
|
||||
import axios from '../lib/utils/axios_utils';
|
||||
import flash from '../flash';
|
||||
|
||||
export default class IntegrationSettingsForm {
|
||||
constructor(formSelector) {
|
||||
|
@ -95,29 +96,26 @@ export default class IntegrationSettingsForm {
|
|||
*/
|
||||
testSettings(formData) {
|
||||
this.toggleSubmitBtnState(true);
|
||||
$.ajax({
|
||||
type: 'PUT',
|
||||
url: this.testEndPoint,
|
||||
data: formData,
|
||||
})
|
||||
.done((res) => {
|
||||
if (res.error) {
|
||||
new Flash(`${res.message} ${res.service_response}`, 'alert', document, {
|
||||
title: 'Save anyway',
|
||||
clickHandler: (e) => {
|
||||
e.preventDefault();
|
||||
this.$form.submit();
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this.$form.submit();
|
||||
}
|
||||
})
|
||||
.fail(() => {
|
||||
new Flash('Something went wrong on our end.');
|
||||
})
|
||||
.always(() => {
|
||||
this.toggleSubmitBtnState(false);
|
||||
});
|
||||
|
||||
return axios.put(this.testEndPoint, formData)
|
||||
.then(({ data }) => {
|
||||
if (data.error) {
|
||||
flash(`${data.message} ${data.service_response}`, 'alert', document, {
|
||||
title: 'Save anyway',
|
||||
clickHandler: (e) => {
|
||||
e.preventDefault();
|
||||
this.$form.submit();
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this.$form.submit();
|
||||
}
|
||||
|
||||
this.toggleSubmitBtnState(false);
|
||||
})
|
||||
.catch(() => {
|
||||
flash('Something went wrong on our end.');
|
||||
this.toggleSubmitBtnState(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* eslint-disable comma-dangle, quotes, consistent-return, func-names, array-callback-return, space-before-function-paren, prefer-arrow-callback, max-len, no-unused-expressions, no-sequences, no-underscore-dangle, no-unused-vars, no-param-reassign */
|
||||
import _ from 'underscore';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import Flash from './flash';
|
||||
|
||||
export default {
|
||||
|
@ -22,15 +23,9 @@ export default {
|
|||
},
|
||||
|
||||
submit() {
|
||||
const _this = this;
|
||||
const xhr = $.ajax({
|
||||
url: this.form.attr('action'),
|
||||
method: this.form.attr('method'),
|
||||
dataType: 'JSON',
|
||||
data: this.getFormDataAsObject()
|
||||
});
|
||||
xhr.done(() => window.location.reload());
|
||||
xhr.fail(() => this.onFormSubmitFailure());
|
||||
axios[this.form.attr('method')](this.form.attr('action'), this.getFormDataAsObject())
|
||||
.then(() => window.location.reload())
|
||||
.catch(() => this.onFormSubmitFailure());
|
||||
},
|
||||
|
||||
onFormSubmitFailure() {
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import axios from './lib/utils/axios_utils';
|
||||
import flash from './flash';
|
||||
import { __ } from './locale';
|
||||
import IssuableBulkUpdateSidebar from './issuable_bulk_update_sidebar';
|
||||
import IssuableBulkUpdateActions from './issuable_bulk_update_actions';
|
||||
|
||||
|
@ -20,23 +23,24 @@ export default class IssuableIndex {
|
|||
}
|
||||
|
||||
static resetIncomingEmailToken() {
|
||||
$('.incoming-email-token-reset').on('click', (e) => {
|
||||
const $resetToken = $('.incoming-email-token-reset');
|
||||
|
||||
$resetToken.on('click', (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
$.ajax({
|
||||
type: 'PUT',
|
||||
url: $('.incoming-email-token-reset').attr('href'),
|
||||
dataType: 'json',
|
||||
success(response) {
|
||||
$('#issuable_email').val(response.new_address).focus();
|
||||
},
|
||||
beforeSend() {
|
||||
$('.incoming-email-token-reset').text('resetting...');
|
||||
},
|
||||
complete() {
|
||||
$('.incoming-email-token-reset').text('reset it');
|
||||
},
|
||||
});
|
||||
$resetToken.text('resetting...');
|
||||
|
||||
axios.put($resetToken.attr('href'))
|
||||
.then(({ data }) => {
|
||||
$('#issuable_email').val(data.new_address).focus();
|
||||
|
||||
$resetToken.text('reset it');
|
||||
})
|
||||
.catch(() => {
|
||||
flash(__('There was an error when reseting email token.'));
|
||||
|
||||
$resetToken.text('reset it');
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, one-var, no-underscore-dangle, one-var-declaration-per-line, object-shorthand, no-unused-vars, no-new, comma-dangle, consistent-return, quotes, dot-notation, quote-props, prefer-arrow-callback, max-len */
|
||||
import 'vendor/jquery.waitforimages';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import { addDelimiter } from './lib/utils/text_utility';
|
||||
import Flash from './flash';
|
||||
import flash from './flash';
|
||||
import TaskList from './task_list';
|
||||
import CreateMergeRequestDropdown from './create_merge_request_dropdown';
|
||||
import IssuablesHelper from './helpers/issuables_helper';
|
||||
|
@ -42,12 +43,8 @@ export default class Issue {
|
|||
this.disableCloseReopenButton($button);
|
||||
|
||||
url = $button.attr('href');
|
||||
return $.ajax({
|
||||
type: 'PUT',
|
||||
url: url
|
||||
})
|
||||
.fail(() => new Flash(issueFailMessage))
|
||||
.done((data) => {
|
||||
return axios.put(url)
|
||||
.then(({ data }) => {
|
||||
const isClosedBadge = $('div.status-box-issue-closed');
|
||||
const isOpenBadge = $('div.status-box-open');
|
||||
const projectIssuesCounter = $('.issue_counter');
|
||||
|
@ -74,9 +71,10 @@ export default class Issue {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
new Flash(issueFailMessage);
|
||||
flash(issueFailMessage);
|
||||
}
|
||||
})
|
||||
.catch(() => flash(issueFailMessage))
|
||||
.then(() => {
|
||||
this.disableCloseReopenButton($button, false);
|
||||
});
|
||||
|
@ -115,24 +113,22 @@ export default class Issue {
|
|||
static initMergeRequests() {
|
||||
var $container;
|
||||
$container = $('#merge-requests');
|
||||
return $.getJSON($container.data('url')).fail(function() {
|
||||
return new Flash('Failed to load referenced merge requests');
|
||||
}).done(function(data) {
|
||||
if ('html' in data) {
|
||||
return $container.html(data.html);
|
||||
}
|
||||
});
|
||||
return axios.get($container.data('url'))
|
||||
.then(({ data }) => {
|
||||
if ('html' in data) {
|
||||
$container.html(data.html);
|
||||
}
|
||||
}).catch(() => flash('Failed to load referenced merge requests'));
|
||||
}
|
||||
|
||||
static initRelatedBranches() {
|
||||
var $container;
|
||||
$container = $('#related-branches');
|
||||
return $.getJSON($container.data('url')).fail(function() {
|
||||
return new Flash('Failed to load related branches');
|
||||
}).done(function(data) {
|
||||
if ('html' in data) {
|
||||
return $container.html(data.html);
|
||||
}
|
||||
});
|
||||
return axios.get($container.data('url'))
|
||||
.then(({ data }) => {
|
||||
if ('html' in data) {
|
||||
$container.html(data.html);
|
||||
}
|
||||
}).catch(() => flash('Failed to load related branches'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import _ from 'underscore';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import { visitUrl } from './lib/utils/url_utility';
|
||||
import bp from './breakpoints';
|
||||
import { numberToHumanSize } from './lib/utils/number_utils';
|
||||
|
@ -8,6 +9,7 @@ export default class Job {
|
|||
constructor(options) {
|
||||
this.timeout = null;
|
||||
this.state = null;
|
||||
this.fetchingStatusFavicon = false;
|
||||
this.options = options || $('.js-build-options').data();
|
||||
|
||||
this.pagePath = this.options.pagePath;
|
||||
|
@ -171,12 +173,23 @@ export default class Job {
|
|||
}
|
||||
|
||||
getBuildTrace() {
|
||||
return $.ajax({
|
||||
url: `${this.pagePath}/trace.json`,
|
||||
data: { state: this.state },
|
||||
return axios.get(`${this.pagePath}/trace.json`, {
|
||||
params: { state: this.state },
|
||||
})
|
||||
.done((log) => {
|
||||
setCiStatusFavicon(`${this.pagePath}/status.json`);
|
||||
.then((res) => {
|
||||
const log = res.data;
|
||||
|
||||
if (!this.fetchingStatusFavicon) {
|
||||
this.fetchingStatusFavicon = true;
|
||||
|
||||
setCiStatusFavicon(`${this.pagePath}/status.json`)
|
||||
.then(() => {
|
||||
this.fetchingStatusFavicon = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.fetchingStatusFavicon = false;
|
||||
});
|
||||
}
|
||||
|
||||
if (log.state) {
|
||||
this.state = log.state;
|
||||
|
@ -217,7 +230,7 @@ export default class Job {
|
|||
visitUrl(this.pagePath);
|
||||
}
|
||||
})
|
||||
.fail(() => {
|
||||
.catch(() => {
|
||||
this.$buildRefreshAnimation.remove();
|
||||
})
|
||||
.then(() => {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
/* eslint-disable comma-dangle, class-methods-use-this, no-underscore-dangle, no-param-reassign, no-unused-vars, consistent-return, func-names, space-before-function-paren, max-len */
|
||||
import Sortable from 'vendor/Sortable';
|
||||
|
||||
import Flash from './flash';
|
||||
import flash from './flash';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
|
||||
export default class LabelManager {
|
||||
constructor({ togglePriorityButton, prioritizedLabels, otherLabels } = {}) {
|
||||
|
@ -50,11 +51,12 @@ export default class LabelManager {
|
|||
if (persistState == null) {
|
||||
persistState = true;
|
||||
}
|
||||
let xhr;
|
||||
const _this = this;
|
||||
const url = $label.find('.js-toggle-priority').data('url');
|
||||
let $target = this.prioritizedLabels;
|
||||
let $from = this.otherLabels;
|
||||
const rollbackLabelPosition = this.rollbackLabelPosition.bind(this, $label, action);
|
||||
|
||||
if (action === 'remove') {
|
||||
$target = this.otherLabels;
|
||||
$from = this.prioritizedLabels;
|
||||
|
@ -71,40 +73,34 @@ export default class LabelManager {
|
|||
return;
|
||||
}
|
||||
if (action === 'remove') {
|
||||
xhr = $.ajax({
|
||||
url,
|
||||
type: 'DELETE'
|
||||
});
|
||||
axios.delete(url)
|
||||
.catch(rollbackLabelPosition);
|
||||
|
||||
// Restore empty message
|
||||
if (!$from.find('li').length) {
|
||||
$from.find('.empty-message').removeClass('hidden');
|
||||
}
|
||||
} else {
|
||||
xhr = this.savePrioritySort($label, action);
|
||||
this.savePrioritySort($label, action)
|
||||
.catch(rollbackLabelPosition);
|
||||
}
|
||||
return xhr.fail(this.rollbackLabelPosition.bind(this, $label, action));
|
||||
}
|
||||
|
||||
onPrioritySortUpdate() {
|
||||
const xhr = this.savePrioritySort();
|
||||
return xhr.fail(function() {
|
||||
return new Flash(this.errorMessage, 'alert');
|
||||
});
|
||||
this.savePrioritySort()
|
||||
.catch(() => flash(this.errorMessage));
|
||||
}
|
||||
|
||||
savePrioritySort() {
|
||||
return $.post({
|
||||
url: this.prioritizedLabels.data('url'),
|
||||
data: {
|
||||
label_ids: this.getSortedLabelsIds()
|
||||
}
|
||||
return axios.post(this.prioritizedLabels.data('url'), {
|
||||
label_ids: this.getSortedLabelsIds(),
|
||||
});
|
||||
}
|
||||
|
||||
rollbackLabelPosition($label, originalAction) {
|
||||
const action = originalAction === 'remove' ? 'add' : 'remove';
|
||||
this.toggleLabelPriority($label, action, false);
|
||||
return new Flash(this.errorMessage, 'alert');
|
||||
flash(this.errorMessage);
|
||||
}
|
||||
|
||||
getSortedLabelsIds() {
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
/* global Issuable */
|
||||
/* global ListLabel */
|
||||
import _ from 'underscore';
|
||||
import { __ } 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';
|
||||
|
||||
export default class LabelsSelect {
|
||||
constructor(els, options = {}) {
|
||||
|
@ -82,99 +85,96 @@ export default class LabelsSelect {
|
|||
}
|
||||
$loading.removeClass('hidden').fadeIn();
|
||||
$dropdown.trigger('loading.gl.dropdown');
|
||||
return $.ajax({
|
||||
type: 'PUT',
|
||||
url: issueUpdateURL,
|
||||
dataType: 'JSON',
|
||||
data: data
|
||||
}).done(function(data) {
|
||||
var labelCount, template, labelTooltipTitle, labelTitles;
|
||||
$loading.fadeOut();
|
||||
$dropdown.trigger('loaded.gl.dropdown');
|
||||
$selectbox.hide();
|
||||
data.issueURLSplit = issueURLSplit;
|
||||
labelCount = 0;
|
||||
if (data.labels.length) {
|
||||
template = labelHTMLTemplate(data);
|
||||
labelCount = data.labels.length;
|
||||
}
|
||||
else {
|
||||
template = labelNoneHTMLTemplate;
|
||||
}
|
||||
$value.removeAttr('style').html(template);
|
||||
$sidebarCollapsedValue.text(labelCount);
|
||||
axios.put(issueUpdateURL, data)
|
||||
.then(({ data }) => {
|
||||
var labelCount, template, labelTooltipTitle, labelTitles;
|
||||
$loading.fadeOut();
|
||||
$dropdown.trigger('loaded.gl.dropdown');
|
||||
$selectbox.hide();
|
||||
data.issueURLSplit = issueURLSplit;
|
||||
labelCount = 0;
|
||||
if (data.labels.length) {
|
||||
template = labelHTMLTemplate(data);
|
||||
labelCount = data.labels.length;
|
||||
}
|
||||
else {
|
||||
template = labelNoneHTMLTemplate;
|
||||
}
|
||||
$value.removeAttr('style').html(template);
|
||||
$sidebarCollapsedValue.text(labelCount);
|
||||
|
||||
if (data.labels.length) {
|
||||
labelTitles = data.labels.map(function(label) {
|
||||
return label.title;
|
||||
});
|
||||
if (data.labels.length) {
|
||||
labelTitles = data.labels.map(function(label) {
|
||||
return label.title;
|
||||
});
|
||||
|
||||
if (labelTitles.length > 5) {
|
||||
labelTitles = labelTitles.slice(0, 5);
|
||||
labelTitles.push('and ' + (data.labels.length - 5) + ' more');
|
||||
if (labelTitles.length > 5) {
|
||||
labelTitles = labelTitles.slice(0, 5);
|
||||
labelTitles.push('and ' + (data.labels.length - 5) + ' more');
|
||||
}
|
||||
|
||||
labelTooltipTitle = labelTitles.join(', ');
|
||||
}
|
||||
else {
|
||||
labelTooltipTitle = '';
|
||||
$sidebarLabelTooltip.tooltip('destroy');
|
||||
}
|
||||
|
||||
labelTooltipTitle = labelTitles.join(', ');
|
||||
}
|
||||
else {
|
||||
labelTooltipTitle = '';
|
||||
$sidebarLabelTooltip.tooltip('destroy');
|
||||
}
|
||||
$sidebarLabelTooltip
|
||||
.attr('title', labelTooltipTitle)
|
||||
.tooltip('fixTitle');
|
||||
|
||||
$sidebarLabelTooltip
|
||||
.attr('title', labelTooltipTitle)
|
||||
.tooltip('fixTitle');
|
||||
|
||||
$('.has-tooltip', $value).tooltip({
|
||||
container: 'body'
|
||||
});
|
||||
});
|
||||
$('.has-tooltip', $value).tooltip({
|
||||
container: 'body'
|
||||
});
|
||||
})
|
||||
.catch(() => flash(__('Error saving label update.')));
|
||||
};
|
||||
$dropdown.glDropdown({
|
||||
showMenuAbove: showMenuAbove,
|
||||
data: function(term, callback) {
|
||||
return $.ajax({
|
||||
url: labelUrl
|
||||
}).done(function(data) {
|
||||
data = _.chain(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();
|
||||
if ($dropdown.hasClass('js-extra-options')) {
|
||||
var extraData = [];
|
||||
if (showNo) {
|
||||
extraData.unshift({
|
||||
id: 0,
|
||||
title: 'No Label'
|
||||
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();
|
||||
if ($dropdown.hasClass('js-extra-options')) {
|
||||
var extraData = [];
|
||||
if (showNo) {
|
||||
extraData.unshift({
|
||||
id: 0,
|
||||
title: 'No Label'
|
||||
});
|
||||
}
|
||||
if (showAny) {
|
||||
extraData.unshift({
|
||||
isAny: true,
|
||||
title: 'Any Label'
|
||||
});
|
||||
}
|
||||
if (extraData.length) {
|
||||
extraData.push('divider');
|
||||
data = extraData.concat(data);
|
||||
}
|
||||
}
|
||||
if (showAny) {
|
||||
extraData.unshift({
|
||||
isAny: true,
|
||||
title: 'Any Label'
|
||||
});
|
||||
}
|
||||
if (extraData.length) {
|
||||
extraData.push('divider');
|
||||
data = extraData.concat(data);
|
||||
}
|
||||
}
|
||||
|
||||
callback(data);
|
||||
if (showMenuAbove) {
|
||||
$dropdown.data('glDropdown').positionMenuAbove();
|
||||
}
|
||||
});
|
||||
callback(data);
|
||||
if (showMenuAbove) {
|
||||
$dropdown.data('glDropdown').positionMenuAbove();
|
||||
}
|
||||
})
|
||||
.catch(() => flash(__('Error fetching labels.')));
|
||||
},
|
||||
renderRow: function(label, instance) {
|
||||
var $a, $li, color, colorEl, indeterminate, removesAll, selectedClass, spacing, i, marked, dropdownName, dropdownValue;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import axios from './axios_utils';
|
||||
import Cache from './cache';
|
||||
|
||||
class AjaxCache extends Cache {
|
||||
|
@ -18,25 +19,18 @@ class AjaxCache extends Cache {
|
|||
let pendingRequest = this.pendingRequests[endpoint];
|
||||
|
||||
if (!pendingRequest) {
|
||||
pendingRequest = new Promise((resolve, reject) => {
|
||||
// jQuery 2 is not Promises/A+ compatible (missing catch)
|
||||
$.ajax(endpoint) // eslint-disable-line promise/catch-or-return
|
||||
.then(data => resolve(data),
|
||||
(jqXHR, textStatus, errorThrown) => {
|
||||
const error = new Error(`${endpoint}: ${errorThrown}`);
|
||||
error.textStatus = textStatus;
|
||||
reject(error);
|
||||
},
|
||||
);
|
||||
})
|
||||
.then((data) => {
|
||||
this.internalStorage[endpoint] = data;
|
||||
delete this.pendingRequests[endpoint];
|
||||
})
|
||||
.catch((error) => {
|
||||
delete this.pendingRequests[endpoint];
|
||||
throw error;
|
||||
});
|
||||
pendingRequest = axios.get(endpoint)
|
||||
.then(({ data }) => {
|
||||
this.internalStorage[endpoint] = data;
|
||||
delete this.pendingRequests[endpoint];
|
||||
})
|
||||
.catch((e) => {
|
||||
const error = new Error(`${endpoint}: ${e.message}`);
|
||||
error.textStatus = e.message;
|
||||
|
||||
delete this.pendingRequests[endpoint];
|
||||
throw error;
|
||||
});
|
||||
|
||||
this.pendingRequests[endpoint] = pendingRequest;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,18 @@ axios.interceptors.response.use((config) => {
|
|||
window.activeVueResources -= 1;
|
||||
|
||||
return config;
|
||||
}, (e) => {
|
||||
window.activeVueResources -= 1;
|
||||
|
||||
return Promise.reject(e);
|
||||
});
|
||||
|
||||
export default axios;
|
||||
|
||||
/**
|
||||
* @return The adapter that axios uses for dispatching requests. This may be overwritten in tests.
|
||||
*
|
||||
* @see https://github.com/axios/axios/tree/master/lib/adapters
|
||||
* @see https://github.com/ctimmerm/axios-mock-adapter/blob/v1.12.0/src/index.js#L39
|
||||
*/
|
||||
export const getDefaultAdapter = () => axios.defaults.adapter;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import axios from './axios_utils';
|
||||
import { getLocationHash } from './url_utility';
|
||||
|
||||
export const getPagePath = (index = 0) => $('body').attr('data-page').split(':')[index];
|
||||
|
@ -27,16 +28,11 @@ export const isInIssuePage = () => {
|
|||
return page === 'issues' && action === 'show';
|
||||
};
|
||||
|
||||
export const ajaxGet = url => $.ajax({
|
||||
type: 'GET',
|
||||
url,
|
||||
dataType: 'script',
|
||||
});
|
||||
|
||||
export const ajaxPost = (url, data) => $.ajax({
|
||||
type: 'POST',
|
||||
url,
|
||||
data,
|
||||
export const ajaxGet = url => axios.get(url, {
|
||||
params: { format: 'js' },
|
||||
responseType: 'text',
|
||||
}).then(({ data }) => {
|
||||
$.globalEval(data);
|
||||
});
|
||||
|
||||
export const rstrip = (val) => {
|
||||
|
@ -382,22 +378,16 @@ export const resetFavicon = () => {
|
|||
}
|
||||
};
|
||||
|
||||
export const setCiStatusFavicon = (pageUrl) => {
|
||||
$.ajax({
|
||||
url: pageUrl,
|
||||
dataType: 'json',
|
||||
success: (data) => {
|
||||
export const setCiStatusFavicon = pageUrl =>
|
||||
axios.get(pageUrl)
|
||||
.then(({ data }) => {
|
||||
if (data && data.favicon) {
|
||||
setFavicon(data.favicon);
|
||||
} else {
|
||||
resetFavicon();
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
resetFavicon();
|
||||
},
|
||||
});
|
||||
};
|
||||
})
|
||||
.catch(resetFavicon);
|
||||
|
||||
export const spriteIcon = (icon, className = '') => {
|
||||
const classAttribute = className.length > 0 ? `class="${className}"` : '';
|
||||
|
@ -417,7 +407,6 @@ window.gl.utils = {
|
|||
getGroupSlug,
|
||||
isInIssuePage,
|
||||
ajaxGet,
|
||||
ajaxPost,
|
||||
rstrip,
|
||||
updateTooltipTitle,
|
||||
disableButtonIfEmptyField,
|
||||
|
|
|
@ -8,16 +8,16 @@ class UsersCache extends Cache {
|
|||
}
|
||||
|
||||
return Api.users('', { username })
|
||||
.then((users) => {
|
||||
if (!users.length) {
|
||||
.then(({ data }) => {
|
||||
if (!data.length) {
|
||||
throw new Error(`User "${username}" could not be found!`);
|
||||
}
|
||||
|
||||
if (users.length > 1) {
|
||||
if (data.length > 1) {
|
||||
throw new Error(`Expected username "${username}" to be unique!`);
|
||||
}
|
||||
|
||||
const user = users[0];
|
||||
const user = data[0];
|
||||
this.internalStorage[username] = user;
|
||||
return user;
|
||||
});
|
||||
|
|
|
@ -26,6 +26,7 @@ import './gl_dropdown';
|
|||
import initTodoToggle from './header';
|
||||
import initImporterStatus from './importer_status';
|
||||
import initLayoutNav from './layout_nav';
|
||||
import './feature_highlight/feature_highlight_options';
|
||||
import LazyLoader from './lazy_loader';
|
||||
import initLogoAnimation from './logo';
|
||||
import './milestone_select';
|
||||
|
@ -33,7 +34,7 @@ import './projects_dropdown';
|
|||
import './render_gfm';
|
||||
import initBreadcrumbs from './breadcrumb';
|
||||
|
||||
import './dispatcher';
|
||||
import initDispatcher from './dispatcher';
|
||||
|
||||
// eslint-disable-next-line global-require, import/no-commonjs
|
||||
if (process.env.NODE_ENV !== 'production') require('./test_utils/');
|
||||
|
@ -265,4 +266,6 @@ $(() => {
|
|||
removeFlashClickListener(flashEl);
|
||||
});
|
||||
}
|
||||
|
||||
initDispatcher();
|
||||
});
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* eslint-disable no-param-reassign, comma-dangle */
|
||||
import axios from '../lib/utils/axios_utils';
|
||||
|
||||
((global) => {
|
||||
global.mergeConflicts = global.mergeConflicts || {};
|
||||
|
@ -10,20 +11,11 @@
|
|||
}
|
||||
|
||||
fetchConflictsData() {
|
||||
return $.ajax({
|
||||
dataType: 'json',
|
||||
url: this.conflictsPath
|
||||
});
|
||||
return axios.get(this.conflictsPath);
|
||||
}
|
||||
|
||||
submitResolveConflicts(data) {
|
||||
return $.ajax({
|
||||
url: this.resolveConflictsPath,
|
||||
data: JSON.stringify(data),
|
||||
contentType: 'application/json',
|
||||
dataType: 'json',
|
||||
method: 'POST'
|
||||
});
|
||||
return axios.post(this.resolveConflictsPath, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,24 +38,23 @@ $(() => {
|
|||
showDiffViewTypeSwitcher() { return mergeConflictsStore.fileTextTypePresent(); }
|
||||
},
|
||||
created() {
|
||||
mergeConflictsService
|
||||
.fetchConflictsData()
|
||||
.done((data) => {
|
||||
mergeConflictsService.fetchConflictsData()
|
||||
.then(({ data }) => {
|
||||
if (data.type === 'error') {
|
||||
mergeConflictsStore.setFailedRequest(data.message);
|
||||
} else {
|
||||
mergeConflictsStore.setConflictsData(data);
|
||||
}
|
||||
})
|
||||
.error(() => {
|
||||
mergeConflictsStore.setFailedRequest();
|
||||
})
|
||||
.always(() => {
|
||||
|
||||
mergeConflictsStore.setLoadingState(false);
|
||||
|
||||
this.$nextTick(() => {
|
||||
syntaxHighlight($('.js-syntax-highlight'));
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
mergeConflictsStore.setLoadingState(false);
|
||||
mergeConflictsStore.setFailedRequest();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
|
@ -82,10 +81,10 @@ $(() => {
|
|||
|
||||
mergeConflictsService
|
||||
.submitResolveConflicts(mergeConflictsStore.getCommitData())
|
||||
.done((data) => {
|
||||
.then(({ data }) => {
|
||||
window.location.href = data.redirect_to;
|
||||
})
|
||||
.error(() => {
|
||||
.catch(() => {
|
||||
mergeConflictsStore.setSubmitState(false);
|
||||
new Flash('Failed to save merge conflicts resolutions. Please try again!');
|
||||
});
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
/* eslint-disable no-new, class-methods-use-this */
|
||||
|
||||
import Cookies from 'js-cookie';
|
||||
import Flash from './flash';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import flash from './flash';
|
||||
import BlobForkSuggestion from './blob/blob_fork_suggestion';
|
||||
import initChangesDropdown from './init_changes_dropdown';
|
||||
import bp from './breakpoints';
|
||||
|
@ -244,15 +245,22 @@ export default class MergeRequestTabs {
|
|||
if (this.commitsLoaded) {
|
||||
return;
|
||||
}
|
||||
this.ajaxGet({
|
||||
url: `${source}.json`,
|
||||
success: (data) => {
|
||||
|
||||
this.toggleLoading(true);
|
||||
|
||||
axios.get(`${source}.json`)
|
||||
.then(({ data }) => {
|
||||
document.querySelector('div#commits').innerHTML = data.html;
|
||||
localTimeAgo($('.js-timeago', 'div#commits'));
|
||||
this.commitsLoaded = true;
|
||||
this.scrollToElement('#commits');
|
||||
},
|
||||
});
|
||||
|
||||
this.toggleLoading(false);
|
||||
})
|
||||
.catch(() => {
|
||||
this.toggleLoading(false);
|
||||
flash('An error occurred while fetching this tab.');
|
||||
});
|
||||
}
|
||||
|
||||
mountPipelinesView() {
|
||||
|
@ -283,9 +291,10 @@ export default class MergeRequestTabs {
|
|||
// some pages like MergeRequestsController#new has query parameters on that anchor
|
||||
const urlPathname = parseUrlPathname(source);
|
||||
|
||||
this.ajaxGet({
|
||||
url: `${urlPathname}.json${location.search}`,
|
||||
success: (data) => {
|
||||
this.toggleLoading(true);
|
||||
|
||||
axios.get(`${urlPathname}.json${location.search}`)
|
||||
.then(({ data }) => {
|
||||
const $container = $('#diffs');
|
||||
$container.html(data.html);
|
||||
|
||||
|
@ -335,8 +344,13 @@ export default class MergeRequestTabs {
|
|||
// (discussion and diff tabs) and `:target` only applies to the first
|
||||
anchor.addClass('target');
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.toggleLoading(false);
|
||||
})
|
||||
.catch(() => {
|
||||
this.toggleLoading(false);
|
||||
flash('An error occurred while fetching this tab.');
|
||||
});
|
||||
}
|
||||
|
||||
// Show or hide the loading spinner
|
||||
|
@ -346,17 +360,6 @@ export default class MergeRequestTabs {
|
|||
$('.mr-loading-status .loading').toggle(status);
|
||||
}
|
||||
|
||||
ajaxGet(options) {
|
||||
const defaults = {
|
||||
beforeSend: () => this.toggleLoading(true),
|
||||
error: () => new Flash('An error occurred while fetching this tab.', 'alert'),
|
||||
complete: () => this.toggleLoading(false),
|
||||
dataType: 'json',
|
||||
type: 'GET',
|
||||
};
|
||||
$.ajax($.extend({}, defaults, options));
|
||||
}
|
||||
|
||||
diffViewType() {
|
||||
return $('.inline-parallel-buttons a.active').data('view-type');
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Flash from './flash';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import flash from './flash';
|
||||
|
||||
export default class Milestone {
|
||||
constructor() {
|
||||
|
@ -33,15 +34,12 @@ export default class Milestone {
|
|||
const tabElId = $target.attr('href');
|
||||
|
||||
if (endpoint && !$target.hasClass('is-loaded')) {
|
||||
$.ajax({
|
||||
url: endpoint,
|
||||
dataType: 'JSON',
|
||||
})
|
||||
.fail(() => new Flash('Error loading milestone tab'))
|
||||
.done((data) => {
|
||||
$(tabElId).html(data.html);
|
||||
$target.addClass('is-loaded');
|
||||
});
|
||||
axios.get(endpoint)
|
||||
.then(({ data }) => {
|
||||
$(tabElId).html(data.html);
|
||||
$target.addClass('is-loaded');
|
||||
})
|
||||
.catch(() => flash('Error loading milestone tab'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
/* global Issuable */
|
||||
/* global ListMilestone */
|
||||
import _ from 'underscore';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import { timeFor } from './lib/utils/datetime_utility';
|
||||
|
||||
export default class MilestoneSelect {
|
||||
|
@ -52,48 +53,47 @@ export default class MilestoneSelect {
|
|||
}
|
||||
return $dropdown.glDropdown({
|
||||
showMenuAbove: showMenuAbove,
|
||||
data: (term, callback) => $.ajax({
|
||||
url: milestonesUrl
|
||||
}).done((data) => {
|
||||
const extraOptions = [];
|
||||
if (showAny) {
|
||||
extraOptions.push({
|
||||
id: 0,
|
||||
name: '',
|
||||
title: 'Any Milestone'
|
||||
});
|
||||
}
|
||||
if (showNo) {
|
||||
extraOptions.push({
|
||||
id: -1,
|
||||
name: 'No Milestone',
|
||||
title: 'No Milestone'
|
||||
});
|
||||
}
|
||||
if (showUpcoming) {
|
||||
extraOptions.push({
|
||||
id: -2,
|
||||
name: '#upcoming',
|
||||
title: 'Upcoming'
|
||||
});
|
||||
}
|
||||
if (showStarted) {
|
||||
extraOptions.push({
|
||||
id: -3,
|
||||
name: '#started',
|
||||
title: 'Started'
|
||||
});
|
||||
}
|
||||
if (extraOptions.length) {
|
||||
extraOptions.push('divider');
|
||||
}
|
||||
data: (term, callback) => axios.get(milestonesUrl)
|
||||
.then(({ data }) => {
|
||||
const extraOptions = [];
|
||||
if (showAny) {
|
||||
extraOptions.push({
|
||||
id: 0,
|
||||
name: '',
|
||||
title: 'Any Milestone'
|
||||
});
|
||||
}
|
||||
if (showNo) {
|
||||
extraOptions.push({
|
||||
id: -1,
|
||||
name: 'No Milestone',
|
||||
title: 'No Milestone'
|
||||
});
|
||||
}
|
||||
if (showUpcoming) {
|
||||
extraOptions.push({
|
||||
id: -2,
|
||||
name: '#upcoming',
|
||||
title: 'Upcoming'
|
||||
});
|
||||
}
|
||||
if (showStarted) {
|
||||
extraOptions.push({
|
||||
id: -3,
|
||||
name: '#started',
|
||||
title: 'Started'
|
||||
});
|
||||
}
|
||||
if (extraOptions.length) {
|
||||
extraOptions.push('divider');
|
||||
}
|
||||
|
||||
callback(extraOptions.concat(data));
|
||||
if (showMenuAbove) {
|
||||
$dropdown.data('glDropdown').positionMenuAbove();
|
||||
}
|
||||
$(`[data-milestone-id="${selectedMilestone}"] > a`).addClass('is-active');
|
||||
}),
|
||||
callback(extraOptions.concat(data));
|
||||
if (showMenuAbove) {
|
||||
$dropdown.data('glDropdown').positionMenuAbove();
|
||||
}
|
||||
$(`[data-milestone-id="${selectedMilestone}"] > a`).addClass('is-active');
|
||||
}),
|
||||
renderRow: milestone => `
|
||||
<li data-milestone-id="${milestone.name}">
|
||||
<a href='#' class='dropdown-menu-milestone-link'>
|
||||
|
@ -200,26 +200,23 @@ export default class MilestoneSelect {
|
|||
data[abilityName].milestone_id = selected != null ? selected : null;
|
||||
$loading.removeClass('hidden').fadeIn();
|
||||
$dropdown.trigger('loading.gl.dropdown');
|
||||
return $.ajax({
|
||||
type: 'PUT',
|
||||
url: issueUpdateURL,
|
||||
data: data
|
||||
}).done((data) => {
|
||||
$dropdown.trigger('loaded.gl.dropdown');
|
||||
$loading.fadeOut();
|
||||
$selectBox.hide();
|
||||
$value.css('display', '');
|
||||
if (data.milestone != null) {
|
||||
data.milestone.full_path = this.currentProject.full_path;
|
||||
data.milestone.remaining = timeFor(data.milestone.due_date);
|
||||
data.milestone.name = data.milestone.title;
|
||||
$value.html(milestoneLinkTemplate(data.milestone));
|
||||
return $sidebarCollapsedValue.find('span').html(collapsedSidebarLabelTemplate(data.milestone));
|
||||
} else {
|
||||
$value.html(milestoneLinkNoneTemplate);
|
||||
return $sidebarCollapsedValue.find('span').text('No');
|
||||
}
|
||||
});
|
||||
return axios.put(issueUpdateURL, data)
|
||||
.then(({ data }) => {
|
||||
$dropdown.trigger('loaded.gl.dropdown');
|
||||
$loading.fadeOut();
|
||||
$selectBox.hide();
|
||||
$value.css('display', '');
|
||||
if (data.milestone != null) {
|
||||
data.milestone.full_path = this.currentProject.full_path;
|
||||
data.milestone.remaining = timeFor(data.milestone.due_date);
|
||||
data.milestone.name = data.milestone.title;
|
||||
$value.html(milestoneLinkTemplate(data.milestone));
|
||||
return $sidebarCollapsedValue.find('span').html(collapsedSidebarLabelTemplate(data.milestone));
|
||||
} else {
|
||||
$value.html(milestoneLinkNoneTemplate);
|
||||
return $sidebarCollapsedValue.find('span').text('No');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* eslint-disable no-new */
|
||||
import Flash from './flash';
|
||||
import flash from './flash';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
|
||||
/**
|
||||
* In each pipelines table we have a mini pipeline graph for each pipeline.
|
||||
|
@ -78,27 +79,22 @@ export default class MiniPipelineGraph {
|
|||
const button = e.relatedTarget;
|
||||
const endpoint = button.dataset.stageEndpoint;
|
||||
|
||||
return $.ajax({
|
||||
dataType: 'json',
|
||||
type: 'GET',
|
||||
url: endpoint,
|
||||
beforeSend: () => {
|
||||
this.renderBuildsList(button, '');
|
||||
this.toggleLoading(button);
|
||||
},
|
||||
success: (data) => {
|
||||
this.renderBuildsList(button, '');
|
||||
this.toggleLoading(button);
|
||||
|
||||
axios.get(endpoint)
|
||||
.then(({ data }) => {
|
||||
this.toggleLoading(button);
|
||||
this.renderBuildsList(button, data.html);
|
||||
this.stopDropdownClickPropagation();
|
||||
},
|
||||
error: () => {
|
||||
})
|
||||
.catch(() => {
|
||||
this.toggleLoading(button);
|
||||
if ($(button).parent().hasClass('open')) {
|
||||
$(button).dropdown('toggle');
|
||||
}
|
||||
new Flash('An error occurred while fetching the builds.', 'alert');
|
||||
},
|
||||
});
|
||||
flash('An error occurred while fetching the builds.', 'alert');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -76,7 +76,13 @@
|
|||
.then(data => this.store.storeDeploymentData(data))
|
||||
.catch(() => new Flash('Error getting deployment information.')),
|
||||
])
|
||||
.then(() => { this.showEmptyState = false; })
|
||||
.then(() => {
|
||||
if (this.store.groups.length < 1) {
|
||||
this.state = 'noData';
|
||||
return;
|
||||
}
|
||||
this.showEmptyState = false;
|
||||
})
|
||||
.catch(() => { this.state = 'unableToConnect'; });
|
||||
},
|
||||
|
||||
|
|
|
@ -34,16 +34,23 @@
|
|||
svgUrl: this.emptyGettingStartedSvgPath,
|
||||
title: 'Get started with performance monitoring',
|
||||
description: `Stay updated about the performance and health
|
||||
of your environment by configuring Prometheus to monitor your deployments.`,
|
||||
of your environment by configuring Prometheus to monitor your deployments.`,
|
||||
buttonText: 'Configure Prometheus',
|
||||
},
|
||||
loading: {
|
||||
svgUrl: this.emptyLoadingSvgPath,
|
||||
title: 'Waiting for performance data',
|
||||
description: `Creating graphs uses the data from the Prometheus server.
|
||||
If this takes a long time, ensure that data is available.`,
|
||||
If this takes a long time, ensure that data is available.`,
|
||||
buttonText: 'View documentation',
|
||||
},
|
||||
noData: {
|
||||
svgUrl: this.emptyUnableToConnectSvgPath,
|
||||
title: 'No data found',
|
||||
description: `You are connected to the Prometheus server, but there is currently
|
||||
no data to display.`,
|
||||
buttonText: 'Configure Prometheus',
|
||||
},
|
||||
unableToConnect: {
|
||||
svgUrl: this.emptyUnableToConnectSvgPath,
|
||||
title: 'Unable to connect to Prometheus server',
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Vue from 'vue';
|
||||
import Dashboard from './components/dashboard.vue';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => new Vue({
|
||||
export default () => new Vue({
|
||||
el: '#prometheus-graphs',
|
||||
render: createElement => createElement(Dashboard),
|
||||
}));
|
||||
});
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, no-var, wrap-iife, quotes, comma-dangle, one-var, one-var-declaration-per-line, no-mixed-operators, no-loop-func, no-floating-decimal, consistent-return, no-unused-vars, prefer-template, prefer-arrow-callback, camelcase, max-len */
|
||||
|
||||
import { __ } from '../locale';
|
||||
import axios from '../lib/utils/axios_utils';
|
||||
import flash from '../flash';
|
||||
import Raphael from './raphael';
|
||||
|
||||
export default (function() {
|
||||
|
@ -26,16 +29,13 @@ export default (function() {
|
|||
}
|
||||
|
||||
BranchGraph.prototype.load = function() {
|
||||
return $.ajax({
|
||||
url: this.options.url,
|
||||
method: "get",
|
||||
dataType: "json",
|
||||
success: $.proxy(function(data) {
|
||||
axios.get(this.options.url)
|
||||
.then(({ data }) => {
|
||||
$(".loading", this.element).hide();
|
||||
this.prepareData(data.days, data.commits);
|
||||
return this.buildGraph();
|
||||
}, this)
|
||||
});
|
||||
this.buildGraph();
|
||||
})
|
||||
.catch(() => __('Error fetching network graph.'));
|
||||
};
|
||||
|
||||
BranchGraph.prototype.prepareData = function(days, commits) {
|
||||
|
|
|
@ -16,6 +16,7 @@ import Autosize from 'autosize';
|
|||
import 'vendor/jquery.caret'; // required by jquery.atwho
|
||||
import 'vendor/jquery.atwho';
|
||||
import AjaxCache from '~/lib/utils/ajax_cache';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import { getLocationHash } from './lib/utils/url_utility';
|
||||
import Flash from './flash';
|
||||
import CommentTypeToggle from './comment_type_toggle';
|
||||
|
@ -23,7 +24,7 @@ import GLForm from './gl_form';
|
|||
import loadAwardsHandler from './awards_handler';
|
||||
import Autosave from './autosave';
|
||||
import TaskList from './task_list';
|
||||
import { ajaxPost, isInViewport, getPagePath, scrollToElement, isMetaKey } from './lib/utils/common_utils';
|
||||
import { isInViewport, getPagePath, scrollToElement, isMetaKey } from './lib/utils/common_utils';
|
||||
import imageDiffHelper from './image_diff/helpers/index';
|
||||
import { localTimeAgo } from './lib/utils/datetime_utility';
|
||||
|
||||
|
@ -252,26 +253,20 @@ export default class Notes {
|
|||
return;
|
||||
}
|
||||
this.refreshing = true;
|
||||
return $.ajax({
|
||||
url: this.notes_url,
|
||||
headers: { 'X-Last-Fetched-At': this.last_fetched_at },
|
||||
dataType: 'json',
|
||||
success: (function(_this) {
|
||||
return function(data) {
|
||||
var notes;
|
||||
notes = data.notes;
|
||||
_this.last_fetched_at = data.last_fetched_at;
|
||||
_this.setPollingInterval(data.notes.length);
|
||||
return $.each(notes, function(i, note) {
|
||||
_this.renderNote(note);
|
||||
});
|
||||
};
|
||||
})(this)
|
||||
}).always((function(_this) {
|
||||
return function() {
|
||||
return _this.refreshing = false;
|
||||
};
|
||||
})(this));
|
||||
axios.get(this.notes_url, {
|
||||
headers: {
|
||||
'X-Last-Fetched-At': this.last_fetched_at,
|
||||
},
|
||||
}).then(({ data }) => {
|
||||
const notes = data.notes;
|
||||
this.last_fetched_at = data.last_fetched_at;
|
||||
this.setPollingInterval(data.notes.length);
|
||||
$.each(notes, (i, note) => this.renderNote(note));
|
||||
|
||||
this.refreshing = false;
|
||||
}).catch(() => {
|
||||
this.refreshing = false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1404,7 +1399,7 @@ export default class Notes {
|
|||
* 2) Identify comment type; a) Main thread b) Discussion thread c) Discussion resolve
|
||||
* 3) Build temporary placeholder element (using `createPlaceholderNote`)
|
||||
* 4) Show placeholder note on UI
|
||||
* 5) Perform network request to submit the note using `ajaxPost`
|
||||
* 5) Perform network request to submit the note using `axios.post`
|
||||
* a) If request is successfully completed
|
||||
* 1. Remove placeholder element
|
||||
* 2. Show submitted Note element
|
||||
|
@ -1486,8 +1481,10 @@ export default class Notes {
|
|||
|
||||
/* eslint-disable promise/catch-or-return */
|
||||
// Make request to submit comment on server
|
||||
ajaxPost(formAction, formData)
|
||||
.then((note) => {
|
||||
axios.post(formAction, formData)
|
||||
.then((res) => {
|
||||
const note = res.data;
|
||||
|
||||
// Submission successful! remove placeholder
|
||||
$notesContainer.find(`#${noteUniqueId}`).remove();
|
||||
|
||||
|
@ -1560,7 +1557,7 @@ export default class Notes {
|
|||
}
|
||||
|
||||
$form.trigger('ajax:success', [note]);
|
||||
}).fail(() => {
|
||||
}).catch(() => {
|
||||
// Submission failed, remove placeholder note and show Flash error message
|
||||
$notesContainer.find(`#${noteUniqueId}`).remove();
|
||||
|
||||
|
@ -1599,7 +1596,7 @@ export default class Notes {
|
|||
*
|
||||
* 1) Get Form metadata
|
||||
* 2) Update note element with new content
|
||||
* 3) Perform network request to submit the updated note using `ajaxPost`
|
||||
* 3) Perform network request to submit the updated note using `axios.post`
|
||||
* a) If request is successfully completed
|
||||
* 1. Show submitted Note element
|
||||
* b) If request failed
|
||||
|
@ -1630,12 +1627,12 @@ export default class Notes {
|
|||
|
||||
/* eslint-disable promise/catch-or-return */
|
||||
// Make request to update comment on server
|
||||
ajaxPost(formAction, formData)
|
||||
.then((note) => {
|
||||
axios.post(formAction, formData)
|
||||
.then(({ data }) => {
|
||||
// Submission successful! render final note element
|
||||
this.updateNote(note, $editingNote);
|
||||
this.updateNote(data, $editingNote);
|
||||
})
|
||||
.fail(() => {
|
||||
.catch(() => {
|
||||
// Submission failed, revert back to original note
|
||||
$noteBodyText.html(_.escape(cachedNoteBodyText));
|
||||
$editingNote.removeClass('being-posted fade-in');
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
import { __ } from './locale';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import flash from './flash';
|
||||
|
||||
export default class NotificationsForm {
|
||||
constructor() {
|
||||
this.toggleCheckbox = this.toggleCheckbox.bind(this);
|
||||
|
@ -27,24 +31,20 @@ export default class NotificationsForm {
|
|||
saveEvent($checkbox, $parent) {
|
||||
const form = $parent.parents('form:first');
|
||||
|
||||
return $.ajax({
|
||||
url: form.attr('action'),
|
||||
method: form.attr('method'),
|
||||
dataType: 'json',
|
||||
data: form.serialize(),
|
||||
beforeSend: () => {
|
||||
this.showCheckboxLoadingSpinner($parent);
|
||||
},
|
||||
}).done((data) => {
|
||||
$checkbox.enable();
|
||||
if (data.saved) {
|
||||
$parent.find('.custom-notification-event-loading').toggleClass('fa-spin fa-spinner fa-check is-done');
|
||||
setTimeout(() => {
|
||||
$parent.removeClass('is-loading')
|
||||
.find('.custom-notification-event-loading')
|
||||
.toggleClass('fa-spin fa-spinner fa-check is-done');
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
this.showCheckboxLoadingSpinner($parent);
|
||||
|
||||
axios[form.attr('method')](form.attr('action'), form.serialize())
|
||||
.then(({ data }) => {
|
||||
$checkbox.enable();
|
||||
if (data.saved) {
|
||||
$parent.find('.custom-notification-event-loading').toggleClass('fa-spin fa-spinner fa-check is-done');
|
||||
setTimeout(() => {
|
||||
$parent.removeClass('is-loading')
|
||||
.find('.custom-notification-event-loading')
|
||||
.toggleClass('fa-spin fa-spinner fa-check is-done');
|
||||
}, 2000);
|
||||
}
|
||||
})
|
||||
.catch(() => flash(__('There was an error saving your notification settings.')));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { getParameterByName } from '~/lib/utils/common_utils';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import { removeParams } from './lib/utils/url_utility';
|
||||
|
||||
const ENDLESS_SCROLL_BOTTOM_PX = 400;
|
||||
|
@ -22,24 +23,22 @@ export default {
|
|||
|
||||
getOld() {
|
||||
this.loading.show();
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: this.url,
|
||||
data: `limit=${this.limit}&offset=${this.offset}`,
|
||||
dataType: 'json',
|
||||
error: () => this.loading.hide(),
|
||||
success: (data) => {
|
||||
this.append(data.count, this.prepareData(data.html));
|
||||
this.callback();
|
||||
|
||||
// keep loading until we've filled the viewport height
|
||||
if (!this.disable && !this.isScrollable()) {
|
||||
this.getOld();
|
||||
} else {
|
||||
this.loading.hide();
|
||||
}
|
||||
axios.get(this.url, {
|
||||
params: {
|
||||
limit: this.limit,
|
||||
offset: this.offset,
|
||||
},
|
||||
});
|
||||
}).then(({ data }) => {
|
||||
this.append(data.count, this.prepareData(data.html));
|
||||
this.callback();
|
||||
|
||||
// keep loading until we've filled the viewport height
|
||||
if (!this.disable && !this.isScrollable()) {
|
||||
this.getOld();
|
||||
} else {
|
||||
this.loading.hide();
|
||||
}
|
||||
}).catch(() => this.loading.hide());
|
||||
},
|
||||
|
||||
append(count, html) {
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import _ from 'underscore';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import flash from '~/flash';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
export default function initBroadcastMessagesForm() {
|
||||
$('input#broadcast_message_color').on('input', function onMessageColorInput() {
|
||||
|
@ -18,13 +21,15 @@ export default function initBroadcastMessagesForm() {
|
|||
if (message === '') {
|
||||
$('.js-broadcast-message-preview').text('Your message here');
|
||||
} else {
|
||||
$.ajax({
|
||||
url: previewPath,
|
||||
type: 'POST',
|
||||
data: {
|
||||
broadcast_message: { message },
|
||||
axios.post(previewPath, {
|
||||
broadcast_message: {
|
||||
message,
|
||||
},
|
||||
});
|
||||
})
|
||||
.then(({ data }) => {
|
||||
$('.js-broadcast-message-preview').html(data.message);
|
||||
})
|
||||
.catch(() => flash(__('An error occurred while rendering preview broadcast message')));
|
||||
}
|
||||
}, 250));
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
export default function UsagePing() {
|
||||
const usageDataUrl = $('.usage-data').data('endpoint');
|
||||
import axios from '../../../lib/utils/axios_utils';
|
||||
import { __ } from '../../../locale';
|
||||
import flash from '../../../flash';
|
||||
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: usageDataUrl,
|
||||
dataType: 'html',
|
||||
success(html) {
|
||||
$('.usage-data').html(html);
|
||||
},
|
||||
});
|
||||
export default function UsagePing() {
|
||||
const el = document.querySelector('.usage-data');
|
||||
|
||||
axios.get(el.dataset.endpoint, {
|
||||
responseType: 'text',
|
||||
}).then(({ data }) => {
|
||||
el.innerHTML = data;
|
||||
}).catch(() => flash(__('Error fetching usage ping data.')));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
import initGroupsList from '../../../../groups';
|
||||
|
||||
export default () => {
|
||||
initGroupsList();
|
||||
};
|
|
@ -1,3 +1,3 @@
|
|||
import projectSelect from '~/project_select';
|
||||
|
||||
export default projectSelect;
|
||||
document.addEventListener('DOMContentLoaded', projectSelect);
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import UsersSelect from '~/users_select';
|
||||
import { isMetaClick } from '~/lib/utils/common_utils';
|
||||
import { __ } from '../../../../locale';
|
||||
import flash from '../../../../flash';
|
||||
import axios from '../../../../lib/utils/axios_utils';
|
||||
|
||||
export default class Todos {
|
||||
constructor() {
|
||||
|
@ -59,18 +62,12 @@ export default class Todos {
|
|||
const target = e.target;
|
||||
target.setAttribute('disabled', true);
|
||||
target.classList.add('disabled');
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: target.dataset.href,
|
||||
dataType: 'json',
|
||||
data: {
|
||||
'_method': target.dataset.method,
|
||||
},
|
||||
success: (data) => {
|
||||
|
||||
axios[target.dataset.method](target.dataset.href)
|
||||
.then(({ data }) => {
|
||||
this.updateRowState(target);
|
||||
return this.updateBadges(data);
|
||||
},
|
||||
});
|
||||
this.updateBadges(data);
|
||||
}).catch(() => flash(__('Error updating todo status.')));
|
||||
}
|
||||
|
||||
updateRowState(target) {
|
||||
|
@ -98,19 +95,15 @@ export default class Todos {
|
|||
e.preventDefault();
|
||||
|
||||
const target = e.currentTarget;
|
||||
const requestData = { '_method': target.dataset.method, ids: this.todo_ids };
|
||||
target.setAttribute('disabled', true);
|
||||
target.classList.add('disabled');
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: target.dataset.href,
|
||||
dataType: 'json',
|
||||
data: requestData,
|
||||
success: (data) => {
|
||||
this.updateAllState(target, data);
|
||||
return this.updateBadges(data);
|
||||
},
|
||||
});
|
||||
|
||||
axios[target.dataset.method](target.dataset.href, {
|
||||
ids: this.todo_ids,
|
||||
}).then(({ data }) => {
|
||||
this.updateAllState(target, data);
|
||||
this.updateBadges(data);
|
||||
}).catch(() => flash(__('Error updating status for all todos.')));
|
||||
}
|
||||
|
||||
updateAllState(target, data) {
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import GroupsList from '~/groups_list';
|
||||
import Landing from '~/landing';
|
||||
import initGroupsList from '../../../groups';
|
||||
|
||||
export default function () {
|
||||
new GroupsList(); // eslint-disable-line no-new
|
||||
initGroupsList();
|
||||
const landingElement = document.querySelector('.js-explore-groups-landing');
|
||||
if (!landingElement) return;
|
||||
const exploreGroupsLanding = new Landing(
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import Activities from '~/activities';
|
||||
|
||||
export default new Activities();
|
||||
export default () => new Activities();
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
import groupAvatar from '~/group_avatar';
|
||||
import TransferDropdown from '~/groups/transfer_dropdown';
|
||||
|
||||
export default groupAvatar;
|
||||
export default () => {
|
||||
groupAvatar();
|
||||
new TransferDropdown(); // eslint-disable-line no-new
|
||||
};
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import Labels from '~/labels';
|
||||
|
||||
export default new Labels();
|
||||
export default () => new Labels();
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import Labels from '~/labels';
|
||||
|
||||
export default new Labels();
|
||||
export default () => new Labels();
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
import initMilestonesShow from '~/pages/milestones/shared/init_milestones_show';
|
||||
|
||||
export default initMilestonesShow;
|
|
@ -3,7 +3,9 @@ import SecretValues from '~/behaviors/secret_values';
|
|||
export default () => {
|
||||
const secretVariableTable = document.querySelector('.js-secret-variable-table');
|
||||
if (secretVariableTable) {
|
||||
const secretVariableTableValues = new SecretValues(secretVariableTable);
|
||||
const secretVariableTableValues = new SecretValues({
|
||||
container: secretVariableTable,
|
||||
});
|
||||
secretVariableTableValues.init();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -5,8 +5,9 @@ import notificationsDropdown from '~/notifications_dropdown';
|
|||
import NotificationsForm from '~/notifications_form';
|
||||
import ProjectsList from '~/projects_list';
|
||||
import ShortcutsNavigation from '~/shortcuts_navigation';
|
||||
import initGroupsList from '../../../groups';
|
||||
|
||||
export default () => {
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const newGroupChildWrapper = document.querySelector('.js-new-project-subgroup');
|
||||
new ShortcutsNavigation();
|
||||
new NotificationsForm();
|
||||
|
@ -16,4 +17,6 @@ export default () => {
|
|||
if (newGroupChildWrapper) {
|
||||
new NewGroupChild(newGroupChildWrapper);
|
||||
}
|
||||
};
|
||||
|
||||
initGroupsList();
|
||||
});
|
||||
|
|