Commit 142bbd90 authored by Jarka Kadlecova's avatar Jarka Kadlecova

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into 18608-lock-issues

# Conflicts:
#	app/assets/javascripts/notes/components/issue_comment_form.vue
parents fea7b9e6 b83dcd3a
......@@ -7,4 +7,5 @@
/vendor/
karma.config.js
webpack.config.js
svg.config.js
/app/assets/javascripts/locale/**/*.js
......@@ -176,11 +176,20 @@ build-package:
image: ruby:2.4-alpine
before_script:
- gem install gitlab --no-doc
# We need to download the script rather than clone the repo since the
# review-docs-cleanup job will not be able to run when the branch gets
# deleted (when merging the MR).
- apk add --update openssl
- wget https://gitlab.com/gitlab-org/gitlab-ce/raw/master/scripts/trigger-build-docs
- chmod 755 trigger-build-docs
services: []
cache: {}
dependencies: []
artifacts: {}
variables:
SETUP_DB: "false"
USE_BUNDLE_INSTALL: "false"
cache: {}
GIT_STRATEGY: none
when: manual
only:
- branches
......@@ -197,7 +206,7 @@ review-docs-deploy:
url: http://preview-$CI_COMMIT_REF_SLUG.$DOCS_REVIEW_APPS_DOMAIN/$DOCS_GITLAB_REPO_SUFFIX
on_stop: review-docs-cleanup
script:
- scripts/trigger-build-docs deploy
- ./trigger-build-docs deploy
# Cleanup remote environment of gitlab-docs
review-docs-cleanup:
......@@ -207,7 +216,7 @@ review-docs-cleanup:
name: review-docs/$CI_COMMIT_REF_NAME
action: stop
script:
- scripts/trigger-build-docs cleanup
- ./trigger-build-docs cleanup
# Retrieve knapsack and rspec_flaky reports
retrieve-tests-metadata:
......
This diff is collapsed.
......@@ -116,7 +116,7 @@ gem 'seed-fu', '~> 2.3.5'
# Markdown and HTML processing
gem 'html-pipeline', '~> 1.11.0'
gem 'deckar01-task_list', '2.0.0'
gem 'gitlab-markup', '~> 1.5.1'
gem 'gitlab-markup', '~> 1.6.2'
gem 'redcarpet', '~> 3.4'
gem 'RedCloth', '~> 4.3.2'
gem 'rdoc', '~> 4.2'
......@@ -128,7 +128,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.0'
gem 'nokogiri', '~> 1.8.1'
# Diffs
gem 'diffy', '~> 3.1.0'
......
......@@ -293,7 +293,7 @@ GEM
diff-lcs (~> 1.1)
mime-types (>= 1.16, < 3)
posix-spawn (~> 0.3)
gitlab-markup (1.5.1)
gitlab-markup (1.6.2)
gitlab_omniauth-ldap (2.0.4)
net-ldap (~> 0.16)
omniauth (~> 1.3)
......@@ -482,7 +482,7 @@ GEM
mime-types (2.99.3)
mimemagic (0.3.0)
mini_mime (0.1.4)
mini_portile2 (2.2.0)
mini_portile2 (2.3.0)
minitest (5.7.0)
mmap2 (2.2.7)
mousetrap-rails (1.4.6)
......@@ -496,8 +496,8 @@ GEM
net-ldap (0.16.0)
net-ssh (4.1.0)
netrc (0.11.0)
nokogiri (1.8.0)
mini_portile2 (~> 2.2.0)
nokogiri (1.8.1)
mini_portile2 (~> 2.3.0)
numerizer (0.1.1)
oauth (0.5.1)
oauth2 (1.4.0)
......@@ -1028,7 +1028,7 @@ DEPENDENCIES
gitaly-proto (~> 0.33.0)
github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-markup (~> 1.5.1)
gitlab-markup (~> 1.6.2)
gitlab_omniauth-ldap (~> 2.0.4)
gollum-lib (~> 4.2)
gollum-rugged_adapter (~> 0.4.4)
......@@ -1068,7 +1068,7 @@ DEPENDENCIES
mysql2 (~> 0.4.5)
net-ldap
net-ssh (~> 4.1.0)
nokogiri (~> 1.8.0)
nokogiri (~> 1.8.1)
oauth2 (~> 1.4)
octokit (~> 4.6.2)
oj (~> 2.17.4)
......
9.6.0-pre
10.1.0-pre
{"iconCount":134,"icons":["abuse","account","admin","angle-double-left","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-right","assignee","bold","book","branch","calendar","cancel","chevron-down","chevron-left","chevron-right","chevron-up","clock","code","comment-dots","comment-next","comment","comments","commit","credit-card","disk","doc_code","doc_image","doc_text","download","duplicate","earth","eye-slash","eye","file-additions","file-deletion","file-modified","filter","folder","fork","geo-nodes","git-merge","group","history","home","hook","issue-block","issue-child","issue-close","issue-duplicate","issue-new","issue-open-m","issue-open","issue-parent","issues","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","merge-request-close-m","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil","pipeline","play","plus-square-o","plus-square","plus","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","star-o","star","stop","talic","task-done","template","thump-down","thump-up","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 250 150"><g fill="none" fill-rule="evenodd"><g fill="#e5e5e5" transform="translate(0 102)"><rect width="74" height="4" x="34" y="21" opacity=".5" rx="2"/><path d="M152 23c0-1.105.887-2 1.998-2h4c1.104 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4A1.994 1.994 0 0 1 152 23m14 0c0-1.105.887-2 1.998-2h4c1.104 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4A1.994 1.994 0 0 1 166 23m14 0c0-1.105.887-2 1.998-2h4c1.104 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4A1.994 1.994 0 0 1 180 23m14 0c0-1.105.887-2 1.998-2h4c1.104 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4A1.994 1.994 0 0 1 194 23m14 0c0-1.105.887-2 1.998-2h4c1.104 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4A1.994 1.994 0 0 1 208 23"/></g><g fill="#31af64"><path fill-rule="nonzero" d="M19 144c-10.493 0-19-8.507-19-19s8.507-19 19-19 19 8.507 19 19-8.507 19-19 19m0-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 15"/><path d="M17.07 127.02l-2.829-2.829a1.995 1.995 0 0 0-2.828 0 1.995 1.995 0 0 0 0 2.828l4.243 4.243a1.995 1.995 0 0 0 2.822.006l7.79-7.79a1.997 1.997 0 0 0-.006-2.823 1.992 1.992 0 0 0-2.823-.006l-6.37 6.37"/></g><g fill="#e52c5a"><path fill-rule="nonzero" d="M126 149.5c-12.979 0-23.5-10.521-23.5-23.5s10.521-23.5 23.5-23.5 23.5 10.521 23.5 23.5-10.521 23.5-23.5 23.5m0-5c10.217 0 18.5-8.283 18.5-18.5s-8.283-18.5-18.5-18.5-18.5 8.283-18.5 18.5 8.283 18.5 18.5 18.5"/><path d="M130.24 126l2.833-2.833a3 3 0 0 0-4.243-4.243l-2.833 2.833-2.833-2.833a3 3 0 0 0-4.243 4.243l2.833 2.833-2.833 2.833a3 3 0 0 0 4.243 4.243l2.833-2.833 2.833 2.833a3 3 0 0 0 4.243-4.243L130.24 126"/></g><path fill="#e5e5e5" fill-rule="nonzero" d="M236 139c-7.732 0-14-6.268-14-14s6.268-14 14-14 14 6.268 14 14-6.268 14-14 14m0-4c5.523 0 10-4.477 10-10s-4.477-10-10-10-10 4.477-10 10 4.477 10 10 10"/><g transform="translate(73 4)"><path stroke="#e5e5e5" stroke-width="4" d="M64.82 76H98c4.419 0 8-3.579 8-7.99V7.99C106 3.577 102.417 0 98 0H8.009c-4.419 0-8 3.579-8 7.99v60.02c0 4.413 3.583 7.99 8 7.99h31.935l9.263 9.855a4.357 4.357 0 0 0 6.354 0L64.824 76"/><rect width="18" height="6" x="11" y="19" fill="#fc8a51" rx="3"/><rect width="18" height="6" x="35" y="35" fill="#e52c5a" rx="3"/><rect width="18" height="6" x="29" y="51" fill="#e5e5e5" rx="3"/><rect width="12" height="6" x="35" y="19" fill="#fde5d8" rx="3"/><rect width="12" height="6" x="53" y="51" fill="#e52c5a" rx="3"/><rect width="12" height="6" x="11" y="51" fill="#b5a7dd" rx="3"/><rect width="18" height="6" x="77" y="19" fill="#fc8a51" rx="3"/><rect width="18" height="6" x="11" y="35" fill="#fde5d8" rx="3"/><rect width="6" height="6" x="53" y="19" fill="#e52c5a" rx="3"/><g fill="#fde5d8"><rect width="6" height="6" x="65" y="19" rx="3"/><rect width="6" height="6" x="71" y="35" rx="3"/></g><rect width="6" height="6" x="59" y="35" fill="#e52c5a" rx="3"/></g><path fill="#6b4fbb" fill-rule="nonzero" d="M151.869 77.403c-13.26 9.264-31.649 7.977-43.484-3.858-13.279-13.279-13.279-34.806 0-48.084 13.278-13.278 34.805-13.278 48.083 0 11.836 11.836 13.118 30.23 3.858 43.485.133.111.262.229.387.354l15.556 15.555a6.004 6.004 0 0 1 0 8.486 5.997 5.997 0 0 1-8.486 0l-15.555-15.556a6.051 6.051 0 0 1-.355-.387m-1.06-9.512c10.154-10.154 10.154-26.617 0-36.77-10.153-10.154-26.616-10.154-36.77 0-10.153 10.153-10.153 26.616 0 36.77 10.154 10.153 26.617 10.153 36.77 0"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 446 249" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path id="a" d="M260.03 114h23.972v-.013c19.972-.53 36-16.887 36-36.987 0-20.435-16.565-37-37-37-.993 0-1.977.039-2.95.116-4.95-14.605-18.773-25.12-35.05-25.12a36.87 36.87 0 0 0-15.32 3.311c-6.649-9.841-17.909-16.311-30.68-16.311-20.435 0-37 16.565-37 37 0 .701.019 1.397.058 2.088C145.95 45.083 134 59.645 134 76.996c0 20.435 16.565 37 37 37 .324 0 .646-.004.968-.012"/><ellipse id="b" cx="41" cy="41" rx="41" ry="41"/><mask id="c" width="186" height="112" x="0" y="0" fill="#fff"><use xlink:href="#a"/></mask><mask id="d" width="82" height="82" x="0" y="0" fill="#fff"><use xlink:href="#b"/></mask></defs><g fill="none" fill-rule="evenodd"><path stroke="#b5a7dd" stroke-width="4" d="M228.415 137.792c8.443 17.156 21.89 32.082 39.688 42.358"/><path fill="#fb722e" d="M284.464 183.822a2.006 2.006 0 0 1 2.74-.727l6.914 3.992a2.001 2.001 0 0 1 .741 2.737 2.006 2.006 0 0 1-2.74.727l-6.914-3.992a2.001 2.001 0 0 1-.74-2.737m-5 8.66a2.006 2.006 0 0 1 2.74-.726l6.913 3.991a2.001 2.001 0 0 1 .741 2.737 2.006 2.006 0 0 1-2.74.727l-6.914-3.991a2.001 2.001 0 0 1-.74-2.737"/><path fill="#fde5d8" fill-rule="nonzero" d="M267.072 189.947l5.196 3a5.998 5.998 0 0 0 8.195-2.194l3.005-5.205a5.995 5.995 0 0 0-2.198-8.193l-5.196-3-9 15.588m6.032-18.447a3.005 3.005 0 0 1 4.098-1.11l6.07 3.505c4.784 2.761 6.426 8.871 3.662 13.658l-3.005 5.204c-2.76 4.782-8.875 6.42-13.659 3.658l-6.07-3.505a2.999 2.999 0 0 1-1.088-4.104l9.992-17.306"/><g fill-rule="nonzero"><path fill="#e5e5e5" d="M260.597 18.747C266.208 9.657 276.116 4 287 4c17.12 0 31 13.879 31 31 0 7.02-2.34 13.685-6.58 19.1l3.149 2.466A34.855 34.855 0 0 0 322 35.001c0-19.33-15.67-35-35-35-12.286 0-23.476 6.384-29.808 16.647l3.404 2.1"/><path fill="#b5a7dd" d="M281.982 23.991l-2.526 1.154-2.992-2.993a.4.4 0 0 0-.564.009l-1.738 1.738a.392.392 0 0 0-.009.564l2.987 2.987-1.147 2.524a12.26 12.26 0 0 0-1.04 3.883l-.269 2.76-4.08 1.093a.399.399 0 0 0-.275.492l.636 2.375c.06.223.273.346.485.29l4.087-1.096 1.611 2.262a12.017 12.017 0 0 0 2.827 2.828l2.26 1.612-1.094 4.08a.399.399 0 0 0 .29.485l2.374.636a.393.393 0 0 0 .493-.275l1.093-4.08 2.763-.267a12.14 12.14 0 0 0 3.862-1.035l2.526-1.154 2.992 2.992a.4.4 0 0 0 .564-.008l1.738-1.738a.392.392 0 0 0 .009-.564l-2.987-2.987 1.147-2.524a12.26 12.26 0 0 0 1.04-3.883l.27-2.76 4.08-1.093a.399.399 0 0 0 .274-.493l-.636-2.374a.393.393 0 0 0-.485-.29l-4.087 1.096-1.611-2.262a12.017 12.017 0 0 0-2.826-2.828l-2.26-1.612 1.093-4.08a.399.399 0 0 0-.29-.485l-2.373-.636a.393.393 0 0 0-.493.274l-1.094 4.081-2.763.266c-1.336.129-2.64.48-3.862 1.036m3.48-5.02l.375-1.4a4.393 4.393 0 0 1 5.392-3.103l2.375.636a4.399 4.399 0 0 1 3.117 5.383l-.375 1.401a16.077 16.077 0 0 1 3.761 3.767l1.405-.376a4.397 4.397 0 0 1 5.386 3.118l.636 2.375a4.398 4.398 0 0 1-3.103 5.39l-1.402.376a16.217 16.217 0 0 1-1.378 5.143l1.027 1.026a4.392 4.392 0 0 1-.008 6.22l-1.739 1.738a4.4 4.4 0 0 1-6.224.008l-1.028-1.028a16.09 16.09 0 0 1-5.14 1.381l-.376 1.4a4.393 4.393 0 0 1-5.392 3.104l-2.374-.636a4.399 4.399 0 0 1-3.118-5.383l.376-1.401a16.077 16.077 0 0 1-3.762-3.767l-1.404.376a4.397 4.397 0 0 1-5.386-3.118l-.637-2.374a4.398 4.398 0 0 1 3.103-5.391l1.402-.376a16.217 16.217 0 0 1 1.378-5.143l-1.026-1.026a4.392 4.392 0 0 1 .008-6.22l1.738-1.738a4.4 4.4 0 0 1 6.224-.008l1.028 1.028a16.09 16.09 0 0 1 5.141-1.381"/><path fill="#6b4fbb" d="M286.367 37.355a2.439 2.439 0 1 0 1.262-4.711 2.439 2.439 0 0 0-1.262 4.711m-1.035 3.864a6.44 6.44 0 1 1 3.333-12.44 6.44 6.44 0 0 1-3.333 12.44"/></g><use fill="#fff" stroke="#e5e5e5" stroke-width="8" mask="url(#c)" stroke-linejoin="round" xlink:href="#a"/><g transform="translate(175 58)"><use fill="#fff" stroke="#e5e5e5" stroke-width="8" mask="url(#d)" xlink:href="#b"/><g fill-rule="nonzero"><path fill="#e5e5e5" d="M41 78c20.435 0 37-16.565 37-37S61.435 4 41 4 4 20.565 4 41s16.565 37 37 37m0 4C18.356 82 0 63.644 0 41S18.356 0 41 0s41 18.356 41 41-18.356 41-41 41"/><path fill="#b5a7dd" d="M34.363 26.44l-2.527 1.154-3.211-3.211a1.495 1.495 0 0 0-2.117-.005l-2.131 2.13a1.504 1.504 0 0 0 .005 2.117l3.206 3.206-1.147 2.524a16.09 16.09 0 0 0-.897 2.503 16.08 16.08 0 0 0-.475 2.616l-.269 2.76-4.379 1.174a1.495 1.495 0 0 0-1.063 1.83l.78 2.911a1.504 1.504 0 0 0 1.836 1.054l4.387-1.176 1.612 2.263a15.954 15.954 0 0 0 3.737 3.742l2.26 1.612-1.173 4.38a1.495 1.495 0 0 0 1.053 1.835l2.908.78a1.504 1.504 0 0 0 1.83-1.063l1.174-4.38 2.763-.266a15.977 15.977 0 0 0 5.108-1.372l2.527-1.154 3.211 3.212a1.495 1.495 0 0 0 2.117.005l2.131-2.131a1.504 1.504 0 0 0-.005-2.117l-3.206-3.206 1.147-2.524a16.09 16.09 0 0 0 .897-2.503 16.1 16.1 0 0 0 .475-2.616l.269-2.76 4.379-1.173a1.495 1.495 0 0 0 1.063-1.83l-.78-2.912a1.504 1.504 0 0 0-1.836-1.054l-4.387 1.176-1.612-2.262a15.954 15.954 0 0 0-3.737-3.743l-2.26-1.612 1.173-4.38a1.495 1.495 0 0 0-1.053-1.835l-2.908-.779a1.504 1.504 0 0 0-1.83 1.063l-1.174 4.38-2.763.265c-1.767.17-3.493.636-5.108 1.373m4.726-5.355l.455-1.699a5.504 5.504 0 0 1 6.73-3.89l2.907.778a5.495 5.495 0 0 1 3.882 6.735l-.455 1.699a19.95 19.95 0 0 1 4.673 4.68l1.704-.457a5.503 5.503 0 0 1 6.734 3.886l.78 2.91a5.493 5.493 0 0 1-3.894 6.73l-1.701.455a20.134 20.134 0 0 1-.593 3.265 20.134 20.134 0 0 1-1.119 3.124l1.245 1.246a5.507 5.507 0 0 1 .008 7.774l-2.13 2.13a5.5 5.5 0 0 1-7.775-.001l-1.248-1.248c-2 .914-4.157 1.502-6.387 1.717l-.455 1.699a5.504 5.504 0 0 1-6.73 3.89l-2.907-.778a5.495 5.495 0 0 1-3.882-6.735l.455-1.699a19.95 19.95 0 0 1-4.673-4.68l-1.704.457a5.503 5.503 0 0 1-6.734-3.886l-.78-2.91a5.493 5.493 0 0 1 3.894-6.73l1.701-.455a20.258 20.258 0 0 1 1.712-6.389l-1.245-1.246a5.507 5.507 0 0 1-.008-7.774l2.13-2.13a5.5 5.5 0 0 1 7.775.001l1.248 1.248c2-.914 4.157-1.502 6.387-1.717"/><path fill="#6b4fbb" d="M39.965 44.863a4 4 0 1 0 2.07-7.727 4 4 0 0 0-2.07 7.727m-1.036 3.864a8 8 0 1 1 4.142-15.455 8 8 0 0 1-4.142 15.455"/></g></g><path fill="#e5e5e5" fill-rule="nonzero" d="M144 169.541v30.01a4.002 4.002 0 0 0 4 3.995h20c2.209 0 4-1.789 4-3.995v-30.01a4.002 4.002 0 0 0-4-3.995h-20c-2.209 0-4 1.789-4 3.995m-4 0c0-4.416 3.583-7.995 8-7.995h20c4.416 0 8 3.584 8 7.995v30.01c0 4.416-3.583 7.995-8 7.995h-20c-4.416 0-8-3.584-8-7.995v-30.01"/><g fill="#fb722e" transform="translate(140 161)"><rect width="4" height="11" x="10" y="18.545" rx="2"/><rect width="4" height="11" x="21" y="18.545" rx="2"/></g><path fill="#e5e5e5" fill-rule="nonzero" d="M445.16 245.34c-16.874-11.778-110.62-20.336-222.14-20.336-111.61 0-205.4 8.571-222.18 20.364a2 2 0 1 0 2.3 3.272c15.756-11.07 109.46-19.636 219.88-19.636 110.34 0 203.99 8.55 219.85 19.617a2.001 2.001 0 0 0 2.29-3.28"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="116" height="68" viewBox="181 0 116 68"><g fill="none" fill-rule="evenodd" transform="translate(182)"><rect width="78" height="34" x="37" y="34" fill="#FAFAFA" rx="3"/><rect width="78" height="34" x="31" y="28" fill="#FFF" stroke="#EEE" stroke-width="4" stroke-linecap="round" rx="3"/><path fill="#FFF" stroke="#FC6D26" stroke-width="3" d="M34 35.8c-.6 0-1.4 0-1.8.4L29 38.8c-1 .7-1.7.4-2-.7l-.6-4c0-.5-.5-1.2-1-1.5L22 30.2c-1-.6-1-1.5 0-2l3.7-2c.5-.2 1-.8 1.2-1.3l1-4.2c.3-1 1-1.3 2-.5l3 3c.3.3 1 .6 1.6.6l4.2-.3c1 0 1.5.7 1 1.7L38 29c-.3.6-.3 1.4 0 2l1.3 3.8c.4 1 0 1.8-1.2 1.6l-4-.6z" stroke-linecap="round"/><path fill="#FDE5D8" d="M51.6 14.3c-.2-.2-.8-.4-1-.3l-2.8.5c-.7 0-1-.4-.8-1l1-2.8V9.5L46.6 7c-.3-.7 0-1.2.8-1h2.7c.3 0 .8-.2 1-.5l2-2c.6-.5 1-.4 1.3.3l.7 2.8c0 .3.4.8.7 1l2.3 1.2c.7.3.7 1 0 1.3l-2.2 1.7-.6 1-.4 3c-.2.6-.7.8-1.3.4l-2-1.7zM5.4 43.2c-.2-.2-.5-.2-.7-.2l-1.8.3c-.6 0-1-.2-.7-.7l.7-1.8V40l-1-1.7c0-.4 0-.7.6-.7h1.8c.3 0 .6 0 .8-.2L6.5 36c.3-.3.7-.2.8.2l.5 2 .5.5 1.6.8c.3.2.3.7 0 1l-1.6 1c-.2 0-.4.4-.4.7l-.4 2c0 .3-.4.5-.8.2l-1.4-1.2zM10.4 9.2C10.2 9 10 9 9.7 9L8 9.3c-.6 0-1-.2-.7-.7L8 6.8V6L7 4.3c0-.4 0-.7.6-.7h1.8c.3 0 .6 0 .8-.2L11.5 2c.3-.3.7-.2.8.2l.5 2 .5.5 1.6.8c.3.2.3.7 0 1l-1.6 1c-.2 0-.4.4-.4.7l-.4 2c0 .3-.4.5-.8.2l-1.4-1.2z"/><rect width="52" height="4" x="43" y="38" fill="#EEE" rx="2"/><rect width="36" height="4" x="43" y="48" fill="#EEE" rx="2"/></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="116" height="68" viewBox="181 0 116 68"><g fill="none" fill-rule="evenodd" transform="translate(182)"><rect width="78" height="34" x="37" y="34" fill="#FAFAFA" rx="3"/><rect width="78" height="34" x="31" y="28" fill="#FFF" stroke="#EEE" stroke-width="4" stroke-linecap="round" rx="3"/><path fill="#FFF" stroke="#FC6D26" stroke-width="3" d="M34 35.8c-.6 0-1.4 0-1.8.4L29 38.8c-1 .7-1.7.4-2-.7l-.6-4c0-.5-.5-1.2-1-1.5L22 30.2c-1-.6-1-1.5 0-2l3.7-2c.5-.2 1-.8 1.2-1.3l1-4.2c.3-1 1-1.3 2-.5l3 3c.3.3 1 .6 1.6.6l4.2-.3c1 0 1.5.7 1 1.7L38 29c-.3.6-.3 1.4 0 2l1.3 3.8c.4 1 0 1.8-1.2 1.6l-4-.6z" stroke-linecap="round"/><path fill="#FDE5D8" d="M51.6 14.3c-.2-.2-.8-.4-1-.3l-2.8.5c-.7 0-1-.4-.8-1l1-2.8V9.5L46.6 7c-.3-.7 0-1.2.8-1h2.7c.3 0 .8-.2 1-.5l2-2c.6-.5 1-.4 1.3.3l.7 2.8c0 .3.4.8.7 1l2.3 1.2c.7.3.7 1 0 1.3l-2.2 1.7-.6 1-.4 3c-.2.6-.7.8-1.3.4l-2-1.7zM5.4 43.2c-.2-.2-.5-.2-.7-.2l-1.8.3c-.6 0-1-.2-.7-.7l.7-1.8V40l-1-1.7c0-.4 0-.7.6-.7h1.8c.3 0 .6 0 .8-.2L6.5 36c.3-.3.7-.2.8.2l.5 2 .5.5 1.6.8c.3.2.3.7 0 1l-1.6 1c-.2 0-.4.4-.4.7l-.4 2c0 .3-.4.5-.8.2l-1.4-1.2zm5-34C10.2 9 10 9 9.7 9L8 9.3c-.6 0-1-.2-.7-.7L8 6.8V6L7 4.3c0-.4 0-.7.6-.7h1.8c.3 0 .6 0 .8-.2L11.5 2c.3-.3.7-.2.8.2l.5 2 .5.5 1.6.8c.3.2.3.7 0 1l-1.6 1c-.2 0-.4.4-.4.7l-.4 2c0 .3-.4.5-.8.2l-1.4-1.2z"/><rect width="52" height="4" x="43" y="38" fill="#EEE" rx="2"/><rect width="36" height="4" x="43" y="48" fill="#EEE" rx="2"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 293 216"><g fill="none" fill-rule="evenodd"><g transform="rotate(-5 211.388 -693.89)"><rect width="163.6" height="200" x=".2" fill="#FFF" stroke="#EEE" stroke-width="3" stroke-linecap="round" stroke-dasharray="6 9" rx="6"/><g transform="translate(24 38)"><path fill="#FC6D26" d="M18.2 14l-4-3.8c-.4-.6-1.4-.6-2 0-.6.6-.6 1.5 0 2l5 5c.3.4.6.5 1 .5s.8 0 1-.4L28 8.8c.6-.6.6-1.5 0-2-.6-.7-1.6-.7-2 0L18 14z"/><path stroke="#6B4FBB" stroke-width="3" d="M27 23.3V27c0 2.3-1.7 4-4 4H4c-2.3 0-4-1.7-4-4V8c0-2.3 1.7-4 4-4h3.8" stroke-linecap="round"/><rect width="76" height="3" x="40" y="11" fill="#6B4FBB" opacity=".5" rx="1.5"/><rect width="43" height="3" x="40" y="21" fill="#6B4FBB" opacity=".5" rx="1.5"/></g><g transform="translate(24 83)"><path fill="#FC6D26" d="M18.2 14l-4-3.8c-.4-.6-1.4-.6-2 0-.6.6-.6 1.5 0 2l5 5c.3.4.6.5 1 .5s.8 0 1-.4L28 8.8c.6-.6.6-1.5 0-2-.6-.7-1.6-.7-2 0L18 14z"/><path stroke="#6B4FBB" stroke-width="3" d="M27 23.3V27c0 2.3-1.7 4-4 4H4c-2.3 0-4-1.7-4-4V8c0-2.3 1.7-4 4-4h3.8" stroke-linecap="round"/><rect width="76" height="3" x="40" y="11" fill="#B5A7DD" rx="1.5"/><rect width="43" height="3" x="40" y="21" fill="#B5A7DD" rx="1.5"/></g><g transform="translate(24 130)"><path fill="#FC6D26" d="M18.2 14l-4-3.8c-.4-.6-1.4-.6-2 0-.6.6-.6 1.5 0 2l5 5c.3.4.6.5 1 .5s.8 0 1-.4L28 8.8c.6-.6.6-1.5 0-2-.6-.7-1.6-.7-2 0L18 14z"/><path stroke="#6B4FBB" stroke-width="3" d="M27 23.3V27c0 2.3-1.7 4-4 4H4c-2.3 0-4-1.7-4-4V8c0-2.3 1.7-4 4-4h3.8" stroke-linecap="round"/><rect width="76" height="3" x="40" y="11" fill="#B5A7DD" rx="1.5"/><rect width="43" height="3" x="40" y="21" fill="#B5A7DD" rx="1.5"/></g></g><path fill="#FFCE29" d="M30 11l-1.8 4-2-4-4-1.8 4-2 2-4 2 4 4 2M286 60l-2.7 6.3-3-6-6-3 6-3 3-6 2.8 6.2 6.6 2.8M263 97l-2 4-2-4-4-2 4-2 2-4 2 4 4 2M12 85l-2.7 6.3-3-6-6-3 6-3 3-6 2.8 6.2 6.6 2.8"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 284 337" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><rect id="a" width="180" height="220" x="66.2" y="74.4" rx="6"/><mask id="l" width="180" height="220" x="0" y="0" fill="#fff"><use xlink:href="#a"/></mask><rect id="b" width="180" height="220" rx="6"/><mask id="m" width="180" height="220" x="0" y="0" fill="#fff"><use xlink:href="#b"/></mask><rect id="c" width="28" height="28" rx="4"/><mask id="n" width="28" height="28" x="0" y="0" fill="#fff"><use xlink:href="#c"/></mask><rect id="d" width="28" height="28" rx="4"/><mask id="o" width="28" height="28" x="0" y="0" fill="#fff"><use xlink:href="#d"/></mask><circle id="e" cx="21.5" cy="21.5" r="21.5"/><mask id="p" width="43" height="43" x="0" y="0" fill="#fff"><use xlink:href="#e"/></mask><circle id="f" cx="26.5" cy="26.5" r="26.5"/><mask id="q" width="53" height="53" x="0" y="0" fill="#fff"><use xlink:href="#f"/></mask><circle id="g" cx="9.5" cy="4.5" r="4.5"/><mask id="r" width="13" height="13" x="-2" y="-2"><path fill="#fff" d="M3-2h13v13H3z"/><use xlink:href="#g"/></mask><circle id="h" cx="26.5" cy="26.5" r="26.5"/><mask id="s" width="53" height="53" x="0" y="0" fill="#fff"><use xlink:href="#h"/></mask><circle id="i" cx="21.5" cy="21.5" r="21.5"/><mask id="t" width="43" height="43" x="0" y="0" fill="#fff"><use xlink:href="#i"/></mask><path id="j" d="M18 38h15c10.5 0 19-8.5 19-19S43.5 0 33 0H19C8.5 0 0 8.5 0 19c0 6.3 3 12 7.8 15.3l5.2 9c.6 1 1.4 1 2 0l3-5.3z"/><mask id="u" width="52" height="44" x="0" y="0" fill="#fff"><use xlink:href="#j"/></mask><circle id="k" cx="18.5" cy="18.5" r="18.5"/><mask id="v" width="37" height="37" x="0" y="0" fill="#fff"><use xlink:href="#k"/></mask></defs><g fill="none" fill-rule="evenodd" transform="translate(-6 -4)"><use stroke="#EEE" stroke-width="6" mask="url(#l)" transform="rotate(-5 156.245 184.425)" xlink:href="#a"/><g transform="rotate(5 -707.333 618.042)"><use fill="#FFF" stroke="#EEE" stroke-width="6" mask="url(#m)" xlink:href="#b"/><g transform="translate(29 24)"><path fill="#FC6D26" d="M18.2 14l-4-3.8c-.4-.6-1.4-.6-2 0-.6.6-.6 1.5 0 2l5 5c.3.4.6.5 1 .5s.8 0 1-.4L28 8.8c.6-.6.6-1.5 0-2-.6-.7-1.6-.7-2 0L18 14z"/><path stroke="#6B4FBB" stroke-width="3" d="M27 23.3V27c0 2.3-1.7 4-4 4H4c-2.3 0-4-1.7-4-4V8c0-2.3 1.7-4 4-4h3.8" stroke-linecap="round"/><rect width="86" height="3" x="40" y="11" fill="#6B4FBB" opacity=".5" rx="1.5"/><rect width="43" height="3" x="40" y="21" fill="#6B4FBB" opacity=".5" rx="1.5"/></g><g transform="translate(29 69)"><path fill="#FC6D26" d="M18.2 14l-4-3.8c-.4-.6-1.4-.6-2 0-.6.6-.6 1.5 0 2l5 5c.3.4.6.5 1 .5s.8 0 1-.4L28 8.8c.6-.6.6-1.5 0-2-.6-.7-1.6-.7-2 0L18 14z"/><path stroke="#6B4FBB" stroke-width="3" d="M27 23.3V27c0 2.3-1.7 4-4 4H4c-2.3 0-4-1.7-4-4V8c0-2.3 1.7-4 4-4h3.8" stroke-linecap="round"/><rect width="86" height="3" x="40" y="11" fill="#B5A7DD" rx="1.5"/><rect width="43" height="3" x="40" y="21" fill="#B5A7DD" rx="1.5"/></g><g transform="translate(28 160)"><use stroke="#E5E5E5" stroke-width="6" mask="url(#n)" opacity=".7" xlink:href="#c"/><rect width="26" height="3" x="41" y="7" fill="#ECECEC" rx="1.5"/><rect width="43" height="3" x="41" y="17" fill="#ECECEC" rx="1.5"/></g><g transform="translate(28 116)"><use stroke="#E5E5E5" stroke-width="6" mask="url(#o)" xlink:href="#d"/><rect width="86" height="3" x="41" y="7" fill="#E5E5E5" rx="1.5"/><rect width="43" height="3" x="41" y="17" fill="#E5E5E5" rx="1.5"/></g></g><g transform="rotate(-15 601.917 -782.362)"><use fill="#FFF" stroke="#B5A7DD" stroke-width="6" mask="url(#p)" xlink:href="#e"/><text fill="#6B4FBB" font-family="SourceSansPro-Black, Source Sans Pro" font-size="20" font-weight="700" letter-spacing="-.1"><tspan x="12" y="27">@</tspan></text></g><g transform="rotate(15 -686.59 1035.907)"><use fill="#FFF" stroke="#FDE5D8" stroke-width="6" mask="url(#q)" xlink:href="#f"/><path fill="#FC6D26" d="M26.5 38.2c3.3 0 9.5-2.5 9.5-9.6 0-7-2.4-6.6-9.5-6.6-7 0-9.5-.4-9.5 6.6s6.2 9.6 9.5 9.6z"/><g transform="translate(17 14)"><use fill="#FC6D26" xlink:href="#g"/><use stroke="#FFF" stroke-width="4" mask="url(#r)" xlink:href="#g"/></g></g><g transform="rotate(15 -85.125 65.185)"><use fill="#FFF" stroke="#B5A7DD" stroke-width="6" mask="url(#s)" xlink:href="#h"/><path fill="#6B4FBB" d="M24 18.5c0-1.4 1-2.5 2.5-2.5 1.4 0 2.5 1 2.5 2.5v9c0 1.4-1 2.5-2.5 2.5-1.4 0-2.5-1-2.5-2.5v-9zM26.5 37c1.4 0 2.5-1 2.5-2.5 0-1.4-1-2.5-2.5-2.5-1.4 0-2.5 1-2.5 2.5 0 1.4 1 2.5 2.5 2.5z"/></g><g transform="rotate(-15 716.492 78.873)"><use fill="#FFF" stroke="#FDE5D8" stroke-width="6" mask="url(#t)" xlink:href="#i"/><path fill="#FC6D26" d="M20 23v-3h3v3h-3zm0 3v1.5c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5V26h-2.5c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5H17v-3h-1.5c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5H17v-2.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5V17h3v-1.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5V17h2.5c.8 0 1.5.7 1.5 1.5s-.7 1.5-1.5 1.5H26v3h1.5c.8 0 1.5.7 1.5 1.5s-.7 1.5-1.5 1.5H26v2.5c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5V26h-3z"/></g><g transform="rotate(-15 129.114 -585.74)"><use stroke="#FDE5D8" stroke-width="6" mask="url(#u)" xlink:href="#j"/><circle cx="16" cy="20" r="2" fill="#FC6D26"/><circle cx="27" cy="20" r="2" fill="#FC6D26"/><circle cx="38" cy="20" r="2" fill="#FC6D26"/></g><g transform="rotate(-15 1254.8 -458.986)"><use stroke="#FDE5D8" stroke-width="6" mask="url(#v)" xlink:href="#k"/><path fill="#FC6D26" d="M10.6 19l2-2c.5-.5.5-1 0-1.5-.3-.4-1-.4-1.3 0l-2.8 2.8c-.2.2-.3.4-.3.7 0 .3 0 .5.3.7l2.8 2.8c.4.4 1 .4 1.4 0 .4-.4.4-1 0-1.4l-2-2zm14.8 0l-2-2c-.5-.5-.5-1 0-1.5.3-.4 1-.4 1.3 0l2.8 2.8c.2.2.3.4.3.7 0 .3 0 .5-.3.7l-2.8 2.8c-.4.4-1 .4-1.4 0-.4-.4-.4-1 0-1.4l2-2z"/><rect width="2" height="7" x="17" y="15.1" fill="#FC6D26" opacity=".5" transform="rotate(15 18.002 18.64)" rx="1"/></g></g></svg>
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -2,6 +2,7 @@
/* global Flash */
import _ from 'underscore';
import Cookies from 'js-cookie';
import { isInIssuePage, updateTooltipTitle } from './lib/utils/common_utils';
const animationEndEventString = 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd';
const transitionEndEventString = 'transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd';
......@@ -23,6 +24,9 @@ const categoryLabelMap = {
flags: 'Flags',
};
const IS_VISIBLE = 'is-visible';
const IS_RENDERED = 'is-rendered';
class AwardsHandler {
constructor(emoji) {
this.emoji = emoji;
......@@ -50,7 +54,7 @@ class AwardsHandler {
if (!$target.closest('.emoji-menu').length) {
if ($('.emoji-menu').is(':visible')) {
$('.js-add-award.is-active').removeClass('is-active');
$('.emoji-menu').removeClass('is-visible');
this.hideMenuElement($('.emoji-menu'));
}
}
});
......@@ -87,12 +91,12 @@ class AwardsHandler {
if ($menu.length) {
if ($menu.is('.is-visible')) {
$addBtn.removeClass('is-active');
$menu.removeClass('is-visible');
this.hideMenuElement($menu);
$('.js-emoji-menu-search').blur();
} else {
$addBtn.addClass('is-active');
this.positionMenu($menu, $addBtn);
$menu.addClass('is-visible');
this.showMenuElement($menu);
$('.js-emoji-menu-search').focus();
}
} else {
......@@ -102,7 +106,7 @@ class AwardsHandler {
$addBtn.removeClass('is-loading');
this.positionMenu($createdMenu, $addBtn);
return setTimeout(() => {
$createdMenu.addClass('is-visible');
this.showMenuElement($createdMenu);
$('.js-emoji-menu-search').focus();
}, 200);
});
......@@ -237,10 +241,11 @@ class AwardsHandler {
addAward(votesBlock, awardUrl, emoji, checkMutuality, callback) {
const isMainAwardsBlock = votesBlock.closest('.js-issue-note-awards').length;
if (gl.utils.isInIssuePage() && !isMainAwardsBlock) {
if (isInIssuePage() && !isMainAwardsBlock) {
const id = votesBlock.attr('id').replace('note_', '');
$('.emoji-menu').removeClass('is-visible');
this.hideMenuElement($('.emoji-menu'));
$('.js-add-award.is-active').removeClass('is-active');
const toggleAwardEvent = new CustomEvent('toggleAward', {
detail: {
......@@ -260,7 +265,8 @@ class AwardsHandler {
return typeof callback === 'function' ? callback() : undefined;
});
$('.emoji-menu').removeClass('is-visible');
this.hideMenuElement($('.emoji-menu'));
return $('.js-add-award.is-active').removeClass('is-active');
}
......@@ -288,7 +294,7 @@ class AwardsHandler {
}
getVotesBlock() {
if (gl.utils.isInIssuePage()) {
if (isInIssuePage()) {
const $el = $('.js-add-award.is-active').closest('.note.timeline-entry');
if ($el.length) {
......@@ -452,11 +458,11 @@ class AwardsHandler {
userAuthored($emojiButton) {
const oldTitle = this.getAwardTooltip($emojiButton);
const newTitle = 'You cannot vote on your own issue, MR and note';
gl.utils.updateTooltipTitle($emojiButton, newTitle).tooltip('show');
updateTooltipTitle($emojiButton, newTitle).tooltip('show');
// Restore tooltip back to award list
return setTimeout(() => {
$emojiButton.tooltip('hide');
gl.utils.updateTooltipTitle($emojiButton, oldTitle);
updateTooltipTitle($emojiButton, oldTitle);
}, 2800);
}
......@@ -528,6 +534,33 @@ class AwardsHandler {
return $matchingElements.closest('li').clone();
}
/* showMenuElement and hideMenuElement are performance optimizations. We use
* opacity to show/hide the emoji menu, because we can animate it. But opacity
* leaves hidden elements in the render tree, which is unacceptable given the number
* of emoji elements in the emoji menu (5k+). To get the best of both worlds, we separately
* apply IS_RENDERED to add/remove the menu from the render tree and IS_VISIBLE to animate
* the menu being opened and closed. */
showMenuElement($emojiMenu) {
$emojiMenu.addClass(IS_RENDERED);
// enqueues animation as a microtask, so it begins ASAP once IS_RENDERED added
return Promise.resolve()
.then(() => $emojiMenu.addClass(IS_VISIBLE));
}
hideMenuElement($emojiMenu) {
$emojiMenu.on(transitionEndEventString, (e) => {
if (e.currentTarget === e.target) {
$emojiMenu
.removeClass(IS_RENDERED)
.off(transitionEndEventString);
}
});
$emojiMenu.removeClass(IS_VISIBLE);
}
destroy() {
this.eventListeners.forEach((entry) => {
entry.element.off.call(entry.element, ...entry.args);
......
import '../commons/bootstrap';
import { isInIssuePage } from '../lib/utils/common_utils';
// Quick Submit behavior
//
......@@ -45,7 +46,7 @@ $(document).on('keydown.quick_submit', '.js-quick-submit', (e) => {
if (!$submitButton.attr('disabled')) {
$submitButton.trigger('click', [e]);
if (!gl.utils.isInIssuePage()) {
if (!isInIssuePage()) {
$submitButton.disable();
}
}
......
......@@ -3,6 +3,7 @@
import '../lib/utils/url_utility';
import { HIDDEN_CLASS } from '../lib/utils/constants';
import csrf from '../lib/utils/csrf';
function toggleLoading($el, $icon, loading) {
if (loading) {
......@@ -36,9 +37,7 @@ export default class BlobFileDropzone {
maxFiles: 1,
addRemoveLinks: true,
previewsContainer: '.dropzone-previews',
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content'),
},
headers: csrf.headers,
init: function () {
this.on('addedfile', function () {
toggleLoading(submitButton, submitButtonLoadingIcon, false);
......
/* global Flash */
import { handleLocationHash } from '../../lib/utils/common_utils';
export default class BlobViewer {
constructor() {
BlobViewer.initAuxiliaryViewer();
......@@ -114,7 +116,7 @@ export default class BlobViewer {
$(viewer).renderGFM();
this.$fileHolder.trigger('highlight:line');
gl.utils.handleLocationHash();
handleLocationHash();
this.toggleCopyButtonState();
})
......
......@@ -8,11 +8,11 @@ gl.issueBoards.ModalEmptyState = Vue.extend({
return ModalStore.store;
},
props: {
image: {
newIssuePath: {
type: String,
required: true,
},
newIssuePath: {
emptyStateSvg: {
type: String,
required: true,
},
......@@ -42,7 +42,7 @@ gl.issueBoards.ModalEmptyState = Vue.extend({
<section class="empty-state">
<div class="row">
<div class="col-xs-12 col-sm-6 col-sm-push-6">
<aside class="svg-content" v-html="image"></aside>
<aside class="svg-content"><img :src="emptyStateSvg"/></aside>
</div>
<div class="col-xs-12 col-sm-6 col-sm-pull-6">
<div class="text-content">
......
......@@ -12,11 +12,11 @@ const ModalStore = gl.issueBoards.ModalStore;
gl.issueBoards.IssuesModal = Vue.extend({
props: {
blankStateImage: {
newIssuePath: {
type: String,
required: true,
},
newIssuePath: {
emptyStateSvg: {
type: String,
required: true,
},
......@@ -150,14 +150,14 @@ gl.issueBoards.IssuesModal = Vue.extend({
:label-path="labelPath">
</modal-header>
<modal-list
:image="blankStateImage"
:issue-link-base="issueLinkBase"
:root-path="rootPath"
:empty-state-svg="emptyStateSvg"
v-if="!loading && showList && !filterLoading"></modal-list>
<empty-state
v-if="showEmptyState"
:image="blankStateImage"
:new-issue-path="newIssuePath"></empty-state>
:new-issue-path="newIssuePath"
:empty-state-svg="emptyStateSvg"></empty-state>
<section
class="add-issues-list text-center"
v-if="loading || filterLoading">
......
......@@ -15,7 +15,7 @@ gl.issueBoards.ModalList = Vue.extend({
type: String,
required: true,
},
image: {
emptyStateSvg: {
type: String,
required: true,
},
......@@ -119,8 +119,8 @@ gl.issueBoards.ModalList = Vue.extend({
class="empty-state add-issues-empty-state-filter text-center"
v-if="issuesCount > 0 && issues.length === 0">
<div
class="svg-content"
v-html="image">
class="svg-content">
<img :src="emptyStateSvg"/>
</div>
<div class="text-content">
<h4>
......
......@@ -2,6 +2,7 @@
/* global List */
import _ from 'underscore';
import Cookies from 'js-cookie';
import { getUrlParamsArray } from '../../lib/utils/common_utils';
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
......@@ -21,7 +22,7 @@ gl.issueBoards.BoardsStore = {
},
create () {
this.state.lists = [];
this.filter.path = gl.utils.getUrlParamsArray().join('&');
this.filter.path = getUrlParamsArray().join('&');
this.detail = { issue: {} };
},
addList (listObj, defaultAvatar) {
......
......@@ -3,6 +3,7 @@ consistent-return, prefer-rest-params */
import _ from 'underscore';
import bp from './breakpoints';
import { bytesToKiB } from './lib/utils/number_utils';
import { setCiStatusFavicon } from './lib/utils/common_utils';
window.Build = (function () {
Build.timeout = null;
......@@ -169,7 +170,7 @@ window.Build = (function () {
data: this.state,
})
.done((log) => {
gl.utils.setCiStatusFavicon(`${this.pageUrl}/status.json`);
setCiStatusFavicon(`${this.pageUrl}/status.json`);
if (log.state) {
this.state = log.state;
......
......@@ -11,14 +11,22 @@
function ImageFile(file) {
this.file = file;
this.requestImageInfo($('.two-up.view .frame.deleted img', this.file), (function(_this) {
// Determine if old and new file has same dimensions, if not show 'two-up' view
return function(deletedWidth, deletedHeight) {
return _this.requestImageInfo($('.two-up.view .frame.added img', _this.file), function(width, height) {
if (width === deletedWidth && height === deletedHeight) {
return _this.initViewModes();
} else {
return _this.initView('two-up');
}
_this.initViewModes();
// Load two-up view after images are loaded
// so that we can display the correct width and height information
const images = $('.two-up.view img', _this.file);
let loadedCount = 0;
images.on('load', () => {
loadedCount += 1;
if (loadedCount === images.length) {
_this.initView('two-up');
}
});
});
};
})(this));
......@@ -134,8 +142,9 @@
width: maxWidth + 1,
height: maxHeight + 2
});
// Set swipeBar left position to match image frame
$swipeBar.css({
left: 0
left: 1
});
wrapPadding = parseInt($swipeWrap.css('right').replace('px', ''), 10);
......
......@@ -35,6 +35,8 @@ document.addEventListener('DOMContentLoaded', () => {
propsData: {
endpoint: pipelineTableViewEl.dataset.endpoint,
helpPagePath: pipelineTableViewEl.dataset.helpPagePath,
emptyStateSvgPath: pipelineTableViewEl.dataset.emptyStateSvgPath,
errorStateSvgPath: pipelineTableViewEl.dataset.errorStateSvgPath,
autoDevopsHelpPath: pipelineTableViewEl.dataset.helpAutoDevopsPath,
},
}).$mount();
......
......@@ -17,6 +17,14 @@
type: String,
required: true,
},
emptyStateSvgPath: {
type: String,
required: true,
},
errorStateSvgPath: {
type: String,
required: true,
},
},
mixins: [
pipelinesMixin,
......@@ -87,10 +95,12 @@
<empty-state
v-if="shouldRenderEmptyState"
:help-page-path="helpPagePath"
:empty-state-svg-path="emptyStateSvgPath"
/>
<error-state
v-if="shouldRenderErrorState"
:error-state-svg-path="errorStateSvgPath"
/>
<div
......
/* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, camelcase, one-var-declaration-per-line, no-else-return, max-len */
import { rstrip } from './lib/utils/common_utils';
window.ConfirmDangerModal = (function() {
function ConfirmDangerModal(form, text) {
......@@ -12,7 +13,7 @@ window.ConfirmDangerModal = (function() {
submit.disable();
$('.js-confirm-danger-input').off('input');
$('.js-confirm-danger-input').on('input', function() {
if (gl.utils.rstrip($(this).val()) === project_path) {
if (rstrip($(this).val()) === project_path) {
return submit.enable();
} else {
return submit.disable();
......
/* eslint-disable class-methods-use-this, object-shorthand, no-unused-vars, no-use-before-define, no-new, max-len, no-restricted-syntax, guard-for-in, no-continue */
import _ from 'underscore';
import './lib/utils/common_utils';
import { insertText, getSelectedFragment, nodeMatchesSelector } from './lib/utils/common_utils';
import { placeholderImage } from './lazy_loader';
const gfmRules = {
......@@ -295,7 +295,7 @@ class CopyAsGFM {
const clipboardData = e.originalEvent.clipboardData;
if (!clipboardData) return;
const documentFragment = window.gl.utils.getSelectedFragment();
const documentFragment = getSelectedFragment();
if (!documentFragment) return;
const el = transformer(documentFragment.cloneNode(true));
......@@ -412,7 +412,7 @@ class CopyAsGFM {
for (const selector in rules) {
const func = rules[selector];
if (!window.gl.utils.nodeMatchesSelector(node, selector)) continue;
if (!nodeMatchesSelector(node, selector)) continue;
let result;
if (func.length === 2) {
......
......@@ -12,34 +12,38 @@ import './components/stage_review_component';
import './components/stage_staging_component';
import './components/stage_test_component';
import './components/total_time_component';
import './cycle_analytics_service';
import './cycle_analytics_store';
import CycleAnalyticsService from './cycle_analytics_service';
import CycleAnalyticsStore from './cycle_analytics_store';
Vue.use(Translate);
$(() => {
const OVERVIEW_DIALOG_COOKIE = 'cycle_analytics_help_dismissed';
const cycleAnalyticsEl = document.querySelector('#cycle-analytics');
const cycleAnalyticsStore = gl.cycleAnalytics.CycleAnalyticsStore;
const cycleAnalyticsService = new gl.cycleAnalytics.CycleAnalyticsService({
requestPath: cycleAnalyticsEl.dataset.requestPath,
});
gl.cycleAnalyticsApp = new Vue({
el: '#cycle-analytics',
name: 'CycleAnalytics',
data: {
state: cycleAnalyticsStore.state,
isLoading: false,
isLoadingStage: false,
isEmptyStage: false,
hasError: false,
startDate: 30,
isOverviewDialogDismissed: Cookies.get(OVERVIEW_DIALOG_COOKIE),
data() {
const cycleAnalyticsEl = document.querySelector('#cycle-analytics');
const cycleAnalyticsService = new CycleAnalyticsService({
requestPath: cycleAnalyticsEl.dataset.requestPath,
});
return {
store: CycleAnalyticsStore,
state: CycleAnalyticsStore.state,
isLoading: false,
isLoadingStage: false,
isEmptyStage: false,
hasError: false,
startDate: 30,
isOverviewDialogDismissed: Cookies.get(OVERVIEW_DIALOG_COOKIE),
service: cycleAnalyticsService,
};
},
computed: {
currentStage() {
return cycleAnalyticsStore.currentActiveStage();
return this.store.currentActiveStage();
},
},
components: {
......@@ -56,7 +60,7 @@ $(() => {
},
methods: {
handleError() {
cycleAnalyticsStore.setErrorState(true);
this.store.setErrorState(true);
return new Flash('There was an error while fetching cycle analytics data.');
},
initDropdown() {
......@@ -77,17 +81,17 @@ $(() => {
this.isLoading = true;
cycleAnalyticsService
this.service
.fetchCycleAnalyticsData(fetchOptions)
.done((response) => {
cycleAnalyticsStore.setCycleAnalyticsData(response);
.then(resp => resp.json())
.then((response) => {
this.store.setCycleAnalyticsData(response);
this.selectDefaultStage();
this.initDropdown();
this.isLoading = false;
})
.error(() => {
.catch(() => {
this.handleError();
})
.always(() => {
this.isLoading = false;
});
},
......@@ -100,27 +104,27 @@ $(() => {
if (this.currentStage === stage) return;
if (!stage.isUserAllowed) {
cycleAnalyticsStore.setActiveStage(stage);
this.store.setActiveStage(stage);
return;
}
this.isLoadingStage = true;
cycleAnalyticsStore.setStageEvents([], stage);
cycleAnalyticsStore.setActiveStage(stage);
this.store.setStageEvents([], stage);
this.store.setActiveStage(stage);
cycleAnalyticsService
this.service
.fetchStageData({
stage,
startDate: this.startDate,
})
.done((response) => {
.then(resp => resp.json())
.then((response) => {
this.isEmptyStage = !response.events.length;
cycleAnalyticsStore.setStageEvents(response.events, stage);
this.store.setStageEvents(response.events, stage);
this.isLoadingStage = false;
})
.error(() => {
.catch(() => {
this.isEmptyStage = true;
})
.always(() => {
this.isLoadingStage = false;
});
},
......
/* eslint-disable no-param-reassign */
import Vue from 'vue';
import VueResource from 'vue-resource';
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
Vue.use(VueResource);
class CycleAnalyticsService {
export default class CycleAnalyticsService {
constructor(options) {
this.requestPath = options.requestPath;
this.cycleAnalytics = Vue.resource(this.requestPath);
}
fetchCycleAnalyticsData(options) {
options = options || { startDate: 30 };
return $.ajax({
url: this.requestPath,
method: 'GET',
dataType: 'json',
contentType: 'application/json',
data: {
cycle_analytics: {
start_date: options.startDate,
},
},
});
fetchCycleAnalyticsData(options = { startDate: 30 }) {
return this.cycleAnalytics.get({ cycle_analytics: { start_date: options.startDate } });
}
fetchStageData(options) {
......@@ -30,12 +19,12 @@ class CycleAnalyticsService {
startDate,
} = options;
return $.get(`${this.requestPath}/events/${stage.name}.json`, {
cycle_analytics: {
start_date: startDate,
return Vue.http.get(`${this.requestPath}/events/${stage.name}.json`, {
params: {
cycle_analytics: {
start_date: startDate,
},
},
});
}
}
global.cycleAnalytics.CycleAnalyticsService = CycleAnalyticsService;
......@@ -4,9 +4,6 @@ import { __ } from '../locale';
import '../lib/utils/text_utility';
import DEFAULT_EVENT_OBJECTS from './default_event_objects';
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
const EMPTY_STAGE_TEXTS = {
issue: __('The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage.'),
plan: __('The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit.'),
......@@ -17,7 +14,7 @@ const EMPTY_STAGE_TEXTS = {
production: __('The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle.'),
};
global.cycleAnalytics.CycleAnalyticsStore = {
export default {
state: {
summary: '',
stats: '',
......
......@@ -77,6 +77,7 @@ import initProjectVisibilitySelector from './project_visibility';
import GpgBadges from './gpg_badges';
import UserFeatureHelper from './helpers/user_feature_helper';
import initChangesDropdown from './init_changes_dropdown';
import { ajaxGet, convertPermissionToBoolean } from './lib/utils/common_utils';
(function() {
var Dispatcher;
......@@ -100,7 +101,7 @@ import initChangesDropdown from './init_changes_dropdown';
$('.js-gfm-input:not(.js-vue-textarea)').each((i, el) => {
const gfm = new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources);
const enableGFM = gl.utils.convertPermissionToBoolean(el.dataset.supportsAutocomplete);
const enableGFM = convertPermissionToBoolean(el.dataset.supportsAutocomplete);
gfm.setup($(el), {
emojis: true,
members: enableGFM,
......@@ -351,7 +352,7 @@ import initChangesDropdown from './init_changes_dropdown';
if ($('.blob-viewer').length) new BlobViewer();
if ($('.project-show-activity').length) new gl.Activities();
$('#tree-slider').waitForImages(function() {
gl.utils.ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
});
break;
case 'projects:edit':
......@@ -427,7 +428,7 @@ import initChangesDropdown from './init_changes_dropdown';
new NewCommitForm($('.js-create-dir-form'));
new UserCallout({ setCalloutPerProject: true });
$('#tree-slider').waitForImages(function() {
gl.utils.ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
});
break;
case 'projects:find_file:show':
......
......@@ -2,6 +2,7 @@
/* global Dropzone */
import _ from 'underscore';
import './preview_markdown';
import csrf from './lib/utils/csrf';
window.DropzoneInput = (function() {
function DropzoneInput(form) {
......@@ -50,9 +51,7 @@ window.DropzoneInput = (function() {
paramName: 'file',
maxFilesize: maxFileSize,
uploadMultiple: false,
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
headers: csrf.headers,
previewContainer: false,
processing: function() {
return $('.div-dropzone-alert').alert('close');
......@@ -260,9 +259,7 @@ window.DropzoneInput = (function() {
dataType: 'json',
processData: false,
contentType: false,
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
headers: csrf.headers,
beforeSend: function() {
showSpinner();
return closeAlertMessage();
......
......@@ -6,7 +6,7 @@ import environmentTable from './environments_table.vue';
import EnvironmentsStore from '../stores/environments_store';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import tablePagination from '../../vue_shared/components/table_pagination.vue';
import '../../lib/utils/common_utils';
import { convertPermissionToBoolean, getParameterByName, setParamInURL } from '../../lib/utils/common_utils';
import eventHub from '../event_hub';
import Poll from '../../lib/utils/poll';
import environmentsMixin from '../mixins/environments_mixin';
......@@ -51,19 +51,19 @@ export default {
computed: {
scope() {
return gl.utils.getParameterByName('scope');
return getParameterByName('scope');
},
canReadEnvironmentParsed() {
return gl.utils.convertPermissionToBoolean(this.canReadEnvironment);
return convertPermissionToBoolean(this.canReadEnvironment);
},
canCreateDeploymentParsed() {
return gl.utils.convertPermissionToBoolean(this.canCreateDeployment);
return convertPermissionToBoolean(this.canCreateDeployment);
},
canCreateEnvironmentParsed() {
return gl.utils.convertPermissionToBoolean(this.canCreateEnvironment);
return convertPermissionToBoolean(this.canCreateEnvironment);
},
},
......@@ -72,8 +72,8 @@ export default {
* Toggles loading property.
*/
created() {
const scope = gl.utils.getParameterByName('scope') || this.visibility;
const page = gl.utils.getParameterByName('page') || this.pageNumber;
const scope = getParameterByName('scope') || this.visibility;
const page = getParameterByName('page') || this.pageNumber;
this.service = new EnvironmentsService(this.endpoint);
......@@ -126,15 +126,15 @@ export default {
* @return {String}
*/
changePage(pageNumber) {
const param = gl.utils.setParamInURL('page', pageNumber);
const param = setParamInURL('page', pageNumber);
gl.utils.visitUrl(param);
return param;
},
fetchEnvironments() {
const scope = gl.utils.getParameterByName('scope') || this.visibility;
const page = gl.utils.getParameterByName('page') || this.pageNumber;
const scope = getParameterByName('scope') || this.visibility;
const page = getParameterByName('page') || this.pageNumber;
this.isLoading = true;
......
......@@ -9,7 +9,7 @@ import tablePagination from '../../vue_shared/components/table_pagination.vue';
import Poll from '../../lib/utils/poll';
import eventHub from '../event_hub';
import environmentsMixin from '../mixins/environments_mixin';
import '../../lib/utils/common_utils';
import { convertPermissionToBoolean, getParameterByName, setParamInURL } from '../../lib/utils/common_utils';
export default {
components: {
......@@ -47,15 +47,15 @@ export default {
computed: {
scope() {
return gl.utils.getParameterByName('scope');
return getParameterByName('scope');
},
canReadEnvironmentParsed() {
return gl.utils.convertPermissionToBoolean(this.canReadEnvironment);
return convertPermissionToBoolean(this.canReadEnvironment);
},
canCreateDeploymentParsed() {
return gl.utils.convertPermissionToBoolean(this.canCreateDeployment);
return convertPermissionToBoolean(this.canCreateDeployment);
},
/**
......@@ -82,8 +82,8 @@ export default {
* Toggles loading property.
*/
created() {
const scope = gl.utils.getParameterByName('scope') || this.visibility;
const page = gl.utils.getParameterByName('page') || this.pageNumber;
const scope = getParameterByName('scope') || this.visibility;
const page = getParameterByName('page') || this.pageNumber;
this.service = new EnvironmentsService(this.endpoint);
......@@ -125,15 +125,15 @@ export default {
* @param {Number} pageNumber desired page to go to.
*/
changePage(pageNumber) {
const param = gl.utils.setParamInURL('page', pageNumber);
const param = setParamInURL('page', pageNumber);
gl.utils.visitUrl(param);
return param;
},
fetchEnvironments() {
const scope = gl.utils.getParameterByName('scope') || this.visibility;
const page = gl.utils.getParameterByName('page') || this.pageNumber;
const scope = getParameterByName('scope') || this.visibility;
const page = getParameterByName('page') || this.pageNumber;
this.isLoading = true;
......
import '~/lib/utils/common_utils';
import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
/**
* Environments Store.
*
......@@ -66,8 +66,8 @@ export default class EnvironmentsStore {
}
setPagination(pagination = {}) {
const normalizedHeaders = gl.utils.normalizeHeaders(pagination);
const paginationInformation = gl.utils.parseIntPagination(normalizedHeaders);
const normalizedHeaders = normalizeHeaders(pagination);
const paginationInformation = parseIntPagination(normalizedHeaders);
this.state.paginationInformation = paginationInformation;
return paginationInformation;
......
......@@ -34,7 +34,7 @@ export const canShowActiveSubItems = (el) => {
export const canShowSubItems = () => bp.getBreakpointSize() === 'sm' || bp.getBreakpointSize() === 'md' || bp.getBreakpointSize() === 'lg';
export const getHideSubItemsInterval = () => {
if (!currentOpenMenu) return 0;
if (!currentOpenMenu || !mousePos.length) return 0;
const currentMousePos = mousePos[mousePos.length - 1];
const prevMousePos = mousePos[0];
......
<script>
import tablePagination from '~/vue_shared/components/table_pagination.vue';
import eventHub from '../event_hub';
import { getParameterByName } from '../../lib/utils/common_utils';
export default {
props: {
......@@ -18,8 +19,8 @@ export default {
},
methods: {
change(page) {
const filterGroupsParam = gl.utils.getParameterByName('filter_groups');
const sortParam = gl.utils.getParameterByName('sort');
const filterGroupsParam = getParameterByName('filter_groups');
const sortParam = getParameterByName('sort');
eventHub.$emit('fetchPage', page, filterGroupsParam, sortParam);
},
},
......
import FilterableList from '~/filterable_list';
import eventHub from './event_hub';
import { getParameterByName } from '../lib/utils/common_utils';
export default class GroupFilterableList extends FilterableList {
constructor({ form, filter, holder, filterEndpoint, pagePath }) {
......@@ -54,7 +55,7 @@ export default class GroupFilterableList extends FilterableList {
e.preventDefault();
const queryData = {};
const sortParam = gl.utils.getParameterByName('sort', e.currentTarget.href);
const sortParam = getParameterByName('sort', e.currentTarget.href);
if (sortParam) {
queryData.sort = sortParam;
......
......@@ -8,6 +8,7 @@ import GroupItem from './components/group_item.vue';
import GroupsStore from './stores/groups_store';
import GroupsService from './services/groups_service';
import eventHub from './event_hub';
import { getParameterByName } from '../lib/utils/common_utils';
document.addEventListener('DOMContentLoaded', () => {
const el = document.getElementById('dashboard-group-app');
......@@ -58,17 +59,17 @@ document.addEventListener('DOMContentLoaded', () => {
this.isLoading = true;
}
pageParam = gl.utils.getParameterByName('page');
pageParam = getParameterByName('page');
if (pageParam) {
page = pageParam;
}
filterGroupsParam = gl.utils.getParameterByName('filter_groups');
filterGroupsParam = getParameterByName('filter_groups');
if (filterGroupsParam) {
filterGroups = filterGroupsParam;
}
sortParam = gl.utils.getParameterByName('sort');
sortParam = getParameterByName('sort');
if (sortParam) {
sort = sortParam;
}
......
import Vue from 'vue';
import { parseIntPagination, normalizeHeaders } from '../../lib/utils/common_utils';
export default class GroupsStore {
constructor() {
......@@ -30,8 +31,8 @@ export default class GroupsStore {
let paginationInfo;
if (Object.keys(pagination).length) {
const normalizedHeaders = gl.utils.normalizeHeaders(pagination);
paginationInfo = gl.utils.parseIntPagination(normalizedHeaders);
const normalizedHeaders = normalizeHeaders(pagination);
paginationInfo = parseIntPagination(normalizedHeaders);
} else {
paginationInfo = pagination;
}
......
......@@ -4,6 +4,7 @@
prefer-rest-params, prefer-spread, no-unused-vars, prefer-template,
promise/catch-or-return */
import Api from './api';
import { normalizeCRLFHeaders } from './lib/utils/common_utils';
var slice = [].slice;
......@@ -30,7 +31,7 @@ window.GroupsSelect = (function() {
$.ajax(params).then((data, status, xhr) => {
const results = data || [];
const headers = gl.utils.normalizeCRLFHeaders(xhr.getAllResponseHeaders());
const headers = normalizeCRLFHeaders(xhr.getAllResponseHeaders());
const currentPage = parseInt(headers['X-PAGE'], 10) || 0;
const totalPages = parseInt(headers['X-TOTAL-PAGES'], 10) || 0;
const more = currentPage < totalPages;
......
// We will render the icons list here
if ($('#user-content-gitlab-icons').length > 0) {
const $iconsHeader = $('#user-content-gitlab-icons');
const $iconsList = $('<div id="iconsList">ICONS</div>');
$($iconsList).insertAfter($iconsHeader.parent());
}
/*
This module provides easy access to the CSRF token and caches
it for re-use. It also exposes some values commonly used in relation
to the CSRF token (header key and headers object).
If you need to refresh the csrfToken for some reason, just call `init` and
then use the accessors as you would normally.
If you need to compose a headers object, use the spread operator:
```
headers: {
...csrf.headers,
someOtherHeader: '12345',
}
```
*/
const csrf = {
init() {
const tokenEl = document.querySelector('meta[name=csrf-token]');
if (tokenEl !== null) {
this.csrfToken = tokenEl.getAttribute('content');
} else {
this.csrfToken = null;
}
},
get token() {
return this.csrfToken;
},
get headerKey() {
return 'X-CSRF-Token';
},
get headers() {
if (this.csrfToken !== null) {
return {
[this.headerKey]: this.token,
};
}
return {};
},
};
csrf.init();
// use our cached token for any $.rails-generated AJAX requests
if ($.rails) {
$.rails.csrfToken = () => csrf.token;
}
export default csrf;
import httpStatusCodes from './http_status';
import { normalizeHeaders } from './common_utils';
/**
* Polling utility for handling realtime updates.
......@@ -57,7 +58,7 @@ export default class Poll {
}
checkConditions(response) {
const headers = gl.utils.normalizeHeaders(response.headers);
const headers = normalizeHeaders(response.headers);
const pollInterval = parseInt(headers[this.intervalHeader], 10);
if (pollInterval > 0 && response.status === httpStatusCodes.OK && this.canPoll) {
......
......@@ -8,6 +8,7 @@ import _ from 'underscore';
import Cookies from 'js-cookie';
import Dropzone from 'dropzone';
import Sortable from 'vendor/Sortable';
import svg4everybody from 'svg4everybody';
// libraries with import side-effects
import 'mousetrap';
......@@ -40,7 +41,7 @@ import './commit/image_file';
// lib/utils
import './lib/utils/bootstrap_linked_tabs';
import './lib/utils/common_utils';
import { handleLocationHash } from './lib/utils/common_utils';
import './lib/utils/datetime_utility';
import './lib/utils/pretty_time';
import './lib/utils/text_utility';
......@@ -151,6 +152,8 @@ if (process.env.NODE_ENV !== 'production') require('./test_utils/');
Dropzone.autoDiscover = false;
svg4everybody();
document.addEventListener('beforeunload', function () {
// Unbind scroll events
$(document).off('scroll');
......@@ -160,10 +163,10 @@ document.addEventListener('beforeunload', function () {
$('[data-toggle="popover"]').popover('destroy');
});
window.addEventListener('hashchange', gl.utils.handleLocationHash);
window.addEventListener('hashchange', handleLocationHash);
window.addEventListener('load', function onLoad() {
window.removeEventListener('load', onLoad, false);
gl.utils.handleLocationHash();
handleLocationHash();
}, false);
gl.lazyLoader = new LazyLoader({
......@@ -189,7 +192,7 @@ $(function () {
$body.on('click', 'a[href^="#"]', function() {
var href = this.getAttribute('href');
if (href.substr(1) === gl.utils.getLocationHash()) {
setTimeout(gl.utils.handleLocationHash, 1);
setTimeout(handleLocationHash, 1);
}
});
......
......@@ -7,6 +7,11 @@ import './flash';
import BlobForkSuggestion from './blob/blob_fork_suggestion';
import initChangesDropdown from './init_changes_dropdown';
import bp from './breakpoints';
import {
parseUrlPathname,
handleLocationHash,
isMetaClick,
} from './lib/utils/common_utils';
/* eslint-disable max-len */
// MergeRequestTabs
......@@ -114,7 +119,7 @@ import bp from './breakpoints';
}
clickTab(e) {
if (e.currentTarget && gl.utils.isMetaClick(e)) {
if (e.currentTarget && isMetaClick(e)) {
const targetLink = e.currentTarget.getAttribute('href');
e.stopImmediatePropagation();
e.preventDefault();
......@@ -243,6 +248,8 @@ import bp from './breakpoints';
propsData: {
endpoint: pipelineTableViewEl.dataset.endpoint,
helpPagePath: pipelineTableViewEl.dataset.helpPagePath,
emptyStateSvgPath: pipelineTableViewEl.dataset.emptyStateSvgPath,
errorStateSvgPath: pipelineTableViewEl.dataset.errorStateSvgPath,
autoDevopsHelpPath: pipelineTableViewEl.dataset.helpAutoDevopsPath,
},
}).$mount();
......@@ -260,7 +267,7 @@ import bp from './breakpoints';
// We extract pathname for the current Changes tab anchor href
// some pages like MergeRequestsController#new has query parameters on that anchor
const urlPathname = gl.utils.parseUrlPathname(source);
const urlPathname = parseUrlPathname(source);
this.ajaxGet({
url: `${urlPathname}.json${location.search}`,
......@@ -309,7 +316,7 @@ import bp from './breakpoints';
forceShow: true,
});
anchor[0].scrollIntoView();
window.gl.utils.handleLocationHash();
handleLocationHash();
// We have multiple elements on the page with `#note_xxx`
// (discussion and diff tabs) and `:target` only applies to the first
anchor.addClass('target');
......
......@@ -7,6 +7,7 @@
import EmptyState from './empty_state.vue';
import MonitoringStore from '../stores/monitoring_store';
import eventHub from '../event_hub';
import { convertPermissionToBoolean } from '../../lib/utils/common_utils';
export default {
......@@ -17,11 +18,14 @@
return {
store,
state: 'gettingStarted',
hasMetrics: gl.utils.convertPermissionToBoolean(metricsData.hasMetrics),
hasMetrics: convertPermissionToBoolean(metricsData.hasMetrics),
documentationPath: metricsData.documentationPath,
settingsPath: metricsData.settingsPath,
metricsEndpoint: metricsData.additionalMetrics,
deploymentEndpoint: metricsData.deploymentEndpoint,
emptyGettingStartedSvgPath: metricsData.emptyGettingStartedSvgPath,
emptyLoadingSvgPath: metricsData.emptyLoadingSvgPath,
emptyUnableToConnectSvgPath: metricsData.emptyUnableToConnectSvgPath,
showEmptyState: true,
updateAspectRatio: false,
updatedAspectRatios: 0,
......@@ -108,5 +112,8 @@
:selected-state="state"
:documentation-path="documentationPath"
:settings-path="settingsPath"
:empty-getting-started-svg-path="emptyGettingStartedSvgPath"
:empty-loading-svg-path="emptyLoadingSvgPath"
:empty-unable-to-connect-svg-path="emptyUnableToConnectSvgPath"
/>
</template>
<script>
import gettingStartedSvg from 'empty_states/monitoring/_getting_started.svg';
import loadingSvg from 'empty_states/monitoring/_loading.svg';
import unableToConnectSvg from 'empty_states/monitoring/_unable_to_connect.svg';
export default {
props: {
documentationPath: {
......@@ -18,24 +14,36 @@
type: String,
required: true,
},
emptyGettingStartedSvgPath: {
type: String,
required: true,
},
emptyLoadingSvgPath: {
type: String,
required: true,
},
emptyUnableToConnectSvgPath: {
type: String,
required: true,
},
},
data() {
return {
states: {
gettingStarted: {
svg: gettingStartedSvg,
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.',
buttonText: 'Configure Prometheus',
},
loading: {
svg: loadingSvg,
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.',
buttonText: 'View documentation',
},
unableToConnect: {
svg: unableToConnectSvg,
svgUrl: this.emptyUnableToConnectSvgPath,
title: 'Unable to connect to Prometheus server',
description: 'Ensure connectivity is available from the GitLab server to the ',
buttonText: 'View documentation',
......@@ -66,7 +74,9 @@
<template>
<div class="prometheus-state">
<div class="row">
<div class="col-md-4 col-md-offset-4 state-svg" v-html="currentState.svg"></div>
<div class="col-md-4 col-md-offset-4 state-svg svg-content">
<img :src="currentState.svgUrl"/>
</div>
</div>
<div class="row">
<div class="col-md-6 col-md-offset-3">
......
import Vue from 'vue';
import VueResource from 'vue-resource';
import statusCodes from '../../lib/utils/http_status';
import { backOff } from '../../lib/utils/common_utils';
Vue.use(VueResource);
......@@ -8,7 +9,7 @@ const MAX_REQUESTS = 3;
function backOffRequest(makeRequestCallback) {
let requestCounter = 0;
return gl.utils.backOff((next, stop) => {
return backOff((next, stop) => {
makeRequestCallback().then((resp) => {
if (resp.status === statusCodes.NO_CONTENT) {
requestCounter += 1;
......
......@@ -23,6 +23,7 @@ import loadAwardsHandler from './awards_handler';
import './autosave';
import './dropzone_input';
import TaskList from './task_list';
import { ajaxPost, isInViewport, getPagePath, scrollToElement, isMetaKey } from './lib/utils/common_utils';
window.autosize = autosize;
window.Dropzone = Dropzone;
......@@ -81,7 +82,7 @@ export default class Notes {
this.setViewType(view);
// We are in the Merge Requests page so we need another edit form for Changes tab
if (gl.utils.getPagePath(1) === 'merge_requests') {
if (getPagePath(1) === 'merge_requests') {
$('.note-edit-form').clone()
.addClass('mr-note-edit-form').insertAfter('.note-edit-form');
}
......@@ -175,7 +176,7 @@ export default class Notes {
keydownNoteText(e) {
var $textarea, discussionNoteForm, editNote, myLastNote, myLastNoteEditBtn, newText, originalText;
if (gl.utils.isMetaKey(e)) {
if (isMetaKey(e)) {
return;
}
......@@ -644,10 +645,10 @@ export default class Notes {
}
else {
var $buttons = $el.find('.note-form-actions');
var isWidgetVisible = gl.utils.isInViewport($el.get(0));
var isWidgetVisible = isInViewport($el.get(0));
if (!isWidgetVisible) {
gl.utils.scrollToElement($el);
scrollToElement($el);
}
$el.find('.js-finish-edit-warning').show();
......@@ -1188,7 +1189,7 @@ export default class Notes {
}
static checkMergeRequestStatus() {
if (gl.utils.getPagePath(1) === 'merge_requests') {
if (getPagePath(1) === 'merge_requests') {
gl.mrWidget.checkStatus();
}
}
......@@ -1326,7 +1327,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 `gl.utils.ajaxPost`
* 5) Perform network request to submit the note using `ajaxPost`
* a) If request is successfully completed
* 1. Remove placeholder element
* 2. Show submitted Note element
......@@ -1408,7 +1409,7 @@ export default class Notes {
/* eslint-disable promise/catch-or-return */
// Make request to submit comment on server
gl.utils.ajaxPost(formAction, formData)
ajaxPost(formAction, formData)
.then((note) => {
// Submission successful! remove placeholder
$notesContainer.find(`#${noteUniqueId}`).remove();
......@@ -1481,7 +1482,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 `gl.utils.ajaxPost`
* 3) Perform network request to submit the updated note using `ajaxPost`
* a) If request is successfully completed
* 1. Show submitted Note element
* b) If request failed
......@@ -1510,7 +1511,7 @@ export default class Notes {
/* eslint-disable promise/catch-or-return */
// Make request to update comment on server
gl.utils.ajaxPost(formAction, formData)
ajaxPost(formAction, formData)
.then((note) => {
// Submission successful! render final note element
this.updateNote(note, $editingNote);
......
......@@ -2,6 +2,7 @@
/* global Flash, Autosave */
import { mapActions, mapGetters } from 'vuex';
import _ from 'underscore';
import autosize from 'vendor/autosize';
import '../../autosave';
import TaskList from '../../task_list';
import * as constants from '../constants';
......@@ -97,6 +98,8 @@
methods: {
...mapActions([
'saveNote',
'stopPolling',
'restartPolling',
'removePlaceholderNotes',
]),
setIsSubmitButtonDisabled(note, isSubmitting) {
......@@ -125,10 +128,14 @@
}
this.isSubmitting = true;
this.note = ''; // Empty textarea while being requested. Repopulate in catch
this.resizeTextarea();
this.stopPolling();
this.saveNote(noteData)
.then((res) => {
this.isSubmitting = false;
this.restartPolling();
if (res.errors) {
if (res.errors.commands_only) {
this.discard();
......@@ -175,6 +182,8 @@
if (shouldClear) {
this.note = '';
this.resizeTextarea();
this.$refs.markdownField.previewMarkdown = false;
}
// reset autostave
......@@ -206,6 +215,11 @@
selector: '.notes',
});
},
resizeTextarea() {
this.$nextTick(() => {
autosize.update(this.$refs.textarea);
});
},
},
mixins: [
issuableStateMixin,
......@@ -258,7 +272,8 @@
:markdown-docs-path="markdownDocsPath"
:quick-actions-docs-path="quickActionsDocsPath"
:add-spacing-classes="false"
:is-confidential-issue="isIssueConfidential(getIssueData)">
:is-confidential-issue="isConfidentialIssue"
ref="markdownField">
<textarea
id="note-body"
name="note[note]"
......
import iconArrowCircle from 'icons/_icon_arrow_circle_o_right.svg';
import iconCheck from 'icons/_icon_check_square_o.svg';
import iconClock from 'icons/_icon_clock_o.svg';
import iconCodeFork from 'icons/_icon_code_fork.svg';
import iconComment from 'icons/_icon_comment_o.svg';
import iconCommit from 'icons/_icon_commit.svg';
import iconEdit from 'icons/_icon_edit.svg';
import iconEye from 'icons/_icon_eye.svg';
import iconEyeSlash from 'icons/_icon_eye_slash.svg';
import iconMerge from 'icons/_icon_merge.svg';
import iconMerged from 'icons/_icon_merged.svg';
import iconRandom from 'icons/_icon_random.svg';
import iconClosed from 'icons/_icon_status_closed.svg';
import iconStatusOpen from 'icons/_icon_status_open.svg';
import iconStopwatch from 'icons/_icon_stopwatch.svg';
import iconTags from 'icons/_icon_tags.svg';
import iconUser from 'icons/_icon_user.svg';
export default {
icon_arrow_circle_o_right: iconArrowCircle,
icon_check_square_o: iconCheck,
icon_clock_o: iconClock,
icon_code_fork: iconCodeFork,
icon_comment_o: iconComment,
icon_commit: iconCommit,
icon_edit: iconEdit,
icon_eye: iconEye,
icon_eye_slash: iconEyeSlash,
icon_merge: iconMerge,
icon_merged: iconMerged,
icon_random: iconRandom,
icon_status_closed: iconClosed,
icon_status_open: iconStatusOpen,
icon_stopwatch: iconStopwatch,
icon_tags: iconTags,
icon_user: iconUser,
};
<script>
import { mapGetters } from 'vuex';
import iconsMap from './issue_note_icons';
import issueNoteHeader from './issue_note_header.vue';
export default {
......@@ -24,9 +23,9 @@
isTargetNote() {
return this.targetNoteHash === this.noteAnchorId;
},
},
created() {
this.svg = iconsMap[this.note.system_note_icon_name];
iconHtml() {
return gl.utils.spriteIcon(this.note.system_note_icon_name);
},
},
};
</script>
......@@ -39,7 +38,7 @@
<div class="timeline-entry-inner">
<div
class="timeline-icon"
v-html="svg">
v-html="iconHtml">
</div>
<div class="timeline-content">
<div class="note-header">
......
......@@ -7,6 +7,7 @@ import * as constants from '../constants';
import service from '../services/issue_notes_service';
import loadAwardsHandler from '../../awards_handler';
import sidebarTimeTrackingEventHub from '../../sidebar/event_hub';
import { isInViewport, scrollToElement } from '../../lib/utils/common_utils';
let eTagPoll;
......@@ -186,6 +187,14 @@ export const poll = ({ commit, state, getters }) => {
});
};
export const stopPolling = () => {
eTagPoll.stop();
};
export const restartPolling = () => {
eTagPoll.restart();
};
export const fetchData = ({ commit, state, getters }) => {
const requestData = { endpoint: state.notesData.notesPath, lastFetchedAt: state.lastFetchedAt };
......@@ -211,7 +220,7 @@ export const toggleAwardRequest = ({ commit, getters, dispatch }, data) => {
};
export const scrollToNoteIfNeeded = (context, el) => {
if (!gl.utils.isInViewport(el[0])) {
gl.utils.scrollToElement(el);
if (!isInViewport(el[0])) {
scrollToElement(el);
}
};
......@@ -5,15 +5,19 @@ import * as constants from '../constants';
export default {
[types.ADD_NEW_NOTE](state, note) {
const { discussion_id, type } = note;
const noteData = {
expanded: true,
id: discussion_id,
individual_note: !(type === constants.DISCUSSION_NOTE),
notes: [note],
reply_id: discussion_id,
};
state.notes.push(noteData);
const [exists] = state.notes.filter(n => n.id === note.discussion_id);
if (!exists) {
const noteData = {
expanded: true,
id: discussion_id,
individual_note: !(type === constants.DISCUSSION_NOTE),
notes: [note],
reply_id: discussion_id,
};
state.notes.push(noteData);
}
},
[types.ADD_NEW_REPLY_TO_DISCUSSION](state, note) {
......
import '~/lib/utils/common_utils';
import { getParameterByName } from '~/lib/utils/common_utils';
import '~/lib/utils/url_utility';
(() => {
......@@ -9,7 +9,7 @@ import '~/lib/utils/url_utility';
init(limit = 0, preload = false, disable = false, prepareData = $.noop, callback = $.noop) {
this.url = $('.content_list').data('href') || gl.utils.removeParams(['limit', 'offset']);
this.limit = limit;
this.offset = parseInt(gl.utils.getParameterByName('offset'), 10) || this.limit;
this.offset = parseInt(getParameterByName('offset'), 10) || this.limit;
this.disable = disable;
this.prepareData = prepareData;
this.callback = callback;
......
import { convertPermissionToBoolean } from '../lib/utils/common_utils';
function insertRow($row) {
const $rowClone = $row.clone();
$rowClone.removeAttr('data-is-persisted');
......@@ -6,7 +8,7 @@ function insertRow($row) {
}
function removeRow($row) {
const isPersisted = gl.utils.convertPermissionToBoolean($row.attr('data-is-persisted'));
const isPersisted = convertPermissionToBoolean($row.attr('data-is-persisted'));
if (isPersisted) {
$row.hide();
......
import LinkedTabs from './lib/utils/bootstrap_linked_tabs';
import { setCiStatusFavicon } from './lib/utils/common_utils';
export default class Pipelines {
constructor(options = {}) {
......@@ -8,7 +9,7 @@ export default class Pipelines {
}
if (options.pipelineStatusUrl) {
gl.utils.setCiStatusFavicon(options.pipelineStatusUrl);
setCiStatusFavicon(options.pipelineStatusUrl);
}
}
}
<script>
import pipelinesEmptyStateSVG from 'empty_states/icons/_pipelines_empty.svg';
export default {
props: {
helpPagePath: {
type: String,
required: true,
},
emptyStateSvgPath: {
type: String,
required: true,
},
},
data: () => ({ pipelinesEmptyStateSVG }),
};
</script>
<template>
<div class="row empty-state js-empty-state">
<div class="col-xs-12">
<div class="svg-content" v-html="pipelinesEmptyStateSVG" />
<div class="svg-content">
<img :src="emptyStateSvgPath"/>
</div>
</div>
<div class="col-xs-12 text-center">
......
<script>
import pipelinesErrorStateSVG from 'empty_states/icons/_pipelines_failed.svg';
export default {
data: () => ({ pipelinesErrorStateSVG }),
props: {
errorStateSvgPath: {
type: String,
required: true,
},
},
};
</script>
<template>
<div class="row empty-state js-pipelines-error-state">
<div class="col-xs-12">
<div class="svg-content" v-html="pipelinesErrorStateSVG" />
<div class="svg-content">
<img :src="errorStateSvgPath"/>
</div>
</div>
<div class="col-xs-12 text-center">
......
......@@ -4,6 +4,7 @@
import tablePagination from '../../vue_shared/components/table_pagination.vue';
import navigationTabs from './navigation_tabs.vue';
import navigationControls from './nav_controls.vue';
import { convertPermissionToBoolean, getParameterByName, setParamInURL } from '../../lib/utils/common_utils';
export default {
props: {
......@@ -26,6 +27,8 @@
return {
endpoint: pipelinesData.endpoint,
helpPagePath: pipelinesData.helpPagePath,
emptyStateSvgPath: pipelinesData.emptyStateSvgPath,
errorStateSvgPath: pipelinesData.errorStateSvgPath,
autoDevopsPath: pipelinesData.helpAutoDevopsPath,
newPipelinePath: pipelinesData.newPipelinePath,
canCreatePipeline: pipelinesData.canCreatePipeline,
......@@ -44,10 +47,10 @@
},
computed: {
canCreatePipelineParsed() {
return gl.utils.convertPermissionToBoolean(this.canCreatePipeline);
return convertPermissionToBoolean(this.canCreatePipeline);
},
scope() {
const scope = gl.utils.getParameterByName('scope');
const scope = getParameterByName('scope');
return scope === null ? 'all' : scope;
},
......@@ -105,10 +108,10 @@
};
},
pageParameter() {
return gl.utils.getParameterByName('page') || this.pagenum;
return getParameterByName('page') || this.pagenum;
},
scopeParameter() {
return gl.utils.getParameterByName('scope') || this.apiScope;
return getParameterByName('scope') || this.apiScope;
},
},
created() {
......@@ -122,7 +125,7 @@
* @param {Number} pageNumber desired page to go to.
*/
change(pageNumber) {
const param = gl.utils.setParamInURL('page', pageNumber);
const param = setParamInURL('page', pageNumber);
gl.utils.visitUrl(param);
return param;
......@@ -181,9 +184,13 @@
<empty-state
v-if="shouldRenderEmptyState"
:help-page-path="helpPagePath"
:empty-state-svg-path="emptyStateSvgPath"
/>
<error-state v-if="shouldRenderErrorState" />
<error-state
v-if="shouldRenderErrorState"
:error-state-svg-path="errorStateSvgPath"
/>
<div
class="blank-state blank-state-no-icon"
......
......@@ -69,8 +69,7 @@
@click="onClickAction(action.path)"
:class="{ disabled: isActionDisabled(action) }"
:disabled="isActionDisabled(action)">
<span v-html="playIconSvg"></span>
<span>{{action.name}}</span>
{{action.name}}
</button>
</li>
</ul>
......
......@@ -39,11 +39,7 @@
rel="nofollow"
download
:href="artifact.path">
<i
class="fa fa-download"
aria-hidden="true">
</i>
<span>Download {{artifact.name}} artifacts</span>
Download {{artifact.name}} artifacts
</a>
</li>
</ul>
......
import { parseIntPagination, normalizeHeaders } from '../../lib/utils/common_utils';
export default class PipelinesStore {
constructor() {
this.state = {};
......@@ -19,8 +21,8 @@ export default class PipelinesStore {
let paginationInfo;
if (Object.keys(pagination).length) {
const normalizedHeaders = gl.utils.normalizeHeaders(pagination);
paginationInfo = gl.utils.parseIntPagination(normalizedHeaders);
const normalizedHeaders = normalizeHeaders(pagination);
paginationInfo = parseIntPagination(normalizedHeaders);
} else {
paginationInfo = pagination;
}
......
/* eslint-disable comma-dangle, no-unused-vars, class-methods-use-this, quotes, consistent-return, func-names, prefer-arrow-callback, space-before-function-paren, max-len */
/* global Flash */
import { getPagePath } from '../lib/utils/common_utils';
((global) => {
class Profile {
......@@ -93,7 +94,7 @@
return $title.val(comment[1]).change();
}
});
if (global.utils.getPagePath() === 'profiles') {
if (getPagePath() === 'profiles') {
return new Profile();
}
});
......
import PANEL_STATE from './constants';
import { backOff } from '../lib/utils/common_utils';
export default class PrometheusMetrics {
constructor(wrapperSelector) {
......@@ -79,7 +80,7 @@ export default class PrometheusMetrics {
loadActiveMetrics() {
this.showMonitoringMetricsPanelState(PANEL_STATE.LOADING);
gl.utils.backOff((next, stop) => {
backOff((next, stop) => {
$.getJSON(this.activeMetricsEndpoint)
.done((res) => {
if (res && res.success) {
......
/* eslint-disable comma-dangle, no-return-assign, one-var, no-var, no-underscore-dangle, one-var-declaration-per-line, no-unused-vars, no-cond-assign, consistent-return, object-shorthand, prefer-arrow-callback, func-names, space-before-function-paren, prefer-template, quotes, class-methods-use-this, no-unused-expressions, no-sequences, wrap-iife, no-lonely-if, no-else-return, no-param-reassign, vars-on-top, max-len */
import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from './lib/utils/common_utils';
((global) => {
const KEYCODE = {
......@@ -146,14 +147,14 @@
}
getCategoryContents() {
var dashboardOptions, groupOptions, issuesPath, items, mrPath, name, options, projectOptions, userId, userName, utils;
var dashboardOptions, groupOptions, issuesPath, items, mrPath, name, options, projectOptions, userId, userName;
userId = gon.current_user_id;
userName = gon.current_username;
utils = gl.utils, projectOptions = gl.projectOptions, groupOptions = gl.groupOptions, dashboardOptions = gl.dashboardOptions;
if (utils.isInGroupsPage() && groupOptions) {
options = groupOptions[utils.getGroupSlug()];
} else if (utils.isInProjectPage() && projectOptions) {
options = projectOptions[utils.getProjectSlug()];
projectOptions = gl.projectOptions, groupOptions = gl.groupOptions, dashboardOptions = gl.dashboardOptions;
if (isInGroupsPage() && groupOptions) {
options = groupOptions[getGroupSlug()];
} else if (isInProjectPage() && projectOptions) {
options = projectOptions[getProjectSlug()];
} else if (dashboardOptions) {
options = dashboardOptions;
}
......
/* eslint-disable class-methods-use-this, no-unneeded-ternary, quote-props */
import UsersSelect from './users_select';
import { isMetaClick } from './lib/utils/common_utils';
export default class Todos {
constructor() {
......@@ -137,22 +138,17 @@ export default class Todos {
goToTodoUrl(e) {
const todoLink = this.dataset.url;
if (!todoLink) {
if (!todoLink || e.target.tagName === 'A' || e.target.tagName === 'IMG') {
return;
}
if (gl.utils.isMetaClick(e)) {
e.stopPropagation();
e.preventDefault();
if (isMetaClick(e)) {
const windowTarget = '_blank';
const selected = e.target;
e.stopPropagation();
e.preventDefault();
if (selected.tagName === 'IMG') {
const avatarUrl = selected.parentElement.getAttribute('href');
window.open(avatarUrl, windowTarget);
} else {
window.open(todoLink, windowTarget);
}
window.open(todoLink, windowTarget);
} else {
gl.utils.visitUrl(todoLink);
}
......
import statusCodes from '../../lib/utils/http_status';
import { bytesToMiB } from '../../lib/utils/number_utils';
import { backOff } from '../../lib/utils/common_utils';
import MemoryGraph from '../../vue_shared/components/memory_graph';
import MRWidgetService from '../services/mr_widget_service';
......@@ -84,7 +84,7 @@ export default {
}
},
loadMetrics() {
gl.utils.backOff((next, stop) => {
backOff((next, stop) => {
MRWidgetService.fetchMetrics(this.metricsUrl)
.then((res) => {
if (res.status === statusCodes.NO_CONTENT) {
......
......@@ -31,6 +31,7 @@ import {
SquashBeforeMerge,
notify,
} from './dependencies';
import { setFavicon } from '../lib/utils/common_utils';
export default {
el: '#js-vue-mr-widget',
......@@ -86,7 +87,7 @@ export default {
.then((res) => {
this.handleNotification(res);
this.mr.setData(res);
this.setFavicon();
this.setFaviconHelper();
if (cb) {
cb.call(null, res);
......@@ -115,9 +116,9 @@ export default {
immediateExecution: true,
});
},
setFavicon() {
setFaviconHelper() {
if (this.mr.ciStatusFaviconPath) {
gl.utils.setFavicon(this.mr.ciStatusFaviconPath);
setFavicon(this.mr.ciStatusFaviconPath);
}
},
fetchDeployments() {
......@@ -193,7 +194,7 @@ export default {
});
},
handleMounted() {
this.setFavicon();
this.setFaviconHelper();
this.initDeploymentsPolling();
},
},
......
<script>
import { s__ } from '../../locale';
const PAGINATION_UI_BUTTON_LIMIT = 4;
const UI_LIMIT = 6;
const SPREAD = '...';
const PREV = 'Prev';
const NEXT = 'Next';
const FIRST = '« First';
const LAST = 'Last »';
const PREV = s__('Pagination|Prev');
const NEXT = s__('Pagination|Next');
const FIRST = s__('Pagination|« First');
const LAST = s__('Pagination|Last »');
export default {
props: {
......
import Vue from 'vue';
import VueResource from 'vue-resource';
import csrf from '../lib/utils/csrf';
Vue.use(VueResource);
......@@ -18,9 +19,7 @@ Vue.http.interceptors.push((request, next) => {
// New Vue Resource version uses Headers, we are expecting a plain object to render pagination
// and polling.
Vue.http.interceptors.push((request, next) => {
if ($.rails) {
request.headers.set('X-CSRF-Token', $.rails.csrfToken());
}
request.headers.set(csrf.headerKey, csrf.token);
next((response) => {
// Headers object has a `forEach` property that iterates through all values.
......
......@@ -9,6 +9,7 @@
}
.emoji-menu {
display: none;
position: absolute;
top: 0;
margin-top: 3px;
......@@ -27,6 +28,10 @@
transition: .3s cubic-bezier(.67, .06, .19, 1.44);
transition-property: transform, opacity;
&.is-rendered {
display: block;
}
&.is-aligned-right {
transform-origin: 100% -45px;
}
......
......@@ -319,16 +319,6 @@
padding: $gl-padding;
}
.svg-content {
text-align: center;
svg {
max-width: 425px;
width: 100%;
padding: $gl-padding;
}
}
.emoji-icon {
display: inline-block;
}
......
......@@ -6,7 +6,7 @@
// Header
header.navbar-gitlab-new {
background: linear-gradient(to right, $color-900, $color-800);
background-color: $color-900;
.navbar-collapse {
color: $color-200;
......@@ -201,7 +201,7 @@ body {
@include gitlab-theme($theme-gray-900, $theme-gray-700, $theme-gray-800, $theme-gray-700, $theme-gray-700, $theme-gray-100, $theme-gray-700);
header.navbar-gitlab-new {
background: $theme-gray-100;
background-color: $theme-gray-100;
box-shadow: 0 2px 0 0 $border-color;
.logo-text svg {
......
......@@ -9,3 +9,27 @@
padding: 10px;
margin-bottom: 10px;
}
.svg-content {
text-align: center;
padding: $gl-padding;
svg,
img {
max-width: 425px;
width: 100%;
}
}
@mixin svg-size($size) {
width: $size;
height: $size;
}
svg {
&.s16 { @include svg-size(16px); }
&.s24 { @include svg-size(24px); }
&.s32 { @include svg-size(32px); }
&.s48 { @include svg-size(48px); }
&.s72 { @include svg-size(72px); }
}
......@@ -375,8 +375,6 @@ header.navbar-gitlab-new {
display: flex;
width: 100%;
position: relative;
padding-top: $gl-padding;
padding-bottom: $gl-padding;
align-items: center;
border-bottom: 1px solid $border-color;
}
......@@ -388,6 +386,11 @@ header.navbar-gitlab-new {
align-self: center;
color: $gl-text-color-secondary;
@media (max-width: $screen-xs-max) {
padding-left: 17px;
border-left: 1px solid $gl-text-color-quaternary;
}
.avatar-tile {
margin-right: 4px;
border: 1px solid $border-color;
......
......@@ -445,9 +445,8 @@ $new-sidebar-collapsed-width: 50px;
background-color: transparent;
border: 0;
padding: 6px 16px;
margin: 0 16px 0 -15px;
margin: 0 0 0 -15px;
height: 46px;
border-right: 1px solid $gl-text-color-quaternary;
i {
font-size: 20px;
......@@ -455,7 +454,12 @@ $new-sidebar-collapsed-width: 50px;
}
@media (max-width: $screen-xs-max) {
display: inline-block;
display: flex;
align-items: center;
i {
font-size: 18px;
}
}
}
......
......@@ -733,6 +733,12 @@ ul.notes {
border-bottom-left-radius: 0;
}
.btn {
svg path {
fill: $gray-darkest;
}
}
.btn.discussion-create-issue-btn {
margin-left: -4px;
border-radius: 0;
......@@ -747,10 +753,6 @@ ul.notes {
border: 0;
}
}
.new-issue-for-discussion path {
fill: $gray-darkest;
}
}
}
......@@ -823,16 +825,6 @@ ul.notes {
vertical-align: middle;
}
.discussion-next-btn {
svg {
margin: 0;
path {
fill: $gray-darkest;
}
}
}
// Merge request notes in diffs
.diff-file {
// Diff is inline
......
......@@ -117,19 +117,32 @@ module IssuableCollections
key = 'issuable_sort'
cookies[key] = params[:sort] if params[:sort].present?
# id_desc and id_asc are old values for these two.
cookies[key] = sort_value_recently_created if cookies[key] == 'id_desc'
cookies[key] = sort_value_oldest_created if cookies[key] == 'id_asc'
cookies[key] = update_cookie_value(cookies[key])
params[:sort] = cookies[key]
end
def default_sort_order
case params[:state]
when 'opened', 'all' then sort_value_recently_created
when 'opened', 'all' then sort_value_created_date
when 'merged', 'closed' then sort_value_recently_updated
else sort_value_recently_created
else sort_value_created_date
end
end
# Update old values to the actual ones.
def update_cookie_value(value)
case value
when 'id_asc' then sort_value_oldest_created
when 'id_desc' then sort_value_recently_created
when 'created_asc' then sort_value_created_date
when 'created_desc' then sort_value_created_date
when 'due_date_asc' then sort_value_due_date
when 'due_date_desc' then sort_value_due_date
when 'milestone_due_asc' then sort_value_milestone
when 'milestone_due_desc' then sort_value_milestone
when 'downvotes_asc' then sort_value_popularity
when 'downvotes_desc' then sort_value_popularity
else value
end
end
end
......@@ -3,8 +3,13 @@ class HelpController < ApplicationController
layout 'help'
# Taken from Jekyll
# https://github.com/jekyll/jekyll/blob/3.5-stable/lib/jekyll/document.rb#L13
YAML_FRONT_MATTER_REGEXP = %r!\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)!m
def index
@help_index = File.read(Rails.root.join('doc', 'README.md'))
# Remove YAML frontmatter so that it doesn't look weird
@help_index = File.read(Rails.root.join('doc', 'README.md')).sub(YAML_FRONT_MATTER_REGEXP, '')
# Prefix Markdown links with `help/` unless they are external links
# See http://rubular.com/r/X3baHTbPO2
......@@ -22,7 +27,8 @@ class HelpController < ApplicationController
path = File.join(Rails.root, 'doc', "#{@path}.md")
if File.exist?(path)
@markdown = File.read(path)
# Remove YAML frontmatter so that it doesn't look weird
@markdown = File.read(path).gsub(YAML_FRONT_MATTER_REGEXP, '')
render 'show.html.haml'
else
......
......@@ -35,7 +35,10 @@ class Projects::TreeController < Projects::ApplicationController
end
format.json do
render json: TreeSerializer.new(project: @project, repository: @repository, ref: @ref).represent(@tree)
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/38261
Gitlab::GitalyClient.allow_n_plus_1_calls do
render json: TreeSerializer.new(project: @project, repository: @repository, ref: @ref).represent(@tree)
end
end
end
end
......
......@@ -30,10 +30,4 @@ module AppearancesHelper
render 'shared/logo.svg'
end
end
def custom_icon(icon_name, size: 16)
# We can't simply do the below, because there are some .erb SVGs.
# File.read(Rails.root.join("app/views/shared/icons/_#{icon_name}.svg")).html_safe
render "shared/icons/#{icon_name}.svg", size: size
end
end
......@@ -13,22 +13,29 @@ module AvatarsHelper
user_name = options[:user].try(:name) || options[:user_name]
avatar_url = options[:url] || avatar_icon(options[:user] || options[:user_email], avatar_size)
has_tooltip = options[:has_tooltip].nil? ? true : options[:has_tooltip]
data_attributes = {}
data_attributes = options[:data] || {}
css_class = %W[avatar s#{avatar_size}].push(*options[:css_class])
if has_tooltip
css_class.push('has-tooltip')
data_attributes = { container: 'body' }
data_attributes[:container] = 'body'
end
image_tag(
avatar_url,
if options[:lazy]
css_class << 'lazy'
data_attributes[:src] = avatar_url
avatar_url = LazyImageTagHelper.placeholder_image
end
image_options = {
alt: "#{user_name}'s avatar",
src: avatar_url,
data: data_attributes,
class: css_class,
alt: "#{user_name}'s avatar",
title: user_name,
data: data_attributes,
lazy: true
)
title: user_name
}
tag(:img, image_options)
end
def user_avatar(options = {})
......
......@@ -176,13 +176,15 @@ module CommitsHelper
end
end
def view_file_button(commit_sha, diff_new_path, project)
def view_file_button(commit_sha, diff_new_path, project, replaced: false)
title = replaced ? _('View replaced file @ ') : _('View file @ ')
link_to(
project_blob_path(project,
tree_join(commit_sha, diff_new_path)),
class: 'btn view-file js-view-file'
) do
raw('View file @ ') + content_tag(:span, Commit.truncate_sha(commit_sha),
raw(title) + content_tag(:span, Commit.truncate_sha(commit_sha),
class: 'commit-sha')
end
end
......
......@@ -125,7 +125,7 @@ module GroupsHelper
end
def default_help
s_("GroupSettings|This setting will be applied to all subgroups unless overridden by a group owner.")
s_("GroupSettings|This setting will be applied to all subgroups unless overridden by a group owner. Groups that already have access to the project will continue to have access unless removed manually.")
end
def ancestor_locked_but_you_can_override(group)
......
......@@ -17,6 +17,18 @@ module IconsHelper
options.include?(:base) ? fa_stacked_icon(names, options) : fa_icon(names, options)
end
def custom_icon(icon_name, size: 16)
# We can't simply do the below, because there are some .erb SVGs.
# File.read(Rails.root.join("app/views/shared/icons/_#{icon_name}.svg")).html_safe
render "shared/icons/#{icon_name}.svg", size: size
end
def sprite_icon(icon_name, size: nil, css_class: nil)
css_classes = size ? "s#{size}" : nil
css_classes << " #{css_class}" unless css_class.blank?
content_tag(:svg, content_tag(:use, "", { "xlink:href" => "#{image_path('icons.svg')}##{icon_name}" } ), class: css_classes)
end
def audit_icon(names, options = {})
case names
when "standard"
......
......@@ -239,8 +239,8 @@ module ProjectsHelper
end
end
def has_projects_or_name?(projects, params)
!!(params[:name] || any_projects?(projects))
def show_projects?(projects, params)
!!(params[:personal] || params[:name] || any_projects?(projects))
end
private
......
This diff is collapsed.
module SystemNoteHelper
ICON_NAMES_BY_ACTION = {
'commit' => 'icon_commit',
'description' => 'icon_edit',
'merge' => 'icon_merge',
'merged' => 'icon_merged',
'opened' => 'icon_status_open',
'closed' => 'icon_status_closed',
'time_tracking' => 'icon_stopwatch',
'assignee' => 'icon_user',
'title' => 'icon_edit',
'task' => 'icon_check_square_o',
'label' => 'icon_tags',
'cross_reference' => 'icon_random',
'branch' => 'icon_code_fork',
'confidential' => 'icon_eye_slash',
'visible' => 'icon_eye',
'milestone' => 'icon_clock_o',
'discussion' => 'icon_comment_o',
'moved' => 'icon_arrow_circle_o_right',
'outdated' => 'icon_edit',
'duplicate' => 'icon_clone'
'commit' => 'commit',
'description' => 'pencil',
'merge' => 'git-merge',
'merged' => 'git-merge',
'opened' => 'issue-open',
'closed' => 'issue-close',
'time_tracking' => 'timer',
'assignee' => 'user',
'title' => 'pencil',
'task' => 'task-done',
'label' => 'label',
'cross_reference' => 'comment-dots',
'branch' => 'fork',
'confidential' => 'eye-slash',
'visible' => 'eye',
'milestone' => 'clock',
'discussion' => 'comment',
'moved' => 'arrow-right',
'outdated' => 'pencil',
'duplicate' => 'issue-duplicate'
}.freeze
def system_note_icon_name(note)
......@@ -28,7 +28,7 @@ module SystemNoteHelper
def icon_for_system_note(note)
icon_name = system_note_icon_name(note)
custom_icon(icon_name) if icon_name
sprite_icon(icon_name) if icon_name
end
extend self
......
......@@ -143,16 +143,18 @@ module Issuable
end
def sort(method, excluded_labels: [])
sorted = case method.to_s
when 'milestone_due_asc' then order_milestone_due_asc
when 'milestone_due_desc' then order_milestone_due_desc
when 'downvotes_desc' then order_downvotes_desc
when 'upvotes_desc' then order_upvotes_desc
when 'label_priority' then order_labels_priority(excluded_labels: excluded_labels)
when 'priority' then order_due_date_and_labels_priority(excluded_labels: excluded_labels)
else
order_by(method)
end
sorted =
case method.to_s
when 'downvotes_desc' then order_downvotes_desc
when 'label_priority' then order_labels_priority(excluded_labels: excluded_labels)
when 'milestone' then order_milestone_due_asc
when 'milestone_due_asc' then order_milestone_due_asc
when 'milestone_due_desc' then order_milestone_due_desc
when 'popularity' then order_upvotes_desc
when 'priority' then order_due_date_and_labels_priority(excluded_labels: excluded_labels)
when 'upvotes_desc' then order_upvotes_desc
else order_by(method)
end
# Break ties with the ID column for pagination
sorted.order(id: :desc)
......@@ -214,7 +216,7 @@ module Issuable
def grouping_columns(sort)
grouping_columns = [arel_table[:id]]
if %w(milestone_due_desc milestone_due_asc).include?(sort)
if %w(milestone_due_desc milestone_due_asc milestone).include?(sort)
milestone_table = Milestone.arel_table
grouping_columns << milestone_table[:id]
grouping_columns << milestone_table[:due_date]
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment