Commit b4af5468 authored by Jose Ivan Vargas's avatar Jose Ivan Vargas

Merge branch 'master' into sh-headless-chrome-support

parents 7fb47732 3b2d68d3
...@@ -7,4 +7,5 @@ ...@@ -7,4 +7,5 @@
/vendor/ /vendor/
karma.config.js karma.config.js
webpack.config.js webpack.config.js
svg.config.js
/app/assets/javascripts/locale/**/*.js /app/assets/javascripts/locale/**/*.js
...@@ -176,11 +176,20 @@ build-package: ...@@ -176,11 +176,20 @@ build-package:
image: ruby:2.4-alpine image: ruby:2.4-alpine
before_script: before_script:
- gem install gitlab --no-doc - 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: [] services: []
cache: {}
dependencies: []
artifacts: {}
variables: variables:
SETUP_DB: "false" SETUP_DB: "false"
USE_BUNDLE_INSTALL: "false" USE_BUNDLE_INSTALL: "false"
cache: {} GIT_STRATEGY: none
when: manual when: manual
only: only:
- branches - branches
...@@ -197,7 +206,7 @@ review-docs-deploy: ...@@ -197,7 +206,7 @@ review-docs-deploy:
url: http://preview-$CI_COMMIT_REF_SLUG.$DOCS_REVIEW_APPS_DOMAIN/$DOCS_GITLAB_REPO_SUFFIX url: http://preview-$CI_COMMIT_REF_SLUG.$DOCS_REVIEW_APPS_DOMAIN/$DOCS_GITLAB_REPO_SUFFIX
on_stop: review-docs-cleanup on_stop: review-docs-cleanup
script: script:
- scripts/trigger-build-docs deploy - ./trigger-build-docs deploy
# Cleanup remote environment of gitlab-docs # Cleanup remote environment of gitlab-docs
review-docs-cleanup: review-docs-cleanup:
...@@ -207,7 +216,7 @@ review-docs-cleanup: ...@@ -207,7 +216,7 @@ review-docs-cleanup:
name: review-docs/$CI_COMMIT_REF_NAME name: review-docs/$CI_COMMIT_REF_NAME
action: stop action: stop
script: script:
- scripts/trigger-build-docs cleanup - ./trigger-build-docs cleanup
# Retrieve knapsack and rspec_flaky reports # Retrieve knapsack and rspec_flaky reports
retrieve-tests-metadata: retrieve-tests-metadata:
......
This diff is collapsed.
...@@ -26,7 +26,7 @@ gem 'doorkeeper', '~> 4.2.0' ...@@ -26,7 +26,7 @@ gem 'doorkeeper', '~> 4.2.0'
gem 'doorkeeper-openid_connect', '~> 1.1.0' gem 'doorkeeper-openid_connect', '~> 1.1.0'
gem 'omniauth', '~> 1.4.2' gem 'omniauth', '~> 1.4.2'
gem 'omniauth-auth0', '~> 1.4.1' gem 'omniauth-auth0', '~> 1.4.1'
gem 'omniauth-azure-oauth2', '~> 0.0.6' gem 'omniauth-azure-oauth2', '~> 0.0.9'
gem 'omniauth-cas3', '~> 1.1.4' gem 'omniauth-cas3', '~> 1.1.4'
gem 'omniauth-facebook', '~> 4.0.0' gem 'omniauth-facebook', '~> 4.0.0'
gem 'omniauth-github', '~> 1.1.1' gem 'omniauth-github', '~> 1.1.1'
...@@ -128,7 +128,7 @@ gem 'asciidoctor-plantuml', '0.0.7' ...@@ -128,7 +128,7 @@ gem 'asciidoctor-plantuml', '0.0.7'
gem 'rouge', '~> 2.0' gem 'rouge', '~> 2.0'
gem 'truncato', '~> 0.7.9' gem 'truncato', '~> 0.7.9'
gem 'bootstrap_form', '~> 2.7.0' gem 'bootstrap_form', '~> 2.7.0'
gem 'nokogiri', '~> 1.8.0' gem 'nokogiri', '~> 1.8.1'
# Diffs # Diffs
gem 'diffy', '~> 3.1.0' gem 'diffy', '~> 3.1.0'
......
...@@ -195,7 +195,7 @@ GEM ...@@ -195,7 +195,7 @@ GEM
factory_girl_rails (4.7.0) factory_girl_rails (4.7.0)
factory_girl (~> 4.7.0) factory_girl (~> 4.7.0)
railties (>= 3.0.0) railties (>= 3.0.0)
faraday (0.12.1) faraday (0.12.2)
multipart-post (>= 1.2, < 3) multipart-post (>= 1.2, < 3)
faraday_middleware (0.11.0.1) faraday_middleware (0.11.0.1)
faraday (>= 0.7.4, < 1.0) faraday (>= 0.7.4, < 1.0)
...@@ -483,7 +483,7 @@ GEM ...@@ -483,7 +483,7 @@ GEM
mime-types (2.99.3) mime-types (2.99.3)
mimemagic (0.3.0) mimemagic (0.3.0)
mini_mime (0.1.4) mini_mime (0.1.4)
mini_portile2 (2.2.0) mini_portile2 (2.3.0)
minitest (5.7.0) minitest (5.7.0)
mmap2 (2.2.7) mmap2 (2.2.7)
mousetrap-rails (1.4.6) mousetrap-rails (1.4.6)
...@@ -497,8 +497,8 @@ GEM ...@@ -497,8 +497,8 @@ GEM
net-ldap (0.16.0) net-ldap (0.16.0)
net-ssh (4.1.0) net-ssh (4.1.0)
netrc (0.11.0) netrc (0.11.0)
nokogiri (1.8.0) nokogiri (1.8.1)
mini_portile2 (~> 2.2.0) mini_portile2 (~> 2.3.0)
numerizer (0.1.1) numerizer (0.1.1)
oauth (0.5.1) oauth (0.5.1)
oauth2 (1.4.0) oauth2 (1.4.0)
...@@ -517,10 +517,10 @@ GEM ...@@ -517,10 +517,10 @@ GEM
omniauth-oauth2 (~> 1.1) omniauth-oauth2 (~> 1.1)
omniauth-authentiq (0.3.1) omniauth-authentiq (0.3.1)
omniauth-oauth2 (~> 1.3, >= 1.3.1) omniauth-oauth2 (~> 1.3, >= 1.3.1)
omniauth-azure-oauth2 (0.0.6) omniauth-azure-oauth2 (0.0.9)
jwt (~> 1.0) jwt (~> 1.0)
omniauth (~> 1.0) omniauth (~> 1.0)
omniauth-oauth2 (~> 1.1) omniauth-oauth2 (~> 1.4)
omniauth-cas3 (1.1.4) omniauth-cas3 (1.1.4)
addressable (~> 2.3) addressable (~> 2.3)
nokogiri (~> 1.7, >= 1.7.1) nokogiri (~> 1.7, >= 1.7.1)
...@@ -546,7 +546,7 @@ GEM ...@@ -546,7 +546,7 @@ GEM
omniauth-oauth (1.1.0) omniauth-oauth (1.1.0)
oauth oauth
omniauth (~> 1.0) omniauth (~> 1.0)
omniauth-oauth2 (1.3.1) omniauth-oauth2 (1.4.0)
oauth2 (~> 1.0) oauth2 (~> 1.0)
omniauth (~> 1.2) omniauth (~> 1.2)
omniauth-oauth2-generic (0.2.2) omniauth-oauth2-generic (0.2.2)
...@@ -1064,14 +1064,14 @@ DEPENDENCIES ...@@ -1064,14 +1064,14 @@ DEPENDENCIES
mysql2 (~> 0.4.5) mysql2 (~> 0.4.5)
net-ldap net-ldap
net-ssh (~> 4.1.0) net-ssh (~> 4.1.0)
nokogiri (~> 1.8.0) nokogiri (~> 1.8.1)
oauth2 (~> 1.4) oauth2 (~> 1.4)
octokit (~> 4.6.2) octokit (~> 4.6.2)
oj (~> 2.17.4) oj (~> 2.17.4)
omniauth (~> 1.4.2) omniauth (~> 1.4.2)
omniauth-auth0 (~> 1.4.1) omniauth-auth0 (~> 1.4.1)
omniauth-authentiq (~> 0.3.1) omniauth-authentiq (~> 0.3.1)
omniauth-azure-oauth2 (~> 0.0.6) omniauth-azure-oauth2 (~> 0.0.9)
omniauth-cas3 (~> 1.1.4) omniauth-cas3 (~> 1.1.4)
omniauth-facebook (~> 4.0.0) omniauth-facebook (~> 4.0.0)
omniauth-github (~> 1.1.1) omniauth-github (~> 1.1.1)
......
File mode changed from 100755 to 100644
{"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.
...@@ -24,6 +24,9 @@ const categoryLabelMap = { ...@@ -24,6 +24,9 @@ const categoryLabelMap = {
flags: 'Flags', flags: 'Flags',
}; };
const IS_VISIBLE = 'is-visible';
const IS_RENDERED = 'is-rendered';
class AwardsHandler { class AwardsHandler {
constructor(emoji) { constructor(emoji) {
this.emoji = emoji; this.emoji = emoji;
...@@ -51,7 +54,7 @@ class AwardsHandler { ...@@ -51,7 +54,7 @@ class AwardsHandler {
if (!$target.closest('.emoji-menu').length) { if (!$target.closest('.emoji-menu').length) {
if ($('.emoji-menu').is(':visible')) { if ($('.emoji-menu').is(':visible')) {
$('.js-add-award.is-active').removeClass('is-active'); $('.js-add-award.is-active').removeClass('is-active');
$('.emoji-menu').removeClass('is-visible'); this.hideMenuElement($('.emoji-menu'));
} }
} }
}); });
...@@ -88,12 +91,12 @@ class AwardsHandler { ...@@ -88,12 +91,12 @@ class AwardsHandler {
if ($menu.length) { if ($menu.length) {
if ($menu.is('.is-visible')) { if ($menu.is('.is-visible')) {
$addBtn.removeClass('is-active'); $addBtn.removeClass('is-active');
$menu.removeClass('is-visible'); this.hideMenuElement($menu);
$('.js-emoji-menu-search').blur(); $('.js-emoji-menu-search').blur();
} else { } else {
$addBtn.addClass('is-active'); $addBtn.addClass('is-active');
this.positionMenu($menu, $addBtn); this.positionMenu($menu, $addBtn);
$menu.addClass('is-visible'); this.showMenuElement($menu);
$('.js-emoji-menu-search').focus(); $('.js-emoji-menu-search').focus();
} }
} else { } else {
...@@ -103,7 +106,7 @@ class AwardsHandler { ...@@ -103,7 +106,7 @@ class AwardsHandler {
$addBtn.removeClass('is-loading'); $addBtn.removeClass('is-loading');
this.positionMenu($createdMenu, $addBtn); this.positionMenu($createdMenu, $addBtn);
return setTimeout(() => { return setTimeout(() => {
$createdMenu.addClass('is-visible'); this.showMenuElement($createdMenu);
$('.js-emoji-menu-search').focus(); $('.js-emoji-menu-search').focus();
}, 200); }, 200);
}); });
...@@ -241,7 +244,8 @@ class AwardsHandler { ...@@ -241,7 +244,8 @@ class AwardsHandler {
if (isInIssuePage() && !isMainAwardsBlock) { if (isInIssuePage() && !isMainAwardsBlock) {
const id = votesBlock.attr('id').replace('note_', ''); const id = votesBlock.attr('id').replace('note_', '');
$('.emoji-menu').removeClass('is-visible'); this.hideMenuElement($('.emoji-menu'));
$('.js-add-award.is-active').removeClass('is-active'); $('.js-add-award.is-active').removeClass('is-active');
const toggleAwardEvent = new CustomEvent('toggleAward', { const toggleAwardEvent = new CustomEvent('toggleAward', {
detail: { detail: {
...@@ -261,7 +265,8 @@ class AwardsHandler { ...@@ -261,7 +265,8 @@ class AwardsHandler {
return typeof callback === 'function' ? callback() : undefined; return typeof callback === 'function' ? callback() : undefined;
}); });
$('.emoji-menu').removeClass('is-visible'); this.hideMenuElement($('.emoji-menu'));
return $('.js-add-award.is-active').removeClass('is-active'); return $('.js-add-award.is-active').removeClass('is-active');
} }
...@@ -529,6 +534,33 @@ class AwardsHandler { ...@@ -529,6 +534,33 @@ class AwardsHandler {
return $matchingElements.closest('li').clone(); 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() { destroy() {
this.eventListeners.forEach((entry) => { this.eventListeners.forEach((entry) => {
entry.element.off.call(entry.element, ...entry.args); entry.element.off.call(entry.element, ...entry.args);
......
...@@ -8,11 +8,11 @@ gl.issueBoards.ModalEmptyState = Vue.extend({ ...@@ -8,11 +8,11 @@ gl.issueBoards.ModalEmptyState = Vue.extend({
return ModalStore.store; return ModalStore.store;
}, },
props: { props: {
image: { newIssuePath: {
type: String, type: String,
required: true, required: true,
}, },
newIssuePath: { emptyStateSvg: {
type: String, type: String,
required: true, required: true,
}, },
...@@ -42,7 +42,7 @@ gl.issueBoards.ModalEmptyState = Vue.extend({ ...@@ -42,7 +42,7 @@ gl.issueBoards.ModalEmptyState = Vue.extend({
<section class="empty-state"> <section class="empty-state">
<div class="row"> <div class="row">
<div class="col-xs-12 col-sm-6 col-sm-push-6"> <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>
<div class="col-xs-12 col-sm-6 col-sm-pull-6"> <div class="col-xs-12 col-sm-6 col-sm-pull-6">
<div class="text-content"> <div class="text-content">
......
...@@ -12,11 +12,11 @@ const ModalStore = gl.issueBoards.ModalStore; ...@@ -12,11 +12,11 @@ const ModalStore = gl.issueBoards.ModalStore;
gl.issueBoards.IssuesModal = Vue.extend({ gl.issueBoards.IssuesModal = Vue.extend({
props: { props: {
blankStateImage: { newIssuePath: {
type: String, type: String,
required: true, required: true,
}, },
newIssuePath: { emptyStateSvg: {
type: String, type: String,
required: true, required: true,
}, },
...@@ -150,14 +150,14 @@ gl.issueBoards.IssuesModal = Vue.extend({ ...@@ -150,14 +150,14 @@ gl.issueBoards.IssuesModal = Vue.extend({
:label-path="labelPath"> :label-path="labelPath">
</modal-header> </modal-header>
<modal-list <modal-list
:image="blankStateImage"
:issue-link-base="issueLinkBase" :issue-link-base="issueLinkBase"
:root-path="rootPath" :root-path="rootPath"
:empty-state-svg="emptyStateSvg"
v-if="!loading && showList && !filterLoading"></modal-list> v-if="!loading && showList && !filterLoading"></modal-list>
<empty-state <empty-state
v-if="showEmptyState" v-if="showEmptyState"
:image="blankStateImage" :new-issue-path="newIssuePath"
:new-issue-path="newIssuePath"></empty-state> :empty-state-svg="emptyStateSvg"></empty-state>
<section <section
class="add-issues-list text-center" class="add-issues-list text-center"
v-if="loading || filterLoading"> v-if="loading || filterLoading">
......
...@@ -15,7 +15,7 @@ gl.issueBoards.ModalList = Vue.extend({ ...@@ -15,7 +15,7 @@ gl.issueBoards.ModalList = Vue.extend({
type: String, type: String,
required: true, required: true,
}, },
image: { emptyStateSvg: {
type: String, type: String,
required: true, required: true,
}, },
...@@ -119,8 +119,8 @@ gl.issueBoards.ModalList = Vue.extend({ ...@@ -119,8 +119,8 @@ gl.issueBoards.ModalList = Vue.extend({
class="empty-state add-issues-empty-state-filter text-center" class="empty-state add-issues-empty-state-filter text-center"
v-if="issuesCount > 0 && issues.length === 0"> v-if="issuesCount > 0 && issues.length === 0">
<div <div
class="svg-content" class="svg-content">
v-html="image"> <img :src="emptyStateSvg"/>
</div> </div>
<div class="text-content"> <div class="text-content">
<h4> <h4>
......
...@@ -35,6 +35,8 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -35,6 +35,8 @@ document.addEventListener('DOMContentLoaded', () => {
propsData: { propsData: {
endpoint: pipelineTableViewEl.dataset.endpoint, endpoint: pipelineTableViewEl.dataset.endpoint,
helpPagePath: pipelineTableViewEl.dataset.helpPagePath, helpPagePath: pipelineTableViewEl.dataset.helpPagePath,
emptyStateSvgPath: pipelineTableViewEl.dataset.emptyStateSvgPath,
errorStateSvgPath: pipelineTableViewEl.dataset.errorStateSvgPath,
autoDevopsHelpPath: pipelineTableViewEl.dataset.helpAutoDevopsPath, autoDevopsHelpPath: pipelineTableViewEl.dataset.helpAutoDevopsPath,
}, },
}).$mount(); }).$mount();
......
...@@ -17,6 +17,14 @@ ...@@ -17,6 +17,14 @@
type: String, type: String,
required: true, required: true,
}, },
emptyStateSvgPath: {
type: String,
required: true,
},
errorStateSvgPath: {
type: String,
required: true,
},
}, },
mixins: [ mixins: [
pipelinesMixin, pipelinesMixin,
...@@ -87,10 +95,12 @@ ...@@ -87,10 +95,12 @@
<empty-state <empty-state
v-if="shouldRenderEmptyState" v-if="shouldRenderEmptyState"
:help-page-path="helpPagePath" :help-page-path="helpPagePath"
:empty-state-svg-path="emptyStateSvgPath"
/> />
<error-state <error-state
v-if="shouldRenderErrorState" v-if="shouldRenderErrorState"
:error-state-svg-path="errorStateSvgPath"
/> />
<div <div
......
export default {
props: {
count: {
type: Number,
required: true,
},
},
template: `
<span v-if="count === 50" class="events-info pull-right">
<i class="fa fa-warning has-tooltip"
aria-hidden="true"
:title="n__('Limited to showing %d event at most', 'Limited to showing %d events at most', 50)"
data-placement="top"></i>
{{ n__('Showing %d event', 'Showing %d events', 50) }}
</span>
`,
};
<script>
import tooltip from '../../vue_shared/directives/tooltip';
export default {
props: {
count: {
type: Number,
required: true,
},
},
directives: {
tooltip,
},
};
</script>
<template>
<span v-if="count === 50" class="events-info pull-right">
<i
class="fa fa-warning"
v-tooltip
aria-hidden="true"
:title="n__('Limited to showing %d event at most', 'Limited to showing %d events at most', 50)"
data-placement="top"></i>
{{ n__('Showing %d event', 'Showing %d events', 50) }}
</span>
</template>
/* eslint-disable no-param-reassign */
import Vue from 'vue';
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StageCodeComponent = Vue.extend({
props: {
items: Array,
stage: Object,
},
components: {
userAvatarImage,
},
template: `
<div>
<div class="events-description">
{{ stage.description }}
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
<li v-for="mergeRequest in items" class="stage-event-item">
<div class="item-details">
<!-- FIXME: Pass an alt attribute here for accessibility -->
<user-avatar-image :img-src="mergeRequest.author.avatarUrl"/>
<h5 class="item-title merge-merquest-title">
<a :href="mergeRequest.url">
{{ mergeRequest.title }}
</a>
</h5>
<a :href="mergeRequest.url" class="issue-link">!{{ mergeRequest.iid }}</a>
&middot;
<span>
{{ s__('OpenedNDaysAgo|Opened') }}
<a :href="mergeRequest.url" class="issue-date">{{ mergeRequest.createdAt }}</a>
</span>
<span>
{{ s__('ByAuthor|by') }}
<a :href="mergeRequest.author.webUrl" class="issue-author-link">{{ mergeRequest.author.name }}</a>
</span>
</div>
<div class="item-time">
<total-time :time="mergeRequest.totalTime"></total-time>
</div>
</li>
</ul>
</div>
`,
});
<script>
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
export default {
props: {
items: Array,
stage: Object,
},
components: {
userAvatarImage,
},
};
</script>
<template>
<div>
<div class="events-description">
{{ stage.description }}
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
<li v-for="mergeRequest in items" class="stage-event-item">
<div class="item-details">
<!-- FIXME: Pass an alt attribute here for accessibility -->
<user-avatar-image :img-src="mergeRequest.author.avatarUrl"/>
<h5 class="item-title merge-merquest-title">
<a :href="mergeRequest.url">
{{ mergeRequest.title }}
</a>
</h5>
<a :href="mergeRequest.url" class="issue-link">!{{ mergeRequest.iid }}</a>
&middot;
<span>
{{ s__('OpenedNDaysAgo|Opened') }}
<a :href="mergeRequest.url" class="issue-date">{{ mergeRequest.createdAt }}</a>
</span>
<span>
{{ s__('ByAuthor|by') }}
<a :href="mergeRequest.author.webUrl" class="issue-author-link">{{ mergeRequest.author.name }}</a>
</span>
</div>
<div class="item-time">
<total-time :time="mergeRequest.totalTime"></total-time>
</div>
</li>
</ul>
</div>
</template>
<script>
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
export default {
props: {
items: Array,
stage: Object,
},
components: {
userAvatarImage,
},
};
</script>
<template>
<div>
<div class="events-description">
{{ stage.description }}
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
<li
v-for="(issue, i) in items"
:key="i"
class="stage-event-item">
<div class="item-details">
<!-- FIXME: Pass an alt attribute here for accessibility -->
<user-avatar-image :img-src="issue.author.avatarUrl"/>
<h5 class="item-title issue-title">
<a class="issue-title" :href="issue.url">
{{ issue.title }}
</a>
</h5>
<a :href="issue.url" class="issue-link">#{{ issue.iid }}</a>
&middot;
<span>
{{ s__('OpenedNDaysAgo|Opened') }}
<a :href="issue.url" class="issue-date">{{ issue.createdAt }}</a>
</span>
<span>
{{ s__('ByAuthor|by') }}
<a :href="issue.author.webUrl" class="issue-author-link">
{{ issue.author.name }}
</a>
</span>
</div>
<div class="item-time">
<total-time :time="issue.totalTime"/>
</div>
</li>
</ul>
</div>
</template>
/* eslint-disable no-param-reassign */
import Vue from 'vue';
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StageIssueComponent = Vue.extend({
props: {
items: Array,
stage: Object,
},
components: {
userAvatarImage,
},
template: `
<div>
<div class="events-description">
{{ stage.description }}
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
<li v-for="issue in items" class="stage-event-item">
<div class="item-details">
<!-- FIXME: Pass an alt attribute here for accessibility -->
<user-avatar-image :img-src="issue.author.avatarUrl"/>
<h5 class="item-title issue-title">
<a class="issue-title" :href="issue.url">
{{ issue.title }}
</a>
</h5>
<a :href="issue.url" class="issue-link">#{{ issue.iid }}</a>
&middot;
<span>
{{ s__('OpenedNDaysAgo|Opened') }}
<a :href="issue.url" class="issue-date">{{ issue.createdAt }}</a>
</span>
<span>
{{ s__('ByAuthor|by') }}
<a :href="issue.author.webUrl" class="issue-author-link">
{{ issue.author.name }}
</a>
</span>
</div>
<div class="item-time">
<total-time :time="issue.totalTime"></total-time>
</div>
</li>
</ul>
</div>
`,
});
/* eslint-disable no-param-reassign */
import Vue from 'vue';
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
import iconCommit from '../svg/icon_commit.svg';
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StagePlanComponent = Vue.extend({
props: {
items: Array,
stage: Object,
},
components: {
userAvatarImage,
},
data() {
return { iconCommit };
},
template: `
<div>
<div class="events-description">
{{ stage.description }}
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
<li v-for="commit in items" class="stage-event-item">
<div class="item-details item-conmmit-component">
<!-- FIXME: Pass an alt attribute here for accessibility -->
<user-avatar-image :img-src="commit.author.avatarUrl"/>
<h5 class="item-title commit-title">
<a :href="commit.commitUrl">
{{ commit.title }}
</a>
</h5>
<span>
{{ s__('FirstPushedBy|First') }}
<span class="commit-icon">${iconCommit}</span>
<a :href="commit.commitUrl" class="commit-hash-link commit-sha">{{ commit.shortSha }}</a>
{{ s__('FirstPushedBy|pushed by') }}
<a :href="commit.author.webUrl" class="commit-author-link">
{{ commit.author.name }}
</a>
</span>
</div>
<div class="item-time">
<total-time :time="commit.totalTime"></total-time>
</div>
</li>
</ul>
</div>
`,
});
<script>
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
import iconCommit from '../svg/icon_commit.svg';
export default {
props: {
items: Array,
stage: Object,
},
components: {
userAvatarImage,
},
computed: {
iconCommit() {
return iconCommit;
},
},
};
</script>
<template>
<div>
<div class="events-description">
{{ stage.description }}
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
<li
v-for="(commit, i) in items"
:key="i"
class="stage-event-item">
<div class="item-details item-conmmit-component">
<!-- FIXME: Pass an alt attribute here for accessibility -->
<user-avatar-image :img-src="commit.author.avatarUrl"/>
<h5 class="item-title commit-title">
<a :href="commit.commitUrl">
{{ commit.title }}
</a>
</h5>
<span>
{{ s__('FirstPushedBy|First') }}
<span class="commit-icon" v-html="iconCommit"></span>
<a :href="commit.commitUrl" class="commit-hash-link commit-sha">{{ commit.shortSha }}</a>
{{ s__('FirstPushedBy|pushed by') }}
<a :href="commit.author.webUrl" class="commit-author-link">
{{ commit.author.name }}
</a>
</span>
</div>
<div class="item-time">
<total-time :time="commit.totalTime" />
</div>
</li>
</ul>
</div>
</template>
/* eslint-disable no-param-reassign */
import Vue from 'vue';
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StageProductionComponent = Vue.extend({
props: {
items: Array,
stage: Object,
},
components: {
userAvatarImage,
},
template: `
<div>
<div class="events-description">
{{ stage.description }}
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
<li v-for="issue in items" class="stage-event-item">
<div class="item-details">
<!-- FIXME: Pass an alt attribute here for accessibility -->
<user-avatar-image :img-src="issue.author.avatarUrl"/>
<h5 class="item-title issue-title">
<a class="issue-title" :href="issue.url">
{{ issue.title }}
</a>
</h5>
<a :href="issue.url" class="issue-link">#{{ issue.iid }}</a>
&middot;
<span>
{{ s__('OpenedNDaysAgo|Opened') }}
<a :href="issue.url" class="issue-date">{{ issue.createdAt }}</a>
</span>
<span>
{{ s__('ByAuthor|by') }}
<a :href="issue.author.webUrl" class="issue-author-link">
{{ issue.author.name }}
</a>
</span>
</div>
<div class="item-time">
<total-time :time="issue.totalTime"></total-time>
</div>
</li>
</ul>
</div>
`,
});
/* eslint-disable no-param-reassign */
import Vue from 'vue';
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StageReviewComponent = Vue.extend({
props: {
items: Array,
stage: Object,
},
components: {
userAvatarImage,
},
template: `
<div>
<div class="events-description">
{{ stage.description }}
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
<li v-for="mergeRequest in items" class="stage-event-item">
<div class="item-details">
<!-- FIXME: Pass an alt attribute here for accessibility -->
<user-avatar-image :img-src="mergeRequest.author.avatarUrl"/>
<h5 class="item-title merge-merquest-title">
<a :href="mergeRequest.url">
{{ mergeRequest.title }}
</a>
</h5>
<a :href="mergeRequest.url" class="issue-link">!{{ mergeRequest.iid }}</a>
&middot;
<span>
{{ s__('OpenedNDaysAgo|Opened') }}
<a :href="mergeRequest.url" class="issue-date">{{ mergeRequest.createdAt }}</a>
</span>
<span>
{{ s__('ByAuthor|by') }}
<a :href="mergeRequest.author.webUrl" class="issue-author-link">{{ mergeRequest.author.name }}</a>
</span>
<template v-if="mergeRequest.state === 'closed'">
<span class="merge-request-state">
<i class="fa fa-ban"></i>
{{ mergeRequest.state.toUpperCase() }}
</span>
</template>
<template v-else>
<span class="merge-request-branch" v-if="mergeRequest.branch">
<i class= "fa fa-code-fork"></i>
<a :href="mergeRequest.branch.url">{{ mergeRequest.branch.name }}</a>
</span>
</template>
</div>
<div class="item-time">
<total-time :time="mergeRequest.totalTime"></total-time>
</div>
</li>
</ul>
</div>
`,
});
<script>
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
export default {
props: {
items: Array,
stage: Object,
},
components: {
userAvatarImage,
},
};
</script>
<template>
<div>
<div class="events-description">
{{ stage.description }}
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
<li
v-for="(mergeRequest, i) in items"
:key="i"
class="stage-event-item">
<div class="item-details">
<!-- FIXME: Pass an alt attribute here for accessibility -->
<user-avatar-image :img-src="mergeRequest.author.avatarUrl"/>
<h5 class="item-title merge-merquest-title">
<a :href="mergeRequest.url">
{{ mergeRequest.title }}
</a>
</h5>
<a :href="mergeRequest.url" class="issue-link">!{{ mergeRequest.iid }}</a>
&middot;
<span>
{{ s__('OpenedNDaysAgo|Opened') }}
<a :href="mergeRequest.url" class="issue-date">{{ mergeRequest.createdAt }}</a>
</span>
<span>
{{ s__('ByAuthor|by') }}
<a :href="mergeRequest.author.webUrl" class="issue-author-link">{{ mergeRequest.author.name }}</a>
</span>
<template v-if="mergeRequest.state === 'closed'">
<span class="merge-request-state">
<i class="fa fa-ban"></i>
{{ mergeRequest.state.toUpperCase() }}
</span>
</template>
<template v-else>
<span class="merge-request-branch" v-if="mergeRequest.branch">
<i class= "fa fa-code-fork"></i>
<a :href="mergeRequest.branch.url">{{ mergeRequest.branch.name }}</a>
</span>
</template>
</div>
<div class="item-time">
<total-time :time="mergeRequest.totalTime"/>
</div>
</li>
</ul>
</div>
</template>
/* eslint-disable no-param-reassign */
import Vue from 'vue';
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
import iconBranch from '../svg/icon_branch.svg';
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StageStagingComponent = Vue.extend({
props: {
items: Array,
stage: Object,
},
data() {
return { iconBranch };
},
components: {
userAvatarImage,
},
template: `
<div>
<div class="events-description">
{{ stage.description }}
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
<li v-for="build in items" class="stage-event-item item-build-component">
<div class="item-details">
<!-- FIXME: Pass an alt attribute here for accessibility -->
<user-avatar-image :img-src="build.author.avatarUrl"/>
<h5 class="item-title">
<a :href="build.url" class="pipeline-id">#{{ build.id }}</a>
<i class="fa fa-code-fork"></i>
<a :href="build.branch.url" class="ref-name">{{ build.branch.name }}</a>
<span class="icon-branch">${iconBranch}</span>
<a :href="build.commitUrl" class="commit-sha">{{ build.shortSha }}</a>
</h5>
<span>
<a :href="build.url" class="build-date">{{ build.date }}</a>
{{ s__('ByAuthor|by') }}
<a :href="build.author.webUrl" class="issue-author-link">
{{ build.author.name }}
</a>
</span>
</div>
<div class="item-time">
<total-time :time="build.totalTime"></total-time>
</div>
</li>
</ul>
</div>
`,
});
<script>
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
import iconBranch from '../svg/icon_branch.svg';
export default {
props: {
items: Array,
stage: Object,
},
components: {
userAvatarImage,
},
computed: {
iconBranch() {
return iconBranch;
},
},
};
</script>
<template>
<div>
<div class="events-description">
{{ stage.description }}
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
<li
v-for="(build, i) in items"
class="stage-event-item item-build-component"
:key="i">
<div class="item-details">
<!-- FIXME: Pass an alt attribute here for accessibility -->
<user-avatar-image :img-src="build.author.avatarUrl"/>
<h5 class="item-title">
<a :href="build.url" class="pipeline-id">#{{ build.id }}</a>
<i class="fa fa-code-fork"></i>
<a :href="build.branch.url" class="ref-name">{{ build.branch.name }}</a>
<span class="icon-branch" v-html="iconBranch"></span>
<a :href="build.commitUrl" class="commit-sha">{{ build.shortSha }}</a>
</h5>
<span>
<a :href="build.url" class="build-date">{{ build.date }}</a>
{{ s__('ByAuthor|by') }}
<a :href="build.author.webUrl" class="issue-author-link">
{{ build.author.name }}
</a>
</span>
</div>
<div class="item-time">
<total-time :time="build.totalTime"/>
</div>
</li>
</ul>
</div>
</template>
/* eslint-disable no-param-reassign */
import Vue from 'vue';
import iconBuildStatus from '../svg/icon_build_status.svg';
import iconBranch from '../svg/icon_branch.svg';
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.StageTestComponent = Vue.extend({
props: {
items: Array,
stage: Object,
},
data() {
return { iconBuildStatus, iconBranch };
},
template: `
<div>
<div class="events-description">
{{ stage.description }}
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
<li v-for="build in items" class="stage-event-item item-build-component">
<div class="item-details">
<h5 class="item-title">
<span class="icon-build-status">${iconBuildStatus}</span>
<a :href="build.url" class="item-build-name">{{ build.name }}</a>
&middot;
<a :href="build.url" class="pipeline-id">#{{ build.id }}</a>
<i class="fa fa-code-fork"></i>
<a :href="build.branch.url" class="ref-name">{{ build.branch.name }}</a>
<span class="icon-branch">${iconBranch}</span>
<a :href="build.commitUrl" class="commit-sha">{{ build.shortSha }}</a>
</h5>
<span>
<a :href="build.url" class="issue-date">
{{ build.date }}
</a>
</span>
</div>
<div class="item-time">
<total-time :time="build.totalTime"></total-time>
</div>
</li>
</ul>
</div>
`,
});
<script>
import iconBuildStatus from '../svg/icon_build_status.svg';
import iconBranch from '../svg/icon_branch.svg';
export default {
props: {
items: Array,
stage: Object,
},
computed: {
iconBuildStatus() {
return iconBuildStatus;
},
iconBranch() {
return iconBranch;
},
},
};
</script>
<template>
<div>
<div class="events-description">
{{ stage.description }}
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
<li
v-for="(build, i) in items"
:key="i"
class="stage-event-item item-build-component">
<div class="item-details">
<h5 class="item-title">
<span class="icon-build-status" v-html="iconBuildStatus"></span>
<a :href="build.url" class="item-build-name">{{ build.name }}</a>
&middot;
<a :href="build.url" class="pipeline-id">#{{ build.id }}</a>
<i class="fa fa-code-fork"></i>
<a :href="build.branch.url" class="ref-name">{{ build.branch.name }}</a>
<span class="icon-branch" v-html="iconBranch"></span>
<a :href="build.commitUrl" class="commit-sha">{{ build.shortSha }}</a>
</h5>
<span>
<a :href="build.url" class="issue-date">
{{ build.date }}
</a>
</span>
</div>
<div class="item-time">
<total-time :time="build.totalTime"/>
</div>
</li>
</ul>
</div>
</template>
/* eslint-disable no-param-reassign */
import Vue from 'vue';
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
global.cycleAnalytics.TotalTimeComponent = Vue.extend({
props: {
time: Object,
},
template: `
<span class="total-time">
<template v-if="Object.keys(time).length">
<template v-if="time.days">{{ time.days }} <span>{{ n__('day', 'days', time.days) }}</span></template>
<template v-if="time.hours">{{ time.hours }} <span>{{ n__('Time|hr', 'Time|hrs', time.hours) }}</span></template>
<template v-if="time.mins && !time.days">{{ time.mins }} <span>{{ n__('Time|min', 'Time|mins', time.mins) }}</span></template>
<template v-if="time.seconds && Object.keys(time).length === 1 || time.seconds === 0">{{ time.seconds }} <span>{{ s__('Time|s') }}</span></template>
</template>
<template v-else>
--
</template>
</span>
`,
});
<script>
export default {
props: {
time: {
type: Object,
required: false,
default: () => ({}),
},
},
computed: {
hasData() {
return Object.keys(this.time).length;
},
},
};
</script>
<template>
<span class="total-time">
<template v-if="hasData">
<template v-if="time.days">{{ time.days }} <span>{{ n__('day', 'days', time.days) }}</span></template>
<template v-if="time.hours">{{ time.hours }} <span>{{ n__('Time|hr', 'Time|hrs', time.hours) }}</span></template>
<template v-if="time.mins && !time.days">{{ time.mins }} <span>{{ n__('Time|min', 'Time|mins', time.mins) }}</span></template>
<template v-if="time.seconds && hasDa === 1 || time.seconds === 0">{{ time.seconds }} <span>{{ s__('Time|s') }}</span></template>
</template>
<template v-else>
--
</template>
</span>
</template>
...@@ -3,60 +3,63 @@ ...@@ -3,60 +3,63 @@
import Vue from 'vue'; import Vue from 'vue';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import Translate from '../vue_shared/translate'; import Translate from '../vue_shared/translate';
import LimitWarningComponent from './components/limit_warning_component'; import limitWarningComponent from './components/limit_warning_component.vue';
import './components/stage_code_component'; import stageCodeComponent from './components/stage_code_component.vue';
import './components/stage_issue_component'; import stagePlanComponent from './components/stage_plan_component.vue';
import './components/stage_plan_component'; import stageComponent from './components/stage_component.vue';
import './components/stage_production_component'; import stageReviewComponent from './components/stage_review_component.vue';
import './components/stage_review_component'; import stageStagingComponent from './components/stage_staging_component.vue';
import './components/stage_staging_component'; import stageTestComponent from './components/stage_test_component.vue';
import './components/stage_test_component'; import totalTime from './components/total_time_component.vue';
import './components/total_time_component'; import CycleAnalyticsService from './cycle_analytics_service';
import './cycle_analytics_service'; import CycleAnalyticsStore from './cycle_analytics_store';
import './cycle_analytics_store';
Vue.use(Translate); Vue.use(Translate);
$(() => { $(() => {
const OVERVIEW_DIALOG_COOKIE = 'cycle_analytics_help_dismissed'; 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({ gl.cycleAnalyticsApp = new Vue({
el: '#cycle-analytics', el: '#cycle-analytics',
name: 'CycleAnalytics', name: 'CycleAnalytics',
data: { data() {
state: cycleAnalyticsStore.state, const cycleAnalyticsEl = document.querySelector('#cycle-analytics');
const cycleAnalyticsService = new CycleAnalyticsService({
requestPath: cycleAnalyticsEl.dataset.requestPath,
});
return {
store: CycleAnalyticsStore,
state: CycleAnalyticsStore.state,
isLoading: false, isLoading: false,
isLoadingStage: false, isLoadingStage: false,
isEmptyStage: false, isEmptyStage: false,
hasError: false, hasError: false,
startDate: 30, startDate: 30,
isOverviewDialogDismissed: Cookies.get(OVERVIEW_DIALOG_COOKIE), isOverviewDialogDismissed: Cookies.get(OVERVIEW_DIALOG_COOKIE),
service: cycleAnalyticsService,
};
}, },
computed: { computed: {
currentStage() { currentStage() {
return cycleAnalyticsStore.currentActiveStage(); return this.store.currentActiveStage();
}, },
}, },
components: { components: {
'stage-issue-component': gl.cycleAnalytics.StageIssueComponent, 'stage-issue-component': stageComponent,
'stage-plan-component': gl.cycleAnalytics.StagePlanComponent, 'stage-plan-component': stagePlanComponent,
'stage-code-component': gl.cycleAnalytics.StageCodeComponent, 'stage-code-component': stageCodeComponent,
'stage-test-component': gl.cycleAnalytics.StageTestComponent, 'stage-test-component': stageTestComponent,
'stage-review-component': gl.cycleAnalytics.StageReviewComponent, 'stage-review-component': stageReviewComponent,
'stage-staging-component': gl.cycleAnalytics.StageStagingComponent, 'stage-staging-component': stageStagingComponent,
'stage-production-component': gl.cycleAnalytics.StageProductionComponent, 'stage-production-component': stageComponent,
}, },
created() { created() {
this.fetchCycleAnalyticsData(); this.fetchCycleAnalyticsData();
}, },
methods: { methods: {
handleError() { handleError() {
cycleAnalyticsStore.setErrorState(true); this.store.setErrorState(true);
return new Flash('There was an error while fetching cycle analytics data.'); return new Flash('There was an error while fetching cycle analytics data.');
}, },
initDropdown() { initDropdown() {
...@@ -77,17 +80,17 @@ $(() => { ...@@ -77,17 +80,17 @@ $(() => {
this.isLoading = true; this.isLoading = true;
cycleAnalyticsService this.service
.fetchCycleAnalyticsData(fetchOptions) .fetchCycleAnalyticsData(fetchOptions)
.done((response) => { .then(resp => resp.json())
cycleAnalyticsStore.setCycleAnalyticsData(response); .then((response) => {
this.store.setCycleAnalyticsData(response);
this.selectDefaultStage(); this.selectDefaultStage();
this.initDropdown(); this.initDropdown();
this.isLoading = false;
}) })
.error(() => { .catch(() => {
this.handleError(); this.handleError();
})
.always(() => {
this.isLoading = false; this.isLoading = false;
}); });
}, },
...@@ -100,27 +103,27 @@ $(() => { ...@@ -100,27 +103,27 @@ $(() => {
if (this.currentStage === stage) return; if (this.currentStage === stage) return;
if (!stage.isUserAllowed) { if (!stage.isUserAllowed) {
cycleAnalyticsStore.setActiveStage(stage); this.store.setActiveStage(stage);
return; return;
} }
this.isLoadingStage = true; this.isLoadingStage = true;
cycleAnalyticsStore.setStageEvents([], stage); this.store.setStageEvents([], stage);
cycleAnalyticsStore.setActiveStage(stage); this.store.setActiveStage(stage);
cycleAnalyticsService this.service
.fetchStageData({ .fetchStageData({
stage, stage,
startDate: this.startDate, startDate: this.startDate,
}) })
.done((response) => { .then(resp => resp.json())
.then((response) => {
this.isEmptyStage = !response.events.length; this.isEmptyStage = !response.events.length;
cycleAnalyticsStore.setStageEvents(response.events, stage); this.store.setStageEvents(response.events, stage);
this.isLoadingStage = false;
}) })
.error(() => { .catch(() => {
this.isEmptyStage = true; this.isEmptyStage = true;
})
.always(() => {
this.isLoadingStage = false; this.isLoadingStage = false;
}); });
}, },
...@@ -132,6 +135,6 @@ $(() => { ...@@ -132,6 +135,6 @@ $(() => {
}); });
// Register global components // Register global components
Vue.component('limit-warning', LimitWarningComponent); Vue.component('limit-warning', limitWarningComponent);
Vue.component('total-time', gl.cycleAnalytics.TotalTimeComponent); Vue.component('total-time', totalTime);
}); });
/* eslint-disable no-param-reassign */ import Vue from 'vue';
import VueResource from 'vue-resource';
const global = window.gl || (window.gl = {}); Vue.use(VueResource);
global.cycleAnalytics = global.cycleAnalytics || {};
class CycleAnalyticsService { export default class CycleAnalyticsService {
constructor(options) { constructor(options) {
this.requestPath = options.requestPath; this.requestPath = options.requestPath;
this.cycleAnalytics = Vue.resource(this.requestPath);
} }
fetchCycleAnalyticsData(options) { fetchCycleAnalyticsData(options = { startDate: 30 }) {
options = options || { startDate: 30 }; return this.cycleAnalytics.get({ cycle_analytics: { start_date: options.startDate } });
return $.ajax({
url: this.requestPath,
method: 'GET',
dataType: 'json',
contentType: 'application/json',
data: {
cycle_analytics: {
start_date: options.startDate,
},
},
});
} }
fetchStageData(options) { fetchStageData(options) {
...@@ -30,12 +19,12 @@ class CycleAnalyticsService { ...@@ -30,12 +19,12 @@ class CycleAnalyticsService {
startDate, startDate,
} = options; } = options;
return $.get(`${this.requestPath}/events/${stage.name}.json`, { return Vue.http.get(`${this.requestPath}/events/${stage.name}.json`, {
params: {
cycle_analytics: { cycle_analytics: {
start_date: startDate, start_date: startDate,
}, },
},
}); });
} }
} }
global.cycleAnalytics.CycleAnalyticsService = CycleAnalyticsService;
...@@ -4,9 +4,6 @@ import { __ } from '../locale'; ...@@ -4,9 +4,6 @@ import { __ } from '../locale';
import '../lib/utils/text_utility'; import '../lib/utils/text_utility';
import DEFAULT_EVENT_OBJECTS from './default_event_objects'; import DEFAULT_EVENT_OBJECTS from './default_event_objects';
const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
const EMPTY_STAGE_TEXTS = { 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.'), 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.'), 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 = { ...@@ -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.'), 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: { state: {
summary: '', summary: '',
stats: '', stats: '',
......
...@@ -34,7 +34,7 @@ export const canShowActiveSubItems = (el) => { ...@@ -34,7 +34,7 @@ export const canShowActiveSubItems = (el) => {
export const canShowSubItems = () => bp.getBreakpointSize() === 'sm' || bp.getBreakpointSize() === 'md' || bp.getBreakpointSize() === 'lg'; export const canShowSubItems = () => bp.getBreakpointSize() === 'sm' || bp.getBreakpointSize() === 'md' || bp.getBreakpointSize() === 'lg';
export const getHideSubItemsInterval = () => { export const getHideSubItemsInterval = () => {
if (!currentOpenMenu) return 0; if (!currentOpenMenu || !mousePos.length) return 0;
const currentMousePos = mousePos[mousePos.length - 1]; const currentMousePos = mousePos[mousePos.length - 1];
const prevMousePos = mousePos[0]; const prevMousePos = mousePos[0];
......
// 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());
}
...@@ -408,6 +408,10 @@ export const setCiStatusFavicon = (pageUrl) => { ...@@ -408,6 +408,10 @@ export const setCiStatusFavicon = (pageUrl) => {
}); });
}; };
export const spriteIcon = icon => `<svg><use xlink:href="${gon.sprite_icons}#${icon}" /></svg>`;
export const imagePath = imgUrl => `${gon.asset_host || ''}${gon.relative_url_root || ''}/assets/${imgUrl}`;
window.gl = window.gl || {}; window.gl = window.gl || {};
window.gl.utils = { window.gl.utils = {
...(window.gl.utils || {}), ...(window.gl.utils || {}),
...@@ -434,4 +438,6 @@ window.gl.utils = { ...@@ -434,4 +438,6 @@ window.gl.utils = {
getSelectedFragment, getSelectedFragment,
insertText, insertText,
nodeMatchesSelector, nodeMatchesSelector,
spriteIcon,
imagePath,
}; };
export const isSticky = (el, scrollY, stickyTop) => { export const createPlaceholder = () => {
const placeholder = document.createElement('div');
placeholder.classList.add('sticky-placeholder');
return placeholder;
};
export const isSticky = (el, scrollY, stickyTop, insertPlaceholder) => {
const top = Math.floor(el.offsetTop - scrollY); const top = Math.floor(el.offsetTop - scrollY);
if (top <= stickyTop) { if (top <= stickyTop && !el.classList.contains('is-stuck')) {
const placeholder = insertPlaceholder ? createPlaceholder() : null;
const heightBefore = el.offsetHeight;
el.classList.add('is-stuck'); el.classList.add('is-stuck');
} else {
if (insertPlaceholder) {
el.parentNode.insertBefore(placeholder, el.nextElementSibling);
placeholder.style.height = `${heightBefore - el.offsetHeight}px`;
}
} else if (top > stickyTop && el.classList.contains('is-stuck')) {
el.classList.remove('is-stuck'); el.classList.remove('is-stuck');
if (insertPlaceholder && el.nextElementSibling && el.nextElementSibling.classList.contains('sticky-placeholder')) {
el.nextElementSibling.remove();
}
} }
}; };
export default (el) => { export default (el, insertPlaceholder = true) => {
if (!el) return; if (!el) return;
const computedStyle = window.getComputedStyle(el); const computedStyle = window.getComputedStyle(el);
...@@ -17,7 +37,7 @@ export default (el) => { ...@@ -17,7 +37,7 @@ export default (el) => {
const stickyTop = parseInt(computedStyle.top, 10); const stickyTop = parseInt(computedStyle.top, 10);
document.addEventListener('scroll', () => isSticky(el, window.scrollY, stickyTop), { document.addEventListener('scroll', () => isSticky(el, window.scrollY, stickyTop, insertPlaceholder), {
passive: true, passive: true,
}); });
}; };
...@@ -8,6 +8,7 @@ import _ from 'underscore'; ...@@ -8,6 +8,7 @@ import _ from 'underscore';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import Dropzone from 'dropzone'; import Dropzone from 'dropzone';
import Sortable from 'vendor/Sortable'; import Sortable from 'vendor/Sortable';
import svg4everybody from 'svg4everybody';
// libraries with import side-effects // libraries with import side-effects
import 'mousetrap'; import 'mousetrap';
...@@ -151,6 +152,8 @@ if (process.env.NODE_ENV !== 'production') require('./test_utils/'); ...@@ -151,6 +152,8 @@ if (process.env.NODE_ENV !== 'production') require('./test_utils/');
Dropzone.autoDiscover = false; Dropzone.autoDiscover = false;
svg4everybody();
document.addEventListener('beforeunload', function () { document.addEventListener('beforeunload', function () {
// Unbind scroll events // Unbind scroll events
$(document).off('scroll'); $(document).off('scroll');
......
...@@ -248,6 +248,8 @@ import { ...@@ -248,6 +248,8 @@ import {
propsData: { propsData: {
endpoint: pipelineTableViewEl.dataset.endpoint, endpoint: pipelineTableViewEl.dataset.endpoint,
helpPagePath: pipelineTableViewEl.dataset.helpPagePath, helpPagePath: pipelineTableViewEl.dataset.helpPagePath,
emptyStateSvgPath: pipelineTableViewEl.dataset.emptyStateSvgPath,
errorStateSvgPath: pipelineTableViewEl.dataset.errorStateSvgPath,
autoDevopsHelpPath: pipelineTableViewEl.dataset.helpAutoDevopsPath, autoDevopsHelpPath: pipelineTableViewEl.dataset.helpAutoDevopsPath,
}, },
}).$mount(); }).$mount();
......
...@@ -23,6 +23,9 @@ ...@@ -23,6 +23,9 @@
settingsPath: metricsData.settingsPath, settingsPath: metricsData.settingsPath,
metricsEndpoint: metricsData.additionalMetrics, metricsEndpoint: metricsData.additionalMetrics,
deploymentEndpoint: metricsData.deploymentEndpoint, deploymentEndpoint: metricsData.deploymentEndpoint,
emptyGettingStartedSvgPath: metricsData.emptyGettingStartedSvgPath,
emptyLoadingSvgPath: metricsData.emptyLoadingSvgPath,
emptyUnableToConnectSvgPath: metricsData.emptyUnableToConnectSvgPath,
showEmptyState: true, showEmptyState: true,
updateAspectRatio: false, updateAspectRatio: false,
updatedAspectRatios: 0, updatedAspectRatios: 0,
...@@ -109,5 +112,8 @@ ...@@ -109,5 +112,8 @@
:selected-state="state" :selected-state="state"
:documentation-path="documentationPath" :documentation-path="documentationPath"
:settings-path="settingsPath" :settings-path="settingsPath"
:empty-getting-started-svg-path="emptyGettingStartedSvgPath"
:empty-loading-svg-path="emptyLoadingSvgPath"
:empty-unable-to-connect-svg-path="emptyUnableToConnectSvgPath"
/> />
</template> </template>
<script> <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 { export default {
props: { props: {
documentationPath: { documentationPath: {
...@@ -18,24 +14,36 @@ ...@@ -18,24 +14,36 @@
type: String, type: String,
required: true, required: true,
}, },
emptyGettingStartedSvgPath: {
type: String,
required: true,
},
emptyLoadingSvgPath: {
type: String,
required: true,
},
emptyUnableToConnectSvgPath: {
type: String,
required: true,
},
}, },
data() { data() {
return { return {
states: { states: {
gettingStarted: { gettingStarted: {
svg: gettingStartedSvg, svgUrl: this.emptyGettingStartedSvgPath,
title: 'Get started with performance monitoring', title: 'Get started with performance monitoring',
description: 'Stay updated about the performance and health of your environment by configuring Prometheus to monitor your deployments.', description: 'Stay updated about the performance and health of your environment by configuring Prometheus to monitor your deployments.',
buttonText: 'Configure Prometheus', buttonText: 'Configure Prometheus',
}, },
loading: { loading: {
svg: loadingSvg, svgUrl: this.emptyLoadingSvgPath,
title: 'Waiting for performance data', 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.', description: 'Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available.',
buttonText: 'View documentation', buttonText: 'View documentation',
}, },
unableToConnect: { unableToConnect: {
svg: unableToConnectSvg, svgUrl: this.emptyUnableToConnectSvgPath,
title: 'Unable to connect to Prometheus server', title: 'Unable to connect to Prometheus server',
description: 'Ensure connectivity is available from the GitLab server to the ', description: 'Ensure connectivity is available from the GitLab server to the ',
buttonText: 'View documentation', buttonText: 'View documentation',
...@@ -66,7 +74,9 @@ ...@@ -66,7 +74,9 @@
<template> <template>
<div class="prometheus-state"> <div class="prometheus-state">
<div class="row"> <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>
<div class="row"> <div class="row">
<div class="col-md-6 col-md-offset-3"> <div class="col-md-6 col-md-offset-3">
......
...@@ -97,6 +97,8 @@ ...@@ -97,6 +97,8 @@
methods: { methods: {
...mapActions([ ...mapActions([
'saveNote', 'saveNote',
'stopPolling',
'restartPolling',
'removePlaceholderNotes', 'removePlaceholderNotes',
]), ]),
setIsSubmitButtonDisabled(note, isSubmitting) { setIsSubmitButtonDisabled(note, isSubmitting) {
...@@ -126,10 +128,13 @@ ...@@ -126,10 +128,13 @@
this.isSubmitting = true; this.isSubmitting = true;
this.note = ''; // Empty textarea while being requested. Repopulate in catch this.note = ''; // Empty textarea while being requested. Repopulate in catch
this.resizeTextarea(); this.resizeTextarea();
this.stopPolling();
this.saveNote(noteData) this.saveNote(noteData)
.then((res) => { .then((res) => {
this.isSubmitting = false; this.isSubmitting = false;
this.restartPolling();
if (res.errors) { if (res.errors) {
if (res.errors.commands_only) { if (res.errors.commands_only) {
this.discard(); this.discard();
...@@ -177,6 +182,7 @@ ...@@ -177,6 +182,7 @@
if (shouldClear) { if (shouldClear) {
this.note = ''; this.note = '';
this.resizeTextarea(); this.resizeTextarea();
this.$refs.markdownField.previewMarkdown = false;
} }
// reset autostave // reset autostave
...@@ -255,7 +261,8 @@ ...@@ -255,7 +261,8 @@
:markdown-docs-path="markdownDocsPath" :markdown-docs-path="markdownDocsPath"
:quick-actions-docs-path="quickActionsDocsPath" :quick-actions-docs-path="quickActionsDocsPath"
:add-spacing-classes="false" :add-spacing-classes="false"
:is-confidential-issue="isConfidentialIssue"> :is-confidential-issue="isConfidentialIssue"
ref="markdownField">
<textarea <textarea
id="note-body" id="note-body"
name="note[note]" 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> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import iconsMap from './issue_note_icons';
import issueNoteHeader from './issue_note_header.vue'; import issueNoteHeader from './issue_note_header.vue';
export default { export default {
...@@ -24,9 +23,9 @@ ...@@ -24,9 +23,9 @@
isTargetNote() { isTargetNote() {
return this.targetNoteHash === this.noteAnchorId; return this.targetNoteHash === this.noteAnchorId;
}, },
iconHtml() {
return gl.utils.spriteIcon(this.note.system_note_icon_name);
}, },
created() {
this.svg = iconsMap[this.note.system_note_icon_name];
}, },
}; };
</script> </script>
...@@ -39,7 +38,7 @@ ...@@ -39,7 +38,7 @@
<div class="timeline-entry-inner"> <div class="timeline-entry-inner">
<div <div
class="timeline-icon" class="timeline-icon"
v-html="svg"> v-html="iconHtml">
</div> </div>
<div class="timeline-content"> <div class="timeline-content">
<div class="note-header"> <div class="note-header">
......
...@@ -187,6 +187,14 @@ export const poll = ({ commit, state, getters }) => { ...@@ -187,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 }) => { export const fetchData = ({ commit, state, getters }) => {
const requestData = { endpoint: state.notesData.notesPath, lastFetchedAt: state.lastFetchedAt }; const requestData = { endpoint: state.notesData.notesPath, lastFetchedAt: state.lastFetchedAt };
......
...@@ -5,6 +5,9 @@ import * as constants from '../constants'; ...@@ -5,6 +5,9 @@ import * as constants from '../constants';
export default { export default {
[types.ADD_NEW_NOTE](state, note) { [types.ADD_NEW_NOTE](state, note) {
const { discussion_id, type } = note; const { discussion_id, type } = note;
const [exists] = state.notes.filter(n => n.id === note.discussion_id);
if (!exists) {
const noteData = { const noteData = {
expanded: true, expanded: true,
id: discussion_id, id: discussion_id,
...@@ -14,6 +17,7 @@ export default { ...@@ -14,6 +17,7 @@ export default {
}; };
state.notes.push(noteData); state.notes.push(noteData);
}
}, },
[types.ADD_NEW_REPLY_TO_DISCUSSION](state, note) { [types.ADD_NEW_REPLY_TO_DISCUSSION](state, note) {
......
<script> <script>
import pipelinesEmptyStateSVG from 'empty_states/icons/_pipelines_empty.svg';
export default { export default {
props: { props: {
helpPagePath: { helpPagePath: {
type: String, type: String,
required: true, required: true,
}, },
emptyStateSvgPath: {
type: String,
required: true,
},
}, },
data: () => ({ pipelinesEmptyStateSVG }),
}; };
</script> </script>
<template> <template>
<div class="row empty-state js-empty-state"> <div class="row empty-state js-empty-state">
<div class="col-xs-12"> <div class="col-xs-12">
<div class="svg-content" v-html="pipelinesEmptyStateSVG" /> <div class="svg-content">
<img :src="emptyStateSvgPath"/>
</div>
</div> </div>
<div class="col-xs-12 text-center"> <div class="col-xs-12 text-center">
......
<script> <script>
import pipelinesErrorStateSVG from 'empty_states/icons/_pipelines_failed.svg';
export default { export default {
data: () => ({ pipelinesErrorStateSVG }), props: {
errorStateSvgPath: {
type: String,
required: true,
},
},
}; };
</script> </script>
<template> <template>
<div class="row empty-state js-pipelines-error-state"> <div class="row empty-state js-pipelines-error-state">
<div class="col-xs-12"> <div class="col-xs-12">
<div class="svg-content" v-html="pipelinesErrorStateSVG" /> <div class="svg-content">
<img :src="errorStateSvgPath"/>
</div>
</div> </div>
<div class="col-xs-12 text-center"> <div class="col-xs-12 text-center">
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
return { return {
endpoint: pipelinesData.endpoint, endpoint: pipelinesData.endpoint,
helpPagePath: pipelinesData.helpPagePath, helpPagePath: pipelinesData.helpPagePath,
emptyStateSvgPath: pipelinesData.emptyStateSvgPath,
errorStateSvgPath: pipelinesData.errorStateSvgPath,
autoDevopsPath: pipelinesData.helpAutoDevopsPath, autoDevopsPath: pipelinesData.helpAutoDevopsPath,
newPipelinePath: pipelinesData.newPipelinePath, newPipelinePath: pipelinesData.newPipelinePath,
canCreatePipeline: pipelinesData.canCreatePipeline, canCreatePipeline: pipelinesData.canCreatePipeline,
...@@ -182,9 +184,13 @@ ...@@ -182,9 +184,13 @@
<empty-state <empty-state
v-if="shouldRenderEmptyState" v-if="shouldRenderEmptyState"
:help-page-path="helpPagePath" :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 <div
class="blank-state blank-state-no-icon" class="blank-state blank-state-no-icon"
......
...@@ -69,8 +69,7 @@ ...@@ -69,8 +69,7 @@
@click="onClickAction(action.path)" @click="onClickAction(action.path)"
:class="{ disabled: isActionDisabled(action) }" :class="{ disabled: isActionDisabled(action) }"
:disabled="isActionDisabled(action)"> :disabled="isActionDisabled(action)">
<span v-html="playIconSvg"></span> {{action.name}}
<span>{{action.name}}</span>
</button> </button>
</li> </li>
</ul> </ul>
......
...@@ -39,11 +39,7 @@ ...@@ -39,11 +39,7 @@
rel="nofollow" rel="nofollow"
download download
:href="artifact.path"> :href="artifact.path">
<i Download {{artifact.name}} artifacts
class="fa fa-download"
aria-hidden="true">
</i>
<span>Download {{artifact.name}} artifacts</span>
</a> </a>
</li> </li>
</ul> </ul>
......
...@@ -178,8 +178,8 @@ const RepoHelper = { ...@@ -178,8 +178,8 @@ const RepoHelper = {
setFile(data, file) { setFile(data, file) {
const newFile = data; const newFile = data;
newFile.url = file.url || Service.url; // Grab the URL from service, happens on page refresh.
newFile.url = file.url;
if (newFile.render_error === 'too_large' || newFile.render_error === 'collapsed') { if (newFile.render_error === 'too_large' || newFile.render_error === 'collapsed') {
newFile.tooLarge = true; newFile.tooLarge = true;
} }
......
<script> <script>
import { s__ } from '../../locale';
const PAGINATION_UI_BUTTON_LIMIT = 4; const PAGINATION_UI_BUTTON_LIMIT = 4;
const UI_LIMIT = 6; const UI_LIMIT = 6;
const SPREAD = '...'; const SPREAD = '...';
const PREV = 'Prev'; const PREV = s__('Pagination|Prev');
const NEXT = 'Next'; const NEXT = s__('Pagination|Next');
const FIRST = '« First'; const FIRST = s__('Pagination|« First');
const LAST = 'Last »'; const LAST = s__('Pagination|Last »');
export default { export default {
props: { props: {
......
...@@ -31,10 +31,12 @@ ...@@ -31,10 +31,12 @@
@import "framework/mobile"; @import "framework/mobile";
@import "framework/modal"; @import "framework/modal";
@import "framework/nav"; @import "framework/nav";
@import "framework/new-nav";
@import "framework/pagination"; @import "framework/pagination";
@import "framework/panels"; @import "framework/panels";
@import "framework/selects"; @import "framework/selects";
@import "framework/sidebar"; @import "framework/sidebar";
@import "framework/new-sidebar";
@import "framework/tables"; @import "framework/tables";
@import "framework/notes"; @import "framework/notes";
@import "framework/timeline"; @import "framework/timeline";
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
} }
.emoji-menu { .emoji-menu {
display: none;
position: absolute; position: absolute;
top: 0; top: 0;
margin-top: 3px; margin-top: 3px;
...@@ -27,6 +28,10 @@ ...@@ -27,6 +28,10 @@
transition: .3s cubic-bezier(.67, .06, .19, 1.44); transition: .3s cubic-bezier(.67, .06, .19, 1.44);
transition-property: transform, opacity; transition-property: transform, opacity;
&.is-rendered {
display: block;
}
&.is-aligned-right { &.is-aligned-right {
transform-origin: 100% -45px; transform-origin: 100% -45px;
} }
......
...@@ -260,7 +260,7 @@ ...@@ -260,7 +260,7 @@
position: relative; position: relative;
border: 1px solid $blue-300; border: 1px solid $blue-300;
border-radius: $border-radius-default; border-radius: $border-radius-default;
background-color: $blue-25; background-color: $blue-50;
justify-content: center; justify-content: center;
.dismiss-button { .dismiss-button {
...@@ -319,16 +319,6 @@ ...@@ -319,16 +319,6 @@
padding: $gl-padding; padding: $gl-padding;
} }
.svg-content {
text-align: center;
svg {
max-width: 425px;
width: 100%;
padding: $gl-padding;
}
}
.emoji-icon { .emoji-icon {
display: inline-block; display: inline-block;
} }
......
...@@ -779,6 +779,14 @@ ...@@ -779,6 +779,14 @@
white-space: normal; white-space: normal;
width: 100%; width: 100%;
&.dropdown-menu-user-link {
white-space: nowrap;
.dropdown-menu-user-username {
display: block;
}
}
// make sure the text color is not overriden // make sure the text color is not overriden
&.text-danger { &.text-danger {
color: $brand-danger; color: $brand-danger;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
// Header // Header
header.navbar-gitlab-new { header.navbar-gitlab-new {
background: linear-gradient(to right, $color-900, $color-800); background-color: $color-900;
.navbar-collapse { .navbar-collapse {
color: $color-200; color: $color-200;
...@@ -201,7 +201,7 @@ body { ...@@ -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); @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 { header.navbar-gitlab-new {
background: $theme-gray-100; background-color: $theme-gray-100;
box-shadow: 0 2px 0 0 $border-color; box-shadow: 0 2px 0 0 $border-color;
.logo-text svg { .logo-text svg {
...@@ -242,10 +242,10 @@ body { ...@@ -242,10 +242,10 @@ body {
&:hover { &:hover {
background-color: $white-light; background-color: $white-light;
box-shadow: inset 0 0 0 1px $blue-100; box-shadow: inset 0 0 0 1px $blue-200;
.location-badge { .location-badge {
box-shadow: inset 0 0 0 1px $blue-100; box-shadow: inset 0 0 0 1px $blue-200;
} }
} }
} }
...@@ -254,6 +254,10 @@ body { ...@@ -254,6 +254,10 @@ body {
.search-icon { .search-icon {
color: $theme-gray-200; color: $theme-gray-200;
} }
.search-input {
color: $gl-text-color;
}
} }
.location-badge { .location-badge {
......
...@@ -9,3 +9,27 @@ ...@@ -9,3 +9,27 @@
padding: 10px; padding: 10px;
margin-bottom: 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); }
}
...@@ -142,5 +142,41 @@ ...@@ -142,5 +142,41 @@
} }
@mixin green-status-color { @mixin green-status-color {
@include status-color($green-50, $green-500, $green-700); @include status-color($green-100, $green-500, $green-700);
}
@mixin fade($gradient-direction, $gradient-color) {
visibility: hidden;
opacity: 0;
z-index: 2;
position: absolute;
bottom: 12px;
width: 43px;
height: 30px;
transition-duration: .3s;
-webkit-transform: translateZ(0);
background: linear-gradient(to $gradient-direction, $gradient-color 45%, rgba($gradient-color, 0.4));
&.scrolling {
visibility: visible;
opacity: 1;
transition-duration: .3s;
}
.fa {
position: relative;
top: 5px;
font-size: 18px;
}
}
@mixin scrolling-links() {
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
display: flex;
&::-webkit-scrollbar {
display: none;
}
} }
@mixin fade($gradient-direction, $gradient-color) {
visibility: hidden;
opacity: 0;
z-index: 2;
position: absolute;
bottom: 12px;
width: 43px;
height: 30px;
transition-duration: .3s;
-webkit-transform: translateZ(0);
background: linear-gradient(to $gradient-direction, $gradient-color 45%, rgba($gradient-color, 0.4));
&.scrolling {
visibility: visible;
opacity: 1;
transition-duration: .3s;
}
.fa {
position: relative;
top: 5px;
font-size: 18px;
}
}
@mixin scrolling-links() {
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
display: flex;
&::-webkit-scrollbar {
display: none;
}
}
.nav-links { .nav-links {
display: flex; display: flex;
......
...@@ -295,75 +295,6 @@ header.navbar-gitlab-new { ...@@ -295,75 +295,6 @@ header.navbar-gitlab-new {
margin-top: 4px; margin-top: 4px;
} }
.search {
margin: 4px 8px 0;
form {
height: 32px;
border: 0;
border-radius: $border-radius-default;
transition: border-color ease-in-out 0.15s, background-color ease-in-out 0.15s;
&:hover {
box-shadow: none;
}
}
&.search-active form {
box-shadow: none;
.search-input {
color: $gl-text-color;
transition: color ease-in-out 0.15s;
}
.search-input::placeholder {
color: $gl-text-color-tertiary;
}
.search-input-wrap {
.search-icon,
.clear-icon {
color: $gl-text-color-tertiary;
transition: color ease-in-out 0.15s;
}
}
}
.search-input {
color: $white-light;
background: none;
transition: color ease-in-out 0.15s;
}
.search-input::placeholder {
transition: color ease-in-out 0.15s;
}
.location-badge {
font-size: 12px;
margin: -4px 4px -4px -4px;
line-height: 25px;
padding: 4px 8px;
border-radius: 2px 0 0 2px;
height: 32px;
transition: border-color ease-in-out 0.15s;
}
&.search-active {
.location-badge {
background-color: $nav-badge-bg;
border-color: $border-color;
}
.search-input-wrap {
.clear-icon {
color: $white-light;
}
}
}
}
.breadcrumbs { .breadcrumbs {
display: flex; display: flex;
min-height: 48px; min-height: 48px;
...@@ -386,11 +317,6 @@ header.navbar-gitlab-new { ...@@ -386,11 +317,6 @@ header.navbar-gitlab-new {
align-self: center; align-self: center;
color: $gl-text-color-secondary; color: $gl-text-color-secondary;
@media (max-width: $screen-xs-max) {
padding-left: 17px;
border-left: 1px solid $gl-text-color-quaternary;
}
.avatar-tile { .avatar-tile {
margin-right: 4px; margin-right: 4px;
border: 1px solid $border-color; border: 1px solid $border-color;
......
...@@ -461,6 +461,13 @@ $new-sidebar-collapsed-width: 50px; ...@@ -461,6 +461,13 @@ $new-sidebar-collapsed-width: 50px;
font-size: 18px; font-size: 18px;
} }
} }
@media (max-width: $screen-xs-max) {
+ .breadcrumbs-links {
padding-left: 17px;
border-left: 1px solid $gl-text-color-quaternary;
}
}
} }
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
......
...@@ -137,7 +137,7 @@ $well-border: #eee; ...@@ -137,7 +137,7 @@ $well-border: #eee;
//## //##
$code-color: $red-600; $code-color: $red-600;
$code-bg: lighten($red-50, 2%); $code-bg: lighten($red-100, 2%);
$kbd-color: $white-light; $kbd-color: $white-light;
$kbd-bg: #333; $kbd-bg: #333;
......
...@@ -6,6 +6,7 @@ $gutter_width: 290px; ...@@ -6,6 +6,7 @@ $gutter_width: 290px;
$gutter_inner_width: 250px; $gutter_inner_width: 250px;
$sidebar-transition-duration: .15s; $sidebar-transition-duration: .15s;
$sidebar-breakpoint: 1024px; $sidebar-breakpoint: 1024px;
$default-transition-duration: .15s;
/* /*
* Color schema * Color schema
...@@ -27,46 +28,45 @@ $gray-dark: darken($gray-light, $darken-dark-factor); ...@@ -27,46 +28,45 @@ $gray-dark: darken($gray-light, $darken-dark-factor);
$gray-darker: #eee; $gray-darker: #eee;
$gray-darkest: #c4c4c4; $gray-darkest: #c4c4c4;
$green-25: #f6fcf8; $green-50: #f1fdf6;
$green-50: #e4f5eb; $green-100: #dcf5e7;
$green-100: #bae6cc; $green-200: #b3e6c8;
$green-200: #8dd5aa; $green-300: #75d09b;
$green-300: #5fc488; $green-400: #37b96d;
$green-400: #3cb76f;
$green-500: #1aaa55; $green-500: #1aaa55;
$green-600: #168f48; $green-600: #168f48;
$green-700: #12753a; $green-700: #12753a;
$green-800: #0e5a2d; $green-800: #0e5a2d;
$green-900: #0a4020; $green-900: #0a4020;
$green-950: #072b15;
$blue-25: #f6fafd; $blue-50: #f6fafe;
$blue-50: #e4eff9; $blue-100: #e4f0fb;
$blue-100: #bcd7f1; $blue-200: #b8d6f4;
$blue-200: #8fbce8; $blue-300: #73afea;
$blue-300: #62a1df; $blue-400: #2e87e0;
$blue-400: #418cd8;
$blue-500: #1f78d1; $blue-500: #1f78d1;
$blue-600: #1b69b6; $blue-600: #1b69b6;
$blue-700: #17599c; $blue-700: #17599c;
$blue-800: #134a81; $blue-800: #134a81;
$blue-900: #0f3b66; $blue-900: #0f3b66;
$blue-950: #0a2744;
$orange-25: #fffcf8; $orange-50: #fffaf4;
$orange-50: #fff2e1; $orange-100: #fff1de;
$orange-100: #fedfb3; $orange-200: #fed69f;
$orange-200: #feca81; $orange-300: #fdbc60;
$orange-300: #fdb44f; $orange-400: #fca121;
$orange-400: #fca429;
$orange-500: #fc9403; $orange-500: #fc9403;
$orange-600: #de7e00; $orange-600: #de7e00;
$orange-700: #c26700; $orange-700: #c26700;
$orange-800: #a35100; $orange-800: #a35200;
$orange-900: #853b00; $orange-900: #853c00;
$orange-950: #592800;
$red-25: #fef7f6; $red-50: #fef6f5;
$red-50: #fbe7e4; $red-100: #fbe5e1;
$red-100: #f4c4bc; $red-200: #f2b4a9;
$red-200: #ed9d90;
$red-300: #e67664; $red-300: #e67664;
$red-400: #e05842; $red-400: #e05842;
$red-500: #db3b21; $red-500: #db3b21;
...@@ -74,6 +74,7 @@ $red-600: #c0341d; ...@@ -74,6 +74,7 @@ $red-600: #c0341d;
$red-700: #a62d19; $red-700: #a62d19;
$red-800: #8b2615; $red-800: #8b2615;
$red-900: #711e11; $red-900: #711e11;
$red-950: #4b140b;
// GitLab themes // GitLab themes
...@@ -184,8 +185,8 @@ $list-text-disabled-color: $gl-text-color-tertiary; ...@@ -184,8 +185,8 @@ $list-text-disabled-color: $gl-text-color-tertiary;
$list-border-light: #eee; $list-border-light: #eee;
$list-border: rgba(0, 0, 0, 0.05); $list-border: rgba(0, 0, 0, 0.05);
$list-text-height: 42px; $list-text-height: 42px;
$list-warning-row-bg: $orange-50; $list-warning-row-bg: $orange-100;
$list-warning-row-border: $orange-100; $list-warning-row-border: $orange-200;
$list-warning-row-color: $orange-700; $list-warning-row-color: $orange-700;
/* /*
...@@ -214,8 +215,8 @@ $gl-sidebar-padding: 22px; ...@@ -214,8 +215,8 @@ $gl-sidebar-padding: 22px;
/* /*
* Misc * Misc
*/ */
$row-hover: $blue-25; $row-hover: $blue-50;
$row-hover-border: $blue-100; $row-hover-border: $blue-200;
$progress-color: #c0392b; $progress-color: #c0392b;
$header-height: 50px; $header-height: 50px;
$new-navbar-height: 40px; $new-navbar-height: 40px;
...@@ -265,8 +266,8 @@ $time-color: #999; ...@@ -265,8 +266,8 @@ $time-color: #999;
$project-member-show-color: #aaa; $project-member-show-color: #aaa;
$gl-promo-color: #aaa; $gl-promo-color: #aaa;
$error-bg: $red-400; $error-bg: $red-400;
$warning-message-bg: $orange-50; $warning-message-bg: $orange-100;
$warning-message-border: $orange-100; $warning-message-border: $orange-200;
$warning-message-color: $orange-700; $warning-message-color: $orange-700;
$control-group-descr-color: #666; $control-group-descr-color: #666;
$table-permission-x-bg: #d9edf7; $table-permission-x-bg: #d9edf7;
...@@ -451,17 +452,17 @@ $builds-trace-bg: #111; ...@@ -451,17 +452,17 @@ $builds-trace-bg: #111;
/* /*
* Callout * Callout
*/ */
$callout-danger-bg: $red-50; $callout-danger-bg: $red-100;
$callout-danger-border: $red-100; $callout-danger-border: $red-200;
$callout-danger-color: $red-700; $callout-danger-color: $red-700;
$callout-warning-bg: $orange-50; $callout-warning-bg: $orange-100;
$callout-warning-border: $orange-100; $callout-warning-border: $orange-200;
$callout-warning-color: $orange-700; $callout-warning-color: $orange-700;
$callout-info-bg: $blue-50; $callout-info-bg: $blue-100;
$callout-info-border: $blue-100; $callout-info-border: $blue-200;
$callout-info-color: $blue-700; $callout-info-color: $blue-700;
$callout-success-bg: $green-50; $callout-success-bg: $green-100;
$callout-success-border: $green-100; $callout-success-border: $green-200;
$callout-success-color: $green-700; $callout-success-color: $green-700;
/* /*
......
...@@ -83,7 +83,7 @@ $space-between-cards: 8px; ...@@ -83,7 +83,7 @@ $space-between-cards: 8px;
border-top-color: $color-low-score; border-top-color: $color-low-score;
.card-score-big { .card-score-big {
background-color: $red-25; background-color: $red-50;
} }
} }
...@@ -91,7 +91,7 @@ $space-between-cards: 8px; ...@@ -91,7 +91,7 @@ $space-between-cards: 8px;
border-top-color: $color-average-score; border-top-color: $color-average-score;
.card-score-big { .card-score-big {
background-color: $orange-25; background-color: $orange-50;
} }
} }
...@@ -99,7 +99,7 @@ $space-between-cards: 8px; ...@@ -99,7 +99,7 @@ $space-between-cards: 8px;
border-top-color: $color-high-score; border-top-color: $color-high-score;
.card-score-big { .card-score-big {
background-color: $green-25; background-color: $green-50;
} }
} }
......
...@@ -451,7 +451,7 @@ ...@@ -451,7 +451,7 @@
} }
.files { .files {
margin-top: -1px; margin-top: 1px;
.diff-file:last-child { .diff-file:last-child {
margin-bottom: 0; margin-bottom: 0;
...@@ -586,11 +586,6 @@ ...@@ -586,11 +586,6 @@
top: 76px; top: 76px;
} }
+ .files,
+ .alert {
margin-top: 1px;
}
&:not(.is-stuck) .diff-stats-additions-deletions-collapsed { &:not(.is-stuck) .diff-stats-additions-deletions-collapsed {
display: none; display: none;
} }
...@@ -605,11 +600,6 @@ ...@@ -605,11 +600,6 @@
.inline-parallel-buttons { .inline-parallel-buttons {
display: none; display: none;
} }
+ .files,
+ .alert {
margin-top: 32px;
}
} }
} }
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
.is-confidential { .is-confidential {
color: $orange-600; color: $orange-600;
background-color: $orange-50; background-color: $orange-100;
border-radius: $border-radius-default; border-radius: $border-radius-default;
padding: 5px; padding: 5px;
margin: 0 3px 0 -4px; margin: 0 3px 0 -4px;
......
...@@ -255,7 +255,7 @@ $colors: ( ...@@ -255,7 +255,7 @@ $colors: (
&.saved { &.saved {
.editor { .editor {
border-top: solid 2px $green-200; border-top: solid 2px $green-300;
} }
} }
......
...@@ -103,7 +103,7 @@ ...@@ -103,7 +103,7 @@
.confidential-issue-warning { .confidential-issue-warning {
color: $orange-600; color: $orange-600;
background-color: $orange-50; background-color: $orange-100;
border-radius: $border-radius-default $border-radius-default 0 0; border-radius: $border-radius-default $border-radius-default 0 0;
border: 1px solid $border-gray-normal; border: 1px solid $border-gray-normal;
border-bottom: none; border-bottom: none;
......
...@@ -644,20 +644,20 @@ button.mini-pipeline-graph-dropdown-toggle { ...@@ -644,20 +644,20 @@ button.mini-pipeline-graph-dropdown-toggle {
// Dropdown button animation in mini pipeline graph // Dropdown button animation in mini pipeline graph
&.ci-status-icon-success { &.ci-status-icon-success {
@include mini-pipeline-graph-color($green-50, $green-500, $green-600); @include mini-pipeline-graph-color($green-100, $green-500, $green-600);
} }
&.ci-status-icon-failed { &.ci-status-icon-failed {
@include mini-pipeline-graph-color($red-50, $red-500, $red-600); @include mini-pipeline-graph-color($red-100, $red-500, $red-600);
} }
&.ci-status-icon-pending, &.ci-status-icon-pending,
&.ci-status-icon-success_with_warnings { &.ci-status-icon-success_with_warnings {
@include mini-pipeline-graph-color($orange-50, $orange-500, $orange-600); @include mini-pipeline-graph-color($orange-100, $orange-500, $orange-600);
} }
&.ci-status-icon-running { &.ci-status-icon-running {
@include mini-pipeline-graph-color($blue-50, $blue-400, $blue-600); @include mini-pipeline-graph-color($blue-100, $blue-400, $blue-600);
} }
&.ci-status-icon-canceled, &.ci-status-icon-canceled,
......
...@@ -291,7 +291,7 @@ table.u2f-registrations { ...@@ -291,7 +291,7 @@ table.u2f-registrations {
.bordered-box { .bordered-box {
border: 1px solid $blue-300; border: 1px solid $blue-300;
border-radius: $border-radius-default; border-radius: $border-radius-default;
background-color: $blue-25; background-color: $blue-50;
position: relative; position: relative;
display: flex; display: flex;
justify-content: center; justify-content: center;
...@@ -379,7 +379,7 @@ table.u2f-registrations { ...@@ -379,7 +379,7 @@ table.u2f-registrations {
.nav-wip { .nav-wip {
border: 1px solid $blue-500; border: 1px solid $blue-500;
background: $blue-25; background: $blue-50;
padding: $gl-padding; padding: $gl-padding;
margin-bottom: $gl-padding; margin-bottom: $gl-padding;
......
...@@ -28,9 +28,7 @@ input[type="checkbox"]:hover { ...@@ -28,9 +28,7 @@ input[type="checkbox"]:hover {
} }
.search { .search {
margin-right: 10px; margin: 4px 8px 0;
margin-left: 10px;
margin-top: ($header-height - 35) / 2;
form { form {
@extend .form-control; @extend .form-control;
...@@ -38,15 +36,23 @@ input[type="checkbox"]:hover { ...@@ -38,15 +36,23 @@ input[type="checkbox"]:hover {
padding: 4px; padding: 4px;
width: $search-input-width; width: $search-input-width;
line-height: 24px; line-height: 24px;
height: 32px;
border: 0;
border-radius: $border-radius-default;
transition: border-color ease-in-out $default-transition-duration, background-color ease-in-out $default-transition-duration;
&:hover { &:hover {
border-color: lighten($dropdown-input-focus-border, 20%); box-shadow: none;
box-shadow: 0 0 4px lighten($search-input-focus-shadow-color, 20%);
} }
} }
.location-text { .location-badge {
font-style: normal; font-size: 12px;
margin: -4px 4px -4px -4px;
line-height: 25px;
padding: 4px 8px;
border-radius: $border-radius-default 0 0 $border-radius-default;
transition: border-color ease-in-out $default-transition-duration;
} }
.search-input { .search-input {
...@@ -56,41 +62,26 @@ input[type="checkbox"]:hover { ...@@ -56,41 +62,26 @@ input[type="checkbox"]:hover {
margin-left: 5px; margin-left: 5px;
line-height: 25px; line-height: 25px;
width: 98%; width: 98%;
color: $white-light;
background: none;
transition: color ease-in-out $default-transition-duration;
} }
.location-badge { .search-input::placeholder {
line-height: 25px; transition: color ease-in-out $default-transition-duration;
padding: 0 5px;
border-radius: $border-radius-default;
font-size: 14px;
font-style: normal;
color: $note-disabled-comment-color;
display: inline-block;
background-color: $gray-normal;
vertical-align: top;
cursor: default;
} }
.search-input-container { .search-input-container {
display: -webkit-flex;
display: flex; display: flex;
position: relative; position: relative;
} }
.search-input-wrap { .search-input-wrap {
// Fallback if flexbox is not supported
display: inline-block;
}
.search-input-wrap {
width: 100%;
.search-icon, .search-icon,
.clear-icon { .clear-icon {
position: absolute; position: absolute;
right: 5px; right: 5px;
top: 0; top: 0;
color: $location-icon-color;
&::before { &::before {
font-family: FontAwesome; font-family: FontAwesome;
...@@ -101,7 +92,7 @@ input[type="checkbox"]:hover { ...@@ -101,7 +92,7 @@ input[type="checkbox"]:hover {
.search-icon { .search-icon {
@extend .fa-search; @extend .fa-search;
transition: color 0.15s; transition: color $default-transition-duration;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none; -ms-user-select: none;
...@@ -148,19 +139,30 @@ input[type="checkbox"]:hover { ...@@ -148,19 +139,30 @@ input[type="checkbox"]:hover {
form { form {
@extend .form-control:focus; @extend .form-control:focus;
border-color: $dropdown-input-focus-border; border-color: $dropdown-input-focus-border;
box-shadow: 0 0 4px $search-input-focus-shadow-color; box-shadow: none;
.search-input-wrap {
.search-icon,
.clear-icon {
color: $gl-text-color-tertiary;
transition: color ease-in-out $default-transition-duration;
}
} }
.location-badge { .search-input {
transition: all 0.15s; color: $gl-text-color;
background-color: $location-badge-active-bg; transition: color ease-in-out $default-transition-duration;
color: $white-light;
} }
.search-input-wrap { .search-input::placeholder {
i { color: $gl-text-color-tertiary;
color: $layout-link-gray; }
} }
.location-badge {
transition: all $default-transition-duration;
background-color: $nav-badge-bg;
border-color: $border-color;
} }
.dropdown-menu { .dropdown-menu {
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
} }
&.ci-failed { &.ci-failed {
@include status-color($red-50, $red-500, $red-600); @include status-color($red-100, $red-500, $red-600);
} }
&.ci-success { &.ci-success {
...@@ -39,12 +39,12 @@ ...@@ -39,12 +39,12 @@
&.ci-pending, &.ci-pending,
&.ci-failed_with_warnings, &.ci-failed_with_warnings,
&.ci-success_with_warnings { &.ci-success_with_warnings {
@include status-color($orange-50, $orange-500, $orange-700); @include status-color($orange-100, $orange-500, $orange-700);
} }
&.ci-info, &.ci-info,
&.ci-running { &.ci-running {
@include status-color($blue-50, $blue-500, $blue-600); @include status-color($blue-100, $blue-500, $blue-600);
} }
&.ci-created, &.ci-created,
......
...@@ -15,3 +15,9 @@ ...@@ -15,3 +15,9 @@
-ms-animation: none !important; -ms-animation: none !important;
animation: none !important; animation: none !important;
} }
// Disable sticky changes bar for tests
.diff-files-changed {
position: relative !important;
top: 0 !important;
}
...@@ -117,19 +117,32 @@ module IssuableCollections ...@@ -117,19 +117,32 @@ module IssuableCollections
key = 'issuable_sort' key = 'issuable_sort'
cookies[key] = params[:sort] if params[:sort].present? cookies[key] = params[:sort] if params[:sort].present?
cookies[key] = update_cookie_value(cookies[key])
# 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'
params[:sort] = cookies[key] params[:sort] = cookies[key]
end end
def default_sort_order def default_sort_order
case params[:state] 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 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 end
end end
...@@ -35,10 +35,13 @@ class Projects::TreeController < Projects::ApplicationController ...@@ -35,10 +35,13 @@ class Projects::TreeController < Projects::ApplicationController
end end
format.json do format.json do
# 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) render json: TreeSerializer.new(project: @project, repository: @repository, ref: @ref).represent(@tree)
end end
end end
end end
end
def create_dir def create_dir
return render_404 unless @commit_params.values.all? return render_404 unless @commit_params.values.all?
......
...@@ -30,10 +30,4 @@ module AppearancesHelper ...@@ -30,10 +30,4 @@ module AppearancesHelper
render 'shared/logo.svg' render 'shared/logo.svg'
end end
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 end
...@@ -13,22 +13,29 @@ module AvatarsHelper ...@@ -13,22 +13,29 @@ module AvatarsHelper
user_name = options[:user].try(:name) || options[:user_name] user_name = options[:user].try(:name) || options[:user_name]
avatar_url = options[:url] || avatar_icon(options[:user] || options[:user_email], avatar_size) avatar_url = options[:url] || avatar_icon(options[:user] || options[:user_email], avatar_size)
has_tooltip = options[:has_tooltip].nil? ? true : options[:has_tooltip] 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]) css_class = %W[avatar s#{avatar_size}].push(*options[:css_class])
if has_tooltip if has_tooltip
css_class.push('has-tooltip') css_class.push('has-tooltip')
data_attributes = { container: 'body' } data_attributes[:container] = 'body'
end end
image_tag( if options[:lazy]
avatar_url, css_class << 'lazy'
class: css_class, data_attributes[:src] = avatar_url
avatar_url = LazyImageTagHelper.placeholder_image
end
image_options = {
alt: "#{user_name}'s avatar", alt: "#{user_name}'s avatar",
title: user_name, src: avatar_url,
data: data_attributes, data: data_attributes,
lazy: true class: css_class,
) title: user_name
}
tag(:img, image_options)
end end
def user_avatar(options = {}) def user_avatar(options = {})
......
...@@ -176,13 +176,15 @@ module CommitsHelper ...@@ -176,13 +176,15 @@ module CommitsHelper
end end
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( link_to(
project_blob_path(project, project_blob_path(project,
tree_join(commit_sha, diff_new_path)), tree_join(commit_sha, diff_new_path)),
class: 'btn view-file js-view-file' class: 'btn view-file js-view-file'
) do ) 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') class: 'commit-sha')
end end
end end
......
...@@ -125,7 +125,7 @@ module GroupsHelper ...@@ -125,7 +125,7 @@ module GroupsHelper
end end
def default_help 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 end
def ancestor_locked_but_you_can_override(group) def ancestor_locked_but_you_can_override(group)
......
...@@ -17,6 +17,18 @@ module IconsHelper ...@@ -17,6 +17,18 @@ module IconsHelper
options.include?(:base) ? fa_stacked_icon(names, options) : fa_icon(names, options) options.include?(:base) ? fa_stacked_icon(names, options) : fa_icon(names, options)
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
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 = {}) def audit_icon(names, options = {})
case names case names
when "standard" when "standard"
......
...@@ -239,8 +239,8 @@ module ProjectsHelper ...@@ -239,8 +239,8 @@ module ProjectsHelper
end end
end end
def has_projects_or_name?(projects, params) def show_projects?(projects, params)
!!(params[:name] || any_projects?(projects)) !!(params[:personal] || params[:name] || any_projects?(projects))
end end
private private
......
This diff is collapsed.
module SystemNoteHelper module SystemNoteHelper
ICON_NAMES_BY_ACTION = { ICON_NAMES_BY_ACTION = {
'commit' => 'icon_commit', 'commit' => 'commit',
'description' => 'icon_edit', 'description' => 'pencil',
'merge' => 'icon_merge', 'merge' => 'git-merge',
'merged' => 'icon_merged', 'merged' => 'git-merge',
'opened' => 'icon_status_open', 'opened' => 'issue-open',
'closed' => 'icon_status_closed', 'closed' => 'issue-close',
'time_tracking' => 'icon_stopwatch', 'time_tracking' => 'timer',
'assignee' => 'icon_user', 'assignee' => 'user',
'title' => 'icon_edit', 'title' => 'pencil',
'task' => 'icon_check_square_o', 'task' => 'task-done',
'label' => 'icon_tags', 'label' => 'label',
'cross_reference' => 'icon_random', 'cross_reference' => 'comment-dots',
'branch' => 'icon_code_fork', 'branch' => 'fork',
'confidential' => 'icon_eye_slash', 'confidential' => 'eye-slash',
'visible' => 'icon_eye', 'visible' => 'eye',
'milestone' => 'icon_clock_o', 'milestone' => 'clock',
'discussion' => 'icon_comment_o', 'discussion' => 'comment',
'moved' => 'icon_arrow_circle_o_right', 'moved' => 'arrow-right',
'outdated' => 'icon_edit', 'outdated' => 'pencil',
'duplicate' => 'icon_clone' 'duplicate' => 'issue-duplicate'
}.freeze }.freeze
def system_note_icon_name(note) def system_note_icon_name(note)
...@@ -28,7 +28,7 @@ module SystemNoteHelper ...@@ -28,7 +28,7 @@ module SystemNoteHelper
def icon_for_system_note(note) def icon_for_system_note(note)
icon_name = system_note_icon_name(note) icon_name = system_note_icon_name(note)
custom_icon(icon_name) if icon_name sprite_icon(icon_name) if icon_name
end end
extend self extend self
......
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.
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
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.
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
This diff is collapsed.
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
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