diff options
Diffstat (limited to 'app/assets')
279 files changed, 6925 insertions, 4731 deletions
diff --git a/app/assets/images/emoji.png b/app/assets/images/emoji.png Binary files differindex 5dcd9c09b70..723c2c3f4c8 100644 --- a/app/assets/images/emoji.png +++ b/app/assets/images/emoji.png diff --git a/app/assets/images/emoji/gay_pride_flag.png b/app/assets/images/emoji/gay_pride_flag.png Binary files differnew file mode 100644 index 00000000000..1bec5f2ffd7 --- /dev/null +++ b/app/assets/images/emoji/gay_pride_flag.png diff --git a/app/assets/images/emoji/mrs_claus.png b/app/assets/images/emoji/mrs_claus.png Binary files differindex 078f0657f95..9cf2458df1a 100644 --- a/app/assets/images/emoji/mrs_claus.png +++ b/app/assets/images/emoji/mrs_claus.png diff --git a/app/assets/images/emoji/speech_left.png b/app/assets/images/emoji/speech_left.png Binary files differnew file mode 100644 index 00000000000..00c05959bcd --- /dev/null +++ b/app/assets/images/emoji/speech_left.png diff --git a/app/assets/images/emoji@2x.png b/app/assets/images/emoji@2x.png Binary files differindex b0fa9e1139e..987279c13cc 100644 --- a/app/assets/images/emoji@2x.png +++ b/app/assets/images/emoji@2x.png diff --git a/app/assets/images/icons.json b/app/assets/images/icons.json index d8d173612d5..4e967936ce0 100644 --- a/app/assets/images/icons.json +++ b/app/assets/images/icons.json @@ -1 +1 @@ -{"iconCount":173,"spriteSize":75815,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-right","assignee","bold","book","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","import","issue-block","issue-child","issue-close","issue-duplicate","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil","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","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]}
\ No newline at end of file +{"iconCount":180,"spriteSize":82176,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","import","issue-block","issue-child","issue-close","issue-duplicate","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]}
\ No newline at end of file diff --git a/app/assets/images/icons.svg b/app/assets/images/icons.svg index c8f10628713..77ce6b2d89f 100644 --- a/app/assets/images/icons.svg +++ b/app/assets/images/icons.svg @@ -1 +1 @@ -<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><symbol viewBox="0 0 16 16" id="abuse" xmlns="http://www.w3.org/2000/svg"><path d="M11.408.328l4.029 3.222A1.5 1.5 0 0 1 16 4.72v6.555a1.5 1.5 0 0 1-.563 1.171l-4.026 3.224a1.5 1.5 0 0 1-.937.329H5.529a1.5 1.5 0 0 1-.937-.328L.563 12.45A1.5 1.5 0 0 1 0 11.28V4.724a1.5 1.5 0 0 1 .563-1.171L4.589.329A1.5 1.5 0 0 1 5.526 0h4.945c.34 0 .67.116.937.328zM10.296 2H5.702L2 4.964v6.074L5.704 14h4.594L14 11.036V4.962L10.296 2zM8 4a1 1 0 0 1 1 1v3a1 1 0 1 1-2 0V5a1 1 0 0 1 1-1zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="account" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9.195 9.965l-.568-.875a.25.25 0 0 1 .015-.294l.405-.5a.25.25 0 0 1 .283-.075l.938.36c.257-.183.543-.325.851-.42l.322-.988A.25.25 0 0 1 11.679 7h.642a.25.25 0 0 1 .238.173l.322.988c.308.095.594.237.851.42l.938-.36a.25.25 0 0 1 .283.076l.405.5a.25.25 0 0 1 .015.293l-.568.875c.113.297.18.616.193.95l.898.54a.25.25 0 0 1 .115.27l-.144.626a.25.25 0 0 1-.222.193l-1.115.098a3.015 3.015 0 0 1-.512.608l.165 1.18a.25.25 0 0 1-.138.259l-.577.281a.25.25 0 0 1-.29-.05l-.874-.905a3.035 3.035 0 0 1-.608 0l-.875.904a.25.25 0 0 1-.289.051l-.577-.281a.25.25 0 0 1-.138-.26l.165-1.18a3.015 3.015 0 0 1-.512-.607l-1.115-.098a.25.25 0 0 1-.222-.193l-.144-.626a.25.25 0 0 1 .115-.27l.898-.54c.013-.334.08-.653.193-.95zM6.789 8.023A12.845 12.845 0 0 0 6 8c-5.036 0-6 2.74-6 4.48C0 14.22.076 15 6 15c.553 0 1.055-.006 1.51-.02A5.977 5.977 0 0 1 6 11c0-1.083.287-2.1.79-2.977zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM12 12a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="admin" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.162 2.5a3.5 3.5 0 0 1-3.163 5.479L6.08 14.766a1.5 1.5 0 0 1-2.598-1.5L7.4 6.479A3.5 3.5 0 0 1 10.564 1L8.9 3.88l2.599 1.5 1.663-2.88zm-8.63 11.949a.5.5 0 1 0 .5-.866.5.5 0 0 0-.5.866z"/></symbol><symbol viewBox="0 0 16 16" id="angle-double-left" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.414 7.95l4.243-4.243a1 1 0 0 0-1.414-1.414l-4.95 4.95a.997.997 0 0 0 0 1.414l4.95 4.95a1 1 0 1 0 1.414-1.415L10.414 7.95zm-7 0l4.243-4.243a1 1 0 0 0-1.414-1.414l-4.95 4.95a.997.997 0 0 0 0 1.414l4.95 4.95a1 1 0 0 0 1.414-1.415L3.414 7.95z"/></symbol><symbol viewBox="0 0 16 16" id="angle-double-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.536 7.95L1.293 3.707a1 1 0 0 1 1.414-1.414l4.95 4.95a.997.997 0 0 1 0 1.414l-4.95 4.95a1 1 0 1 1-1.414-1.415L5.536 7.95zm7 0L8.293 3.707a1 1 0 0 1 1.414-1.414l4.95 4.95a.997.997 0 0 1 0 1.414l-4.95 4.95a1 1 0 0 1-1.414-1.415l4.243-4.242z"/></symbol><symbol viewBox="0 0 16 16" id="angle-down" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 10.243l-4.95-4.95a1 1 0 0 0-1.414 1.414l5.657 5.657a.997.997 0 0 0 1.414 0l5.657-5.657a1 1 0 0 0-1.414-1.414L8 10.243z"/></symbol><symbol viewBox="0 0 16 16" id="angle-left" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.757 8l4.95-4.95a1 1 0 1 0-1.414-1.414L3.636 7.293a.997.997 0 0 0 0 1.414l5.657 5.657a1 1 0 0 0 1.414-1.414L5.757 8z"/></symbol><symbol viewBox="0 0 16 16" id="angle-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.243 8l-4.95-4.95a1 1 0 0 1 1.414-1.414l5.657 5.657a.997.997 0 0 1 0 1.414l-5.657 5.657a1 1 0 0 1-1.414-1.414L10.243 8z"/></symbol><symbol viewBox="0 0 16 16" id="angle-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 6.757l-4.95 4.95a1 1 0 1 1-1.414-1.414l5.657-5.657a.997.997 0 0 1 1.414 0l5.657 5.657a1 1 0 0 1-1.414 1.414L8 6.757z"/></symbol><symbol viewBox="0 0 16 16" id="appearance" xmlns="http://www.w3.org/2000/svg"><path d="M11.161 12.456l.232.121c.1.053.175.094.249.137.53.318.844.75.857 1.402.012 1.397-1.116 1.756-3.12 1.858a23.85 23.85 0 0 1-1.38.026A8 8 0 0 1 0 8a8 8 0 0 1 8-8c4.417 0 7.998 3.582 7.998 7.977.06 2.621-1.312 3.586-4.48 3.648-.602.008-1.068.043-1.4.104.228.192.598.47 1.043.727zm-3.287-.943c-.019-1.495 1.228-1.856 3.611-1.888C13.67 9.582 14.028 9.33 13.998 8A6 6 0 1 0 8 14c.603 0 .91-.004 1.277-.023a9.7 9.7 0 0 0 .478-.035c-1.172-.738-1.868-1.47-1.88-2.43zM6 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 3a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm-2-3a1 1 0 1 1 0-2 1 1 0 0 1 0 2zM4 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="applications" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1 0h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm0 6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm6-6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm0 1v2h2V1H7zm0 5h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm6-6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm0 6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm0 1v2h2V7h-2zM1 12h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1zm0 1v2h2v-2H1zm6-1h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1zm6 0h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="approval" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.536 10.657l2.828-2.829a1 1 0 0 1 1.414 1.415l-3.535 3.535a.997.997 0 0 1-1.415 0l-2.12-2.121A1 1 0 1 1 9.12 9.243l1.415 1.414zM7.632 8.109A2 2 0 0 0 7 11.364l2.121 2.121a1.996 1.996 0 0 0 2.807.021C11.686 14.554 10.627 15 6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8c.6 0 1.142.038 1.632.109zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"/></symbol><symbol viewBox="0 0 16 16" id="arrow-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9 6H2a2 2 0 1 0 0 4h7v2.586a1 1 0 0 0 1.707.707l4.586-4.586a1 1 0 0 0 0-1.414l-4.586-4.586A1 1 0 0 0 9 3.414V6z"/></symbol><symbol viewBox="0 0 16 16" id="assignee" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12 5V4a1 1 0 0 1 2 0v1h1a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0V7h-1a1 1 0 0 1 0-2h1zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8s6 2.692 6 4.48c0 1.788-.076 2.52-6 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="bold" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4 12.5v-9A1.5 1.5 0 0 1 5.5 2h2.104c2.182 0 3.879.681 3.879 2.982 0 1.067-.517 2.227-1.374 2.595v.073C11.176 7.963 12 8.865 12 10.466 12 12.914 10.19 14 7.911 14H5.5A1.5 1.5 0 0 1 4 12.5zm2.376-5.696H7.49c1.164 0 1.665-.552 1.665-1.417 0-.94-.534-1.289-1.649-1.289h-1.13v2.706zm0 5.098h1.341c1.293 0 1.956-.515 1.956-1.62 0-1.049-.647-1.472-1.956-1.472H6.376v3.092z"/></symbol><symbol viewBox="0 0 16 16" id="book" xmlns="http://www.w3.org/2000/svg"><path d="M7 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2v4.191a.5.5 0 0 1-.724.447l-1.052-.526a.5.5 0 0 0-.448 0l-1.052.526A.5.5 0 0 1 7 6.191V2zM5 0h6a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z"/></symbol><symbol viewBox="0 0 16 16" id="branch" xmlns="http://www.w3.org/2000/svg"><path d="M6 11.978v.29a2 2 0 1 1-2 0V3.732a2 2 0 1 1 2 0v3.849c.592-.491 1.31-.854 2.15-1.081 1.308-.353 1.875-.882 1.893-1.743a2 2 0 1 1 2.002-.051C12.053 6.54 10.857 7.84 8.67 8.43 7.056 8.867 6.195 9.98 6 11.978zM5 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm6 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM5 15a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="bullhorn" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6.143 10H7V4H3a3 3 0 1 0 0 6h.143l.734 5.141a1 1 0 0 0 .99.859h1.556a.5.5 0 0 0 .495-.57L6.143 10zM8 4c1.034.02 2.039-.274 3.014-.883.727-.455 1.836-1.334 3.328-2.637A1 1 0 0 1 16 1.233v10.764a1 1 0 0 1-1.595.803c-1.658-1.227-2.788-1.992-3.392-2.294-.781-.39-1.785-.559-3.013-.506V4z"/></symbol><symbol viewBox="0 0 16 16" id="calendar" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12 2h2a2 2 0 0 1 2 2H0a2 2 0 0 1 2-2h2V1a1 1 0 1 1 2 0v1h4V1a1 1 0 1 1 2 0v1zM0 4h16v9a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V4zm2 2.5V13a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6.5a.5.5 0 0 0-.5-.5h-11a.5.5 0 0 0-.5.5zM5 8h2a1 1 0 1 1 0 2H5a1 1 0 1 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="cancel" xmlns="http://www.w3.org/2000/svg"><path d="M3.11 4.523a6 6 0 0 0 8.367 8.367L3.109 4.524zM4.522 3.11l8.368 8.368A6 6 0 0 0 4.524 3.11zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16z"/></symbol><symbol viewBox="0 0 16 16" id="chart" xmlns="http://www.w3.org/2000/svg"><path d="M15 14a1 1 0 0 1 0 2H2a2 2 0 0 1-2-2V1a1 1 0 1 1 2 0v13h13zM3.142 8.735l2.502-2.561a.5.5 0 0 1 .714-.003L8 7.833l3.592-4.553a.5.5 0 0 1 .796.015l2.516 3.454a.5.5 0 0 1 .096.295V12.5a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5V9.085a.5.5 0 0 1 .142-.35z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-down" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.078 8.2l3.535-3.536a2 2 0 0 1 2.828 2.828l-4.949 4.95c-.39.39-.902.586-1.414.586a1.994 1.994 0 0 1-1.414-.586l-4.95-4.95a2 2 0 1 1 2.828-2.828l3.536 3.535z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-left" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.977 7.998l3.535-3.535a2 2 0 1 0-2.828-2.828l-4.95 4.949c-.39.39-.586.902-.586 1.414 0 .512.196 1.024.586 1.414l4.95 4.95a2 2 0 1 0 2.828-2.828L7.977 7.998z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.22 7.998L4.683 4.463a2 2 0 0 1 2.828-2.828l4.95 4.949c.39.39.586.902.586 1.414a1.99 1.99 0 0 1-.586 1.414l-4.95 4.95a2 2 0 0 1-2.828-2.828l3.535-3.536z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.778 8.957l3.535 3.535a2 2 0 1 0 2.828-2.828l-4.949-4.95a1.994 1.994 0 0 0-1.414-.586c-.512 0-1.024.196-1.414.586l-4.95 4.95a2 2 0 1 0 2.828 2.828l3.536-3.535z"/></symbol><symbol viewBox="0 0 16 16" id="clock" xmlns="http://www.w3.org/2000/svg"><path d="M9 7h1a1 1 0 0 1 0 2H8a.997.997 0 0 1-1-1V5a1 1 0 1 1 2 0v2zm-1 9A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="close" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9.414 8l4.95-4.95a1 1 0 0 0-1.414-1.414L8 6.586l-4.95-4.95A1 1 0 0 0 1.636 3.05L6.586 8l-4.95 4.95a1 1 0 1 0 1.414 1.414L8 9.414l4.95 4.95a1 1 0 1 0 1.414-1.414L9.414 8z"/></symbol><symbol viewBox="0 0 16 16" id="code" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M15.871 8.243a.997.997 0 0 0-.293-.707L12.75 4.707a1 1 0 0 0-1.414 1.414l2.12 2.122-2.12 2.121a1 1 0 0 0 1.414 1.414l2.828-2.828a.997.997 0 0 0 .293-.707zm-13.243 0L4.75 6.12a1 1 0 1 0-1.414-1.414L.507 7.536a.997.997 0 0 0 0 1.414l2.829 2.828a1 1 0 1 0 1.414-1.414L2.628 8.243zm6.407-4.107a1 1 0 0 1 .707 1.225L8.19 11.157a1 1 0 1 1-1.931-.518L7.81 4.843a1 1 0 0 1 1.224-.707z"/></symbol><symbol viewBox="0 0 9 13" id="collapse"><path d="M.084.25C.01.18-.015.12.008.071.031.024.093 0 .194 0h8.521c.1 0 .162.024.185.072.023.048-.002.107-.075.177l-4.11 3.935a.372.372 0 0 1-.11.072h-.301a.508.508 0 0 1-.11-.072L.084.249zM.377 6.88a.364.364 0 0 1-.26-.105.334.334 0 0 1-.11-.25v-.709c0-.096.036-.179.11-.249a.364.364 0 0 1 .26-.105h8.15c.101 0 .188.035.261.105.074.07.11.153.11.25v.709c0 .096-.036.179-.11.249a.364.364 0 0 1-.26.105H.377zM.084 12.132c-.074.07-.099.129-.076.177.023.048.085.072.186.072h8.521c.1 0 .162-.024.185-.072.023-.048-.002-.107-.075-.177l-4.11-3.935a.372.372 0 0 0-.11-.072h-.301a.508.508 0 0 0-.11.072l-4.11 3.935z"/></symbol><symbol viewBox="0 0 16 16" id="comment" xmlns="http://www.w3.org/2000/svg"><path d="M1.707 15.707C1.077 16.337 0 15.891 0 15V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5.414l-3.707 3.707zM2 12.586l2.293-2.293A1 1 0 0 1 5 10h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v9.586z"/></symbol><symbol viewBox="0 0 16 16" id="comment-dots" xmlns="http://www.w3.org/2000/svg"><path d="M1.707 15.707C1.077 16.337 0 15.891 0 15V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5.414l-3.707 3.707zM2 12.586l2.293-2.293A1 1 0 0 1 5 10h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v9.586zM5 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="comment-next" xmlns="http://www.w3.org/2000/svg"><path d="M8 5V4a.5.5 0 0 1 .8-.4l2.667 2a.5.5 0 0 1 0 .8L8.8 8.4A.5.5 0 0 1 8 8V7H6a1 1 0 1 1 0-2h2zM1.707 15.707C1.077 16.337 0 15.891 0 15V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5.414l-3.707 3.707zM2 12.586l2.293-2.293A1 1 0 0 1 5 10h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v9.586z"/></symbol><symbol viewBox="0 0 16 16" id="comments" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3.75 10L0 13V3a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2H3.75zM13 5h1a2 2 0 0 1 2 2v8l-2.667-2H8a2 2 0 0 1-2-2h4a3 3 0 0 0 3-3V5z"/></symbol><symbol viewBox="0 0 16 16" id="commit" xmlns="http://www.w3.org/2000/svg"><path d="M8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm3.876-1.008a4.002 4.002 0 0 1-7.752 0A1.01 1.01 0 0 1 4 9H1a1 1 0 1 1 0-2h3c.042 0 .083.003.124.008a4.002 4.002 0 0 1 7.752 0A1.01 1.01 0 0 1 12 7h3a1 1 0 0 1 0 2h-3a1.01 1.01 0 0 1-.124-.008z"/></symbol><symbol viewBox="0 0 16 16" id="credit-card" xmlns="http://www.w3.org/2000/svg"><path d="M14 5a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1h12zm0 3H2v3a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V8zM3 2h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zm6.5 8h3a.5.5 0 1 1 0 1h-3a.5.5 0 1 1 0-1z"/></symbol><symbol viewBox="0 0 16 16" id="cut" xmlns="http://www.w3.org/2000/svg"><rect width="16" height="2" y="7" fill-rule="evenodd" rx="1"/></symbol><symbol viewBox="0 0 16 16" id="dashboard" xmlns="http://www.w3.org/2000/svg"><path d="M7.709 10.021l.696-2.6a.5.5 0 0 1 .966.26l-.657 2.45A2 2 0 0 1 10 12H6a2 2 0 0 1 1.709-1.979zM0 8.9a8 8 0 0 1 15.998 0H16v3.6a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5V8.9zM14 9A6 6 0 1 0 2 9v3.5a.5.5 0 0 0 .5.5h11a.5.5 0 0 0 .5-.5V9zM3.5 9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm9 0a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-7-3a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm5 0a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1z"/></symbol><symbol viewBox="0 0 16 16" id="disk" xmlns="http://www.w3.org/2000/svg"><path d="M16 11.764V3a3 3 0 0 0-3-3H3a3 3 0 0 0-3 3v8.764A2.989 2.989 0 0 1 2 11V3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v8c.768 0 1.47.289 2 .764zM2 12h12a2 2 0 1 1 0 4H2a2 2 0 1 1 0-4zm10 1a1 1 0 1 0 0 2 1 1 0 0 0 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="doc_code" xmlns="http://www.w3.org/2000/svg"><path d="M8 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V7h-3a2 2 0 0 1-2-2V2zm2 .414V5h2.586L10 2.414zm1.036 7.607a.498.498 0 0 1-.147.354l-1.414 1.414a.5.5 0 0 1-.707-.707l1.06-1.06-1.06-1.061a.5.5 0 0 1 .707-.707l1.414 1.414a.498.498 0 0 1 .147.353zm-4.822 0l1.06 1.061a.5.5 0 0 1-.706.707l-1.414-1.414a.498.498 0 0 1 0-.707l1.414-1.414a.5.5 0 1 1 .707.707l-1.06 1.06zM5 0h4.586A2 2 0 0 1 11 .586L14.414 4A2 2 0 0 1 15 5.414V12a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z"/></symbol><symbol viewBox="0 0 16 16" id="doc_image" xmlns="http://www.w3.org/2000/svg"><path d="M8 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V7h-3a2 2 0 0 1-2-2V2zm2 .414V5h2.586L10 2.414zM7.333 9.667l1.313-1.313a.5.5 0 0 1 .708 0L12 11H4l2.188-1.75a.5.5 0 0 1 .624 0l.521.417zM5 0h4.586A2 2 0 0 1 11 .586L14.414 4A2 2 0 0 1 15 5.414V12a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm.5 8a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zM4 11h8v.7a.3.3 0 0 1-.3.3H4.3a.3.3 0 0 1-.3-.3V11z"/></symbol><symbol viewBox="0 0 16 16" id="doc_text" xmlns="http://www.w3.org/2000/svg"><path d="M8 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V7h-3a2 2 0 0 1-2-2V2zm2 .414V5h2.586L10 2.414zM5 0h4.586A2 2 0 0 1 11 .586L14.414 4A2 2 0 0 1 15 5.414V12a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm.5 11h5a.5.5 0 1 1 0 1h-5a.5.5 0 1 1 0-1zm0-2h5a.5.5 0 1 1 0 1h-5a.5.5 0 0 1 0-1zm0-2h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1z"/></symbol><symbol viewBox="0 0 105 26" id="double-headed-arrow" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1.018 11.089L15.138.614c1.23-.911 3.086-.795 4.147.26.461.46.715 1.045.715 1.651v20.95C20 24.869 18.684 26 17.06 26a3.238 3.238 0 0 1-1.921-.614L1.019 14.911C-.212 14-.347 12.405.714 11.35c.094-.094.195-.18.303-.261zm102.964 0c.108.08.21.167.303.26 1.061 1.056.925 2.65-.303 3.562l-14.12 10.475A3.238 3.238 0 0 1 87.94 26C86.316 26 85 24.87 85 23.475V2.525c0-.606.254-1.192.715-1.65 1.061-1.056 2.917-1.172 4.146-.26l14.12 10.474zM35 17a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm18 0a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm18 0a4 4 0 1 1 0-8 4 4 0 0 1 0 8z"/></symbol><symbol viewBox="0 0 16 16" id="download" xmlns="http://www.w3.org/2000/svg"><path d="M9 12h1a.5.5 0 0 1 .4.8l-2 2.667a.5.5 0 0 1-.8 0l-2-2.667A.5.5 0 0 1 6 12h1V8a1 1 0 1 1 2 0v4zM4 9a1 1 0 1 1 0 2 4 4 0 0 1-1.971-7.481 4 4 0 0 1 6.633-2.505 3.999 3.999 0 0 1 3.82 2.014A4 4 0 0 1 12 11a1 1 0 0 1 0-2 2 2 0 1 0 0-4h-1a2 2 0 0 0-3.112-1.662A2 2 0 1 0 4.268 5H4a2 2 0 1 0 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="duplicate" xmlns="http://www.w3.org/2000/svg"><path d="M14 10h-3a1 1 0 0 1-1-1V6H8.527A.527.527 0 0 0 8 6.527V13a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1v-3zm-4-7H8.527c-.18 0-.355.013-.527.04V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2v2H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h4a3 3 0 0 1 3 3zM8.527 4h2.323a.5.5 0 0 1 .35.143l4.65 4.551a.5.5 0 0 1 .15.357V13a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V6.527A2.527 2.527 0 0 1 8.527 4z"/></symbol><symbol viewBox="0 0 16 16" id="earth" xmlns="http://www.w3.org/2000/svg"><path d="M8.7 2.04l-.082.177c.283.223.422.413.417.571-.008.237-.311.057-.444.274-.133.218.038.542-.112.637-.15.096-.398-.386-.479-.46-.054-.049-.166-.257-.336-.625l-.216-.225a.844.844 0 0 0-.418-.035c-.177.038-.075.1-.035.132.04.032.32.037.452.2.132.164.03.224-.05.298-.054.05-.157.062-.31.035H5.952l-.402.398.03.325.229.455.324-.463c.008-.206.058-.342.15-.41.14-.1.342-.15.534-.085.191.066-.057.218.011.271.068.053.204-.098.313-.02.11.08.07.155.104.322.036.167.254.114.398.328.144.215.19.29.147.483-.043.195-.168.26-.305.232-.138-.028-.107-.246-.275-.348-.168-.102-.266-.114-.386-.054-.12.06-.016.129.023.235.04.106.274.321.224.43-.05.107-.108.116-.42 0-.21-.077-.414-.007-.615.212l-.76.722c-.153.715-.3 1.13-.44 1.243-.211.17-.177-.483-.483-.656-.306-.174-.494-.047-.8-.07-.307-.023-.42.65-.38.873a.434.434 0 0 0 .221.321c.236-.141.39-.184.465-.128.11.084-.144.267-.074.425.07.158.314.069.386.283.073.213.084.48-.05.706-.135.227-.275.178-.4.053-.127-.126-.033-.375-.255-.704-.223-.329-.381-.337-.63-.787-.158-.287-.35-.743-.575-1.366a6 6 0 0 0 3.21 7.198l.001-.075c0-.577-.004-.944-.012-1.102-.011-.236-.95-.945-1.104-1.2-.154-.256-.34-.595-.355-.746-.016-.151.185-.232.344-.325.16-.093-.11-.367.028-.626.137-.258.395-.438.496-.356.101.081.058.228.267.333.209.104.077-.213.456-.178.38.035.143.201.252.216.11.016.113-.127.299-.143.186-.015.282.445.471.622.19.178.452.008.611.043.159.034.267.09.402.255.136.166-.03.352.073.557.103.205 1.07.22 1.433.255.364.034.371.011.371.324s-.166.314-.453.507c-.286.193-.166.462-.38.762-.212.3-.316.062-.622.14-.306.077-.413.382-.452.568-.039.186-.386.094-.877.232-.29.082-.429.144-.569.204a6.002 6.002 0 0 0 7.682-4.3c-.094-.384-.18-.63-.258-.74-.213-.297-.36.21-.924.49-.564.278-.57-.288-.81-.49-.16-.133-.212-.44-.158-.92-.005-.478.02-.828.077-1.049.057-.221.126-.543.207-.965.351-.373.606-.572.764-.595.237-.034.336.374.658.3a.315.315 0 0 0 .035-.01 5.993 5.993 0 0 0-.475-.824l-.309-.043a.646.646 0 0 0-.332-.117c-.205-.02-.025.128-.089.24-.064.112-.235.724-.437.685-.201-.039-.204-.374-.17-.668.036-.294-.077-.35-.2-.412-.124-.062-.325-.213-.556-.295-.232-.082-.123-.175-.093-.274.03-.1.208-.015.193-.058-.014-.044-.313-.135-.266-.167.03-.02.2-.02.506.003l.216-.012.293-.163a.58.58 0 0 0-.376-.22c-.233-.036-.513-.034-.73-.142-.205-.103-.458-.36-.643-.638A5.965 5.965 0 0 0 8.7 2.04zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16z"/></symbol><symbol viewBox="0 0 16 16" id="external-link" xmlns="http://www.w3.org/2000/svg"><path d="M13.121 4.177l-4.95 4.95a1 1 0 1 1-1.414-1.414l4.95-4.95-1.386-1.386a.5.5 0 0 1 .299-.85l4.709-.524a.5.5 0 0 1 .552.552l-.523 4.71a.5.5 0 0 1-.851.297l-1.386-1.385zM12 8.884a1 1 0 0 1 2 0v4a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3v-8a3 3 0 0 1 3-3h4a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-4z"/></symbol><symbol viewBox="0 0 16 16" id="eye" xmlns="http://www.w3.org/2000/svg"><path d="M8 14C4.816 14 2.253 12.284.393 8.981a2 2 0 0 1 0-1.962C2.253 3.716 4.816 2 8 2s5.747 1.716 7.607 5.019a2 2 0 0 1 0 1.962C13.747 12.284 11.184 14 8 14zm0-2c2.41 0 4.338-1.29 5.864-4C12.338 5.29 10.411 4 8 4 5.59 4 3.662 5.29 2.136 8 3.662 10.71 5.589 12 8 12zm0-1a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm1-3a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="eye-slash" xmlns="http://www.w3.org/2000/svg"><path d="M13.618 2.62L1.62 14.619a1 1 0 0 1-.985-1.668l1.525-1.526C1.516 10.742.926 9.927.393 8.981a2 2 0 0 1 0-1.962C2.253 3.716 4.816 2 8 2c1.074 0 2.076.195 3.006.58l.944-.944a1 1 0 0 1 1.668.985zM8.068 11a3 3 0 0 0 2.931-2.932l-2.931 2.931zm-3.02-2.462a3 3 0 0 1 3.49-3.49l.884-.884A6.044 6.044 0 0 0 8 4C5.59 4 3.662 5.29 2.136 8c.445.79.924 1.46 1.439 2.011l1.473-1.473zm.421 5.06l1.658-1.658c.283.04.575.06.873.06 2.41 0 4.338-1.29 5.864-4a11.023 11.023 0 0 0-1.133-1.664l1.418-1.418a12.799 12.799 0 0 1 1.458 2.1 2 2 0 0 1 0 1.963C13.747 12.284 11.184 14 8 14a7.883 7.883 0 0 1-2.53-.402z"/></symbol><symbol viewBox="0 0 16 16" id="file-addition" xmlns="http://www.w3.org/2000/svg"><path d="M7 7V5a1 1 0 1 1 2 0v2h2a1 1 0 0 1 0 2H9v2a1 1 0 0 1-2 0V9H5a1 1 0 1 1 0-2h2zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3z"/></symbol><symbol viewBox="0 0 16 16" id="file-deletion" xmlns="http://www.w3.org/2000/svg"><path d="M3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3zm2 6h6a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="file-modified" xmlns="http://www.w3.org/2000/svg"><path d="M3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3zm5 4a3 3 0 1 1 0 6 3 3 0 0 1 0-6z"/></symbol><symbol viewBox="0 0 16 16" id="filter" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 6v9l-3.724-1.862A.5.5 0 0 1 6 12.691V6L1.854 1.854A.5.5 0 0 1 2.207 1h11.586a.5.5 0 0 1 .353.854L10 6z"/></symbol><symbol viewBox="0 0 16 16" id="folder" xmlns="http://www.w3.org/2000/svg"><path d="M7.228 5l-.475-1.335A1 1 0 0 0 5.81 3H2v9a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1H7.228zM13 3a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a2 2 0 0 1 2-2h3.81a3 3 0 0 1 2.827 1.995L13 3z"/></symbol><symbol viewBox="0 0 16 16" id="fork" xmlns="http://www.w3.org/2000/svg"><path d="M9 12.268a2 2 0 1 1-2 0V8.874A4.002 4.002 0 0 1 4 5V3.732a2 2 0 1 1 2 0V5a2 2 0 1 0 4 0V3.732a2 2 0 1 1 2 0V5a4.002 4.002 0 0 1-3 3.874v3.394zM11 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM5 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm3 12a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="geo-nodes" xmlns="http://www.w3.org/2000/svg"><path d="M9.7 13.1l-.2.2c-.7.8-2 .9-2.8.1-.1 0-.1-.1-.1-.1l-.2-.2c-2 .2-3.4.7-3.4 1.4 0 .8 2.2 1.5 5 1.5s5-.7 5-1.5c0-.7-1.4-1.2-3.3-1.4M7.3 12.7c.4.4 1 .3 1.4-.1C11.6 9.5 13 7 13 5.3 13 2.4 10.8 0 8 0S3 2.4 3 5.3C3 7 4.4 9.5 7.3 12.7M8 2c1.6 0 3 1.4 3 3.3 0 1-1 2.8-3 5.2-2-2.4-3-4.2-3-5.2C5 3.4 6.4 2 8 2"/><circle cx="8" cy="5" r="1"/></symbol><symbol viewBox="0 0 16 16" id="git-merge" xmlns="http://www.w3.org/2000/svg"><path d="M11 12.268V5a1 1 0 0 0-1-1v1a.5.5 0 0 1-.8.4l-2.667-2a.5.5 0 0 1 0-.8L9.2.6a.5.5 0 0 1 .8.4v1a3 3 0 0 1 3 3v7.268a2 2 0 1 1-2 0zm-6 0a2 2 0 1 1-2 0V4.732a2 2 0 1 1 2 0v7.536zM4 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm0 11a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm8 0a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="group" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3.048 11.997C-.377 11.975.013 11.782.013 10.56.013 9.235.653 8 4 8c.444 0 .84.022 1.194.062.164.435.426.82.76 1.132-1.786.389-2.721 1.353-2.906 2.803zm2.94-7.222a2.993 2.993 0 0 0-.976 1.95 2 2 0 1 1 .975-1.95zm6.964 7.222c-.185-1.45-1.12-2.414-2.906-2.803.334-.311.596-.697.76-1.132C11.16 8.022 11.556 8 12 8c3.346 0 3.987 1.235 3.987 2.56 0 1.222.39 1.415-3.035 1.437zm-1.964-5.272a2.993 2.993 0 0 0-.976-1.95 2 2 0 1 1 .976 1.95zM8 9a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 5c-2.177 0-3.987-.115-3.987-1.44S4.653 10 8 10c3.346 0 3.987 1.235 3.987 2.56S10.177 14 8 14z"/></symbol><symbol viewBox="0 0 16 16" id="history" xmlns="http://www.w3.org/2000/svg"><path d="M2.868 3.24a7 7 0 1 1-.043 9.475 1 1 0 0 1 1.478-1.348 5 5 0 1 0 .124-6.865l.796.645a.5.5 0 0 1-.193.873l-3.232.814a.5.5 0 0 1-.622-.504L1.3 3a.5.5 0 0 1 .814-.37l.754.61zM9 8h1a1 1 0 0 1 0 2H8a.997.997 0 0 1-1-1V6a1 1 0 1 1 2 0v2z"/></symbol><symbol viewBox="0 0 16 16" id="home" xmlns="http://www.w3.org/2000/svg"><path d="M8.462 2.177a.505.505 0 0 1-.038.044l.038-.044zm-.787 0l.038.043a.5.5 0 0 1-.038-.043zM3.706 7h8.725L8.069 2.585 3.706 7zM7 13.369V12a1 1 0 0 1 2 0v1.369h3V9H4v4.369h3zM14 9v4.836c0 .833-.657 1.533-1.5 1.533h-9c-.843 0-1.5-.7-1.5-1.533V9h-.448a1.1 1.1 0 0 1-.783-1.873L6.934.887a1.5 1.5 0 0 1 2.269 0l6.165 6.24A1.1 1.1 0 0 1 14.585 9H14z"/></symbol><symbol viewBox="0 0 16 16" id="hook" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1h4zm0 1H6v1a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1V4zM7 8a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h2a3 3 0 0 1 3 3v2a3 3 0 0 1-3 3v4a2 2 0 1 0 4 0h-.44a.3.3 0 0 1-.25-.466l1.44-2.16a.3.3 0 0 1 .5 0l1.44 2.16a.3.3 0 0 1-.25.466H15a4 4 0 0 1-7 2.646A4 4 0 0 1 1 12H.56a.3.3 0 0 1-.25-.466l1.44-2.16a.3.3 0 0 1 .5 0l1.44 2.16a.3.3 0 0 1-.25.466H3a2 2 0 1 0 4 0V8z"/></symbol><symbol viewBox="0 0 16 16" id="hourglass" xmlns="http://www.w3.org/2000/svg"><path d="M10.331 4.889A2.988 2.988 0 0 0 11 3V2H5v1c0 .362.064.709.182 1.03l5.15.859zM3 14v-1c0-1.78.93-3.342 2.33-4.228.447-.327.67-.582.67-.764 0-.19-.242-.46-.725-.815A4.996 4.996 0 0 1 3 3V2H2a1 1 0 1 1 0-2h12a1 1 0 0 1 0 2h-1v1a4.997 4.997 0 0 1-2.39 4.266c-.407.3-.61.545-.61.734 0 .19.203.434.61.734A4.997 4.997 0 0 1 13 13v1h1a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2h1zm8 0v-1a3 3 0 0 0-6 0v1h6z"/></symbol><symbol viewBox="0 0 24 30" id="image-comment-dark" xmlns="http://www.w3.org/2000/svg"><title>cursor_active</title><g fill="none" fill-rule="evenodd"><path d="M24 12.105c0 6.686-5.74 11.58-12 17.895C5.74 23.684 0 18.79 0 12.105 0 5.42 5.373 0 12 0s12 5.42 12 12.105z" fill="#FFF" fill-rule="nonzero"/><path d="M15.28 25.249c1.458-1.475 2.539-2.635 3.474-3.747 2.851-3.394 4.203-6.265 4.203-9.397 0-6.111-4.908-11.062-10.957-11.062-6.05 0-10.957 4.951-10.957 11.062 0 3.132 1.352 6.003 4.203 9.397.935 1.112 2.016 2.272 3.474 3.747.511.517 2.216 2.213 3.28 3.275 1.064-1.062 2.769-2.758 3.28-3.275z" fill="#1F78D1"/><path d="M14.551 8.256A6.874 6.874 0 0 0 12 7.787a6.92 6.92 0 0 0-2.558.469c-.79.308-1.42.725-1.888 1.252-.465.527-.697 1.096-.697 1.708 0 .5.159.977.476 1.433.321.45.772.841 1.352 1.172l.583.334-.181.643c-.107.407-.263.79-.469 1.152a6.604 6.604 0 0 0 1.842-1.145l.288-.254.381.04c.309.035.599.053.871.053.91 0 1.761-.154 2.551-.462.795-.312 1.424-.732 1.889-1.259.468-.526.703-1.096.703-1.707 0-.612-.235-1.181-.703-1.708-.465-.527-1.094-.944-1.889-1.252zm2.645.81c.536.656.804 1.373.804 2.15 0 .776-.268 1.495-.804 2.156-.535.656-1.263 1.176-2.183 1.56-.92.38-1.924.57-3.013.57a9.16 9.16 0 0 1-.971-.054 7.32 7.32 0 0 1-3.08 1.62 5.044 5.044 0 0 1-.764.148h-.033a.26.26 0 0 1-.181-.074.324.324 0 0 1-.107-.18v-.007c-.014-.018-.016-.045-.007-.08.014-.037.018-.059.014-.068a.19.19 0 0 1 .033-.067.645.645 0 0 0 .04-.06 1.73 1.73 0 0 0 .047-.054l.054-.06a53.034 53.034 0 0 1 .435-.489c.049-.049.118-.136.207-.26a2.57 2.57 0 0 0 .221-.342c.054-.103.114-.235.181-.395a4.18 4.18 0 0 0 .174-.51c-.7-.397-1.254-.888-1.66-1.473A3.261 3.261 0 0 1 6 11.216c0-.777.268-1.494.804-2.15.535-.66 1.263-1.18 2.183-1.56.92-.384 1.924-.576 3.013-.576 1.09 0 2.094.192 3.013.576.92.38 1.648.9 2.183 1.56z" fill="#FFF" fill-rule="nonzero"/></g></symbol><symbol viewBox="0 0 16 16" id="import" xmlns="http://www.w3.org/2000/svg"><path d="M9 8h1a.5.5 0 0 1 .4.8l-2 2.667a.5.5 0 0 1-.8 0L5.6 8.8A.5.5 0 0 1 6 8h1V1a1 1 0 1 1 2 0v7zM0 8a1 1 0 1 1 2 0 6 6 0 1 0 12 0 1 1 0 0 1 2 0A8 8 0 1 1 0 8z"/></symbol><symbol viewBox="0 0 16 16" id="issue-block" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.803 8a5.97 5.97 0 0 0-.462 1H4.5a.5.5 0 0 1 0-1h1.303zM4.5 5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1 0-1zm7.5.083a6.04 6.04 0 0 0-2 0V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h2.083a5.96 5.96 0 0 0 .72 2H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h6a3 3 0 0 1 3 3v2.083zm1.121 3.796zM11 16a5 5 0 1 1 0-10 5 5 0 0 1 0 10zm-1.293-2.292a3 3 0 0 0 4.001-4.001l-4.001 4zm-1.415-1.415l4.001-4a3 3 0 0 0-4.001 4.001z"/></symbol><symbol viewBox="0 0 16 16" id="issue-child" xmlns="http://www.w3.org/2000/svg"><path d="M11 8H5v1h1a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h2V7a.997.997 0 0 1 1-1h3V4H4.5a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5H9v2h3a.997.997 0 0 1 1 1v2h2a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-5a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h1V8zm-9 3v2h3v-2H2zm9 0v2h3v-2h-3z"/></symbol><symbol viewBox="0 0 16 16" id="issue-close" xmlns="http://www.w3.org/2000/svg"><path d="M7.536 8.657l2.828-2.829a1 1 0 0 1 1.414 1.415l-3.535 3.535a.997.997 0 0 1-1.415 0l-2.12-2.121A1 1 0 0 1 6.12 7.243l1.415 1.414zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="issue-duplicate" xmlns="http://www.w3.org/2000/svg"><path d="M10.874 2H12a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3h-2c-.918 0-1.74-.413-2.29-1.063a3.987 3.987 0 0 0 1.988-.984A1 1 0 0 0 10 14h2a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1h-1V3c0-.345-.044-.68-.126-1zM4 0h3a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H4z"/></symbol><symbol viewBox="0 0 16 16" id="issue-new" xmlns="http://www.w3.org/2000/svg"><path d="M10 2V1a1 1 0 0 1 2 0v1h1a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0V4H9a1 1 0 1 1 0-2h1zm0 6a1 1 0 0 1 2 0v5a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h1a1 1 0 1 1 0 2H5a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V8z"/></symbol><symbol viewBox="0 0 16 16" id="issue-open" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm0-2a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-2a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="issue-open-m" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="issue-parent" xmlns="http://www.w3.org/2000/svg"><path d="M11 11H5v1h1.5a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5h-6a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5H3v-2a.997.997 0 0 1 1-1h3V7H5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H9v2h3a.997.997 0 0 1 1 1v2h2.5a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5h-6a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5H11v-1zM6 3v2h4V3H6z"/></symbol><symbol viewBox="0 0 16 16" id="issues" xmlns="http://www.w3.org/2000/svg"><path d="M10.458 15.012l.311.055a3 3 0 0 0 3.476-2.433l1.389-7.879A3 3 0 0 0 13.2 1.28L11.23.933a3.002 3.002 0 0 0-.824-.031c.364.59.58 1.28.593 2.02l1.854.328a1 1 0 0 1 .811 1.158l-1.389 7.879a1 1 0 0 1-1.158.81l-.118-.02a3.98 3.98 0 0 1-.541 1.935zM3 0h4a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3z"/></symbol><symbol viewBox="0 0 16 16" id="italic" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.5 12l2-8H6a1 1 0 1 1 0-2h6a1 1 0 0 1 0 2h-1.5l-2 8H10a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2h1.5z"/></symbol><symbol viewBox="0 0 16 16" id="key" xmlns="http://www.w3.org/2000/svg"><path d="M7.575 6.689a4.002 4.002 0 0 1 6.274-4.86 4 4 0 0 1-4.86 6.274l-2.21 2.21.706.708a1 1 0 1 1-1.414 1.414l-.707-.707-.707.707.707.707a1 1 0 1 1-1.414 1.414l-.707-.707a1 1 0 0 1-1.414-1.414l5.746-5.746zm2.032-.618a2 2 0 1 0 2.828-2.828A2 2 0 0 0 9.607 6.07z"/></symbol><symbol viewBox="0 0 16 16" id="key-2" xmlns="http://www.w3.org/2000/svg"><path d="M5.172 14.157l-.344.344-2.485.133a.462.462 0 0 1-.497-.503l.14-2.24a.599.599 0 0 1 .177-.382l5.155-5.155a4 4 0 1 1 2.828 2.828l-1.439 1.44-1.06-.354-.708.707.354 1.06-.707.708-1.06-.354-.708.707.354 1.06zm6.01-8.839a1 1 0 1 0 1.414-1.414 1 1 0 0 0-1.414 1.414z"/></symbol><symbol viewBox="0 0 16 16" id="label" xmlns="http://www.w3.org/2000/svg"><path d="M11.782 14.718a3 3 0 0 1-4.242 0L1.652 8.829a2 2 0 0 1-.565-1.702l.54-3.703a2 2 0 0 1 1.69-1.69l3.703-.54a2 2 0 0 1 1.703.564l5.888 5.888a3 3 0 0 1 0 4.243l-2.829 2.829zm1.415-5.657L7.309 3.173l-3.703.54-.54 3.702 5.888 5.888a1 1 0 0 0 1.414 0l2.829-2.828a1 1 0 0 0 0-1.414zM5.732 5.525A1 1 0 1 1 7.146 6.94a1 1 0 0 1-1.414-1.414z"/></symbol><symbol viewBox="0 0 16 16" id="labels" xmlns="http://www.w3.org/2000/svg"><path d="M9.424 2.254l2.08-.905a1 1 0 0 1 1.206.326l3.013 4.12a1 1 0 0 1 .16.849l-1.947 7.264a3 3 0 0 1-3.675 2.122l-.5-.135a3.999 3.999 0 0 0 1.082-1.782 1 1 0 0 0 1.16-.722l1.823-6.802-2.258-3.087-.687.299a2 2 0 0 0-.628-.88l-.829-.667zM.377 3.7L4.4.498a1 1 0 0 1 1.25.003L9.627 3.7a1 1 0 0 1 .373.78V13a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V4.482A1 1 0 0 1 .377 3.7zM2 13a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V4.958L5.02 2.561 2 4.964V13zm3-6a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="leave" xmlns="http://www.w3.org/2000/svg"><path d="M11 7V5.883a.5.5 0 0 1 .757-.429l3.528 2.117a.5.5 0 0 1 0 .858l-3.528 2.117a.5.5 0 0 1-.757-.43V9H7a1 1 0 1 1 0-2h4zm-2 6.256a1 1 0 0 1 2 0A2.744 2.744 0 0 1 8.256 16H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h5.19A2.81 2.81 0 0 1 11 2.81a1 1 0 0 1-2 0A.81.81 0 0 0 8.19 2H3a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h5.256c.41 0 .744-.333.744-.744z"/></symbol><symbol viewBox="0 0 16 16" id="level-up" xmlns="http://www.w3.org/2000/svg"><path fill="#2E2E2E" fill-rule="evenodd" d="M7 6h3.489a.5.5 0 0 0 .373-.832L6.374.117a.5.5 0 0 0-.748 0l-4.488 5.05A.5.5 0 0 0 1.51 6H5v7a3 3 0 0 0 3 3h6a1 1 0 0 0 0-2H8a1 1 0 0 1-1-1V6z"/></symbol><symbol viewBox="0 0 16 16" id="license" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12.56 8.9l2.66 4.606a.3.3 0 0 1-.243.45l-1.678.094a.1.1 0 0 0-.078.044l-.953 1.432a.3.3 0 0 1-.51-.016L9.097 10.9a5.994 5.994 0 0 0 3.464-2zm-5.23 2.063L4.707 15.51a.3.3 0 0 1-.51.016l-.953-1.432a.1.1 0 0 0-.078-.044l-1.678-.094a.3.3 0 0 1-.243-.45l2.48-4.297a5.983 5.983 0 0 0 3.607 1.754zM8 10A5 5 0 1 1 8 0a5 5 0 0 1 0 10zm0-2a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-1a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="link" xmlns="http://www.w3.org/2000/svg"><path d="M6.986 3.35l2.12-2.122a4 4 0 0 1 5.657 5.657l-2.828 2.829a4 4 0 0 1-5.657 0 1 1 0 0 1 1.414-1.415 2 2 0 0 0 2.829 0l2.828-2.828a2 2 0 1 0-2.828-2.828l-1.001 1a5.018 5.018 0 0 0-2.534-.294zm2.12 9.192l-2.12 2.121a4 4 0 1 1-5.658-5.656l2.829-2.829a4 4 0 0 1 5.657 0 1 1 0 1 1-1.415 1.414 2 2 0 0 0-2.828 0l-2.828 2.829a2 2 0 1 0 2.828 2.828l1.001-1.001a5.018 5.018 0 0 0 2.534.294z"/></symbol><symbol viewBox="0 0 16 16" id="list-bulleted" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm0 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4-7h10a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2zm0 5h10a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2zm-4 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4-2h10a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="list-numbered" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6 2h8a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2zm0 5h8a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2zm0 5h8a1 1 0 0 1 0 2H6a1 1 0 0 1 0-2zM1.156 5v-.828h.816V2.204h-.72v-.636c.432-.084.708-.192.996-.372h.756v2.976h.684V5H1.156zm-.18 5v-.588c.9-.828 1.596-1.464 1.596-1.98 0-.342-.192-.504-.468-.504-.252 0-.444.18-.624.36l-.552-.552c.396-.42.756-.612 1.32-.612.768 0 1.308.492 1.308 1.248 0 .612-.576 1.284-1.092 1.812.192-.024.468-.048.636-.048h.636V10H.976zm1.26 5.072c-.618 0-1.068-.204-1.356-.54l.468-.648c.234.216.51.36.78.36.336 0 .552-.12.552-.36 0-.288-.15-.456-.948-.456v-.72c.636 0 .828-.168.828-.432 0-.228-.138-.348-.396-.348-.252 0-.432.108-.672.312l-.516-.624c.372-.312.768-.492 1.236-.492.84 0 1.38.384 1.38 1.074 0 .366-.204.642-.612.822v.024c.432.132.732.432.732.912 0 .72-.684 1.116-1.476 1.116z"/></symbol><symbol viewBox="0 0 16 16" id="location" xmlns="http://www.w3.org/2000/svg"><path d="M8.755 15.144a1 1 0 0 1-1.51 0C3.748 11.114 2 8.065 2 6a6 6 0 1 1 12 0c0 2.065-1.748 5.113-5.245 9.144zM12 6a4 4 0 1 0-8 0c0 1.314 1.312 3.71 4 6.944C10.688 9.71 12 7.314 12 6zM8 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="location-dot" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6.314 13.087C4.382 13.295 3 13.85 3 14.5c0 .828 2.239 1.5 5 1.5s5-.672 5-1.5c0-.65-1.382-1.205-3.314-1.413l-.202.225a2 2 0 0 1-2.968 0l-.202-.225zm2.428-.445a1 1 0 0 1-1.484 0C4.419 9.5 3 7.037 3 5.252 3 2.353 5.239 0 8 0s5 2.352 5 5.253c0 1.784-1.42 4.247-4.258 7.389zM11 5.252C11 3.436 9.634 2 8 2S5 3.435 5 5.253c0 1.027.974 2.824 3 5.203 2.026-2.38 3-4.176 3-5.203zM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="lock" xmlns="http://www.w3.org/2000/svg"><path d="M10 5V4h2v1a3 3 0 0 1 3 3v5a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V8a3 3 0 0 1 3-3V4h2v1h4zM4 7a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V8a1 1 0 0 0-1-1H4zm0-3a4 4 0 1 1 8 0h-2a2 2 0 1 0-4 0H4z"/></symbol><symbol viewBox="0 0 16 16" id="lock-open" xmlns="http://www.w3.org/2000/svg"><path d="M4.044 4a4 4 0 0 1 6.99-2.658 1 1 0 1 1-1.495 1.33A2 2 0 0 0 6.044 4a.998.998 0 0 1-.07.367v.701H12a3 3 0 0 1 3 3v5a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3v-5a3 3 0 0 1 2.974-3V4h.07zM4 7.07a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-5a1 1 0 0 0-1-1H4z"/></symbol><symbol viewBox="0 0 16 16" id="log" xmlns="http://www.w3.org/2000/svg"><path d="M4 0h8a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H4zm1 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm0 3a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3-5h3a1 1 0 0 1 0 2H8a1 1 0 1 1 0-2zm0 3h3a1 1 0 0 1 0 2H8a1 1 0 1 1 0-2zm-3 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3-2h3a1 1 0 0 1 0 2H8a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="mail" xmlns="http://www.w3.org/2000/svg"><path d="M14 5.6L9.338 9.796a2 2 0 0 1-2.676 0L2 5.6V11a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V5.6zM3 2h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zm.212 2L8 8.31 12.788 4H3.212z"/></symbol><symbol viewBox="0 0 16 16" id="menu" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1.143 2h13.714C15.488 2 16 2.448 16 3s-.512 1-1.143 1H1.143C.512 4 0 3.552 0 3s.512-1 1.143-1zm0 5h13.714C15.488 7 16 7.448 16 8s-.512 1-1.143 1H1.143C.512 9 0 8.552 0 8s.512-1 1.143-1zm0 5h13.714c.631 0 1.143.448 1.143 1s-.512 1-1.143 1H1.143C.512 14 0 13.552 0 13s.512-1 1.143-1z"/></symbol><symbol viewBox="0 0 16 16" id="merge-request-close" xmlns="http://www.w3.org/2000/svg"><path d="M9.414 8l1.414 1.414a1 1 0 1 1-1.414 1.414L8 9.414l-1.414 1.414a1 1 0 1 1-1.414-1.414L6.586 8 5.172 6.586a1 1 0 1 1 1.414-1.414L8 6.586l1.414-1.414a1 1 0 1 1 1.414 1.414L9.414 8zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="messages" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.588 8.942l1.173 5.862A1 1 0 0 1 8.78 16H7.22a1 1 0 0 1-.98-1.196l1.172-5.862a3.014 3.014 0 0 0 1.176 0zM8 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4zM4.464 2.464L5.88 3.88a3 3 0 0 0 0 4.242L4.464 9.536a5 5 0 0 1 0-7.072zm7.072 7.072L10.12 8.12a3 3 0 0 0 0-4.242l1.415-1.415a5 5 0 0 1 0 7.072zM2.343.343l1.414 1.414a6 6 0 0 0 0 8.486l-1.414 1.414a8 8 0 0 1 0-11.314zm11.314 11.314l-1.414-1.414a6 6 0 0 0 0-8.486L13.657.343a8 8 0 0 1 0 11.314z"/></symbol><symbol viewBox="0 0 16 16" id="mobile-issue-close" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.657 10.728L2.12 7.192A1 1 0 1 0 .707 8.607l4.243 4.242a.997.997 0 0 0 1.414 0l8.485-8.485a1 1 0 1 0-1.414-1.414l-7.778 7.778z"/></symbol><symbol viewBox="0 0 16 16" id="monitor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 13v1h3a1 1 0 0 1 0 2H3a1 1 0 0 1 0-2h3v-1H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v7a3 3 0 0 1-3 3h-3zM3 2a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3zm5.723 6.416l-2.66-1.773-1.71 1.71a.5.5 0 1 1-.707-.707l2-2a.5.5 0 0 1 .631-.062l2.66 1.773 2.71-2.71a.5.5 0 0 1 .707.707l-3 3a.5.5 0 0 1-.631.062z"/></symbol><symbol viewBox="0 0 16 16" id="more" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 4a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 6a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 6a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="notifications" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6 14H2.435a2 2 0 0 1-1.761-2.947c.962-1.788 1.521-3.065 1.68-3.832.322-1.566.947-5.501 4.65-6.134a1 1 0 1 1 1.994-.024c3.755.528 4.375 4.27 4.761 6.043.188.86.742 2.188 1.661 3.982A2 2 0 0 1 13.64 14H10a2 2 0 1 1-4 0zm5.805-6.468c-.325-1.492-.37-1.674-.61-2.288C10.6 3.716 9.742 3 8.07 3c-1.608 0-2.49.718-3.103 2.197-.28.676-.356.982-.654 2.428-.208 1.012-.827 2.424-1.877 4.375H13.64c-.993-1.937-1.6-3.396-1.835-4.468z"/></symbol><symbol viewBox="0 0 16 16" id="notifications-off" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.26 5.089c.243.757.382 1.478.5 2.017.187.86.74 2.188 1.66 3.982A2 2 0 0 1 13.64 14H10a2 2 0 1 1-4 0H4.35l2-2h7.29c-.993-1.937-1.6-3.396-1.835-4.468-.07-.326-.129-.59-.178-.81l1.634-1.633zM10.943 1.75l-1.48 1.48C9.07 3.076 8.612 3 8.069 3c-1.608 0-2.49.718-3.103 2.197-.28.676-.356.982-.654 2.428-.065.317-.17.673-.317 1.073L.45 12.242a1.99 1.99 0 0 1 .224-1.19c.962-1.787 1.521-3.064 1.68-3.831.322-1.566.947-5.501 4.65-6.134a1 1 0 1 1 1.994-.024 4.867 4.867 0 0 1 1.944.688zm2.932-.105a1 1 0 0 1 0 1.415L2.561 14.374a1 1 0 1 1-1.415-1.414L12.46 1.646a1 1 0 0 1 1.414 0z"/></symbol><symbol viewBox="0 0 16 16" id="overview" xmlns="http://www.w3.org/2000/svg"><path d="M2 0h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm0 2v3h3V2H2zm9-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2h-3a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm0 2v3h3V2h-3zM2 9h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2zm0 2v3h3v-3H2zm9-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2h-3a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2zm0 2v3h3v-3h-3z"/></symbol><symbol viewBox="0 0 16 16" id="pencil" xmlns="http://www.w3.org/2000/svg"><path d="M13.02 1.293l1.414 1.414a1 1 0 0 1 0 1.414L4.119 14.436a1 1 0 0 1-.704.293l-2.407.008L1 12.316a1 1 0 0 1 .293-.71L11.605 1.292a1 1 0 0 1 1.414 0zm-1.416 1.415l-.707.707L12.31 4.83l.707-.707-1.414-1.415zM3.411 13.73l1.123-1.122H3.12v-1.415L2 12.312l.005 1.422 1.406-.005z"/></symbol><symbol viewBox="0 0 16 16" id="pipeline" xmlns="http://www.w3.org/2000/svg"><path d="M8.969 7.25a2 2 0 1 1-1.938 0A1.002 1.002 0 0 1 7 7V5.083a.2.2 0 0 1 .06-.142l.877-.87a.1.1 0 0 1 .141 0l.864.87A.2.2 0 0 1 9 5.083V7c0 .086-.01.17-.031.25zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm4.5-4a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-3a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-2 6a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-5 9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-2 6a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-3a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zM8 10a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="play" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2.765 15.835c-.545.321-1.258.159-1.593-.363A1.075 1.075 0 0 1 1 14.89V1.11C1 .496 1.518 0 2.158 0c.214 0 .424.057.607.165l11.684 6.89c.544.321.714 1.005.38 1.526a1.135 1.135 0 0 1-.38.364l-11.684 6.89z"/></symbol><symbol viewBox="0 0 16 16" id="plus" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7 7V1a1 1 0 1 1 2 0v6h6a1 1 0 0 1 0 2H9v6a1 1 0 0 1-2 0V9H1a1 1 0 1 1 0-2h6z"/></symbol><symbol viewBox="0 0 16 16" id="plus-square" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9 7V4a1 1 0 1 0-2 0v3H4a1 1 0 1 0 0 2h3v3a1 1 0 0 0 2 0V9h3a1 1 0 0 0 0-2H9zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3z"/></symbol><symbol viewBox="0 0 16 16" id="plus-square-o" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7 7V5a1 1 0 1 1 2 0v2h2a1 1 0 0 1 0 2H9v2a1 1 0 0 1-2 0V9H5a1 1 0 1 1 0-2h2zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3z"/></symbol><symbol viewBox="0 0 16 16" id="preferences" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5 12h10a1 1 0 0 1 0 2H5a1 1 0 0 1-2 0v-2a1 1 0 0 1 2 0zm-3 0H1a1 1 0 0 0 0 2h1v-2zm11-5h2a1 1 0 0 1 0 2h-2a1 1 0 0 1-2 0V7a1 1 0 0 1 2 0zm-3 0H1a1 1 0 1 0 0 2h9V7zM6 2h9a1 1 0 0 1 0 2H6a1 1 0 1 1-2 0V2a1 1 0 1 1 2 0zM3 2H1a1 1 0 1 0 0 2h2V2z"/></symbol><symbol viewBox="0 0 16 16" id="profile" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm-4.274-3.404C4.412 9.709 5.694 9 8 9c2.313 0 3.595.7 4.28 1.586A4.997 4.997 0 0 1 8 13a4.997 4.997 0 0 1-4.274-2.404zM8 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="project" xmlns="http://www.w3.org/2000/svg"><path d="M8.462 2.177l-.038.044a.505.505 0 0 0 .038-.044zm-.787 0a.5.5 0 0 0 .038.043l-.038-.043zM3.706 7h8.725L8.069 2.585 3.706 7zM7 13.369V12a1 1 0 0 1 2 0v1.369h3V9H4v4.369h3zM14 9v4.836c0 .833-.657 1.533-1.5 1.533h-9c-.843 0-1.5-.7-1.5-1.533V9h-.448a1.1 1.1 0 0 1-.783-1.873L6.934.887a1.5 1.5 0 0 1 2.269 0l6.165 6.24A1.1 1.1 0 0 1 14.585 9H14z"/></symbol><symbol viewBox="0 0 16 16" id="push-rules" xmlns="http://www.w3.org/2000/svg"><path d="M6.268 9a2 2 0 0 1 3.464 0H11a1 1 0 0 1 0 2H9.732a2 2 0 0 1-3.464 0H5a1 1 0 0 1 0-2h1.268zM7 2H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1h-1v3.515a.3.3 0 0 1-.434.268l-1.432-.716a.3.3 0 0 0-.268 0l-1.432.716A.3.3 0 0 1 7 5.515V2zM4 0h8a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm4 11a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="question" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm-1.46-5.602h2.233a3.97 3.97 0 0 1 .051-.558c.029-.17.073-.326.133-.469.06-.143.14-.28.242-.41.102-.13.228-.263.38-.399.26-.24.504-.467.733-.683a5.03 5.03 0 0 0 .598-.668c.17-.23.302-.477.399-.742a2.66 2.66 0 0 0 .144-.907c0-.505-.083-.95-.25-1.335a2.55 2.55 0 0 0-.723-.97 3.2 3.2 0 0 0-1.152-.589 5.441 5.441 0 0 0-1.531-.2c-.516 0-.998.063-1.445.188a3.19 3.19 0 0 0-1.168.59c-.331.268-.594.61-.79 1.027-.195.417-.295.917-.3 1.5h2.64c.006-.224.04-.416.102-.578.062-.161.142-.293.238-.394a.921.921 0 0 1 .332-.227 1.04 1.04 0 0 1 .39-.074c.34 0 .593.095.763.285.169.19.254.488.254.895 0 .328-.106.63-.317.906-.21.276-.499.565-.863.867-.214.182-.39.374-.531.574-.141.2-.253.42-.336.657a3.656 3.656 0 0 0-.176.777 7.89 7.89 0 0 0-.05.937zm-.321 2.375c0 .188.035.362.105.524.07.161.17.3.301.418.13.117.284.21.46.277.178.068.376.102.595.102.218 0 .416-.034.593-.102.178-.068.331-.16.461-.277a1.2 1.2 0 0 0 .301-.418c.07-.162.106-.336.106-.524a1.3 1.3 0 0 0-.106-.523 1.2 1.2 0 0 0-.3-.418 1.461 1.461 0 0 0-.462-.277 1.651 1.651 0 0 0-.593-.102c-.22 0-.417.034-.594.102a1.46 1.46 0 0 0-.461.277 1.2 1.2 0 0 0-.3.418 1.284 1.284 0 0 0-.106.523z"/></symbol><symbol viewBox="0 0 16 16" id="question-o" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm-.778-4.151c0-.301.014-.575.044-.82a3.2 3.2 0 0 1 .154-.68c.073-.208.17-.4.294-.575.123-.176.278-.343.465-.503a4.81 4.81 0 0 0 .755-.758c.185-.242.277-.506.277-.793 0-.356-.074-.617-.222-.783-.148-.166-.37-.25-.667-.25a.92.92 0 0 0-.342.065.806.806 0 0 0-.29.199 1.04 1.04 0 0 0-.209.345 1.5 1.5 0 0 0-.088.506H5.082c.005-.51.092-.948.263-1.313.171-.364.401-.664.69-.899.29-.234.63-.406 1.023-.516a4.66 4.66 0 0 1 1.264-.164c.497 0 .944.058 1.34.174.397.117.733.289 1.008.517.276.227.487.51.633.847.146.337.218.727.218 1.17 0 .295-.042.56-.126.792a2.52 2.52 0 0 1-.349.65 4.4 4.4 0 0 1-.523.584c-.2.19-.414.389-.642.598a2.73 2.73 0 0 0-.332.349c-.089.114-.16.233-.212.359a1.868 1.868 0 0 0-.116.41 3.39 3.39 0 0 0-.044.489H7.222zm-.28 2.078c0-.164.03-.317.092-.458a1.05 1.05 0 0 1 .263-.366c.114-.103.248-.183.403-.243a1.45 1.45 0 0 1 .52-.089c.191 0 .364.03.52.09.154.059.289.14.403.242.114.103.201.224.263.366.061.141.092.294.092.458 0 .164-.03.316-.092.458a1.05 1.05 0 0 1-.263.365 1.278 1.278 0 0 1-.404.243 1.43 1.43 0 0 1-.52.089c-.19 0-.364-.03-.519-.089-.155-.06-.29-.14-.403-.243a1.05 1.05 0 0 1-.263-.365 1.135 1.135 0 0 1-.093-.458z"/></symbol><symbol viewBox="0 0 16 16" id="quote" xmlns="http://www.w3.org/2000/svg"><path d="M15 3v8a3 3 0 0 1-3 3 1 1 0 0 1 0-2 1 1 0 0 0 1-1V9h-2a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h3a1 1 0 0 1 1 1zM7 3v8a3 3 0 0 1-3 3 1 1 0 0 1 0-2 1 1 0 0 0 1-1V9H3a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h3a1 1 0 0 1 1 1z"/></symbol><symbol viewBox="0 0 16 16" id="redo" xmlns="http://www.w3.org/2000/svg"><path d="M4.666 4.423a5 5 0 1 1-.203 6.944 1 1 0 1 0-1.478 1.347 7 7 0 1 0 .12-9.556L1.842 2.137a.5.5 0 0 0-.815.385L1 7.26a.5.5 0 0 0 .607.492l4.629-1.013a.5.5 0 0 0 .207-.877L4.666 4.423z"/></symbol><symbol viewBox="0 0 16 16" id="remove" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 3a1 1 0 1 1 0-2h12a1 1 0 0 1 0 2v10a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3V3zm3-2a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1H5zM4 3v10a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V3H4zm2.5 2a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5zm3 0a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5z"/></symbol><symbol viewBox="0 0 16 16" id="repeat" xmlns="http://www.w3.org/2000/svg"><path d="M11.494 4.423a5 5 0 1 0 .203 6.944 1 1 0 1 1 1.478 1.347 7 7 0 1 1-.12-9.556l1.262-1.021a.5.5 0 0 1 .815.385l.028 4.738a.5.5 0 0 1-.607.492L9.924 6.739a.5.5 0 0 1-.207-.877l1.777-1.439z"/></symbol><symbol viewBox="0 0 16 16" id="retry" xmlns="http://www.w3.org/2000/svg"><path d="M4.114 6.958a4 4 0 0 0 5.283 4.775 1 1 0 1 1 .712 1.87A6 6 0 0 1 2.182 6.44l-.741-.2a.5.5 0 0 1-.12-.915l2.195-1.268a.5.5 0 0 1 .683.183l1.268 2.196a.5.5 0 0 1-.563.733l-.79-.212zm7.777 2.084a4 4 0 0 0-5.284-4.775 1 1 0 0 1-.712-1.87 6 6 0 0 1 7.927 7.162l.742.2a.5.5 0 0 1 .12.915l-2.196 1.268a.5.5 0 0 1-.683-.183l-1.267-2.196a.5.5 0 0 1 .562-.733l.79.212z"/></symbol><symbol viewBox="0 0 16 16" id="scale" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.99 9a.792.792 0 0 0-.078-.231L13 7l-.912 1.769a.791.791 0 0 0-.077.231h1.978zm-10 0a.792.792 0 0 0-.078-.231L3 7l-.912 1.769A.791.791 0 0 0 2.011 9h1.978zM2 0h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm3 14h6a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2zM8 4a1 1 0 0 1 1 1v9H7V5a1 1 0 0 1 1-1zm-4.53-.714l2.265 4.735c.68 1.42.006 3.091-1.504 3.73A3.161 3.161 0 0 1 3 12c-1.657 0-3-1.263-3-2.821 0-.4.09-.794.264-1.158L2.53 3.286a.53.53 0 0 1 .94 0zm10 0l2.265 4.735c.68 1.42.006 3.091-1.504 3.73A3.161 3.161 0 0 1 13 12c-1.657 0-3-1.263-3-2.821 0-.4.09-.794.264-1.158l2.266-4.735a.53.53 0 0 1 .94 0z"/></symbol><symbol viewBox="0 0 16 16" id="screen-full" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M14 14v-2a1 1 0 0 1 2 0v3a.997.997 0 0 1-1 1h-3a1 1 0 0 1 0-2h2zM2 14v-2a1 1 0 0 0-2 0v3a1 1 0 0 0 1 1h3a1 1 0 0 0 0-2H2zM15.707.293A.997.997 0 0 1 16 1v3a1 1 0 0 1-2 0V2h-2a1 1 0 0 1 0-2h3c.276 0 .526.112.707.293zM2 2v2a1 1 0 1 1-2 0V1a.997.997 0 0 1 1-1h3a1 1 0 1 1 0 2H2zm4 4h4a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="screen-normal" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3 3V1a1 1 0 1 1 2 0v3a.997.997 0 0 1-1 1H1a1 1 0 1 1 0-2h2zm10 0h2a1 1 0 0 1 0 2h-3a.997.997 0 0 1-1-1V1a1 1 0 0 1 2 0v2zM3 13H1a1 1 0 0 1 0-2h3a.997.997 0 0 1 1 1v3a1 1 0 0 1-2 0v-2zm10 0v2a1 1 0 0 1-2 0v-3a.997.997 0 0 1 1-1h3a1 1 0 0 1 0 2h-2zM6.5 7h3a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5z"/></symbol><symbol viewBox="0 0 12 16" id="scroll_down" xmlns="http://www.w3.org/2000/svg"><path class="eofirst-triangle" d="M1.048 14.155a.508.508 0 0 0-.32.105c-.091.07-.136.154-.136.25v.71c0 .095.045.178.135.249.09.07.197.105.321.105h10.043a.51.51 0 0 0 .321-.105c.09-.07.136-.154.136-.25v-.71c0-.095-.045-.178-.136-.249a.508.508 0 0 0-.32-.105"/><path class="eosecond-triangle" d="M.687 8.027c-.09-.087-.122-.16-.093-.22.028-.06.104-.09.228-.09h10.5c.123 0 .2.03.228.09.029.06-.002.133-.093.22L6.393 12.91a.458.458 0 0 1-.136.089h-.37a.626.626 0 0 1-.136-.09"/><path class="eothird-triangle" d="M.687 1.027C.597.94.565.867.594.807c.028-.06.104-.09.228-.09h10.5c.123 0 .2.03.228.09.029.06-.002.133-.093.22L6.393 5.91a.458.458 0 0 1-.136.09h-.37a.626.626 0 0 1-.136-.09"/></symbol><symbol viewBox="0 0 12 16" id="scroll_up" xmlns="http://www.w3.org/2000/svg"><path d="M1.048 1.845a.508.508 0 0 1-.32-.105c-.091-.07-.136-.154-.136-.25V.78c0-.095.045-.178.135-.249a.508.508 0 0 1 .321-.105h10.043a.51.51 0 0 1 .321.105c.09.07.136.154.136.25v.71c0 .095-.045.178-.136.249a.508.508 0 0 1-.32.105M.687 7.973c-.09.087-.122.16-.093.22.028.06.104.09.228.09h10.5c.123 0 .2-.03.228-.09.029-.06-.002-.133-.093-.22L6.393 3.09A.458.458 0 0 0 6.257 3h-.37a.626.626 0 0 0-.136.09M.687 14.973c-.09.087-.122.16-.093.22.028.06.104.09.228.09h10.5c.123 0 .2-.03.228-.09.029-.06-.002-.133-.093-.22L6.393 10.09a.458.458 0 0 0-.136-.09h-.37a.626.626 0 0 0-.136.09"/></symbol><symbol viewBox="0 0 16 16" id="search" xmlns="http://www.w3.org/2000/svg"><path d="M8.853 8.854a3.5 3.5 0 1 0-4.95-4.95 3.5 3.5 0 0 0 4.95 4.95zm.207 2.328a5.5 5.5 0 1 1 2.121-2.121l3.329 3.328a1.5 1.5 0 0 1-2.121 2.121L9.06 11.182z"/></symbol><symbol viewBox="0 0 16 16" id="settings" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2.415 5.803L1.317 4.084A.5.5 0 0 1 1.35 3.5l.805-.994a.5.5 0 0 1 .564-.153l1.878.704a5.975 5.975 0 0 1 1.65-.797L6.885.342A.5.5 0 0 1 7.36 0h1.28a.5.5 0 0 1 .474.342l.639 1.918a5.97 5.97 0 0 1 1.65.797l1.877-.704a.5.5 0 0 1 .565.153l.805.994a.5.5 0 0 1 .032.584l-1.097 1.719c.217.551.354 1.143.399 1.76l1.731 1.058a.5.5 0 0 1 .227.54l-.288 1.246a.5.5 0 0 1-.44.385l-2.008.19a6.026 6.026 0 0 1-1.142 1.431l.265 1.995a.5.5 0 0 1-.277.516l-1.15.56a.5.5 0 0 1-.576-.1l-1.424-1.452a6.047 6.047 0 0 1-1.804 0l-1.425 1.453a.5.5 0 0 1-.576.1l-1.15-.561a.5.5 0 0 1-.276-.516l.265-1.995a6.026 6.026 0 0 1-1.143-1.43l-2.008-.191a.5.5 0 0 1-.44-.385L.058 9.16a.5.5 0 0 1 .226-.539l1.732-1.058a5.968 5.968 0 0 1 .399-1.76zM8 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/></symbol><symbol viewBox="0 0 16 16" id="shield" xmlns="http://www.w3.org/2000/svg"><path d="M4 0h8a3 3 0 0 1 3 3v7.186a3 3 0 0 1-1.426 2.554l-4 2.465a3 3 0 0 1-3.148 0l-4-2.465A3 3 0 0 1 1 10.186V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v7.186a1 1 0 0 0 .475.852l4 2.464a1 1 0 0 0 1.05 0l4-2.464a1 1 0 0 0 .475-.852V3a1 1 0 0 0-1-1H4zm0 1.5a.5.5 0 0 1 .5-.5h4v8.837a.5.5 0 0 1-.753.431l-3.5-2.052A.5.5 0 0 1 4 9.785V3.5z"/></symbol><symbol viewBox="0 0 16 16" id="slight-frown" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm-2.163-3.275a2.499 2.499 0 0 1 4.343.03.5.5 0 0 1-.871.49 1.5 1.5 0 0 0-2.607-.018.5.5 0 1 1-.865-.502zM5 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="slight-smile" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM5 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm-5.163 2.254a.5.5 0 1 1 .865-.502 1.499 1.499 0 0 0 2.607-.018.5.5 0 1 1 .871.49 2.499 2.499 0 0 1-4.343.03z"/></symbol><symbol viewBox="0 0 16 16" id="smile" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM6.18 6.27a.5.5 0 0 1-.873.487.5.5 0 0 0-.872-.003.5.5 0 1 1-.87-.495 1.5 1.5 0 0 1 2.616.012zm6 0a.5.5 0 1 1-.873.487.5.5 0 0 0-.872-.003.5.5 0 1 1-.87-.495 1.5 1.5 0 0 1 2.616.012zM5 9a3 3 0 0 0 6 0H5z"/></symbol><symbol viewBox="0 0 16 16" id="smiley" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM5 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zM5 9h6a3 3 0 0 1-6 0z"/></symbol><symbol viewBox="0 0 16 16" id="snippet" xmlns="http://www.w3.org/2000/svg"><path d="M10.67 9.31a3.001 3.001 0 0 1 2.062 5.546 3 3 0 0 1-3.771-4.559 1.007 1.007 0 0 1-.095-.137l-4.5-7.794a1 1 0 0 1 1.732-1l4.5 7.794c.028.05.052.1.071.15zm-3.283.35l-.289.5c-.028.05-.06.095-.095.137a3.001 3.001 0 0 1-3.77 4.56A3 3 0 0 1 5.294 9.31c.02-.051.043-.102.071-.15l.866-1.5 1.155 2zm2.31-4l-1.156-2 1.325-2.294a1 1 0 0 1 1.732 1L9.696 5.66zm-5.465 7.464a1 1 0 1 0 1-1.732 1 1 0 0 0-1 1.732zm7.5 0a1 1 0 1 0-1-1.732 1 1 0 0 0 1 1.732z"/></symbol><symbol viewBox="0 0 16 16" id="spam" xmlns="http://www.w3.org/2000/svg"><path d="M8.75.433l5.428 3.134a1.5 1.5 0 0 1 .75 1.299v6.268a1.5 1.5 0 0 1-.75 1.299L8.75 15.567a1.5 1.5 0 0 1-1.5 0l-5.428-3.134a1.5 1.5 0 0 1-.75-1.299V4.866a1.5 1.5 0 0 1 .75-1.299L7.25.433a1.5 1.5 0 0 1 1.5 0zM3.072 5.155v5.69L8 13.691l4.928-2.846v-5.69L8 2.309 3.072 5.155zM8 4a1 1 0 0 1 1 1v3a1 1 0 1 1-2 0V5a1 1 0 0 1 1-1zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 14 14" id="spinner" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><circle cx="7" cy="7" r="6" stroke="#000" stroke-opacity=".1" stroke-width="2"/><path fill="#000" fill-opacity=".1" fill-rule="nonzero" d="M7 0a7 7 0 0 1 7 7h-2a5 5 0 0 0-5-5V0z"/></g></symbol><symbol viewBox="0 0 16 16" id="star" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.609 14.394l-3.465 1.473a1 1 0 0 1-1.39-.989l.276-4.024a1 1 0 0 0-.219-.694L.303 7.037A1 1 0 0 1 .83 5.443l3.715-.964a1 1 0 0 0 .609-.457L7.14.682a1 1 0 0 1 1.72 0l1.985 3.34a1 1 0 0 0 .609.457l3.715.964a1 1 0 0 1 .528 1.594L13.19 10.16a1 1 0 0 0-.219.694l.275 4.024a1 1 0 0 1-1.389.989l-3.465-1.473a1 1 0 0 0-.782 0z"/></symbol><symbol viewBox="0 0 16 16" id="star-o" xmlns="http://www.w3.org/2000/svg"><path d="M10.975 10.99a3 3 0 0 1 .655-2.083l1.54-1.916-2.219-.576a3 3 0 0 1-1.825-1.37L8 3.15 6.874 5.044a3 3 0 0 1-1.825 1.371l-2.218.576 1.54 1.916a3 3 0 0 1 .654 2.083l-.165 2.4 1.965-.836a3 3 0 0 1 2.348 0l1.965.836-.164-2.399zM7.61 14.394l-3.465 1.473a1 1 0 0 1-1.39-.989l.276-4.024a1 1 0 0 0-.219-.694L.303 7.037A1 1 0 0 1 .83 5.443l3.715-.964a1 1 0 0 0 .609-.457L7.14.682a1 1 0 0 1 1.72 0l1.985 3.34a1 1 0 0 0 .609.457l3.715.964a1 1 0 0 1 .528 1.594L13.19 10.16a1 1 0 0 0-.219.694l.275 4.024a1 1 0 0 1-1.389.989l-3.465-1.473a1 1 0 0 0-.782 0z"/></symbol><symbol viewBox="0 0 14 14" id="status_canceled" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M5.2 3.8l4.9 4.9c.2.2.2.5 0 .7l-.7.7c-.2.2-.5.2-.7 0L3.8 5.2c-.2-.2-.2-.5 0-.7l.7-.7c.2-.2.5-.2.7 0"/></g></symbol><symbol viewBox="0 0 22 22" id="status_canceled_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M8.171 5.971l7.7 7.7a.76.76 0 0 1 0 1.1l-1.1 1.1a.76.76 0 0 1-1.1 0l-7.7-7.7a.76.76 0 0 1 0-1.1l1.1-1.1a.76.76 0 0 1 1.1 0"/></symbol><symbol viewBox="0 0 16 16" id="status_closed" xmlns="http://www.w3.org/2000/svg"><path d="M7.536 8.657l2.828-2.83a1 1 0 0 1 1.414 1.416l-3.535 3.535a1 1 0 0 1-1.415.001l-2.12-2.12a1 1 0 1 1 1.413-1.415zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 14 14" id="status_created" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><circle cx="7" cy="7" r="3.25"/></g></symbol><symbol viewBox="0 0 22 22" id="status_created_borderless" xmlns="http://www.w3.org/2000/svg"><circle cx="11" cy="11" r="5.107"/></symbol><symbol viewBox="0 0 14 14" id="status_failed" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M7 5.969L5.599 4.568a.29.29 0 0 0-.413.004l-.614.614a.294.294 0 0 0-.004.413L5.968 7l-1.4 1.401a.29.29 0 0 0 .004.413l.614.614c.113.114.3.117.413.004L7 8.032l1.401 1.4a.29.29 0 0 0 .413-.004l.614-.614a.294.294 0 0 0 .004-.413L8.032 7l1.4-1.401a.29.29 0 0 0-.004-.413l-.614-.614a.294.294 0 0 0-.413-.004L7 5.968z"/></g></symbol><symbol viewBox="0 0 22 22" id="status_failed_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M11 9.38L8.798 7.178a.455.455 0 0 0-.65.006l-.964.965a.462.462 0 0 0-.006.65L9.38 11l-2.202 2.202a.455.455 0 0 0 .006.65l.965.964a.462.462 0 0 0 .65.006L11 12.62l2.202 2.202a.455.455 0 0 0 .65-.006l.964-.965a.462.462 0 0 0 .006-.65L12.62 11l2.202-2.202a.455.455 0 0 0-.006-.65l-.965-.964a.462.462 0 0 0-.65-.006L11 9.38z"/></symbol><symbol viewBox="0 0 14 14" id="status_manual" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M10.5 7.63V6.37l-.787-.13c-.044-.175-.132-.349-.263-.61l.481-.652-.918-.913-.657.478a2.346 2.346 0 0 0-.612-.26L7.656 3.5H6.388l-.132.783c-.219.043-.394.13-.612.26l-.657-.478-.918.913.437.652c-.131.218-.175.392-.262.61l-.744.086v1.261l.787.13c.044.218.132.392.263.61l-.438.651.92.913.655-.434c.175.086.394.173.613.26l.131.783h1.313l.131-.783c.219-.043.394-.13.613-.26l.656.478.918-.913-.48-.652c.13-.218.218-.435.262-.61l.656-.13zM7 8.283a1.285 1.285 0 0 1-1.313-1.305c0-.739.57-1.304 1.313-1.304.744 0 1.313.565 1.313 1.304 0 .74-.57 1.305-1.313 1.305z"/></g></symbol><symbol viewBox="0 0 22 22" id="status_manual_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M16.5 11.99v-1.98l-1.238-.206c-.068-.273-.206-.546-.412-.956l.756-1.025-1.444-1.435-1.03.752a3.686 3.686 0 0 0-.963-.41L12.03 5.5h-1.994l-.206 1.23c-.343.068-.618.205-.962.41l-1.031-.752-1.444 1.435.687 1.025c-.206.341-.275.615-.412.956L5.5 9.941v1.981l1.237.205c.07.342.207.615.413.957l-.688 1.025 1.444 1.434 1.032-.683c.274.137.618.274.962.41l.206 1.23h2.063l.206-1.23c.344-.068.619-.205.963-.41l1.03.752 1.444-1.435-.756-1.025c.207-.341.344-.683.413-.956l1.031-.205zM11 13.017c-1.169 0-2.063-.889-2.063-2.05 0-1.162.894-2.05 2.063-2.05s2.063.888 2.063 2.05c0 1.161-.894 2.05-2.063 2.05z"/></symbol><symbol viewBox="0 0 22 22" id="status_notfound_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M12.822 11.29c.816-.581 1.421-1.348 1.683-2.322.603-2.243-.973-4.553-3.53-4.553-1.15 0-2.085.41-2.775 1.089-.42.413-.672.835-.8 1.167a1.179 1.179 0 0 0 2.2.847c.016-.043.1-.184.252-.334.264-.259.613-.412 1.123-.412.938 0 1.47.78 1.254 1.584-.105.39-.37.726-.773 1.012a3.25 3.25 0 0 1-.945.47 1.179 1.179 0 0 0-.874 1.138v2.234a1.179 1.179 0 1 0 2.358 0v-1.43a5.9 5.9 0 0 0 .827-.492z"/><ellipse cx="10.825" cy="16.711" rx="1.275" ry="1.322"/></symbol><symbol viewBox="0 0 14 14" id="status_open" xmlns="http://www.w3.org/2000/svg"><path d="M0 7c0-3.866 3.142-7 7-7 3.866 0 7 3.142 7 7 0 3.866-3.142 7-7 7-3.866 0-7-3.142-7-7z"/><path d="M1 7c0 3.309 2.69 6 6 6 3.309 0 6-2.69 6-6 0-3.309-2.69-6-6-6-3.309 0-6 2.69-6 6z" fill="#FFF"/><path d="M7 9.219a2.218 2.218 0 1 0 0-4.436A2.218 2.218 0 0 0 7 9.22zm0 1.12a3.338 3.338 0 1 1 0-6.676 3.338 3.338 0 0 1 0 6.676z"/></symbol><symbol viewBox="0 0 14 14" id="status_pending" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M4.7 5.3c0-.2.1-.3.3-.3h.9c.2 0 .3.1.3.3v3.4c0 .2-.1.3-.3.3H5c-.2 0-.3-.1-.3-.3V5.3m3 0c0-.2.1-.3.3-.3h.9c.2 0 .3.1.3.3v3.4c0 .2-.1.3-.3.3H8c-.2 0-.3-.1-.3-.3V5.3"/></g></symbol><symbol viewBox="0 0 22 22" id="status_pending_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M7.386 8.329c0-.315.157-.472.471-.472h1.414c.315 0 .472.157.472.472v5.342c0 .315-.157.472-.472.472H7.857c-.314 0-.471-.157-.471-.472V8.33m4.714 0c0-.315.157-.472.471-.472h1.415c.314 0 .471.157.471.472v5.342c0 .315-.157.472-.471.472H12.57c-.314 0-.471-.157-.471-.472V8.33"/></symbol><symbol viewBox="0 0 14 14" id="status_running" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M7 3c2.2 0 4 1.8 4 4s-1.8 4-4 4c-1.3 0-2.5-.7-3.3-1.7L7 7V3"/></g></symbol><symbol viewBox="0 0 22 22" id="status_running_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M11 4.714c3.457 0 6.286 2.829 6.286 6.286 0 3.457-2.829 6.286-6.286 6.286-2.043 0-3.929-1.1-5.186-2.672L11 11V4.714"/></symbol><symbol viewBox="0 0 14 14" id="status_skipped" xmlns="http://www.w3.org/2000/svg"><path d="M7 14A7 7 0 1 1 7 0a7 7 0 0 1 0 14z"/><path d="M7 13A6 6 0 1 0 7 1a6 6 0 0 0 0 12z" fill="#FFF"/><path d="M6.415 7.04L4.579 5.203a.295.295 0 0 1 .004-.416l.349-.349a.29.29 0 0 1 .416-.004l2.214 2.214a.289.289 0 0 1 .019.021l.132.133c.11.11.108.291 0 .398L5.341 9.573a.282.282 0 0 1-.398 0l-.331-.331a.285.285 0 0 1 0-.399L6.415 7.04zm2.54 0L7.119 5.203a.295.295 0 0 1 .004-.416l.349-.349a.29.29 0 0 1 .416-.004l2.214 2.214a.289.289 0 0 1 .019.021l.132.133c.11.11.108.291 0 .398L7.881 9.573a.282.282 0 0 1-.398 0l-.331-.331a.285.285 0 0 1 0-.399L8.955 7.04z"/></symbol><symbol viewBox="0 0 22 22" id="status_skipped_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M14.072 11.063l-2.82 2.82a.46.46 0 0 0-.001.652l.495.495a.457.457 0 0 0 .653-.001l3.7-3.7a.46.46 0 0 0 .001-.653l-.196-.196a.453.453 0 0 0-.03-.033l-3.479-3.479a.464.464 0 0 0-.654.007l-.548.548a.463.463 0 0 0-.007.654l2.886 2.886z"/><path d="M10.08 11.063l-2.819 2.82a.46.46 0 0 0-.002.652l.496.495a.457.457 0 0 0 .652-.001l3.7-3.7a.46.46 0 0 0 .002-.653l-.196-.196a.453.453 0 0 0-.03-.033l-3.48-3.479a.464.464 0 0 0-.653.007l-.548.548a.463.463 0 0 0-.007.654l2.886 2.886z"/></symbol><symbol viewBox="0 0 14 14" id="status_success" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M6.278 7.697L5.045 6.464a.296.296 0 0 0-.42-.002l-.613.614a.298.298 0 0 0 .002.42l1.91 1.909a.5.5 0 0 0 .703.005l.265-.265L9.997 6.04a.291.291 0 0 0-.009-.408l-.614-.614a.29.29 0 0 0-.408-.009L6.278 7.697z"/></g></symbol><symbol viewBox="0 0 22 22" id="status_success_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M9.866 12.095l-1.95-1.95a.462.462 0 0 0-.647.01l-.964.964a.46.46 0 0 0-.01.646l3.013 3.014a.787.787 0 0 0 1.106.008l.425-.425 4.854-4.853a.462.462 0 0 0 .002-.659l-.964-.964a.468.468 0 0 0-.658.002l-4.207 4.207z"/></symbol><symbol viewBox="0 0 14 14" id="status_success_solid" xmlns="http://www.w3.org/2000/svg"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7zm6.278.697L5.045 6.464a.296.296 0 0 0-.42-.002l-.613.614a.298.298 0 0 0 .002.42l1.91 1.909a.5.5 0 0 0 .703.005l.265-.265L9.997 6.04a.291.291 0 0 0-.009-.408l-.614-.614a.29.29 0 0 0-.408-.009L6.278 7.697z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 14 14" id="status_warning" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M6 3.5c0-.3.2-.5.5-.5h1c.3 0 .5.2.5.5v4c0 .3-.2.5-.5.5h-1c-.3 0-.5-.2-.5-.5v-4m0 6c0-.3.2-.5.5-.5h1c.3 0 .5.2.5.5v1c0 .3-.2.5-.5.5h-1c-.3 0-.5-.2-.5-.5v-1"/></g></symbol><symbol viewBox="0 0 22 22" id="status_warning_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M9.429 5.5c0-.471.314-.786.785-.786h1.572c.471 0 .785.315.785.786v6.286c0 .471-.314.785-.785.785h-1.572c-.471 0-.785-.314-.785-.785V5.5m0 9.429c0-.472.314-.786.785-.786h1.572c.471 0 .785.314.785.786V16.5c0 .471-.314.786-.785.786h-1.572c-.471 0-.785-.315-.785-.786v-1.571"/></symbol><symbol viewBox="0 0 16 16" id="stop" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 0h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2z"/></symbol><symbol viewBox="0 0 16 16" id="task-done" xmlns="http://www.w3.org/2000/svg"><path d="M7.536 8.657l2.828-2.829a1 1 0 0 1 1.414 1.415l-3.535 3.535a.997.997 0 0 1-1.415 0l-2.12-2.121A1 1 0 0 1 6.12 7.243l1.415 1.414zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3z"/></symbol><symbol viewBox="0 0 16 16" id="template" xmlns="http://www.w3.org/2000/svg"><path d="M3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3zm.8 2h2.4a.8.8 0 0 1 .8.8v1.4a.8.8 0 0 1-.8.8H3.8a.8.8 0 0 1-.8-.8V4.8a.8.8 0 0 1 .8-.8zm4.7 0h4a.5.5 0 1 1 0 1h-4a.5.5 0 0 1 0-1zm0 2h4a.5.5 0 1 1 0 1h-4a.5.5 0 0 1 0-1zm-5 3h9a.5.5 0 1 1 0 1h-9a.5.5 0 0 1 0-1zm0 2h9a.5.5 0 1 1 0 1h-9a.5.5 0 1 1 0-1z"/></symbol><symbol viewBox="0 0 16 16" id="terminal" xmlns="http://www.w3.org/2000/svg"><path d="M7 8a.997.997 0 0 1-.293.707l-1.414 1.414a1 1 0 1 1-1.414-1.414L4.586 8l-.707-.707a1 1 0 1 1 1.414-1.414l1.414 1.414A.997.997 0 0 1 7 8zM4 0h8a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm0 2a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H4zm5 7h2a1 1 0 0 1 0 2H9a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="thumb-down" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.33 11h5.282a2 2 0 0 0 1.963-2.38l-.563-2.905a3 3 0 0 0-.243-.732l-1.103-2.286A3 3 0 0 0 10.964 1H7a3 3 0 0 0-3 3v6.3a2 2 0 0 0 .436 1.247l3.11 3.9a.632.632 0 0 0 .941.053l.137-.137a1 1 0 0 0 .28-.87L8.329 11zM1 10h2V3H1a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1z"/></symbol><symbol viewBox="0 0 16 16" id="thumb-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.33 5h5.282a2 2 0 0 1 1.963 2.38l-.563 2.905a3 3 0 0 1-.243.732l-1.103 2.286A3 3 0 0 1 10.964 15H7a3 3 0 0 1-3-3V5.7a2 2 0 0 1 .436-1.247l3.11-3.9A.632.632 0 0 1 8.487.5l.137.137a1 1 0 0 1 .28.87L8.329 5zM1 6h2v7H1a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="thumbtack" xmlns="http://www.w3.org/2000/svg"><path d="M7.125 9h-2.19a.5.5 0 0 1-.417-.777L6 6V2L5.362.724A.5.5 0 0 1 5.809 0h4.382a.5.5 0 0 1 .447.724L10 2v4l1.482 2.223a.5.5 0 0 1-.416.777H8.875L8 16l-.875-7z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 16 16" id="timer" xmlns="http://www.w3.org/2000/svg"><path d="M12.022 3.27l.77-.77a1 1 0 0 1 1.415 1.414l-.728.729a7 7 0 1 1-1.456-1.372zM8 14A5 5 0 1 0 8 4a5 5 0 0 0 0 10zm0-9a1 1 0 0 1 1 1v2a1 1 0 1 1-2 0V6a1 1 0 0 1 1-1zM6 0h4a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="todo-add" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 4V2a1 1 0 0 1 2 0v2h2a1 1 0 0 1 0 2h-2v2a1 1 0 0 1-2 0V6H8a1 1 0 1 1 0-2h2zm2 7a1 1 0 0 1 2 0v2a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h2a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-2z"/></symbol><symbol viewBox="0 0 16 16" id="todo-done" xmlns="http://www.w3.org/2000/svg"><path d="M8.243 7.485l4.95-4.95a1 1 0 1 1 1.414 1.415L8.95 9.607a.997.997 0 0 1-1.414 0L4.707 6.778a1 1 0 0 1 1.414-1.414l2.122 2.121zM12 11a1 1 0 0 1 2 0v2a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h2a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-2z"/></symbol><symbol viewBox="0 0 16 16" id="token" xmlns="http://www.w3.org/2000/svg"><path d="M3 2h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H3zm1 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="unapproval" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M11.95 8.536l1.06-1.061a1 1 0 0 1 1.415 1.414l-1.061 1.06 1.06 1.061a1 1 0 0 1-1.414 1.415l-1.06-1.061-1.06 1.06a1 1 0 1 1-1.415-1.414l1.06-1.06-1.06-1.06a1 1 0 0 1 1.414-1.415l1.06 1.06zm-3.768-.33c.006.503.201 1.006.586 1.39l.353.354-.353.353a2 2 0 1 0 2.828 2.829l.354-.354.047.048C11.964 14.363 11.527 15 6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8c.834 0 1.557.074 2.182.205zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"/></symbol><symbol viewBox="0 0 16 16" id="unassignee" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M11 5h4a1 1 0 0 1 0 2h-4a1 1 0 0 1 0-2zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8s6 2.692 6 4.48c0 1.788-.076 2.52-6 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="unlink" xmlns="http://www.w3.org/2000/svg"><path d="M11.295 8.845l-.659-1.664a1.78 1.78 0 0 0 .04-.04l1.415-1.414c.586-.586.654-1.468.152-1.97s-1.384-.434-1.97.152L8.859 5.323a1.781 1.781 0 0 0-.04.04l-1.664-.658c.141-.208.305-.408.491-.594l1.415-1.414c1.366-1.367 3.424-1.525 4.596-.354 1.171 1.172 1.013 3.23-.354 4.596L11.89 8.354c-.186.186-.386.35-.594.491zm-2.45 2.45a4.075 4.075 0 0 1-.491.594l-1.415 1.414c-1.366 1.367-3.424 1.525-4.596.354-1.171-1.172-1.013-3.23.354-4.596L4.11 7.646c.186-.186.386-.35.594-.491l.659 1.664a1.781 1.781 0 0 0-.04.04l-1.415 1.414c-.586.586-.654 1.468-.152 1.97s1.384.434 1.97-.152l1.414-1.414a1.78 1.78 0 0 0 .04-.04l1.664.658zm3.812-2.088h2a.5.5 0 0 1 .5.5v.05a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-.05a.5.5 0 0 1 .5-.5zm-.384 2.116l1.415 1.414a.5.5 0 0 1 0 .708l-.037.036a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 0-.707l.036-.037a.5.5 0 0 1 .707 0zm-2.823 1.09a.5.5 0 0 1 .5-.5h.052a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5H9.95a.5.5 0 0 1-.5-.5v-2zm-2.748-9.16a.5.5 0 0 1-.5.5h-.05a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5h.05a.5.5 0 0 1 .5.5v2zm-2.116.383a.5.5 0 0 1 0 .707l-.036.036a.5.5 0 0 1-.707 0L2.428 2.965a.5.5 0 0 1 0-.707l.037-.036a.5.5 0 0 1 .707 0l1.414 1.414zm-1.09 2.823h-2a.5.5 0 0 1-.5-.5v-.051a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 .5.5v.05a.5.5 0 0 1-.5.5z"/></symbol><symbol viewBox="0 0 16 16" id="user" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0 8c-6.888 0-6.976-.78-6.976-2.52S2.144 8 8 8s6.976 2.692 6.976 4.48c0 1.788-.088 2.52-6.976 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="users" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.521 8.01C15.103 8.19 16 10.755 16 12.48c0 1.533-.056 2.29-3.808 2.475.609-.54.808-1.331.808-2.475 0-1.911-.804-3.503-2.479-4.47zm-1.67-1.228A3.987 3.987 0 0 0 9.976 4a3.987 3.987 0 0 0-1.125-2.782 3 3 0 1 1 0 5.563zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8s6 2.692 6 4.48c0 1.788-.076 2.52-6 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="volume-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1 5h1v6H1a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1zm2 0l4.445-2.964A1 1 0 0 1 9 2.87v10.26a1 1 0 0 1-1.555.833L3 11V5zm10.283 7.89a.5.5 0 0 1-.66-.752A5.485 5.485 0 0 0 14.5 8c0-1.601-.687-3.09-1.865-4.128a.5.5 0 0 1 .661-.75A6.484 6.484 0 0 1 15.5 8a6.485 6.485 0 0 1-2.217 4.89zm-2.002-2.236a.5.5 0 1 1-.652-.758c.55-.472.871-1.157.871-1.896 0-.732-.315-1.411-.856-1.883a.5.5 0 0 1 .658-.753A3.492 3.492 0 0 1 12.5 8c0 1.033-.45 1.994-1.219 2.654z"/></symbol><symbol viewBox="0 0 16 16" id="warning" xmlns="http://www.w3.org/2000/svg"><path d="M15.34 10.479A3 3 0 0 1 12.756 15h-9.51A3 3 0 0 1 .66 10.479l4.755-8.083a3 3 0 0 1 5.172 0l4.755 8.083zm-6.478-7.07a1 1 0 0 0-1.724 0l-4.755 8.084A1 1 0 0 0 3.245 13h9.51a1 1 0 0 0 .862-1.507L8.862 3.41zM8 5a1 1 0 0 1 1 1v2a1 1 0 1 1-2 0V6a1 1 0 0 1 1-1zm0 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="work" xmlns="http://www.w3.org/2000/svg"><path d="M12 3h1a3 3 0 0 1 3 3v7a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h1V2a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v1zM6 2v1h4V2H6zM3 5a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1H3zm1.5 1a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5zm7 0a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5z"/></symbol></svg>
\ No newline at end of file +<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><symbol viewBox="0 0 16 16" id="abuse" xmlns="http://www.w3.org/2000/svg"><path d="M11.408.328l4.029 3.222A1.5 1.5 0 0 1 16 4.72v6.555a1.5 1.5 0 0 1-.563 1.171l-4.026 3.224a1.5 1.5 0 0 1-.937.329H5.529a1.5 1.5 0 0 1-.937-.328L.563 12.45A1.5 1.5 0 0 1 0 11.28V4.724a1.5 1.5 0 0 1 .563-1.171L4.589.329A1.5 1.5 0 0 1 5.526 0h4.945c.34 0 .67.116.937.328zM10.296 2H5.702L2 4.964v6.074L5.704 14h4.594L14 11.036V4.962L10.296 2zM8 4a1 1 0 0 1 1 1v3a1 1 0 1 1-2 0V5a1 1 0 0 1 1-1zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="account" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9.195 9.965l-.568-.875a.25.25 0 0 1 .015-.294l.405-.5a.25.25 0 0 1 .283-.075l.938.36c.257-.183.543-.325.851-.42l.322-.988A.25.25 0 0 1 11.679 7h.642a.25.25 0 0 1 .238.173l.322.988c.308.095.594.237.851.42l.938-.36a.25.25 0 0 1 .283.076l.405.5a.25.25 0 0 1 .015.293l-.568.875c.113.297.18.616.193.95l.898.54a.25.25 0 0 1 .115.27l-.144.626a.25.25 0 0 1-.222.193l-1.115.098a3.015 3.015 0 0 1-.512.608l.165 1.18a.25.25 0 0 1-.138.259l-.577.281a.25.25 0 0 1-.29-.05l-.874-.905a3.035 3.035 0 0 1-.608 0l-.875.904a.25.25 0 0 1-.289.051l-.577-.281a.25.25 0 0 1-.138-.26l.165-1.18a3.015 3.015 0 0 1-.512-.607l-1.115-.098a.25.25 0 0 1-.222-.193l-.144-.626a.25.25 0 0 1 .115-.27l.898-.54c.013-.334.08-.653.193-.95zM6.789 8.023A12.845 12.845 0 0 0 6 8c-5.036 0-6 2.74-6 4.48C0 14.22.076 15 6 15c.553 0 1.055-.006 1.51-.02A5.977 5.977 0 0 1 6 11c0-1.083.287-2.1.79-2.977zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM12 12a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="admin" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.162 2.5a3.5 3.5 0 0 1-3.163 5.479L6.08 14.766a1.5 1.5 0 0 1-2.598-1.5L7.4 6.479A3.5 3.5 0 0 1 10.564 1L8.9 3.88l2.599 1.5 1.663-2.88zm-8.63 11.949a.5.5 0 1 0 .5-.866.5.5 0 0 0-.5.866z"/></symbol><symbol viewBox="0 0 16 16" id="angle-double-left" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.414 7.95l4.243-4.243a1 1 0 0 0-1.414-1.414l-4.95 4.95a.997.997 0 0 0 0 1.414l4.95 4.95a1 1 0 1 0 1.414-1.415L10.414 7.95zm-7 0l4.243-4.243a1 1 0 0 0-1.414-1.414l-4.95 4.95a.997.997 0 0 0 0 1.414l4.95 4.95a1 1 0 0 0 1.414-1.415L3.414 7.95z"/></symbol><symbol viewBox="0 0 16 16" id="angle-double-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.536 7.95L1.293 3.707a1 1 0 0 1 1.414-1.414l4.95 4.95a.997.997 0 0 1 0 1.414l-4.95 4.95a1 1 0 1 1-1.414-1.415L5.536 7.95zm7 0L8.293 3.707a1 1 0 0 1 1.414-1.414l4.95 4.95a.997.997 0 0 1 0 1.414l-4.95 4.95a1 1 0 0 1-1.414-1.415l4.243-4.242z"/></symbol><symbol viewBox="0 0 16 16" id="angle-down" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 10.243l-4.95-4.95a1 1 0 0 0-1.414 1.414l5.657 5.657a.997.997 0 0 0 1.414 0l5.657-5.657a1 1 0 0 0-1.414-1.414L8 10.243z"/></symbol><symbol viewBox="0 0 16 16" id="angle-left" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.757 8l4.95-4.95a1 1 0 1 0-1.414-1.414L3.636 7.293a.997.997 0 0 0 0 1.414l5.657 5.657a1 1 0 0 0 1.414-1.414L5.757 8z"/></symbol><symbol viewBox="0 0 16 16" id="angle-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.243 8l-4.95-4.95a1 1 0 0 1 1.414-1.414l5.657 5.657a.997.997 0 0 1 0 1.414l-5.657 5.657a1 1 0 0 1-1.414-1.414L10.243 8z"/></symbol><symbol viewBox="0 0 16 16" id="angle-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 6.757l-4.95 4.95a1 1 0 1 1-1.414-1.414l5.657-5.657a.997.997 0 0 1 1.414 0l5.657 5.657a1 1 0 0 1-1.414 1.414L8 6.757z"/></symbol><symbol viewBox="0 0 16 16" id="appearance" xmlns="http://www.w3.org/2000/svg"><path d="M11.161 12.456l.232.121c.1.053.175.094.249.137.53.318.844.75.857 1.402.012 1.397-1.116 1.756-3.12 1.858a23.85 23.85 0 0 1-1.38.026A8 8 0 0 1 0 8a8 8 0 0 1 8-8c4.417 0 7.998 3.582 7.998 7.977.06 2.621-1.312 3.586-4.48 3.648-.602.008-1.068.043-1.4.104.228.192.598.47 1.043.727zm-3.287-.943c-.019-1.495 1.228-1.856 3.611-1.888C13.67 9.582 14.028 9.33 13.998 8A6 6 0 1 0 8 14c.603 0 .91-.004 1.277-.023a9.7 9.7 0 0 0 .478-.035c-1.172-.738-1.868-1.47-1.88-2.43zM6 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 3a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm-2-3a1 1 0 1 1 0-2 1 1 0 0 1 0 2zM4 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="applications" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1 0h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm0 6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm6-6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm0 1v2h2V1H7zm0 5h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm6-6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm0 6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm0 1v2h2V7h-2zM1 12h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1zm0 1v2h2v-2H1zm6-1h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1zm6 0h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="approval" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.536 10.657l2.828-2.829a1 1 0 0 1 1.414 1.415l-3.535 3.535a.997.997 0 0 1-1.415 0l-2.12-2.121A1 1 0 1 1 9.12 9.243l1.415 1.414zM7.632 8.109A2 2 0 0 0 7 11.364l2.121 2.121a1.996 1.996 0 0 0 2.807.021C11.686 14.554 10.627 15 6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8c.6 0 1.142.038 1.632.109zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"/></symbol><symbol viewBox="0 0 16 16" id="arrow-down" xmlns="http://www.w3.org/2000/svg"><path d="M10.472 7.282a.862.862 0 0 1 1.26-.006c.357.364.357.958 0 1.285L8.627 11.73A.886.886 0 0 1 8 12a.849.849 0 0 1-.627-.27L4.275 8.561a.904.904 0 0 1-.013-1.285.861.861 0 0 1 1.26-.007l2.486 2.527z"/></symbol><symbol viewBox="0 0 16 16" id="arrow-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9 6H2a2 2 0 1 0 0 4h7v2.586a1 1 0 0 0 1.707.707l4.586-4.586a1 1 0 0 0 0-1.414l-4.586-4.586A1 1 0 0 0 9 3.414V6z"/></symbol><symbol viewBox="0 0 16 16" id="assignee" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12 5V4a1 1 0 0 1 2 0v1h1a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0V7h-1a1 1 0 0 1 0-2h1zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8s6 2.692 6 4.48c0 1.788-.076 2.52-6 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="bold" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4 12.5v-9A1.5 1.5 0 0 1 5.5 2h2.104c2.182 0 3.879.681 3.879 2.982 0 1.067-.517 2.227-1.374 2.595v.073C11.176 7.963 12 8.865 12 10.466 12 12.914 10.19 14 7.911 14H5.5A1.5 1.5 0 0 1 4 12.5zm2.376-5.696H7.49c1.164 0 1.665-.552 1.665-1.417 0-.94-.534-1.289-1.649-1.289h-1.13v2.706zm0 5.098h1.341c1.293 0 1.956-.515 1.956-1.62 0-1.049-.647-1.472-1.956-1.472H6.376v3.092z"/></symbol><symbol viewBox="0 0 16 16" id="book" xmlns="http://www.w3.org/2000/svg"><path d="M7 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2v4.191a.5.5 0 0 1-.724.447l-1.052-.526a.5.5 0 0 0-.448 0l-1.052.526A.5.5 0 0 1 7 6.191V2zM5 0h6a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z"/></symbol><symbol viewBox="0 0 16 16" id="branch" xmlns="http://www.w3.org/2000/svg"><path d="M6 11.978v.29a2 2 0 1 1-2 0V3.732a2 2 0 1 1 2 0v3.849c.592-.491 1.31-.854 2.15-1.081 1.308-.353 1.875-.882 1.893-1.743a2 2 0 1 1 2.002-.051C12.053 6.54 10.857 7.84 8.67 8.43 7.056 8.867 6.195 9.98 6 11.978zM5 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm6 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM5 15a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="bullhorn" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6.143 10H7V4H3a3 3 0 1 0 0 6h.143l.734 5.141a1 1 0 0 0 .99.859h1.556a.5.5 0 0 0 .495-.57L6.143 10zM8 4c1.034.02 2.039-.274 3.014-.883.727-.455 1.836-1.334 3.328-2.637A1 1 0 0 1 16 1.233v10.764a1 1 0 0 1-1.595.803c-1.658-1.227-2.788-1.992-3.392-2.294-.781-.39-1.785-.559-3.013-.506V4z"/></symbol><symbol viewBox="0 0 16 16" id="calendar" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12 2h2a2 2 0 0 1 2 2H0a2 2 0 0 1 2-2h2V1a1 1 0 1 1 2 0v1h4V1a1 1 0 1 1 2 0v1zM0 4h16v9a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V4zm2 2.5V13a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6.5a.5.5 0 0 0-.5-.5h-11a.5.5 0 0 0-.5.5zM5 8h2a1 1 0 1 1 0 2H5a1 1 0 1 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="cancel" xmlns="http://www.w3.org/2000/svg"><path d="M3.11 4.523a6 6 0 0 0 8.367 8.367L3.109 4.524zM4.522 3.11l8.368 8.368A6 6 0 0 0 4.524 3.11zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16z"/></symbol><symbol viewBox="0 0 16 16" id="chart" xmlns="http://www.w3.org/2000/svg"><path d="M15 14a1 1 0 0 1 0 2H2a2 2 0 0 1-2-2V1a1 1 0 1 1 2 0v13h13zM3.142 8.735l2.502-2.561a.5.5 0 0 1 .714-.003L8 7.833l3.592-4.553a.5.5 0 0 1 .796.015l2.516 3.454a.5.5 0 0 1 .096.295V12.5a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5V9.085a.5.5 0 0 1 .142-.35z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-down" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.078 8.2l3.535-3.536a2 2 0 0 1 2.828 2.828l-4.949 4.95c-.39.39-.902.586-1.414.586a1.994 1.994 0 0 1-1.414-.586l-4.95-4.95a2 2 0 1 1 2.828-2.828l3.536 3.535z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-left" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.977 7.998l3.535-3.535a2 2 0 1 0-2.828-2.828l-4.95 4.949c-.39.39-.586.902-.586 1.414 0 .512.196 1.024.586 1.414l4.95 4.95a2 2 0 1 0 2.828-2.828L7.977 7.998z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.22 7.998L4.683 4.463a2 2 0 0 1 2.828-2.828l4.95 4.949c.39.39.586.902.586 1.414a1.99 1.99 0 0 1-.586 1.414l-4.95 4.95a2 2 0 0 1-2.828-2.828l3.535-3.536z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.778 8.957l3.535 3.535a2 2 0 1 0 2.828-2.828l-4.949-4.95a1.994 1.994 0 0 0-1.414-.586c-.512 0-1.024.196-1.414.586l-4.95 4.95a2 2 0 1 0 2.828 2.828l3.536-3.535z"/></symbol><symbol viewBox="0 0 16 16" id="clock" xmlns="http://www.w3.org/2000/svg"><path d="M9 7h1a1 1 0 0 1 0 2H8a.997.997 0 0 1-1-1V5a1 1 0 1 1 2 0v2zm-1 9A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="close" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9.414 8l4.95-4.95a1 1 0 0 0-1.414-1.414L8 6.586l-4.95-4.95A1 1 0 0 0 1.636 3.05L6.586 8l-4.95 4.95a1 1 0 1 0 1.414 1.414L8 9.414l4.95 4.95a1 1 0 1 0 1.414-1.414L9.414 8z"/></symbol><symbol viewBox="0 0 16 16" id="code" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M15.871 8.243a.997.997 0 0 0-.293-.707L12.75 4.707a1 1 0 0 0-1.414 1.414l2.12 2.122-2.12 2.121a1 1 0 0 0 1.414 1.414l2.828-2.828a.997.997 0 0 0 .293-.707zm-13.243 0L4.75 6.12a1 1 0 1 0-1.414-1.414L.507 7.536a.997.997 0 0 0 0 1.414l2.829 2.828a1 1 0 1 0 1.414-1.414L2.628 8.243zm6.407-4.107a1 1 0 0 1 .707 1.225L8.19 11.157a1 1 0 1 1-1.931-.518L7.81 4.843a1 1 0 0 1 1.224-.707z"/></symbol><symbol viewBox="0 0 9 13" id="collapse"><path d="M.084.25C.01.18-.015.12.008.071.031.024.093 0 .194 0h8.521c.1 0 .162.024.185.072.023.048-.002.107-.075.177l-4.11 3.935a.372.372 0 0 1-.11.072h-.301a.508.508 0 0 1-.11-.072L.084.249zM.377 6.88a.364.364 0 0 1-.26-.105.334.334 0 0 1-.11-.25v-.709c0-.096.036-.179.11-.249a.364.364 0 0 1 .26-.105h8.15c.101 0 .188.035.261.105.074.07.11.153.11.25v.709c0 .096-.036.179-.11.249a.364.364 0 0 1-.26.105H.377zM.084 12.132c-.074.07-.099.129-.076.177.023.048.085.072.186.072h8.521c.1 0 .162-.024.185-.072.023-.048-.002-.107-.075-.177l-4.11-3.935a.372.372 0 0 0-.11-.072h-.301a.508.508 0 0 0-.11.072l-4.11 3.935z"/></symbol><symbol viewBox="0 0 16 16" id="comment" xmlns="http://www.w3.org/2000/svg"><path d="M1.707 15.707C1.077 16.337 0 15.891 0 15V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5.414l-3.707 3.707zM2 12.586l2.293-2.293A1 1 0 0 1 5 10h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v9.586z"/></symbol><symbol viewBox="0 0 16 16" id="comment-dots" xmlns="http://www.w3.org/2000/svg"><path d="M1.707 15.707C1.077 16.337 0 15.891 0 15V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5.414l-3.707 3.707zM2 12.586l2.293-2.293A1 1 0 0 1 5 10h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v9.586zM5 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="comment-next" xmlns="http://www.w3.org/2000/svg"><path d="M8 5V4a.5.5 0 0 1 .8-.4l2.667 2a.5.5 0 0 1 0 .8L8.8 8.4A.5.5 0 0 1 8 8V7H6a1 1 0 1 1 0-2h2zM1.707 15.707C1.077 16.337 0 15.891 0 15V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5.414l-3.707 3.707zM2 12.586l2.293-2.293A1 1 0 0 1 5 10h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v9.586z"/></symbol><symbol viewBox="0 0 16 16" id="comments" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3.75 10L0 13V3a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2H3.75zM13 5h1a2 2 0 0 1 2 2v8l-2.667-2H8a2 2 0 0 1-2-2h4a3 3 0 0 0 3-3V5z"/></symbol><symbol viewBox="0 0 16 16" id="commit" xmlns="http://www.w3.org/2000/svg"><path d="M8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm3.876-1.008a4.002 4.002 0 0 1-7.752 0A1.01 1.01 0 0 1 4 9H1a1 1 0 1 1 0-2h3c.042 0 .083.003.124.008a4.002 4.002 0 0 1 7.752 0A1.01 1.01 0 0 1 12 7h3a1 1 0 0 1 0 2h-3a1.01 1.01 0 0 1-.124-.008z"/></symbol><symbol viewBox="0 0 16 16" id="credit-card" xmlns="http://www.w3.org/2000/svg"><path d="M14 5a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1h12zm0 3H2v3a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V8zM3 2h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zm6.5 8h3a.5.5 0 1 1 0 1h-3a.5.5 0 1 1 0-1z"/></symbol><symbol viewBox="0 0 16 16" id="cut" xmlns="http://www.w3.org/2000/svg"><rect width="16" height="2" y="7" fill-rule="evenodd" rx="1"/></symbol><symbol viewBox="0 0 16 16" id="dashboard" xmlns="http://www.w3.org/2000/svg"><path d="M7.709 10.021l.696-2.6a.5.5 0 0 1 .966.26l-.657 2.45A2 2 0 0 1 10 12H6a2 2 0 0 1 1.709-1.979zM0 8.9a8 8 0 0 1 15.998 0H16v3.6a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5V8.9zM14 9A6 6 0 1 0 2 9v3.5a.5.5 0 0 0 .5.5h11a.5.5 0 0 0 .5-.5V9zM3.5 9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm9 0a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-7-3a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm5 0a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1z"/></symbol><symbol viewBox="0 0 16 16" id="disk" xmlns="http://www.w3.org/2000/svg"><path d="M16 11.764V3a3 3 0 0 0-3-3H3a3 3 0 0 0-3 3v8.764A2.989 2.989 0 0 1 2 11V3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v8c.768 0 1.47.289 2 .764zM2 12h12a2 2 0 1 1 0 4H2a2 2 0 1 1 0-4zm10 1a1 1 0 1 0 0 2 1 1 0 0 0 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="doc_code" xmlns="http://www.w3.org/2000/svg"><path d="M8 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V7h-3a2 2 0 0 1-2-2V2zm2 .414V5h2.586L10 2.414zm1.036 7.607a.498.498 0 0 1-.147.354l-1.414 1.414a.5.5 0 0 1-.707-.707l1.06-1.06-1.06-1.061a.5.5 0 0 1 .707-.707l1.414 1.414a.498.498 0 0 1 .147.353zm-4.822 0l1.06 1.061a.5.5 0 0 1-.706.707l-1.414-1.414a.498.498 0 0 1 0-.707l1.414-1.414a.5.5 0 1 1 .707.707l-1.06 1.06zM5 0h4.586A2 2 0 0 1 11 .586L14.414 4A2 2 0 0 1 15 5.414V12a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z"/></symbol><symbol viewBox="0 0 16 16" id="doc_image" xmlns="http://www.w3.org/2000/svg"><path d="M8 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V7h-3a2 2 0 0 1-2-2V2zm2 .414V5h2.586L10 2.414zM7.333 9.667l1.313-1.313a.5.5 0 0 1 .708 0L12 11H4l2.188-1.75a.5.5 0 0 1 .624 0l.521.417zM5 0h4.586A2 2 0 0 1 11 .586L14.414 4A2 2 0 0 1 15 5.414V12a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm.5 8a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zM4 11h8v.7a.3.3 0 0 1-.3.3H4.3a.3.3 0 0 1-.3-.3V11z"/></symbol><symbol viewBox="0 0 16 16" id="doc_text" xmlns="http://www.w3.org/2000/svg"><path d="M8 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V7h-3a2 2 0 0 1-2-2V2zm2 .414V5h2.586L10 2.414zM5 0h4.586A2 2 0 0 1 11 .586L14.414 4A2 2 0 0 1 15 5.414V12a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm.5 11h5a.5.5 0 1 1 0 1h-5a.5.5 0 1 1 0-1zm0-2h5a.5.5 0 1 1 0 1h-5a.5.5 0 0 1 0-1zm0-2h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1z"/></symbol><symbol viewBox="0 0 105 26" id="double-headed-arrow" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1.018 11.089L15.138.614c1.23-.911 3.086-.795 4.147.26.461.46.715 1.045.715 1.651v20.95C20 24.869 18.684 26 17.06 26a3.238 3.238 0 0 1-1.921-.614L1.019 14.911C-.212 14-.347 12.405.714 11.35c.094-.094.195-.18.303-.261zm102.964 0c.108.08.21.167.303.26 1.061 1.056.925 2.65-.303 3.562l-14.12 10.475A3.238 3.238 0 0 1 87.94 26C86.316 26 85 24.87 85 23.475V2.525c0-.606.254-1.192.715-1.65 1.061-1.056 2.917-1.172 4.146-.26l14.12 10.474zM35 17a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm18 0a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm18 0a4 4 0 1 1 0-8 4 4 0 0 1 0 8z"/></symbol><symbol viewBox="0 0 16 16" id="download" xmlns="http://www.w3.org/2000/svg"><path d="M9 12h1a.5.5 0 0 1 .4.8l-2 2.667a.5.5 0 0 1-.8 0l-2-2.667A.5.5 0 0 1 6 12h1V8a1 1 0 1 1 2 0v4zM4 9a1 1 0 1 1 0 2 4 4 0 0 1-1.971-7.481 4 4 0 0 1 6.633-2.505 3.999 3.999 0 0 1 3.82 2.014A4 4 0 0 1 12 11a1 1 0 0 1 0-2 2 2 0 1 0 0-4h-1a2 2 0 0 0-3.112-1.662A2 2 0 1 0 4.268 5H4a2 2 0 1 0 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="duplicate" xmlns="http://www.w3.org/2000/svg"><path d="M14 10h-3a1 1 0 0 1-1-1V6H8.527A.527.527 0 0 0 8 6.527V13a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1v-3zm-4-7H8.527c-.18 0-.355.013-.527.04V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2v2H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h4a3 3 0 0 1 3 3zM8.527 4h2.323a.5.5 0 0 1 .35.143l4.65 4.551a.5.5 0 0 1 .15.357V13a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V6.527A2.527 2.527 0 0 1 8.527 4z"/></symbol><symbol viewBox="0 0 16 16" id="earth" xmlns="http://www.w3.org/2000/svg"><path d="M8.7 2.04l-.082.177c.283.223.422.413.417.571-.008.237-.311.057-.444.274-.133.218.038.542-.112.637-.15.096-.398-.386-.479-.46-.054-.049-.166-.257-.336-.625l-.216-.225a.844.844 0 0 0-.418-.035c-.177.038-.075.1-.035.132.04.032.32.037.452.2.132.164.03.224-.05.298-.054.05-.157.062-.31.035H5.952l-.402.398.03.325.229.455.324-.463c.008-.206.058-.342.15-.41.14-.1.342-.15.534-.085.191.066-.057.218.011.271.068.053.204-.098.313-.02.11.08.07.155.104.322.036.167.254.114.398.328.144.215.19.29.147.483-.043.195-.168.26-.305.232-.138-.028-.107-.246-.275-.348-.168-.102-.266-.114-.386-.054-.12.06-.016.129.023.235.04.106.274.321.224.43-.05.107-.108.116-.42 0-.21-.077-.414-.007-.615.212l-.76.722c-.153.715-.3 1.13-.44 1.243-.211.17-.177-.483-.483-.656-.306-.174-.494-.047-.8-.07-.307-.023-.42.65-.38.873a.434.434 0 0 0 .221.321c.236-.141.39-.184.465-.128.11.084-.144.267-.074.425.07.158.314.069.386.283.073.213.084.48-.05.706-.135.227-.275.178-.4.053-.127-.126-.033-.375-.255-.704-.223-.329-.381-.337-.63-.787-.158-.287-.35-.743-.575-1.366a6 6 0 0 0 3.21 7.198l.001-.075c0-.577-.004-.944-.012-1.102-.011-.236-.95-.945-1.104-1.2-.154-.256-.34-.595-.355-.746-.016-.151.185-.232.344-.325.16-.093-.11-.367.028-.626.137-.258.395-.438.496-.356.101.081.058.228.267.333.209.104.077-.213.456-.178.38.035.143.201.252.216.11.016.113-.127.299-.143.186-.015.282.445.471.622.19.178.452.008.611.043.159.034.267.09.402.255.136.166-.03.352.073.557.103.205 1.07.22 1.433.255.364.034.371.011.371.324s-.166.314-.453.507c-.286.193-.166.462-.38.762-.212.3-.316.062-.622.14-.306.077-.413.382-.452.568-.039.186-.386.094-.877.232-.29.082-.429.144-.569.204a6.002 6.002 0 0 0 7.682-4.3c-.094-.384-.18-.63-.258-.74-.213-.297-.36.21-.924.49-.564.278-.57-.288-.81-.49-.16-.133-.212-.44-.158-.92-.005-.478.02-.828.077-1.049.057-.221.126-.543.207-.965.351-.373.606-.572.764-.595.237-.034.336.374.658.3a.315.315 0 0 0 .035-.01 5.993 5.993 0 0 0-.475-.824l-.309-.043a.646.646 0 0 0-.332-.117c-.205-.02-.025.128-.089.24-.064.112-.235.724-.437.685-.201-.039-.204-.374-.17-.668.036-.294-.077-.35-.2-.412-.124-.062-.325-.213-.556-.295-.232-.082-.123-.175-.093-.274.03-.1.208-.015.193-.058-.014-.044-.313-.135-.266-.167.03-.02.2-.02.506.003l.216-.012.293-.163a.58.58 0 0 0-.376-.22c-.233-.036-.513-.034-.73-.142-.205-.103-.458-.36-.643-.638A5.965 5.965 0 0 0 8.7 2.04zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16z"/></symbol><symbol viewBox="0 0 1600 1600" id="ellipsis_v" xmlns="http://www.w3.org/2000/svg"><path d="M1088 1248v192q0 40-28 68t-68 28H800q-40 0-68-28t-28-68v-192q0-40 28-68t68-28h192q40 0 68 28t28 68zm0-512v192q0 40-28 68t-68 28H800q-40 0-68-28t-28-68V736q0-40 28-68t68-28h192q40 0 68 28t28 68zm0-512v192q0 40-28 68t-68 28H800q-40 0-68-28t-28-68V224q0-40 28-68t68-28h192q40 0 68 28t28 68z"/></symbol><symbol viewBox="0 0 18 18" id="emoji_slightly_smiling_face" xmlns="http://www.w3.org/2000/svg"><path d="M13.29 11.098a4.328 4.328 0 0 1-1.618 2.285c-.79.578-1.68.867-2.672.867-.992 0-1.883-.29-2.672-.867a4.328 4.328 0 0 1-1.617-2.285.721.721 0 0 1 .047-.569.715.715 0 0 1 .445-.369.721.721 0 0 1 .568.047.715.715 0 0 1 .37.445 2.91 2.91 0 0 0 1.084 1.518A2.93 2.93 0 0 0 9 12.75a2.93 2.93 0 0 0 1.775-.58 2.913 2.913 0 0 0 1.084-1.518.711.711 0 0 1 .375-.445.737.737 0 0 1 .575-.047c.195.063.34.186.433.37.094.183.11.372.047.568zM7.5 6c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 6 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 4.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 6 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm6 0c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 12 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 10.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 12 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm3 3a7.29 7.29 0 0 0-.598-2.912 7.574 7.574 0 0 0-1.6-2.39 7.574 7.574 0 0 0-2.39-1.6A7.29 7.29 0 0 0 9 1.5a7.29 7.29 0 0 0-2.912.598 7.574 7.574 0 0 0-2.39 1.6 7.574 7.574 0 0 0-1.6 2.39A7.29 7.29 0 0 0 1.5 9c0 1.016.2 1.986.598 2.912a7.574 7.574 0 0 0 1.6 2.39 7.574 7.574 0 0 0 2.39 1.6A7.29 7.29 0 0 0 9 16.5a7.29 7.29 0 0 0 2.912-.598 7.574 7.574 0 0 0 2.39-1.6 7.574 7.574 0 0 0 1.6-2.39A7.29 7.29 0 0 0 16.5 9zM18 9a8.804 8.804 0 0 1-1.207 4.518 8.96 8.96 0 0 1-3.275 3.275A8.804 8.804 0 0 1 9 18a8.804 8.804 0 0 1-4.518-1.207 8.96 8.96 0 0 1-3.275-3.275A8.804 8.804 0 0 1 0 9c0-1.633.402-3.139 1.207-4.518a8.96 8.96 0 0 1 3.275-3.275A8.804 8.804 0 0 1 9 0c1.633 0 3.139.402 4.518 1.207a8.96 8.96 0 0 1 3.275 3.275A8.804 8.804 0 0 1 18 9z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 18 18" id="emoji_smile" xmlns="http://www.w3.org/2000/svg"><path d="M13.29 11.098a4.328 4.328 0 0 1-1.618 2.285c-.79.578-1.68.867-2.672.867-.992 0-1.883-.29-2.672-.867a4.328 4.328 0 0 1-1.617-2.285.721.721 0 0 1 .047-.569.715.715 0 0 1 .445-.369c.195-.062 7.41-.062 7.606 0 .195.063.34.186.433.37.094.183.11.372.047.568zM14 6.37c0 .398-.04.755-.513.755-.473 0-.498-.272-1.237-.272-.74 0-.74.215-1.165.215-.425 0-.585-.3-.585-.698 0-.397.17-.736.513-1.017.341-.281.754-.422 1.237-.422.483 0 .896.14 1.237.422.342.28.513.62.513 1.017zm-6.5 0c0 .398-.04.755-.513.755-.473 0-.498-.272-1.237-.272-.74 0-.74.215-1.165.215-.425 0-.585-.3-.585-.698 0-.397.17-.736.513-1.017.341-.281.754-.422 1.237-.422.483 0 .896.14 1.237.422.342.28.513.62.513 1.017zm9 2.63a7.29 7.29 0 0 0-.598-2.912 7.574 7.574 0 0 0-1.6-2.39 7.574 7.574 0 0 0-2.39-1.6A7.29 7.29 0 0 0 9 1.5a7.29 7.29 0 0 0-2.912.598 7.574 7.574 0 0 0-2.39 1.6 7.574 7.574 0 0 0-1.6 2.39A7.29 7.29 0 0 0 1.5 9c0 1.016.2 1.986.598 2.912a7.574 7.574 0 0 0 1.6 2.39 7.574 7.574 0 0 0 2.39 1.6A7.29 7.29 0 0 0 9 16.5a7.29 7.29 0 0 0 2.912-.598 7.574 7.574 0 0 0 2.39-1.6 7.574 7.574 0 0 0 1.6-2.39A7.29 7.29 0 0 0 16.5 9zM18 9a8.804 8.804 0 0 1-1.207 4.518 8.96 8.96 0 0 1-3.275 3.275A8.804 8.804 0 0 1 9 18a8.804 8.804 0 0 1-4.518-1.207 8.96 8.96 0 0 1-3.275-3.275A8.804 8.804 0 0 1 0 9c0-1.633.402-3.139 1.207-4.518a8.96 8.96 0 0 1 3.275-3.275A8.804 8.804 0 0 1 9 0c1.633 0 3.139.402 4.518 1.207a8.96 8.96 0 0 1 3.275 3.275A8.804 8.804 0 0 1 18 9z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 18 18" id="emoji_smiley" xmlns="http://www.w3.org/2000/svg"><path d="M13.29 11.098a4.328 4.328 0 0 1-1.618 2.285c-.79.578-1.68.867-2.672.867-.992 0-1.883-.29-2.672-.867a4.328 4.328 0 0 1-1.617-2.285.721.721 0 0 1 .047-.569.715.715 0 0 1 .445-.369c.195-.062 7.41-.062 7.606 0 .195.063.34.186.433.37.094.183.11.372.047.568h.001zM7.5 6c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 6 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 4.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 6 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm6 0c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 12 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 10.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 12 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm3 3a7.29 7.29 0 0 0-.598-2.912 7.574 7.574 0 0 0-1.6-2.39 7.574 7.574 0 0 0-2.39-1.6A7.29 7.29 0 0 0 9 1.5a7.29 7.29 0 0 0-2.912.598 7.574 7.574 0 0 0-2.39 1.6 7.574 7.574 0 0 0-1.6 2.39A7.29 7.29 0 0 0 1.5 9c0 1.016.2 1.986.598 2.912a7.574 7.574 0 0 0 1.6 2.39 7.574 7.574 0 0 0 2.39 1.6c.92.397 1.91.6 2.912.598a7.29 7.29 0 0 0 2.912-.598 7.574 7.574 0 0 0 2.39-1.6 7.574 7.574 0 0 0 1.6-2.39c.397-.92.6-1.91.598-2.912zM18 9a8.804 8.804 0 0 1-1.207 4.518 8.96 8.96 0 0 1-3.275 3.275A8.804 8.804 0 0 1 9 18a8.804 8.804 0 0 1-4.518-1.207 8.96 8.96 0 0 1-3.275-3.275A8.804 8.804 0 0 1 0 9c0-1.633.402-3.139 1.207-4.518a8.96 8.96 0 0 1 3.275-3.275A8.804 8.804 0 0 1 9 0c1.633 0 3.139.402 4.518 1.207a8.96 8.96 0 0 1 3.275 3.275A8.804 8.804 0 0 1 18 9z"/></symbol><symbol viewBox="0 0 16 16" id="epic" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M14.985 8.044l-.757 2.272a1 1 0 0 1-.949.684H1.618a1 1 0 0 1-.894-1.447l.318-.637A2 2 0 0 0 1.618 9h11.661a2 2 0 0 0 1.706-.956zm0 3l-.757 2.272a1 1 0 0 1-.949.684H1.618a1 1 0 0 1-.894-1.447l.318-.637a2 2 0 0 0 .576.084h11.661a2 2 0 0 0 1.706-.956zM3.618 2h10.995a1 1 0 0 1 .948 1.316l-1.333 4a1 1 0 0 1-.949.684H1.618a1 1 0 0 1-.894-1.447l2-4A1 1 0 0 1 3.618 2zm-.382 4h9.322l.667-2H4.236l-1 2z"/></symbol><symbol viewBox="0 0 16 16" id="external-link" xmlns="http://www.w3.org/2000/svg"><path d="M13.121 4.177l-4.95 4.95a1 1 0 1 1-1.414-1.414l4.95-4.95-1.386-1.386a.5.5 0 0 1 .299-.85l4.709-.524a.5.5 0 0 1 .552.552l-.523 4.71a.5.5 0 0 1-.851.297l-1.386-1.385zM12 8.884a1 1 0 0 1 2 0v4a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3v-8a3 3 0 0 1 3-3h4a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-4z"/></symbol><symbol viewBox="0 0 16 16" id="eye" xmlns="http://www.w3.org/2000/svg"><path d="M8 14C4.816 14 2.253 12.284.393 8.981a2 2 0 0 1 0-1.962C2.253 3.716 4.816 2 8 2s5.747 1.716 7.607 5.019a2 2 0 0 1 0 1.962C13.747 12.284 11.184 14 8 14zm0-2c2.41 0 4.338-1.29 5.864-4C12.338 5.29 10.411 4 8 4 5.59 4 3.662 5.29 2.136 8 3.662 10.71 5.589 12 8 12zm0-1a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm1-3a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="eye-slash" xmlns="http://www.w3.org/2000/svg"><path d="M13.618 2.62L1.62 14.619a1 1 0 0 1-.985-1.668l1.525-1.526C1.516 10.742.926 9.927.393 8.981a2 2 0 0 1 0-1.962C2.253 3.716 4.816 2 8 2c1.074 0 2.076.195 3.006.58l.944-.944a1 1 0 0 1 1.668.985zM8.068 11a3 3 0 0 0 2.931-2.932l-2.931 2.931zm-3.02-2.462a3 3 0 0 1 3.49-3.49l.884-.884A6.044 6.044 0 0 0 8 4C5.59 4 3.662 5.29 2.136 8c.445.79.924 1.46 1.439 2.011l1.473-1.473zm.421 5.06l1.658-1.658c.283.04.575.06.873.06 2.41 0 4.338-1.29 5.864-4a11.023 11.023 0 0 0-1.133-1.664l1.418-1.418a12.799 12.799 0 0 1 1.458 2.1 2 2 0 0 1 0 1.963C13.747 12.284 11.184 14 8 14a7.883 7.883 0 0 1-2.53-.402z"/></symbol><symbol viewBox="0 0 16 16" id="file-addition" xmlns="http://www.w3.org/2000/svg"><path d="M7 7V5a1 1 0 1 1 2 0v2h2a1 1 0 0 1 0 2H9v2a1 1 0 0 1-2 0V9H5a1 1 0 1 1 0-2h2zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3z"/></symbol><symbol viewBox="0 0 16 16" id="file-deletion" xmlns="http://www.w3.org/2000/svg"><path d="M3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3zm2 6h6a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="file-modified" xmlns="http://www.w3.org/2000/svg"><path d="M3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3zm5 4a3 3 0 1 1 0 6 3 3 0 0 1 0-6z"/></symbol><symbol viewBox="0 0 16 16" id="filter" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 6v9l-3.724-1.862A.5.5 0 0 1 6 12.691V6L1.854 1.854A.5.5 0 0 1 2.207 1h11.586a.5.5 0 0 1 .353.854L10 6z"/></symbol><symbol viewBox="0 0 16 16" id="folder" xmlns="http://www.w3.org/2000/svg"><path d="M7.228 5l-.475-1.335A1 1 0 0 0 5.81 3H2v9a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1H7.228zM13 3a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a2 2 0 0 1 2-2h3.81a3 3 0 0 1 2.827 1.995L13 3z"/></symbol><symbol viewBox="0 0 16 16" id="fork" xmlns="http://www.w3.org/2000/svg"><path d="M9 12.268a2 2 0 1 1-2 0V8.874A4.002 4.002 0 0 1 4 5V3.732a2 2 0 1 1 2 0V5a2 2 0 1 0 4 0V3.732a2 2 0 1 1 2 0V5a4.002 4.002 0 0 1-3 3.874v3.394zM11 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM5 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm3 12a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="geo-nodes" xmlns="http://www.w3.org/2000/svg"><path d="M9.7 13.1l-.2.2c-.7.8-2 .9-2.8.1-.1 0-.1-.1-.1-.1l-.2-.2c-2 .2-3.4.7-3.4 1.4 0 .8 2.2 1.5 5 1.5s5-.7 5-1.5c0-.7-1.4-1.2-3.3-1.4M7.3 12.7c.4.4 1 .3 1.4-.1C11.6 9.5 13 7 13 5.3 13 2.4 10.8 0 8 0S3 2.4 3 5.3C3 7 4.4 9.5 7.3 12.7M8 2c1.6 0 3 1.4 3 3.3 0 1-1 2.8-3 5.2-2-2.4-3-4.2-3-5.2C5 3.4 6.4 2 8 2"/><circle cx="8" cy="5" r="1"/></symbol><symbol viewBox="0 0 16 16" id="git-merge" xmlns="http://www.w3.org/2000/svg"><path d="M11 12.268V5a1 1 0 0 0-1-1v1a.5.5 0 0 1-.8.4l-2.667-2a.5.5 0 0 1 0-.8L9.2.6a.5.5 0 0 1 .8.4v1a3 3 0 0 1 3 3v7.268a2 2 0 1 1-2 0zm-6 0a2 2 0 1 1-2 0V4.732a2 2 0 1 1 2 0v7.536zM4 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm0 11a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm8 0a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="group" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3.048 11.997C-.377 11.975.013 11.782.013 10.56.013 9.235.653 8 4 8c.444 0 .84.022 1.194.062.164.435.426.82.76 1.132-1.786.389-2.721 1.353-2.906 2.803zm2.94-7.222a2.993 2.993 0 0 0-.976 1.95 2 2 0 1 1 .975-1.95zm6.964 7.222c-.185-1.45-1.12-2.414-2.906-2.803.334-.311.596-.697.76-1.132C11.16 8.022 11.556 8 12 8c3.346 0 3.987 1.235 3.987 2.56 0 1.222.39 1.415-3.035 1.437zm-1.964-5.272a2.993 2.993 0 0 0-.976-1.95 2 2 0 1 1 .976 1.95zM8 9a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 5c-2.177 0-3.987-.115-3.987-1.44S4.653 10 8 10c3.346 0 3.987 1.235 3.987 2.56S10.177 14 8 14z"/></symbol><symbol viewBox="0 0 16 16" id="history" xmlns="http://www.w3.org/2000/svg"><path d="M2.868 3.24a7 7 0 1 1-.043 9.475 1 1 0 0 1 1.478-1.348 5 5 0 1 0 .124-6.865l.796.645a.5.5 0 0 1-.193.873l-3.232.814a.5.5 0 0 1-.622-.504L1.3 3a.5.5 0 0 1 .814-.37l.754.61zM9 8h1a1 1 0 0 1 0 2H8a.997.997 0 0 1-1-1V6a1 1 0 1 1 2 0v2z"/></symbol><symbol viewBox="0 0 16 16" id="home" xmlns="http://www.w3.org/2000/svg"><path d="M8.462 2.177a.505.505 0 0 1-.038.044l.038-.044zm-.787 0l.038.043a.5.5 0 0 1-.038-.043zM3.706 7h8.725L8.069 2.585 3.706 7zM7 13.369V12a1 1 0 0 1 2 0v1.369h3V9H4v4.369h3zM14 9v4.836c0 .833-.657 1.533-1.5 1.533h-9c-.843 0-1.5-.7-1.5-1.533V9h-.448a1.1 1.1 0 0 1-.783-1.873L6.934.887a1.5 1.5 0 0 1 2.269 0l6.165 6.24A1.1 1.1 0 0 1 14.585 9H14z"/></symbol><symbol viewBox="0 0 16 16" id="hook" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1h4zm0 1H6v1a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1V4zM7 8a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h2a3 3 0 0 1 3 3v2a3 3 0 0 1-3 3v4a2 2 0 1 0 4 0h-.44a.3.3 0 0 1-.25-.466l1.44-2.16a.3.3 0 0 1 .5 0l1.44 2.16a.3.3 0 0 1-.25.466H15a4 4 0 0 1-7 2.646A4 4 0 0 1 1 12H.56a.3.3 0 0 1-.25-.466l1.44-2.16a.3.3 0 0 1 .5 0l1.44 2.16a.3.3 0 0 1-.25.466H3a2 2 0 1 0 4 0V8z"/></symbol><symbol viewBox="0 0 16 16" id="hourglass" xmlns="http://www.w3.org/2000/svg"><path d="M10.331 4.889A2.988 2.988 0 0 0 11 3V2H5v1c0 .362.064.709.182 1.03l5.15.859zM3 14v-1c0-1.78.93-3.342 2.33-4.228.447-.327.67-.582.67-.764 0-.19-.242-.46-.725-.815A4.996 4.996 0 0 1 3 3V2H2a1 1 0 1 1 0-2h12a1 1 0 0 1 0 2h-1v1a4.997 4.997 0 0 1-2.39 4.266c-.407.3-.61.545-.61.734 0 .19.203.434.61.734A4.997 4.997 0 0 1 13 13v1h1a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2h1zm8 0v-1a3 3 0 0 0-6 0v1h6z"/></symbol><symbol viewBox="0 0 24 30" id="image-comment-dark" xmlns="http://www.w3.org/2000/svg"><title>cursor_active</title><g fill="none" fill-rule="evenodd"><path d="M24 12.105c0 6.686-5.74 11.58-12 17.895C5.74 23.684 0 18.79 0 12.105 0 5.42 5.373 0 12 0s12 5.42 12 12.105z" fill="#FFF" fill-rule="nonzero"/><path d="M15.28 25.249c1.458-1.475 2.539-2.635 3.474-3.747 2.851-3.394 4.203-6.265 4.203-9.397 0-6.111-4.908-11.062-10.957-11.062-6.05 0-10.957 4.951-10.957 11.062 0 3.132 1.352 6.003 4.203 9.397.935 1.112 2.016 2.272 3.474 3.747.511.517 2.216 2.213 3.28 3.275 1.064-1.062 2.769-2.758 3.28-3.275z" fill="#1F78D1"/><path d="M14.551 8.256A6.874 6.874 0 0 0 12 7.787a6.92 6.92 0 0 0-2.558.469c-.79.308-1.42.725-1.888 1.252-.465.527-.697 1.096-.697 1.708 0 .5.159.977.476 1.433.321.45.772.841 1.352 1.172l.583.334-.181.643c-.107.407-.263.79-.469 1.152a6.604 6.604 0 0 0 1.842-1.145l.288-.254.381.04c.309.035.599.053.871.053.91 0 1.761-.154 2.551-.462.795-.312 1.424-.732 1.889-1.259.468-.526.703-1.096.703-1.707 0-.612-.235-1.181-.703-1.708-.465-.527-1.094-.944-1.889-1.252zm2.645.81c.536.656.804 1.373.804 2.15 0 .776-.268 1.495-.804 2.156-.535.656-1.263 1.176-2.183 1.56-.92.38-1.924.57-3.013.57a9.16 9.16 0 0 1-.971-.054 7.32 7.32 0 0 1-3.08 1.62 5.044 5.044 0 0 1-.764.148h-.033a.26.26 0 0 1-.181-.074.324.324 0 0 1-.107-.18v-.007c-.014-.018-.016-.045-.007-.08.014-.037.018-.059.014-.068a.19.19 0 0 1 .033-.067.645.645 0 0 0 .04-.06 1.73 1.73 0 0 0 .047-.054l.054-.06a53.034 53.034 0 0 1 .435-.489c.049-.049.118-.136.207-.26a2.57 2.57 0 0 0 .221-.342c.054-.103.114-.235.181-.395a4.18 4.18 0 0 0 .174-.51c-.7-.397-1.254-.888-1.66-1.473A3.261 3.261 0 0 1 6 11.216c0-.777.268-1.494.804-2.15.535-.66 1.263-1.18 2.183-1.56.92-.384 1.924-.576 3.013-.576 1.09 0 2.094.192 3.013.576.92.38 1.648.9 2.183 1.56z" fill="#FFF" fill-rule="nonzero"/></g></symbol><symbol viewBox="0 0 16 16" id="import" xmlns="http://www.w3.org/2000/svg"><path d="M9 8h1a.5.5 0 0 1 .4.8l-2 2.667a.5.5 0 0 1-.8 0L5.6 8.8A.5.5 0 0 1 6 8h1V1a1 1 0 1 1 2 0v7zM0 8a1 1 0 1 1 2 0 6 6 0 1 0 12 0 1 1 0 0 1 2 0A8 8 0 1 1 0 8z"/></symbol><symbol viewBox="0 0 16 16" id="issue-block" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.803 8a5.97 5.97 0 0 0-.462 1H4.5a.5.5 0 0 1 0-1h1.303zM4.5 5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1 0-1zm7.5.083a6.04 6.04 0 0 0-2 0V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h2.083a5.96 5.96 0 0 0 .72 2H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h6a3 3 0 0 1 3 3v2.083zm1.121 3.796zM11 16a5 5 0 1 1 0-10 5 5 0 0 1 0 10zm-1.293-2.292a3 3 0 0 0 4.001-4.001l-4.001 4zm-1.415-1.415l4.001-4a3 3 0 0 0-4.001 4.001z"/></symbol><symbol viewBox="0 0 16 16" id="issue-child" xmlns="http://www.w3.org/2000/svg"><path d="M11 8H5v1h1a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h2V7a.997.997 0 0 1 1-1h3V4H4.5a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5H9v2h3a.997.997 0 0 1 1 1v2h2a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-5a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h1V8zm-9 3v2h3v-2H2zm9 0v2h3v-2h-3z"/></symbol><symbol viewBox="0 0 16 16" id="issue-close" xmlns="http://www.w3.org/2000/svg"><path d="M7.536 8.657l2.828-2.829a1 1 0 0 1 1.414 1.415l-3.535 3.535a.997.997 0 0 1-1.415 0l-2.12-2.121A1 1 0 0 1 6.12 7.243l1.415 1.414zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="issue-duplicate" xmlns="http://www.w3.org/2000/svg"><path d="M10.874 2H12a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3h-2c-.918 0-1.74-.413-2.29-1.063a3.987 3.987 0 0 0 1.988-.984A1 1 0 0 0 10 14h2a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1h-1V3c0-.345-.044-.68-.126-1zM4 0h3a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H4z"/></symbol><symbol viewBox="0 0 16 16" id="issue-new" xmlns="http://www.w3.org/2000/svg"><path d="M10 2V1a1 1 0 0 1 2 0v1h1a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0V4H9a1 1 0 1 1 0-2h1zm0 6a1 1 0 0 1 2 0v5a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h1a1 1 0 1 1 0 2H5a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V8z"/></symbol><symbol viewBox="0 0 16 16" id="issue-open" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm0-2a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-2a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="issue-open-m" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="issue-parent" xmlns="http://www.w3.org/2000/svg"><path d="M11 11H5v1h1.5a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5h-6a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5H3v-2a.997.997 0 0 1 1-1h3V7H5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H9v2h3a.997.997 0 0 1 1 1v2h2.5a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5h-6a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5H11v-1zM6 3v2h4V3H6z"/></symbol><symbol viewBox="0 0 16 16" id="issues" xmlns="http://www.w3.org/2000/svg"><path d="M10.458 15.012l.311.055a3 3 0 0 0 3.476-2.433l1.389-7.879A3 3 0 0 0 13.2 1.28L11.23.933a3.002 3.002 0 0 0-.824-.031c.364.59.58 1.28.593 2.02l1.854.328a1 1 0 0 1 .811 1.158l-1.389 7.879a1 1 0 0 1-1.158.81l-.118-.02a3.98 3.98 0 0 1-.541 1.935zM3 0h4a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3z"/></symbol><symbol viewBox="0 0 16 16" id="italic" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.5 12l2-8H6a1 1 0 1 1 0-2h6a1 1 0 0 1 0 2h-1.5l-2 8H10a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2h1.5z"/></symbol><symbol viewBox="0 0 16 16" id="key" xmlns="http://www.w3.org/2000/svg"><path d="M7.575 6.689a4.002 4.002 0 0 1 6.274-4.86 4 4 0 0 1-4.86 6.274l-2.21 2.21.706.708a1 1 0 1 1-1.414 1.414l-.707-.707-.707.707.707.707a1 1 0 1 1-1.414 1.414l-.707-.707a1 1 0 0 1-1.414-1.414l5.746-5.746zm2.032-.618a2 2 0 1 0 2.828-2.828A2 2 0 0 0 9.607 6.07z"/></symbol><symbol viewBox="0 0 16 16" id="key-2" xmlns="http://www.w3.org/2000/svg"><path d="M5.172 14.157l-.344.344-2.485.133a.462.462 0 0 1-.497-.503l.14-2.24a.599.599 0 0 1 .177-.382l5.155-5.155a4 4 0 1 1 2.828 2.828l-1.439 1.44-1.06-.354-.708.707.354 1.06-.707.708-1.06-.354-.708.707.354 1.06zm6.01-8.839a1 1 0 1 0 1.414-1.414 1 1 0 0 0-1.414 1.414z"/></symbol><symbol viewBox="0 0 16 16" id="label" xmlns="http://www.w3.org/2000/svg"><path d="M11.782 14.718a3 3 0 0 1-4.242 0L1.652 8.829a2 2 0 0 1-.565-1.702l.54-3.703a2 2 0 0 1 1.69-1.69l3.703-.54a2 2 0 0 1 1.703.564l5.888 5.888a3 3 0 0 1 0 4.243l-2.829 2.829zm1.415-5.657L7.309 3.173l-3.703.54-.54 3.702 5.888 5.888a1 1 0 0 0 1.414 0l2.829-2.828a1 1 0 0 0 0-1.414zM5.732 5.525A1 1 0 1 1 7.146 6.94a1 1 0 0 1-1.414-1.414z"/></symbol><symbol viewBox="0 0 16 16" id="labels" xmlns="http://www.w3.org/2000/svg"><path d="M9.424 2.254l2.08-.905a1 1 0 0 1 1.206.326l3.013 4.12a1 1 0 0 1 .16.849l-1.947 7.264a3 3 0 0 1-3.675 2.122l-.5-.135a3.999 3.999 0 0 0 1.082-1.782 1 1 0 0 0 1.16-.722l1.823-6.802-2.258-3.087-.687.299a2 2 0 0 0-.628-.88l-.829-.667zM.377 3.7L4.4.498a1 1 0 0 1 1.25.003L9.627 3.7a1 1 0 0 1 .373.78V13a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V4.482A1 1 0 0 1 .377 3.7zM2 13a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V4.958L5.02 2.561 2 4.964V13zm3-6a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="leave" xmlns="http://www.w3.org/2000/svg"><path d="M11 7V5.883a.5.5 0 0 1 .757-.429l3.528 2.117a.5.5 0 0 1 0 .858l-3.528 2.117a.5.5 0 0 1-.757-.43V9H7a1 1 0 1 1 0-2h4zm-2 6.256a1 1 0 0 1 2 0A2.744 2.744 0 0 1 8.256 16H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h5.19A2.81 2.81 0 0 1 11 2.81a1 1 0 0 1-2 0A.81.81 0 0 0 8.19 2H3a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h5.256c.41 0 .744-.333.744-.744z"/></symbol><symbol viewBox="0 0 16 16" id="level-up" xmlns="http://www.w3.org/2000/svg"><path fill="#2E2E2E" fill-rule="evenodd" d="M7 6h3.489a.5.5 0 0 0 .373-.832L6.374.117a.5.5 0 0 0-.748 0l-4.488 5.05A.5.5 0 0 0 1.51 6H5v7a3 3 0 0 0 3 3h6a1 1 0 0 0 0-2H8a1 1 0 0 1-1-1V6z"/></symbol><symbol viewBox="0 0 16 16" id="license" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12.56 8.9l2.66 4.606a.3.3 0 0 1-.243.45l-1.678.094a.1.1 0 0 0-.078.044l-.953 1.432a.3.3 0 0 1-.51-.016L9.097 10.9a5.994 5.994 0 0 0 3.464-2zm-5.23 2.063L4.707 15.51a.3.3 0 0 1-.51.016l-.953-1.432a.1.1 0 0 0-.078-.044l-1.678-.094a.3.3 0 0 1-.243-.45l2.48-4.297a5.983 5.983 0 0 0 3.607 1.754zM8 10A5 5 0 1 1 8 0a5 5 0 0 1 0 10zm0-2a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-1a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="link" xmlns="http://www.w3.org/2000/svg"><path d="M6.986 3.35l2.12-2.122a4 4 0 0 1 5.657 5.657l-2.828 2.829a4 4 0 0 1-5.657 0 1 1 0 0 1 1.414-1.415 2 2 0 0 0 2.829 0l2.828-2.828a2 2 0 1 0-2.828-2.828l-1.001 1a5.018 5.018 0 0 0-2.534-.294zm2.12 9.192l-2.12 2.121a4 4 0 1 1-5.658-5.656l2.829-2.829a4 4 0 0 1 5.657 0 1 1 0 1 1-1.415 1.414 2 2 0 0 0-2.828 0l-2.828 2.829a2 2 0 1 0 2.828 2.828l1.001-1.001a5.018 5.018 0 0 0 2.534.294z"/></symbol><symbol viewBox="0 0 16 16" id="list-bulleted" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm0 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4-7h10a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2zm0 5h10a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2zm-4 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4-2h10a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="list-numbered" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6 2h8a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2zm0 5h8a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2zm0 5h8a1 1 0 0 1 0 2H6a1 1 0 0 1 0-2zM1.156 5v-.828h.816V2.204h-.72v-.636c.432-.084.708-.192.996-.372h.756v2.976h.684V5H1.156zm-.18 5v-.588c.9-.828 1.596-1.464 1.596-1.98 0-.342-.192-.504-.468-.504-.252 0-.444.18-.624.36l-.552-.552c.396-.42.756-.612 1.32-.612.768 0 1.308.492 1.308 1.248 0 .612-.576 1.284-1.092 1.812.192-.024.468-.048.636-.048h.636V10H.976zm1.26 5.072c-.618 0-1.068-.204-1.356-.54l.468-.648c.234.216.51.36.78.36.336 0 .552-.12.552-.36 0-.288-.15-.456-.948-.456v-.72c.636 0 .828-.168.828-.432 0-.228-.138-.348-.396-.348-.252 0-.432.108-.672.312l-.516-.624c.372-.312.768-.492 1.236-.492.84 0 1.38.384 1.38 1.074 0 .366-.204.642-.612.822v.024c.432.132.732.432.732.912 0 .72-.684 1.116-1.476 1.116z"/></symbol><symbol viewBox="0 0 16 16" id="location" xmlns="http://www.w3.org/2000/svg"><path d="M8.755 15.144a1 1 0 0 1-1.51 0C3.748 11.114 2 8.065 2 6a6 6 0 1 1 12 0c0 2.065-1.748 5.113-5.245 9.144zM12 6a4 4 0 1 0-8 0c0 1.314 1.312 3.71 4 6.944C10.688 9.71 12 7.314 12 6zM8 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="location-dot" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6.314 13.087C4.382 13.295 3 13.85 3 14.5c0 .828 2.239 1.5 5 1.5s5-.672 5-1.5c0-.65-1.382-1.205-3.314-1.413l-.202.225a2 2 0 0 1-2.968 0l-.202-.225zm2.428-.445a1 1 0 0 1-1.484 0C4.419 9.5 3 7.037 3 5.252 3 2.353 5.239 0 8 0s5 2.352 5 5.253c0 1.784-1.42 4.247-4.258 7.389zM11 5.252C11 3.436 9.634 2 8 2S5 3.435 5 5.253c0 1.027.974 2.824 3 5.203 2.026-2.38 3-4.176 3-5.203zM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="lock" xmlns="http://www.w3.org/2000/svg"><path d="M10 5V4h2v1a3 3 0 0 1 3 3v5a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V8a3 3 0 0 1 3-3V4h2v1h4zM4 7a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V8a1 1 0 0 0-1-1H4zm0-3a4 4 0 1 1 8 0h-2a2 2 0 1 0-4 0H4z"/></symbol><symbol viewBox="0 0 16 16" id="lock-open" xmlns="http://www.w3.org/2000/svg"><path d="M4.044 4a4 4 0 0 1 6.99-2.658 1 1 0 1 1-1.495 1.33A2 2 0 0 0 6.044 4a.998.998 0 0 1-.07.367v.701H12a3 3 0 0 1 3 3v5a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3v-5a3 3 0 0 1 2.974-3V4h.07zM4 7.07a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-5a1 1 0 0 0-1-1H4z"/></symbol><symbol viewBox="0 0 16 16" id="log" xmlns="http://www.w3.org/2000/svg"><path d="M4 0h8a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H4zm1 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm0 3a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3-5h3a1 1 0 0 1 0 2H8a1 1 0 1 1 0-2zm0 3h3a1 1 0 0 1 0 2H8a1 1 0 1 1 0-2zm-3 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3-2h3a1 1 0 0 1 0 2H8a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="mail" xmlns="http://www.w3.org/2000/svg"><path d="M14 5.6L9.338 9.796a2 2 0 0 1-2.676 0L2 5.6V11a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V5.6zM3 2h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zm.212 2L8 8.31 12.788 4H3.212z"/></symbol><symbol viewBox="0 0 16 16" id="menu" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1.143 2h13.714C15.488 2 16 2.448 16 3s-.512 1-1.143 1H1.143C.512 4 0 3.552 0 3s.512-1 1.143-1zm0 5h13.714C15.488 7 16 7.448 16 8s-.512 1-1.143 1H1.143C.512 9 0 8.552 0 8s.512-1 1.143-1zm0 5h13.714c.631 0 1.143.448 1.143 1s-.512 1-1.143 1H1.143C.512 14 0 13.552 0 13s.512-1 1.143-1z"/></symbol><symbol viewBox="0 0 16 16" id="merge-request-close" xmlns="http://www.w3.org/2000/svg"><path d="M9.414 8l1.414 1.414a1 1 0 1 1-1.414 1.414L8 9.414l-1.414 1.414a1 1 0 1 1-1.414-1.414L6.586 8 5.172 6.586a1 1 0 1 1 1.414-1.414L8 6.586l1.414-1.414a1 1 0 1 1 1.414 1.414L9.414 8zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="messages" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.588 8.942l1.173 5.862A1 1 0 0 1 8.78 16H7.22a1 1 0 0 1-.98-1.196l1.172-5.862a3.014 3.014 0 0 0 1.176 0zM8 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4zM4.464 2.464L5.88 3.88a3 3 0 0 0 0 4.242L4.464 9.536a5 5 0 0 1 0-7.072zm7.072 7.072L10.12 8.12a3 3 0 0 0 0-4.242l1.415-1.415a5 5 0 0 1 0 7.072zM2.343.343l1.414 1.414a6 6 0 0 0 0 8.486l-1.414 1.414a8 8 0 0 1 0-11.314zm11.314 11.314l-1.414-1.414a6 6 0 0 0 0-8.486L13.657.343a8 8 0 0 1 0 11.314z"/></symbol><symbol viewBox="0 0 16 16" id="mobile-issue-close" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.657 10.728L2.12 7.192A1 1 0 1 0 .707 8.607l4.243 4.242a.997.997 0 0 0 1.414 0l8.485-8.485a1 1 0 1 0-1.414-1.414l-7.778 7.778z"/></symbol><symbol viewBox="0 0 16 16" id="monitor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 13v1h3a1 1 0 0 1 0 2H3a1 1 0 0 1 0-2h3v-1H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v7a3 3 0 0 1-3 3h-3zM3 2a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3zm5.723 6.416l-2.66-1.773-1.71 1.71a.5.5 0 1 1-.707-.707l2-2a.5.5 0 0 1 .631-.062l2.66 1.773 2.71-2.71a.5.5 0 0 1 .707.707l-3 3a.5.5 0 0 1-.631.062z"/></symbol><symbol viewBox="0 0 16 16" id="more" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 4a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 6a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 6a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="notifications" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6 14H2.435a2 2 0 0 1-1.761-2.947c.962-1.788 1.521-3.065 1.68-3.832.322-1.566.947-5.501 4.65-6.134a1 1 0 1 1 1.994-.024c3.755.528 4.375 4.27 4.761 6.043.188.86.742 2.188 1.661 3.982A2 2 0 0 1 13.64 14H10a2 2 0 1 1-4 0zm5.805-6.468c-.325-1.492-.37-1.674-.61-2.288C10.6 3.716 9.742 3 8.07 3c-1.608 0-2.49.718-3.103 2.197-.28.676-.356.982-.654 2.428-.208 1.012-.827 2.424-1.877 4.375H13.64c-.993-1.937-1.6-3.396-1.835-4.468z"/></symbol><symbol viewBox="0 0 16 16" id="notifications-off" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.26 5.089c.243.757.382 1.478.5 2.017.187.86.74 2.188 1.66 3.982A2 2 0 0 1 13.64 14H10a2 2 0 1 1-4 0H4.35l2-2h7.29c-.993-1.937-1.6-3.396-1.835-4.468-.07-.326-.129-.59-.178-.81l1.634-1.633zM10.943 1.75l-1.48 1.48C9.07 3.076 8.612 3 8.069 3c-1.608 0-2.49.718-3.103 2.197-.28.676-.356.982-.654 2.428-.065.317-.17.673-.317 1.073L.45 12.242a1.99 1.99 0 0 1 .224-1.19c.962-1.787 1.521-3.064 1.68-3.831.322-1.566.947-5.501 4.65-6.134a1 1 0 1 1 1.994-.024 4.867 4.867 0 0 1 1.944.688zm2.932-.105a1 1 0 0 1 0 1.415L2.561 14.374a1 1 0 1 1-1.415-1.414L12.46 1.646a1 1 0 0 1 1.414 0z"/></symbol><symbol viewBox="0 0 16 16" id="overview" xmlns="http://www.w3.org/2000/svg"><path d="M2 0h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm0 2v3h3V2H2zm9-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2h-3a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm0 2v3h3V2h-3zM2 9h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2zm0 2v3h3v-3H2zm9-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2h-3a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2zm0 2v3h3v-3h-3z"/></symbol><symbol viewBox="0 0 16 16" id="pencil" xmlns="http://www.w3.org/2000/svg"><path d="M13.02 1.293l1.414 1.414a1 1 0 0 1 0 1.414L4.119 14.436a1 1 0 0 1-.704.293l-2.407.008L1 12.316a1 1 0 0 1 .293-.71L11.605 1.292a1 1 0 0 1 1.414 0zm-1.416 1.415l-.707.707L12.31 4.83l.707-.707-1.414-1.415zM3.411 13.73l1.123-1.122H3.12v-1.415L2 12.312l.005 1.422 1.406-.005z"/></symbol><symbol viewBox="0 0 16 16" id="pencil-square" xmlns="http://www.w3.org/2000/svg"><path d="M12 9a1 1 0 0 1 2 0v4a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h4a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V9zm.778-7.179l1.414 1.415-6.476 6.476a1 1 0 0 1-.498.27l-1.51.325.323-1.512a1 1 0 0 1 .27-.497l6.477-6.477zM15.607.407a1 1 0 0 1 0 1.414l-.708.707-1.414-1.414.707-.707a1 1 0 0 1 1.415 0z"/></symbol><symbol viewBox="0 0 16 16" id="pipeline" xmlns="http://www.w3.org/2000/svg"><path d="M8.969 7.25a2 2 0 1 1-1.938 0A1.002 1.002 0 0 1 7 7V5.083a.2.2 0 0 1 .06-.142l.877-.87a.1.1 0 0 1 .141 0l.864.87A.2.2 0 0 1 9 5.083V7c0 .086-.01.17-.031.25zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm4.5-4a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-3a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-2 6a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-5 9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-2 6a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-3a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zM8 10a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="play" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2.765 15.835c-.545.321-1.258.159-1.593-.363A1.075 1.075 0 0 1 1 14.89V1.11C1 .496 1.518 0 2.158 0c.214 0 .424.057.607.165l11.684 6.89c.544.321.714 1.005.38 1.526a1.135 1.135 0 0 1-.38.364l-11.684 6.89z"/></symbol><symbol viewBox="0 0 16 16" id="plus" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7 7V1a1 1 0 1 1 2 0v6h6a1 1 0 0 1 0 2H9v6a1 1 0 0 1-2 0V9H1a1 1 0 1 1 0-2h6z"/></symbol><symbol viewBox="0 0 16 16" id="plus-square" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9 7V4a1 1 0 1 0-2 0v3H4a1 1 0 1 0 0 2h3v3a1 1 0 0 0 2 0V9h3a1 1 0 0 0 0-2H9zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3z"/></symbol><symbol viewBox="0 0 16 16" id="plus-square-o" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7 7V5a1 1 0 1 1 2 0v2h2a1 1 0 0 1 0 2H9v2a1 1 0 0 1-2 0V9H5a1 1 0 1 1 0-2h2zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3z"/></symbol><symbol viewBox="0 0 16 16" id="preferences" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5 12h10a1 1 0 0 1 0 2H5a1 1 0 0 1-2 0v-2a1 1 0 0 1 2 0zm-3 0H1a1 1 0 0 0 0 2h1v-2zm11-5h2a1 1 0 0 1 0 2h-2a1 1 0 0 1-2 0V7a1 1 0 0 1 2 0zm-3 0H1a1 1 0 1 0 0 2h9V7zM6 2h9a1 1 0 0 1 0 2H6a1 1 0 1 1-2 0V2a1 1 0 1 1 2 0zM3 2H1a1 1 0 1 0 0 2h2V2z"/></symbol><symbol viewBox="0 0 16 16" id="profile" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm-4.274-3.404C4.412 9.709 5.694 9 8 9c2.313 0 3.595.7 4.28 1.586A4.997 4.997 0 0 1 8 13a4.997 4.997 0 0 1-4.274-2.404zM8 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="project" xmlns="http://www.w3.org/2000/svg"><path d="M8.462 2.177l-.038.044a.505.505 0 0 0 .038-.044zm-.787 0a.5.5 0 0 0 .038.043l-.038-.043zM3.706 7h8.725L8.069 2.585 3.706 7zM7 13.369V12a1 1 0 0 1 2 0v1.369h3V9H4v4.369h3zM14 9v4.836c0 .833-.657 1.533-1.5 1.533h-9c-.843 0-1.5-.7-1.5-1.533V9h-.448a1.1 1.1 0 0 1-.783-1.873L6.934.887a1.5 1.5 0 0 1 2.269 0l6.165 6.24A1.1 1.1 0 0 1 14.585 9H14z"/></symbol><symbol viewBox="0 0 16 16" id="push-rules" xmlns="http://www.w3.org/2000/svg"><path d="M6.268 9a2 2 0 0 1 3.464 0H11a1 1 0 0 1 0 2H9.732a2 2 0 0 1-3.464 0H5a1 1 0 0 1 0-2h1.268zM7 2H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1h-1v3.515a.3.3 0 0 1-.434.268l-1.432-.716a.3.3 0 0 0-.268 0l-1.432.716A.3.3 0 0 1 7 5.515V2zM4 0h8a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm4 11a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="question" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm-1.46-5.602h2.233a3.97 3.97 0 0 1 .051-.558c.029-.17.073-.326.133-.469.06-.143.14-.28.242-.41.102-.13.228-.263.38-.399.26-.24.504-.467.733-.683a5.03 5.03 0 0 0 .598-.668c.17-.23.302-.477.399-.742a2.66 2.66 0 0 0 .144-.907c0-.505-.083-.95-.25-1.335a2.55 2.55 0 0 0-.723-.97 3.2 3.2 0 0 0-1.152-.589 5.441 5.441 0 0 0-1.531-.2c-.516 0-.998.063-1.445.188a3.19 3.19 0 0 0-1.168.59c-.331.268-.594.61-.79 1.027-.195.417-.295.917-.3 1.5h2.64c.006-.224.04-.416.102-.578.062-.161.142-.293.238-.394a.921.921 0 0 1 .332-.227 1.04 1.04 0 0 1 .39-.074c.34 0 .593.095.763.285.169.19.254.488.254.895 0 .328-.106.63-.317.906-.21.276-.499.565-.863.867-.214.182-.39.374-.531.574-.141.2-.253.42-.336.657a3.656 3.656 0 0 0-.176.777 7.89 7.89 0 0 0-.05.937zm-.321 2.375c0 .188.035.362.105.524.07.161.17.3.301.418.13.117.284.21.46.277.178.068.376.102.595.102.218 0 .416-.034.593-.102.178-.068.331-.16.461-.277a1.2 1.2 0 0 0 .301-.418c.07-.162.106-.336.106-.524a1.3 1.3 0 0 0-.106-.523 1.2 1.2 0 0 0-.3-.418 1.461 1.461 0 0 0-.462-.277 1.651 1.651 0 0 0-.593-.102c-.22 0-.417.034-.594.102a1.46 1.46 0 0 0-.461.277 1.2 1.2 0 0 0-.3.418 1.284 1.284 0 0 0-.106.523z"/></symbol><symbol viewBox="0 0 16 16" id="question-o" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm-.778-4.151c0-.301.014-.575.044-.82a3.2 3.2 0 0 1 .154-.68c.073-.208.17-.4.294-.575.123-.176.278-.343.465-.503a4.81 4.81 0 0 0 .755-.758c.185-.242.277-.506.277-.793 0-.356-.074-.617-.222-.783-.148-.166-.37-.25-.667-.25a.92.92 0 0 0-.342.065.806.806 0 0 0-.29.199 1.04 1.04 0 0 0-.209.345 1.5 1.5 0 0 0-.088.506H5.082c.005-.51.092-.948.263-1.313.171-.364.401-.664.69-.899.29-.234.63-.406 1.023-.516a4.66 4.66 0 0 1 1.264-.164c.497 0 .944.058 1.34.174.397.117.733.289 1.008.517.276.227.487.51.633.847.146.337.218.727.218 1.17 0 .295-.042.56-.126.792a2.52 2.52 0 0 1-.349.65 4.4 4.4 0 0 1-.523.584c-.2.19-.414.389-.642.598a2.73 2.73 0 0 0-.332.349c-.089.114-.16.233-.212.359a1.868 1.868 0 0 0-.116.41 3.39 3.39 0 0 0-.044.489H7.222zm-.28 2.078c0-.164.03-.317.092-.458a1.05 1.05 0 0 1 .263-.366c.114-.103.248-.183.403-.243a1.45 1.45 0 0 1 .52-.089c.191 0 .364.03.52.09.154.059.289.14.403.242.114.103.201.224.263.366.061.141.092.294.092.458 0 .164-.03.316-.092.458a1.05 1.05 0 0 1-.263.365 1.278 1.278 0 0 1-.404.243 1.43 1.43 0 0 1-.52.089c-.19 0-.364-.03-.519-.089-.155-.06-.29-.14-.403-.243a1.05 1.05 0 0 1-.263-.365 1.135 1.135 0 0 1-.093-.458z"/></symbol><symbol viewBox="0 0 16 16" id="quote" xmlns="http://www.w3.org/2000/svg"><path d="M15 3v8a3 3 0 0 1-3 3 1 1 0 0 1 0-2 1 1 0 0 0 1-1V9h-2a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h3a1 1 0 0 1 1 1zM7 3v8a3 3 0 0 1-3 3 1 1 0 0 1 0-2 1 1 0 0 0 1-1V9H3a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h3a1 1 0 0 1 1 1z"/></symbol><symbol viewBox="0 0 16 16" id="redo" xmlns="http://www.w3.org/2000/svg"><path d="M4.666 4.423a5 5 0 1 1-.203 6.944 1 1 0 1 0-1.478 1.347 7 7 0 1 0 .12-9.556L1.842 2.137a.5.5 0 0 0-.815.385L1 7.26a.5.5 0 0 0 .607.492l4.629-1.013a.5.5 0 0 0 .207-.877L4.666 4.423z"/></symbol><symbol viewBox="0 0 16 16" id="remove" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 3a1 1 0 1 1 0-2h12a1 1 0 0 1 0 2v10a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3V3zm3-2a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1H5zM4 3v10a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V3H4zm2.5 2a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5zm3 0a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5z"/></symbol><symbol viewBox="0 0 16 16" id="repeat" xmlns="http://www.w3.org/2000/svg"><path d="M11.494 4.423a5 5 0 1 0 .203 6.944 1 1 0 1 1 1.478 1.347 7 7 0 1 1-.12-9.556l1.262-1.021a.5.5 0 0 1 .815.385l.028 4.738a.5.5 0 0 1-.607.492L9.924 6.739a.5.5 0 0 1-.207-.877l1.777-1.439z"/></symbol><symbol viewBox="0 0 16 16" id="retry" xmlns="http://www.w3.org/2000/svg"><path d="M4.114 6.958a4 4 0 0 0 5.283 4.775 1 1 0 1 1 .712 1.87A6 6 0 0 1 2.182 6.44l-.741-.2a.5.5 0 0 1-.12-.915l2.195-1.268a.5.5 0 0 1 .683.183l1.268 2.196a.5.5 0 0 1-.563.733l-.79-.212zm7.777 2.084a4 4 0 0 0-5.284-4.775 1 1 0 0 1-.712-1.87 6 6 0 0 1 7.927 7.162l.742.2a.5.5 0 0 1 .12.915l-2.196 1.268a.5.5 0 0 1-.683-.183l-1.267-2.196a.5.5 0 0 1 .562-.733l.79.212z"/></symbol><symbol viewBox="0 0 16 16" id="scale" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.99 9a.792.792 0 0 0-.078-.231L13 7l-.912 1.769a.791.791 0 0 0-.077.231h1.978zm-10 0a.792.792 0 0 0-.078-.231L3 7l-.912 1.769A.791.791 0 0 0 2.011 9h1.978zM2 0h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm3 14h6a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2zM8 4a1 1 0 0 1 1 1v9H7V5a1 1 0 0 1 1-1zm-4.53-.714l2.265 4.735c.68 1.42.006 3.091-1.504 3.73A3.161 3.161 0 0 1 3 12c-1.657 0-3-1.263-3-2.821 0-.4.09-.794.264-1.158L2.53 3.286a.53.53 0 0 1 .94 0zm10 0l2.265 4.735c.68 1.42.006 3.091-1.504 3.73A3.161 3.161 0 0 1 13 12c-1.657 0-3-1.263-3-2.821 0-.4.09-.794.264-1.158l2.266-4.735a.53.53 0 0 1 .94 0z"/></symbol><symbol viewBox="0 0 16 16" id="screen-full" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M14 14v-2a1 1 0 0 1 2 0v3a.997.997 0 0 1-1 1h-3a1 1 0 0 1 0-2h2zM2 14v-2a1 1 0 0 0-2 0v3a1 1 0 0 0 1 1h3a1 1 0 0 0 0-2H2zM15.707.293A.997.997 0 0 1 16 1v3a1 1 0 0 1-2 0V2h-2a1 1 0 0 1 0-2h3c.276 0 .526.112.707.293zM2 2v2a1 1 0 1 1-2 0V1a.997.997 0 0 1 1-1h3a1 1 0 1 1 0 2H2zm4 4h4a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="screen-normal" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3 3V1a1 1 0 1 1 2 0v3a.997.997 0 0 1-1 1H1a1 1 0 1 1 0-2h2zm10 0h2a1 1 0 0 1 0 2h-3a.997.997 0 0 1-1-1V1a1 1 0 0 1 2 0v2zM3 13H1a1 1 0 0 1 0-2h3a.997.997 0 0 1 1 1v3a1 1 0 0 1-2 0v-2zm10 0v2a1 1 0 0 1-2 0v-3a.997.997 0 0 1 1-1h3a1 1 0 0 1 0 2h-2zM6.5 7h3a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5z"/></symbol><symbol viewBox="0 0 12 16" id="scroll_down" xmlns="http://www.w3.org/2000/svg"><path class="evfirst-triangle" d="M1.048 14.155a.508.508 0 0 0-.32.105c-.091.07-.136.154-.136.25v.71c0 .095.045.178.135.249.09.07.197.105.321.105h10.043a.51.51 0 0 0 .321-.105c.09-.07.136-.154.136-.25v-.71c0-.095-.045-.178-.136-.249a.508.508 0 0 0-.32-.105"/><path class="evsecond-triangle" d="M.687 8.027c-.09-.087-.122-.16-.093-.22.028-.06.104-.09.228-.09h10.5c.123 0 .2.03.228.09.029.06-.002.133-.093.22L6.393 12.91a.458.458 0 0 1-.136.089h-.37a.626.626 0 0 1-.136-.09"/><path class="evthird-triangle" d="M.687 1.027C.597.94.565.867.594.807c.028-.06.104-.09.228-.09h10.5c.123 0 .2.03.228.09.029.06-.002.133-.093.22L6.393 5.91a.458.458 0 0 1-.136.09h-.37a.626.626 0 0 1-.136-.09"/></symbol><symbol viewBox="0 0 12 16" id="scroll_up" xmlns="http://www.w3.org/2000/svg"><path d="M1.048 1.845a.508.508 0 0 1-.32-.105c-.091-.07-.136-.154-.136-.25V.78c0-.095.045-.178.135-.249a.508.508 0 0 1 .321-.105h10.043a.51.51 0 0 1 .321.105c.09.07.136.154.136.25v.71c0 .095-.045.178-.136.249a.508.508 0 0 1-.32.105M.687 7.973c-.09.087-.122.16-.093.22.028.06.104.09.228.09h10.5c.123 0 .2-.03.228-.09.029-.06-.002-.133-.093-.22L6.393 3.09A.458.458 0 0 0 6.257 3h-.37a.626.626 0 0 0-.136.09M.687 14.973c-.09.087-.122.16-.093.22.028.06.104.09.228.09h10.5c.123 0 .2-.03.228-.09.029-.06-.002-.133-.093-.22L6.393 10.09a.458.458 0 0 0-.136-.09h-.37a.626.626 0 0 0-.136.09"/></symbol><symbol viewBox="0 0 16 16" id="search" xmlns="http://www.w3.org/2000/svg"><path d="M8.853 8.854a3.5 3.5 0 1 0-4.95-4.95 3.5 3.5 0 0 0 4.95 4.95zm.207 2.328a5.5 5.5 0 1 1 2.121-2.121l3.329 3.328a1.5 1.5 0 0 1-2.121 2.121L9.06 11.182z"/></symbol><symbol viewBox="0 0 16 16" id="settings" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2.415 5.803L1.317 4.084A.5.5 0 0 1 1.35 3.5l.805-.994a.5.5 0 0 1 .564-.153l1.878.704a5.975 5.975 0 0 1 1.65-.797L6.885.342A.5.5 0 0 1 7.36 0h1.28a.5.5 0 0 1 .474.342l.639 1.918a5.97 5.97 0 0 1 1.65.797l1.877-.704a.5.5 0 0 1 .565.153l.805.994a.5.5 0 0 1 .032.584l-1.097 1.719c.217.551.354 1.143.399 1.76l1.731 1.058a.5.5 0 0 1 .227.54l-.288 1.246a.5.5 0 0 1-.44.385l-2.008.19a6.026 6.026 0 0 1-1.142 1.431l.265 1.995a.5.5 0 0 1-.277.516l-1.15.56a.5.5 0 0 1-.576-.1l-1.424-1.452a6.047 6.047 0 0 1-1.804 0l-1.425 1.453a.5.5 0 0 1-.576.1l-1.15-.561a.5.5 0 0 1-.276-.516l.265-1.995a6.026 6.026 0 0 1-1.143-1.43l-2.008-.191a.5.5 0 0 1-.44-.385L.058 9.16a.5.5 0 0 1 .226-.539l1.732-1.058a5.968 5.968 0 0 1 .399-1.76zM8 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/></symbol><symbol viewBox="0 0 16 16" id="shield" xmlns="http://www.w3.org/2000/svg"><path d="M4 0h8a3 3 0 0 1 3 3v7.186a3 3 0 0 1-1.426 2.554l-4 2.465a3 3 0 0 1-3.148 0l-4-2.465A3 3 0 0 1 1 10.186V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v7.186a1 1 0 0 0 .475.852l4 2.464a1 1 0 0 0 1.05 0l4-2.464a1 1 0 0 0 .475-.852V3a1 1 0 0 0-1-1H4zm0 1.5a.5.5 0 0 1 .5-.5h4v8.837a.5.5 0 0 1-.753.431l-3.5-2.052A.5.5 0 0 1 4 9.785V3.5z"/></symbol><symbol viewBox="0 0 16 16" id="slight-frown" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm-2.163-3.275a2.499 2.499 0 0 1 4.343.03.5.5 0 0 1-.871.49 1.5 1.5 0 0 0-2.607-.018.5.5 0 1 1-.865-.502zM5 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="slight-smile" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM5 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm-5.163 2.254a.5.5 0 1 1 .865-.502 1.499 1.499 0 0 0 2.607-.018.5.5 0 1 1 .871.49 2.499 2.499 0 0 1-4.343.03z"/></symbol><symbol viewBox="0 0 16 16" id="smile" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM6.18 6.27a.5.5 0 0 1-.873.487.5.5 0 0 0-.872-.003.5.5 0 1 1-.87-.495 1.5 1.5 0 0 1 2.616.012zm6 0a.5.5 0 1 1-.873.487.5.5 0 0 0-.872-.003.5.5 0 1 1-.87-.495 1.5 1.5 0 0 1 2.616.012zM5 9a3 3 0 0 0 6 0H5z"/></symbol><symbol viewBox="0 0 16 16" id="smiley" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM5 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zM5 9h6a3 3 0 0 1-6 0z"/></symbol><symbol viewBox="0 0 16 16" id="snippet" xmlns="http://www.w3.org/2000/svg"><path d="M10.67 9.31a3.001 3.001 0 0 1 2.062 5.546 3 3 0 0 1-3.771-4.559 1.007 1.007 0 0 1-.095-.137l-4.5-7.794a1 1 0 0 1 1.732-1l4.5 7.794c.028.05.052.1.071.15zm-3.283.35l-.289.5c-.028.05-.06.095-.095.137a3.001 3.001 0 0 1-3.77 4.56A3 3 0 0 1 5.294 9.31c.02-.051.043-.102.071-.15l.866-1.5 1.155 2zm2.31-4l-1.156-2 1.325-2.294a1 1 0 0 1 1.732 1L9.696 5.66zm-5.465 7.464a1 1 0 1 0 1-1.732 1 1 0 0 0-1 1.732zm7.5 0a1 1 0 1 0-1-1.732 1 1 0 0 0 1 1.732z"/></symbol><symbol viewBox="0 0 16 16" id="spam" xmlns="http://www.w3.org/2000/svg"><path d="M8.75.433l5.428 3.134a1.5 1.5 0 0 1 .75 1.299v6.268a1.5 1.5 0 0 1-.75 1.299L8.75 15.567a1.5 1.5 0 0 1-1.5 0l-5.428-3.134a1.5 1.5 0 0 1-.75-1.299V4.866a1.5 1.5 0 0 1 .75-1.299L7.25.433a1.5 1.5 0 0 1 1.5 0zM3.072 5.155v5.69L8 13.691l4.928-2.846v-5.69L8 2.309 3.072 5.155zM8 4a1 1 0 0 1 1 1v3a1 1 0 1 1-2 0V5a1 1 0 0 1 1-1zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 14 14" id="spinner" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><circle cx="7" cy="7" r="6" stroke="#000" stroke-opacity=".1" stroke-width="2"/><path fill="#000" fill-opacity=".1" fill-rule="nonzero" d="M7 0a7 7 0 0 1 7 7h-2a5 5 0 0 0-5-5V0z"/></g></symbol><symbol viewBox="0 0 16 16" id="star" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.609 14.394l-3.465 1.473a1 1 0 0 1-1.39-.989l.276-4.024a1 1 0 0 0-.219-.694L.303 7.037A1 1 0 0 1 .83 5.443l3.715-.964a1 1 0 0 0 .609-.457L7.14.682a1 1 0 0 1 1.72 0l1.985 3.34a1 1 0 0 0 .609.457l3.715.964a1 1 0 0 1 .528 1.594L13.19 10.16a1 1 0 0 0-.219.694l.275 4.024a1 1 0 0 1-1.389.989l-3.465-1.473a1 1 0 0 0-.782 0z"/></symbol><symbol viewBox="0 0 16 16" id="star-o" xmlns="http://www.w3.org/2000/svg"><path d="M10.975 10.99a3 3 0 0 1 .655-2.083l1.54-1.916-2.219-.576a3 3 0 0 1-1.825-1.37L8 3.15 6.874 5.044a3 3 0 0 1-1.825 1.371l-2.218.576 1.54 1.916a3 3 0 0 1 .654 2.083l-.165 2.4 1.965-.836a3 3 0 0 1 2.348 0l1.965.836-.164-2.399zM7.61 14.394l-3.465 1.473a1 1 0 0 1-1.39-.989l.276-4.024a1 1 0 0 0-.219-.694L.303 7.037A1 1 0 0 1 .83 5.443l3.715-.964a1 1 0 0 0 .609-.457L7.14.682a1 1 0 0 1 1.72 0l1.985 3.34a1 1 0 0 0 .609.457l3.715.964a1 1 0 0 1 .528 1.594L13.19 10.16a1 1 0 0 0-.219.694l.275 4.024a1 1 0 0 1-1.389.989l-3.465-1.473a1 1 0 0 0-.782 0z"/></symbol><symbol viewBox="0 0 14 14" id="status_canceled" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M5.2 3.8l4.9 4.9c.2.2.2.5 0 .7l-.7.7c-.2.2-.5.2-.7 0L3.8 5.2c-.2-.2-.2-.5 0-.7l.7-.7c.2-.2.5-.2.7 0"/></g></symbol><symbol viewBox="0 0 22 22" id="status_canceled_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M8.171 5.971l7.7 7.7a.76.76 0 0 1 0 1.1l-1.1 1.1a.76.76 0 0 1-1.1 0l-7.7-7.7a.76.76 0 0 1 0-1.1l1.1-1.1a.76.76 0 0 1 1.1 0"/></symbol><symbol viewBox="0 0 16 16" id="status_closed" xmlns="http://www.w3.org/2000/svg"><path d="M7.536 8.657l2.828-2.83a1 1 0 0 1 1.414 1.416l-3.535 3.535a1 1 0 0 1-1.415.001l-2.12-2.12a1 1 0 1 1 1.413-1.415zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 14 14" id="status_created" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><circle cx="7" cy="7" r="3.25"/></g></symbol><symbol viewBox="0 0 22 22" id="status_created_borderless" xmlns="http://www.w3.org/2000/svg"><circle cx="11" cy="11" r="5.107"/></symbol><symbol viewBox="0 0 14 14" id="status_failed" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M7 5.969L5.599 4.568a.29.29 0 0 0-.413.004l-.614.614a.294.294 0 0 0-.004.413L5.968 7l-1.4 1.401a.29.29 0 0 0 .004.413l.614.614c.113.114.3.117.413.004L7 8.032l1.401 1.4a.29.29 0 0 0 .413-.004l.614-.614a.294.294 0 0 0 .004-.413L8.032 7l1.4-1.401a.29.29 0 0 0-.004-.413l-.614-.614a.294.294 0 0 0-.413-.004L7 5.968z"/></g></symbol><symbol viewBox="0 0 22 22" id="status_failed_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M11 9.38L8.798 7.178a.455.455 0 0 0-.65.006l-.964.965a.462.462 0 0 0-.006.65L9.38 11l-2.202 2.202a.455.455 0 0 0 .006.65l.965.964a.462.462 0 0 0 .65.006L11 12.62l2.202 2.202a.455.455 0 0 0 .65-.006l.964-.965a.462.462 0 0 0 .006-.65L12.62 11l2.202-2.202a.455.455 0 0 0-.006-.65l-.965-.964a.462.462 0 0 0-.65-.006L11 9.38z"/></symbol><symbol viewBox="0 0 14 14" id="status_manual" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M10.5 7.63V6.37l-.787-.13c-.044-.175-.132-.349-.263-.61l.481-.652-.918-.913-.657.478a2.346 2.346 0 0 0-.612-.26L7.656 3.5H6.388l-.132.783c-.219.043-.394.13-.612.26l-.657-.478-.918.913.437.652c-.131.218-.175.392-.262.61l-.744.086v1.261l.787.13c.044.218.132.392.263.61l-.438.651.92.913.655-.434c.175.086.394.173.613.26l.131.783h1.313l.131-.783c.219-.043.394-.13.613-.26l.656.478.918-.913-.48-.652c.13-.218.218-.435.262-.61l.656-.13zM7 8.283a1.285 1.285 0 0 1-1.313-1.305c0-.739.57-1.304 1.313-1.304.744 0 1.313.565 1.313 1.304 0 .74-.57 1.305-1.313 1.305z"/></g></symbol><symbol viewBox="0 0 22 22" id="status_manual_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M16.5 11.99v-1.98l-1.238-.206c-.068-.273-.206-.546-.412-.956l.756-1.025-1.444-1.435-1.03.752a3.686 3.686 0 0 0-.963-.41L12.03 5.5h-1.994l-.206 1.23c-.343.068-.618.205-.962.41l-1.031-.752-1.444 1.435.687 1.025c-.206.341-.275.615-.412.956L5.5 9.941v1.981l1.237.205c.07.342.207.615.413.957l-.688 1.025 1.444 1.434 1.032-.683c.274.137.618.274.962.41l.206 1.23h2.063l.206-1.23c.344-.068.619-.205.963-.41l1.03.752 1.444-1.435-.756-1.025c.207-.341.344-.683.413-.956l1.031-.205zM11 13.017c-1.169 0-2.063-.889-2.063-2.05 0-1.162.894-2.05 2.063-2.05s2.063.888 2.063 2.05c0 1.161-.894 2.05-2.063 2.05z"/></symbol><symbol viewBox="0 0 22 22" id="status_notfound_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M12.822 11.29c.816-.581 1.421-1.348 1.683-2.322.603-2.243-.973-4.553-3.53-4.553-1.15 0-2.085.41-2.775 1.089-.42.413-.672.835-.8 1.167a1.179 1.179 0 0 0 2.2.847c.016-.043.1-.184.252-.334.264-.259.613-.412 1.123-.412.938 0 1.47.78 1.254 1.584-.105.39-.37.726-.773 1.012a3.25 3.25 0 0 1-.945.47 1.179 1.179 0 0 0-.874 1.138v2.234a1.179 1.179 0 1 0 2.358 0v-1.43a5.9 5.9 0 0 0 .827-.492z"/><ellipse cx="10.825" cy="16.711" rx="1.275" ry="1.322"/></symbol><symbol viewBox="0 0 14 14" id="status_open" xmlns="http://www.w3.org/2000/svg"><path d="M0 7c0-3.866 3.142-7 7-7 3.866 0 7 3.142 7 7 0 3.866-3.142 7-7 7-3.866 0-7-3.142-7-7z"/><path d="M1 7c0 3.309 2.69 6 6 6 3.309 0 6-2.69 6-6 0-3.309-2.69-6-6-6-3.309 0-6 2.69-6 6z" fill="#FFF"/><path d="M7 9.219a2.218 2.218 0 1 0 0-4.436A2.218 2.218 0 0 0 7 9.22zm0 1.12a3.338 3.338 0 1 1 0-6.676 3.338 3.338 0 0 1 0 6.676z"/></symbol><symbol viewBox="0 0 14 14" id="status_pending" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M4.7 5.3c0-.2.1-.3.3-.3h.9c.2 0 .3.1.3.3v3.4c0 .2-.1.3-.3.3H5c-.2 0-.3-.1-.3-.3V5.3m3 0c0-.2.1-.3.3-.3h.9c.2 0 .3.1.3.3v3.4c0 .2-.1.3-.3.3H8c-.2 0-.3-.1-.3-.3V5.3"/></g></symbol><symbol viewBox="0 0 22 22" id="status_pending_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M7.386 8.329c0-.315.157-.472.471-.472h1.414c.315 0 .472.157.472.472v5.342c0 .315-.157.472-.472.472H7.857c-.314 0-.471-.157-.471-.472V8.33m4.714 0c0-.315.157-.472.471-.472h1.415c.314 0 .471.157.471.472v5.342c0 .315-.157.472-.471.472H12.57c-.314 0-.471-.157-.471-.472V8.33"/></symbol><symbol viewBox="0 0 14 14" id="status_running" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M7 3c2.2 0 4 1.8 4 4s-1.8 4-4 4c-1.3 0-2.5-.7-3.3-1.7L7 7V3"/></g></symbol><symbol viewBox="0 0 22 22" id="status_running_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M11 4.714c3.457 0 6.286 2.829 6.286 6.286 0 3.457-2.829 6.286-6.286 6.286-2.043 0-3.929-1.1-5.186-2.672L11 11V4.714"/></symbol><symbol viewBox="0 0 14 14" id="status_skipped" xmlns="http://www.w3.org/2000/svg"><path d="M7 14A7 7 0 1 1 7 0a7 7 0 0 1 0 14z"/><path d="M7 13A6 6 0 1 0 7 1a6 6 0 0 0 0 12z" fill="#FFF"/><path d="M6.415 7.04L4.579 5.203a.295.295 0 0 1 .004-.416l.349-.349a.29.29 0 0 1 .416-.004l2.214 2.214a.289.289 0 0 1 .019.021l.132.133c.11.11.108.291 0 .398L5.341 9.573a.282.282 0 0 1-.398 0l-.331-.331a.285.285 0 0 1 0-.399L6.415 7.04zm2.54 0L7.119 5.203a.295.295 0 0 1 .004-.416l.349-.349a.29.29 0 0 1 .416-.004l2.214 2.214a.289.289 0 0 1 .019.021l.132.133c.11.11.108.291 0 .398L7.881 9.573a.282.282 0 0 1-.398 0l-.331-.331a.285.285 0 0 1 0-.399L8.955 7.04z"/></symbol><symbol viewBox="0 0 22 22" id="status_skipped_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M14.072 11.063l-2.82 2.82a.46.46 0 0 0-.001.652l.495.495a.457.457 0 0 0 .653-.001l3.7-3.7a.46.46 0 0 0 .001-.653l-.196-.196a.453.453 0 0 0-.03-.033l-3.479-3.479a.464.464 0 0 0-.654.007l-.548.548a.463.463 0 0 0-.007.654l2.886 2.886z"/><path d="M10.08 11.063l-2.819 2.82a.46.46 0 0 0-.002.652l.496.495a.457.457 0 0 0 .652-.001l3.7-3.7a.46.46 0 0 0 .002-.653l-.196-.196a.453.453 0 0 0-.03-.033l-3.48-3.479a.464.464 0 0 0-.653.007l-.548.548a.463.463 0 0 0-.007.654l2.886 2.886z"/></symbol><symbol viewBox="0 0 14 14" id="status_success" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M6.278 7.697L5.045 6.464a.296.296 0 0 0-.42-.002l-.613.614a.298.298 0 0 0 .002.42l1.91 1.909a.5.5 0 0 0 .703.005l.265-.265L9.997 6.04a.291.291 0 0 0-.009-.408l-.614-.614a.29.29 0 0 0-.408-.009L6.278 7.697z"/></g></symbol><symbol viewBox="0 0 22 22" id="status_success_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M9.866 12.095l-1.95-1.95a.462.462 0 0 0-.647.01l-.964.964a.46.46 0 0 0-.01.646l3.013 3.014a.787.787 0 0 0 1.106.008l.425-.425 4.854-4.853a.462.462 0 0 0 .002-.659l-.964-.964a.468.468 0 0 0-.658.002l-4.207 4.207z"/></symbol><symbol viewBox="0 0 14 14" id="status_success_solid" xmlns="http://www.w3.org/2000/svg"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7zm6.278.697L5.045 6.464a.296.296 0 0 0-.42-.002l-.613.614a.298.298 0 0 0 .002.42l1.91 1.909a.5.5 0 0 0 .703.005l.265-.265L9.997 6.04a.291.291 0 0 0-.009-.408l-.614-.614a.29.29 0 0 0-.408-.009L6.278 7.697z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 14 14" id="status_warning" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M6 3.5c0-.3.2-.5.5-.5h1c.3 0 .5.2.5.5v4c0 .3-.2.5-.5.5h-1c-.3 0-.5-.2-.5-.5v-4m0 6c0-.3.2-.5.5-.5h1c.3 0 .5.2.5.5v1c0 .3-.2.5-.5.5h-1c-.3 0-.5-.2-.5-.5v-1"/></g></symbol><symbol viewBox="0 0 22 22" id="status_warning_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M9.429 5.5c0-.471.314-.786.785-.786h1.572c.471 0 .785.315.785.786v6.286c0 .471-.314.785-.785.785h-1.572c-.471 0-.785-.314-.785-.785V5.5m0 9.429c0-.472.314-.786.785-.786h1.572c.471 0 .785.314.785.786V16.5c0 .471-.314.786-.785.786h-1.572c-.471 0-.785-.315-.785-.786v-1.571"/></symbol><symbol viewBox="0 0 16 16" id="stop" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 0h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2z"/></symbol><symbol viewBox="0 0 16 16" id="task-done" xmlns="http://www.w3.org/2000/svg"><path d="M7.536 8.657l2.828-2.829a1 1 0 0 1 1.414 1.415l-3.535 3.535a.997.997 0 0 1-1.415 0l-2.12-2.121A1 1 0 0 1 6.12 7.243l1.415 1.414zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3z"/></symbol><symbol viewBox="0 0 16 16" id="template" xmlns="http://www.w3.org/2000/svg"><path d="M3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3zm.8 2h2.4a.8.8 0 0 1 .8.8v1.4a.8.8 0 0 1-.8.8H3.8a.8.8 0 0 1-.8-.8V4.8a.8.8 0 0 1 .8-.8zm4.7 0h4a.5.5 0 1 1 0 1h-4a.5.5 0 0 1 0-1zm0 2h4a.5.5 0 1 1 0 1h-4a.5.5 0 0 1 0-1zm-5 3h9a.5.5 0 1 1 0 1h-9a.5.5 0 0 1 0-1zm0 2h9a.5.5 0 1 1 0 1h-9a.5.5 0 1 1 0-1z"/></symbol><symbol viewBox="0 0 16 16" id="terminal" xmlns="http://www.w3.org/2000/svg"><path d="M7 8a.997.997 0 0 1-.293.707l-1.414 1.414a1 1 0 1 1-1.414-1.414L4.586 8l-.707-.707a1 1 0 1 1 1.414-1.414l1.414 1.414A.997.997 0 0 1 7 8zM4 0h8a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm0 2a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H4zm5 7h2a1 1 0 0 1 0 2H9a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="thumb-down" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.33 11h5.282a2 2 0 0 0 1.963-2.38l-.563-2.905a3 3 0 0 0-.243-.732l-1.103-2.286A3 3 0 0 0 10.964 1H7a3 3 0 0 0-3 3v6.3a2 2 0 0 0 .436 1.247l3.11 3.9a.632.632 0 0 0 .941.053l.137-.137a1 1 0 0 0 .28-.87L8.329 11zM1 10h2V3H1a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1z"/></symbol><symbol viewBox="0 0 16 16" id="thumb-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.33 5h5.282a2 2 0 0 1 1.963 2.38l-.563 2.905a3 3 0 0 1-.243.732l-1.103 2.286A3 3 0 0 1 10.964 15H7a3 3 0 0 1-3-3V5.7a2 2 0 0 1 .436-1.247l3.11-3.9A.632.632 0 0 1 8.487.5l.137.137a1 1 0 0 1 .28.87L8.329 5zM1 6h2v7H1a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="thumbtack" xmlns="http://www.w3.org/2000/svg"><path d="M7.125 9h-2.19a.5.5 0 0 1-.417-.777L6 6V2L5.362.724A.5.5 0 0 1 5.809 0h4.382a.5.5 0 0 1 .447.724L10 2v4l1.482 2.223a.5.5 0 0 1-.416.777H8.875L8 16l-.875-7z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 16 16" id="timer" xmlns="http://www.w3.org/2000/svg"><path d="M12.022 3.27l.77-.77a1 1 0 0 1 1.415 1.414l-.728.729a7 7 0 1 1-1.456-1.372zM8 14A5 5 0 1 0 8 4a5 5 0 0 0 0 10zm0-9a1 1 0 0 1 1 1v2a1 1 0 1 1-2 0V6a1 1 0 0 1 1-1zM6 0h4a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="todo-add" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 4V2a1 1 0 0 1 2 0v2h2a1 1 0 0 1 0 2h-2v2a1 1 0 0 1-2 0V6H8a1 1 0 1 1 0-2h2zm2 7a1 1 0 0 1 2 0v2a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h2a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-2z"/></symbol><symbol viewBox="0 0 16 16" id="todo-done" xmlns="http://www.w3.org/2000/svg"><path d="M8.243 7.485l4.95-4.95a1 1 0 1 1 1.414 1.415L8.95 9.607a.997.997 0 0 1-1.414 0L4.707 6.778a1 1 0 0 1 1.414-1.414l2.122 2.121zM12 11a1 1 0 0 1 2 0v2a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h2a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-2z"/></symbol><symbol viewBox="0 0 16 16" id="token" xmlns="http://www.w3.org/2000/svg"><path d="M3 2h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H3zm1 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="unapproval" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M11.95 8.536l1.06-1.061a1 1 0 0 1 1.415 1.414l-1.061 1.06 1.06 1.061a1 1 0 0 1-1.414 1.415l-1.06-1.061-1.06 1.06a1 1 0 1 1-1.415-1.414l1.06-1.06-1.06-1.06a1 1 0 0 1 1.414-1.415l1.06 1.06zm-3.768-.33c.006.503.201 1.006.586 1.39l.353.354-.353.353a2 2 0 1 0 2.828 2.829l.354-.354.047.048C11.964 14.363 11.527 15 6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8c.834 0 1.557.074 2.182.205zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"/></symbol><symbol viewBox="0 0 16 16" id="unassignee" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M11 5h4a1 1 0 0 1 0 2h-4a1 1 0 0 1 0-2zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8s6 2.692 6 4.48c0 1.788-.076 2.52-6 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="unlink" xmlns="http://www.w3.org/2000/svg"><path d="M11.295 8.845l-.659-1.664a1.78 1.78 0 0 0 .04-.04l1.415-1.414c.586-.586.654-1.468.152-1.97s-1.384-.434-1.97.152L8.859 5.323a1.781 1.781 0 0 0-.04.04l-1.664-.658c.141-.208.305-.408.491-.594l1.415-1.414c1.366-1.367 3.424-1.525 4.596-.354 1.171 1.172 1.013 3.23-.354 4.596L11.89 8.354c-.186.186-.386.35-.594.491zm-2.45 2.45a4.075 4.075 0 0 1-.491.594l-1.415 1.414c-1.366 1.367-3.424 1.525-4.596.354-1.171-1.172-1.013-3.23.354-4.596L4.11 7.646c.186-.186.386-.35.594-.491l.659 1.664a1.781 1.781 0 0 0-.04.04l-1.415 1.414c-.586.586-.654 1.468-.152 1.97s1.384.434 1.97-.152l1.414-1.414a1.78 1.78 0 0 0 .04-.04l1.664.658zm3.812-2.088h2a.5.5 0 0 1 .5.5v.05a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-.05a.5.5 0 0 1 .5-.5zm-.384 2.116l1.415 1.414a.5.5 0 0 1 0 .708l-.037.036a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 0-.707l.036-.037a.5.5 0 0 1 .707 0zm-2.823 1.09a.5.5 0 0 1 .5-.5h.052a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5H9.95a.5.5 0 0 1-.5-.5v-2zm-2.748-9.16a.5.5 0 0 1-.5.5h-.05a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5h.05a.5.5 0 0 1 .5.5v2zm-2.116.383a.5.5 0 0 1 0 .707l-.036.036a.5.5 0 0 1-.707 0L2.428 2.965a.5.5 0 0 1 0-.707l.037-.036a.5.5 0 0 1 .707 0l1.414 1.414zm-1.09 2.823h-2a.5.5 0 0 1-.5-.5v-.051a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 .5.5v.05a.5.5 0 0 1-.5.5z"/></symbol><symbol viewBox="0 0 16 16" id="user" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0 8c-6.888 0-6.976-.78-6.976-2.52S2.144 8 8 8s6.976 2.692 6.976 4.48c0 1.788-.088 2.52-6.976 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="users" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.521 8.01C15.103 8.19 16 10.755 16 12.48c0 1.533-.056 2.29-3.808 2.475.609-.54.808-1.331.808-2.475 0-1.911-.804-3.503-2.479-4.47zm-1.67-1.228A3.987 3.987 0 0 0 9.976 4a3.987 3.987 0 0 0-1.125-2.782 3 3 0 1 1 0 5.563zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8s6 2.692 6 4.48c0 1.788-.076 2.52-6 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="volume-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1 5h1v6H1a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1zm2 0l4.445-2.964A1 1 0 0 1 9 2.87v10.26a1 1 0 0 1-1.555.833L3 11V5zm10.283 7.89a.5.5 0 0 1-.66-.752A5.485 5.485 0 0 0 14.5 8c0-1.601-.687-3.09-1.865-4.128a.5.5 0 0 1 .661-.75A6.484 6.484 0 0 1 15.5 8a6.485 6.485 0 0 1-2.217 4.89zm-2.002-2.236a.5.5 0 1 1-.652-.758c.55-.472.871-1.157.871-1.896 0-.732-.315-1.411-.856-1.883a.5.5 0 0 1 .658-.753A3.492 3.492 0 0 1 12.5 8c0 1.033-.45 1.994-1.219 2.654z"/></symbol><symbol viewBox="0 0 16 16" id="warning" xmlns="http://www.w3.org/2000/svg"><path d="M15.34 10.479A3 3 0 0 1 12.756 15h-9.51A3 3 0 0 1 .66 10.479l4.755-8.083a3 3 0 0 1 5.172 0l4.755 8.083zm-6.478-7.07a1 1 0 0 0-1.724 0l-4.755 8.084A1 1 0 0 0 3.245 13h9.51a1 1 0 0 0 .862-1.507L8.862 3.41zM8 5a1 1 0 0 1 1 1v2a1 1 0 1 1-2 0V6a1 1 0 0 1 1-1zm0 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="work" xmlns="http://www.w3.org/2000/svg"><path d="M12 3h1a3 3 0 0 1 3 3v7a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h1V2a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v1zM6 2v1h4V2H6zM3 5a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1H3zm1.5 1a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5zm7 0a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5z"/></symbol></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/clusters_empty.svg b/app/assets/images/illustrations/clusters_empty.svg new file mode 100644 index 00000000000..39627a1c314 --- /dev/null +++ b/app/assets/images/illustrations/clusters_empty.svg @@ -0,0 +1 @@ +<svg height="128" viewBox="0 0 142 128" width="142" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="M94 62h20v4H94z" fill="#f0edf8"/><path d="M84.828 84l17.678 17.678-2.828 2.828L82 86.828z" fill="#fee1d3"/><path d="M42.828 24l17.678 17.678-2.828 2.828L40 26.828zM40 101.678L57.678 84l2.828 2.828-17.678 17.678z" fill="#f0edf8"/><path d="M82 41.678L99.678 24l2.828 2.828-17.678 17.678zM28 62h20v4H28zM3 52h24v24H3z" fill="#fee1d3"/><path d="M31 3h24v24H31z" fill="#f0edf8"/><path d="M87 3h24v24H87z" fill="#fef0e8"/><path d="M115 52h24v24h-24z" fill="#f0edf8"/><path d="M87 101h24v24H87z" fill="#fee1d3"/><path d="M31 101h24v24H31z" fill="#f0edf8"/><path d="M49 42h44v44H49z" fill="#c3b8e3"/><g fill-rule="nonzero"><path d="M5 53a1 1 0 0 0-1 1v20a1 1 0 0 0 1 1h20a1 1 0 0 0 1-1V54a1 1 0 0 0-1-1zm0-4h20a5 5 0 0 1 5 5v20a5 5 0 0 1-5 5H5a5 5 0 0 1-5-5V54a5 5 0 0 1 5-5z" fill="#fdc4a8"/><path d="M56 43a6 6 0 0 0-6 6v30a6 6 0 0 0 6 6h30a6 6 0 0 0 6-6V49a6 6 0 0 0-6-6zm0-4h30c5.523 0 10 4.477 10 10v30c0 5.523-4.477 10-10 10H56c-5.523 0-10-4.477-10-10V49c0-5.523 4.477-10 10-10z" fill="#6b4fbb"/><path d="M89 4a1 1 0 0 0-1 1v20a1 1 0 0 0 1 1h20a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1zm0-4h20a5 5 0 0 1 5 5v20a5 5 0 0 1-5 5H89a5 5 0 0 1-5-5V5a5 5 0 0 1 5-5z" fill="#fee1d3"/><path d="M89 102a1 1 0 0 0-1 1v20a1 1 0 0 0 1 1h20a1 1 0 0 0 1-1v-20a1 1 0 0 0-1-1zm0-4h20a5 5 0 0 1 5 5v20a5 5 0 0 1-5 5H89a5 5 0 0 1-5-5v-20a5 5 0 0 1 5-5z" fill="#fdc4a8"/><path d="M117 53a1 1 0 0 0-1 1v20a1 1 0 0 0 1 1h20a1 1 0 0 0 1-1V54a1 1 0 0 0-1-1zm0-4h20a5 5 0 0 1 5 5v20a5 5 0 0 1-5 5h-20a5 5 0 0 1-5-5V54a5 5 0 0 1 5-5zM33 102a1 1 0 0 0-1 1v20a1 1 0 0 0 1 1h20a1 1 0 0 0 1-1v-20a1 1 0 0 0-1-1zm0-4h20a5 5 0 0 1 5 5v20a5 5 0 0 1-5 5H33a5 5 0 0 1-5-5v-20a5 5 0 0 1 5-5zM33 4a1 1 0 0 0-1 1v20a1 1 0 0 0 1 1h20a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1zm0-4h20a5 5 0 0 1 5 5v20a5 5 0 0 1-5 5H33a5 5 0 0 1-5-5V5a5 5 0 0 1 5-5z" fill="#e1dbf1"/></g></g></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/convdev/convdev_no_data.svg b/app/assets/images/illustrations/convdev/convdev_no_data.svg new file mode 100644 index 00000000000..b90eddcccfa --- /dev/null +++ b/app/assets/images/illustrations/convdev/convdev_no_data.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="360" height="220" viewBox="0 0 360 220"><g fill="none" fill-rule="evenodd"><path fill="#000" fill-opacity=".02" d="M125 44V24.003C125 18.48 129.483 14 135.005 14h89.99C230.52 14 235 18.477 235 24.003V43h84.992C326.624 43 332 48.372 332 55.002v144.996c0 6.63-5.38 12.002-12.008 12.002h-85.984c-6.632 0-12.008-5.372-12.008-12.002V183h-78v17.002c0 6.626-5.38 11.998-12.008 11.998H46.008C39.376 212 34 206.624 34 200.002V55.998C34 49.372 39.38 44 46.008 44H125z"/><g transform="translate(214 36)"><rect width="110" height="168" x="2" y="2" fill="#FFF" rx="10"/><path fill="#EEE" fill-rule="nonzero" d="M4 12.006c0-2.208.896-4.27 2.457-5.77a2 2 0 0 0-2.773-2.883A11.974 11.974 0 0 0 0 12.006a2 2 0 1 0 4 0zM14.388 4h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm17.51.227a8.015 8.015 0 0 1 5.022 3.756 2 2 0 1 0 3.458-2.011A12.01 12.01 0 0 0 104.844.34a2 2 0 0 0-.946 3.887zM110 16.78v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm-.024 17.844a7.99 7.99 0 0 1-2.903 5.558 2 2 0 0 0 2.54 3.09 11.977 11.977 0 0 0 4.35-8.338 2.002 2.002 0 0 0-1.838-2.15 2.003 2.003 0 0 0-2.15 1.84zM98.826 168h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-17.334-.4a8.032 8.032 0 0 1-4.71-4.143 1.998 1.998 0 0 0-2.667-.938 1.997 1.997 0 0 0-.938 2.667 12.022 12.022 0 0 0 7.063 6.21 1.998 1.998 0 1 0 1.252-3.798zM4 154.434v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0z"/><path fill="#F0EDF8" fill-rule="nonzero" d="M57 111c-11.598 0-21-9.402-21-21s9.402-21 21-21 21 9.402 21 21-9.402 21-21 21zm0-4c9.39 0 17-7.61 17-17s-7.61-17-17-17-17 7.61-17 17 7.61 17 17 17z"/><path fill="#6B4FBB" d="M58 88v-6.997c0-1.11-.895-2.003-2-2.003-1.112 0-2 .897-2 2.003v8.994a1.999 1.999 0 0 0 2.503 1.94c.162.04.33.063.506.063h7.98a2 2 0 0 0 .001-4H58z"/><rect width="8" height="4" x="8" y="14" fill="#EEE" rx="2"/><path fill="#EEE" d="M21 16c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 21 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 34 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 47 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 60 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 73 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 86 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 99 16z"/></g><g transform="translate(118 7)"><rect width="110" height="168" x="2" y="2" fill="#FFF" rx="10"/><path fill="#EEE" fill-rule="nonzero" d="M4 12.006c0-2.208.896-4.27 2.457-5.77a2 2 0 0 0-2.773-2.883A11.974 11.974 0 0 0 0 12.006a2 2 0 1 0 4 0zM14.388 4h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm17.51.227a8.015 8.015 0 0 1 5.022 3.756 2 2 0 1 0 3.458-2.011A12.01 12.01 0 0 0 104.844.34a2 2 0 0 0-.946 3.887zM110 16.78v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm-.024 17.844a7.99 7.99 0 0 1-2.903 5.558 2 2 0 0 0 2.54 3.09 11.977 11.977 0 0 0 4.35-8.338 2.002 2.002 0 0 0-1.838-2.15 2.003 2.003 0 0 0-2.15 1.84zM98.826 168h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-17.334-.4a8.032 8.032 0 0 1-4.71-4.143 1.998 1.998 0 0 0-2.667-.938 1.997 1.997 0 0 0-.938 2.667 12.022 12.022 0 0 0 7.063 6.21 1.998 1.998 0 1 0 1.252-3.798zM4 154.434v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0z"/><g fill-rule="nonzero"><path fill="#F0EDF8" d="M57 112c-12.15 0-22-9.85-22-22s9.85-22 22-22 22 9.85 22 22-9.85 22-22 22zm0-6c8.837 0 16-7.163 16-16s-7.163-16-16-16-16 7.163-16 16 7.163 16 16 16z"/><path fill="#6B4FBB" d="M41.692 105.8A21.93 21.93 0 0 0 57 112c12.15 0 22-9.85 22-22s-9.85-22-22-22v6c8.837 0 16 7.163 16 16s-7.163 16-16 16a15.935 15.935 0 0 1-11.133-4.508l-4.175 4.31z"/></g><path fill="#EEE" d="M8 16c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2H9.998A1.995 1.995 0 0 1 8 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 21 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 34 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 47 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 60 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 73 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 86 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 99 16z"/></g><g transform="translate(26 36)"><rect width="110" height="168" x="2" y="2" fill="#FFF" rx="10"/><path fill="#EEE" fill-rule="nonzero" d="M4 12.006v147.988A8 8 0 0 0 12.005 168h89.99a8.007 8.007 0 0 0 8.005-8.006V12.006A8 8 0 0 0 101.995 4h-89.99A8.007 8.007 0 0 0 4 12.006zm-4 0C0 5.376 5.377 0 12.005 0h89.99C108.628 0 114 5.37 114 12.006v147.988c0 6.63-5.377 12.006-12.005 12.006h-89.99C5.372 172 0 166.63 0 159.994V12.006z"/><g transform="translate(21 82)"><rect width="24" height="4" y="10" fill="#F0EDF8" rx="2"/><rect width="14" height="4" x="5" fill="#6B4FBB" rx="2"/></g><g transform="translate(69 82)"><rect width="24" height="4" y="10" fill="#F0EDF8" rx="2"/><rect width="14" height="4" x="5" fill="#6B4FBB" rx="2"/></g><g transform="translate(38 42)"><rect width="22" height="4" x="8" fill="#FEE1D3" rx="2"/><rect width="38" height="4" y="12" fill="#FB722E" rx="2"/></g><path fill="#EEE" d="M4 14h106v4H4z"/><path fill="#333" d="M35.724 138h9.696v-2.856h-2.856V122.76h-2.592c-1.08.648-2.136 1.08-3.792 1.392v2.184h2.856v8.808h-3.312V138zm17.736.288c-2.952 0-5.76-2.208-5.76-7.56 0-5.688 2.952-8.256 6.168-8.256 2.016 0 3.48.84 4.44 1.824l-1.848 2.112c-.528-.576-1.488-1.08-2.376-1.08-1.68 0-3.024 1.2-3.144 4.752.792-1.008 2.112-1.608 3.048-1.608 2.616 0 4.536 1.488 4.536 4.704 0 3.168-2.304 5.112-5.064 5.112zm-.072-2.64c1.056 0 1.92-.744 1.92-2.472 0-1.608-.84-2.208-1.992-2.208-.792 0-1.68.432-2.304 1.512.312 2.4 1.32 3.168 2.376 3.168zM63.9 132c-2.256 0-3.888-1.848-3.888-4.992 0-3.12 1.632-4.944 3.888-4.944 2.256 0 3.912 1.824 3.912 4.944 0 3.144-1.656 4.992-3.912 4.992zm0-1.968c.792 0 1.44-.792 1.44-3.024s-.648-2.976-1.44-2.976c-.792 0-1.44.744-1.44 2.976s.648 3.024 1.44 3.024zm.528 8.256l8.448-16.224h2.04l-8.448 16.224h-2.04zm11.016 0c-2.256 0-3.888-1.848-3.888-4.992 0-3.12 1.632-4.944 3.888-4.944 2.256 0 3.912 1.824 3.912 4.944 0 3.144-1.656 4.992-3.912 4.992zm0-1.968c.792 0 1.44-.792 1.44-3.024s-.648-2.976-1.44-2.976c-.792 0-1.44.744-1.44 2.976s.648 3.024 1.44 3.024z"/></g></g></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/convdev/convdev_no_index.svg b/app/assets/images/illustrations/convdev/convdev_no_index.svg new file mode 100644 index 00000000000..4aaf505e0b8 --- /dev/null +++ b/app/assets/images/illustrations/convdev/convdev_no_index.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="360" height="200" viewBox="0 0 360 200"><g fill="none" fill-rule="evenodd" transform="translate(3 11)"><rect width="110" height="168" x="6" y="8" fill="#000" fill-opacity=".02" rx="10"/><g transform="translate(0 2)"><rect width="110" height="168" fill="#FFF" rx="10"/><path fill="#EEE" fill-rule="nonzero" d="M2 10.006v147.988A8 8 0 0 0 10.005 166h89.99a8.007 8.007 0 0 0 8.005-8.006V10.006A8 8 0 0 0 99.995 2h-89.99A8.007 8.007 0 0 0 2 10.006zm-4 0C-2 3.376 3.377-2 10.005-2h89.99C106.628-2 112 3.37 112 10.006v147.988c0 6.63-5.377 12.006-12.005 12.006h-89.99C3.372 170-2 164.63-2 157.994V10.006z"/><g transform="translate(19 80)"><rect width="24" height="4" y="10" fill="#F0EDF8" rx="2"/><rect width="14" height="4" x="5" fill="#6B4FBB" rx="2"/></g><g transform="translate(67 80)"><rect width="24" height="4" y="10" fill="#F0EDF8" rx="2"/><rect width="14" height="4" x="5" fill="#6B4FBB" rx="2"/></g><g transform="translate(36 40)"><rect width="22" height="4" x="8" fill="#FEE1D3" rx="2"/><rect width="38" height="4" y="12" fill="#FB722E" rx="2"/></g><path fill="#EEE" d="M2 12h106v4H2z"/><path fill="#333" d="M38.048 127.792c.792 0 1.68-.432 2.28-1.512-.312-2.4-1.296-3.168-2.376-3.168-1.032 0-1.92.744-1.92 2.472 0 1.608.864 2.208 2.016 2.208zm-.552 8.496c-2.016 0-3.504-.864-4.464-1.824l1.872-2.112c.504.576 1.464 1.08 2.352 1.08 1.704 0 3.024-1.2 3.144-4.752-.792 1.008-2.112 1.608-3.048 1.608-2.592 0-4.536-1.488-4.536-4.704 0-3.168 2.304-5.112 5.064-5.112 2.952 0 5.784 2.208 5.784 7.56 0 5.688-2.976 8.256-6.168 8.256zm13.488 0c-3.048 0-5.304-1.704-5.304-4.176 0-1.848 1.152-2.976 2.592-3.744v-.096c-1.176-.888-2.04-1.992-2.04-3.6 0-2.592 2.04-4.2 4.872-4.2 2.784 0 4.632 1.656 4.632 4.176 0 1.464-.936 2.64-1.992 3.336v.096c1.464.792 2.64 1.968 2.64 3.984 0 2.4-2.16 4.224-5.4 4.224zm.96-9.168c.6-.696.936-1.44.936-2.232 0-1.176-.696-1.968-1.848-1.968-.936 0-1.704.576-1.704 1.752 0 1.248 1.056 1.848 2.616 2.448zm-.888 6.72c1.176 0 2.04-.624 2.04-1.896 0-1.344-1.296-1.848-3.216-2.664-.672.624-1.176 1.488-1.176 2.424 0 1.344 1.08 2.136 2.352 2.136zm10.8-3.84c-2.256 0-3.888-1.848-3.888-4.992 0-3.12 1.632-4.944 3.888-4.944 2.256 0 3.912 1.824 3.912 4.944 0 3.144-1.656 4.992-3.912 4.992zm0-1.968c.792 0 1.44-.792 1.44-3.024s-.648-2.976-1.44-2.976c-.792 0-1.44.744-1.44 2.976s.648 3.024 1.44 3.024zm.528 8.256l8.448-16.224h2.04l-8.448 16.224h-2.04zm11.016 0c-2.256 0-3.888-1.848-3.888-4.992 0-3.12 1.632-4.944 3.888-4.944 2.256 0 3.912 1.824 3.912 4.944 0 3.144-1.656 4.992-3.912 4.992zm0-1.968c.792 0 1.44-.792 1.44-3.024s-.648-2.976-1.44-2.976c-.792 0-1.44.744-1.44 2.976s.648 3.024 1.44 3.024z"/></g><g transform="translate(122)"><rect width="110" height="168" x="2" y="2" fill="#FFF" rx="10"/><path fill="#EEE" fill-rule="nonzero" d="M4 12.006c0-2.208.896-4.27 2.457-5.77a2 2 0 0 0-2.773-2.883A11.974 11.974 0 0 0 0 12.006a2 2 0 1 0 4 0zM14.388 4h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm17.51.227a8.015 8.015 0 0 1 5.022 3.756 2 2 0 1 0 3.458-2.011A12.01 12.01 0 0 0 104.844.34a2 2 0 0 0-.946 3.887zM110 16.78v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm-.024 17.844a7.99 7.99 0 0 1-2.903 5.558 2 2 0 0 0 2.54 3.09 11.977 11.977 0 0 0 4.35-8.338 2.002 2.002 0 0 0-1.838-2.15 2.003 2.003 0 0 0-2.15 1.84zM98.826 168h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-17.334-.4a8.032 8.032 0 0 1-4.71-4.143 1.998 1.998 0 0 0-2.667-.938 1.997 1.997 0 0 0-.938 2.667 12.022 12.022 0 0 0 7.063 6.21 1.998 1.998 0 1 0 1.252-3.798zM4 154.434v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0z"/><g transform="translate(21 82)"><rect width="24" height="4" y="10" fill="#F0EDF8" rx="2"/><rect width="14" height="4" x="5" fill="#C3B8E3" rx="2"/></g><g transform="translate(69 82)"><rect width="24" height="4" y="10" fill="#F0EDF8" rx="2"/><rect width="14" height="4" x="5" fill="#C3B8E3" rx="2"/></g><path fill="#FEE1D3" d="M44 44a2 2 0 0 1 1.998-2h2.004a2 2 0 0 1 0 4h-2.004A1.994 1.994 0 0 1 44 44zm10 0a2 2 0 0 1 1.998-2h2.004a2 2 0 0 1 0 4h-2.004A1.994 1.994 0 0 1 54 44zm10 0a2 2 0 0 1 1.998-2h2.004a2 2 0 0 1 0 4h-2.004A1.994 1.994 0 0 1 64 44zM34 56a2 2 0 0 1 1.998-2h2.004a2 2 0 0 1 0 4h-2.004A1.994 1.994 0 0 1 34 56zm10 0a2 2 0 0 1 1.998-2h2.004a2 2 0 0 1 0 4h-2.004A1.994 1.994 0 0 1 44 56zm10 0a2 2 0 0 1 1.998-2h2.004a2 2 0 0 1 0 4h-2.004A1.994 1.994 0 0 1 54 56zm10 0a2 2 0 0 1 1.998-2h2.004a2 2 0 0 1 0 4h-2.004A1.994 1.994 0 0 1 64 56zm10 0a2 2 0 0 1 1.998-2h2.004a2 2 0 0 1 0 4h-2.004A1.994 1.994 0 0 1 74 56z"/><rect width="8" height="4" x="8" y="14" fill="#EEE" rx="2"/><rect width="8" height="4" x="21" y="14" fill="#EEE" rx="2"/><rect width="8" height="4" x="34" y="14" fill="#EEE" rx="2"/><rect width="8" height="4" x="47" y="14" fill="#EEE" rx="2"/><rect width="8" height="4" x="60" y="14" fill="#EEE" rx="2"/><rect width="8" height="4" x="73" y="14" fill="#EEE" rx="2"/><rect width="8" height="4" x="86" y="14" fill="#EEE" rx="2"/><rect width="8" height="4" x="99" y="14" fill="#EEE" rx="2"/><path fill="#EEE" d="M46.716 138.288c-3.264 0-5.448-2.784-5.448-7.968s2.184-7.848 5.448-7.848c3.264 0 5.448 2.664 5.448 7.848 0 5.184-2.184 7.968-5.448 7.968zm0-2.736c1.2 0 2.112-1.08 2.112-5.232 0-4.176-.912-5.112-2.112-5.112-1.176 0-2.112.936-2.112 5.112 0 4.152.936 5.232 2.112 5.232zM57.564 132c-2.256 0-3.888-1.848-3.888-4.992 0-3.12 1.632-4.944 3.888-4.944 2.256 0 3.912 1.824 3.912 4.944 0 3.144-1.656 4.992-3.912 4.992zm0-1.968c.792 0 1.44-.792 1.44-3.024s-.648-2.976-1.44-2.976c-.792 0-1.44.744-1.44 2.976s.648 3.024 1.44 3.024zm.528 8.256l8.448-16.224h2.04l-8.448 16.224h-2.04zm11.016 0c-2.256 0-3.888-1.848-3.888-4.992 0-3.12 1.632-4.944 3.888-4.944 2.256 0 3.912 1.824 3.912 4.944 0 3.144-1.656 4.992-3.912 4.992zm0-1.968c.792 0 1.44-.792 1.44-3.024s-.648-2.976-1.44-2.976c-.792 0-1.44.744-1.44 2.976s.648 3.024 1.44 3.024z"/></g><g transform="translate(243)"><rect width="110" height="168" x="2" y="2" fill="#FFF" rx="10"/><path fill="#EEE" fill-rule="nonzero" d="M4 12.006c0-2.208.896-4.27 2.457-5.77a2 2 0 0 0-2.773-2.883A11.974 11.974 0 0 0 0 12.006a2 2 0 1 0 4 0zM14.388 4h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm17.51.227a8.015 8.015 0 0 1 5.022 3.756 2 2 0 1 0 3.458-2.011A12.01 12.01 0 0 0 104.844.34a2 2 0 0 0-.946 3.887zM110 16.78v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm-.024 17.844a7.99 7.99 0 0 1-2.903 5.558 2 2 0 0 0 2.54 3.09 11.977 11.977 0 0 0 4.35-8.338 2.002 2.002 0 0 0-1.838-2.15 2.003 2.003 0 0 0-2.15 1.84zM98.826 168h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-17.334-.4a8.032 8.032 0 0 1-4.71-4.143 1.998 1.998 0 0 0-2.667-.938 1.997 1.997 0 0 0-.938 2.667 12.022 12.022 0 0 0 7.063 6.21 1.998 1.998 0 1 0 1.252-3.798zM4 154.434v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0z"/><path fill="#FEE1D3" d="M44 44a2 2 0 0 1 1.998-2h2.004a2 2 0 0 1 0 4h-2.004A1.994 1.994 0 0 1 44 44zm10 0a2 2 0 0 1 1.998-2h2.004a2 2 0 0 1 0 4h-2.004A1.994 1.994 0 0 1 54 44zm10 0a2 2 0 0 1 1.998-2h2.004a2 2 0 0 1 0 4h-2.004A1.994 1.994 0 0 1 64 44zM34 56a2 2 0 0 1 1.998-2h2.004a2 2 0 0 1 0 4h-2.004A1.994 1.994 0 0 1 34 56zm10 0a2 2 0 0 1 1.998-2h2.004a2 2 0 0 1 0 4h-2.004A1.994 1.994 0 0 1 44 56zm10 0a2 2 0 0 1 1.998-2h2.004a2 2 0 0 1 0 4h-2.004A1.994 1.994 0 0 1 54 56zm10 0a2 2 0 0 1 1.998-2h2.004a2 2 0 0 1 0 4h-2.004A1.994 1.994 0 0 1 64 56zm10 0a2 2 0 0 1 1.998-2h2.004a2 2 0 0 1 0 4h-2.004A1.994 1.994 0 0 1 74 56z"/><g transform="translate(21 82)"><rect width="24" height="4" y="10" fill="#F0EDF8" rx="2"/><rect width="14" height="4" x="5" fill="#C3B8E3" rx="2"/></g><g transform="translate(69 82)"><rect width="24" height="4" y="10" fill="#F0EDF8" rx="2"/><rect width="14" height="4" x="5" fill="#C3B8E3" rx="2"/></g><rect width="8" height="4" x="8" y="14" fill="#EEE" rx="2"/><rect width="8" height="4" x="21" y="14" fill="#EEE" rx="2"/><rect width="8" height="4" x="34" y="14" fill="#EEE" rx="2"/><rect width="8" height="4" x="47" y="14" fill="#EEE" rx="2"/><rect width="8" height="4" x="60" y="14" fill="#EEE" rx="2"/><rect width="8" height="4" x="73" y="14" fill="#EEE" rx="2"/><rect width="8" height="4" x="86" y="14" fill="#EEE" rx="2"/><rect width="8" height="4" x="99" y="14" fill="#EEE" rx="2"/><path fill="#EEE" d="M46.716 138.288c-3.264 0-5.448-2.784-5.448-7.968s2.184-7.848 5.448-7.848c3.264 0 5.448 2.664 5.448 7.848 0 5.184-2.184 7.968-5.448 7.968zm0-2.736c1.2 0 2.112-1.08 2.112-5.232 0-4.176-.912-5.112-2.112-5.112-1.176 0-2.112.936-2.112 5.112 0 4.152.936 5.232 2.112 5.232zM57.564 132c-2.256 0-3.888-1.848-3.888-4.992 0-3.12 1.632-4.944 3.888-4.944 2.256 0 3.912 1.824 3.912 4.944 0 3.144-1.656 4.992-3.912 4.992zm0-1.968c.792 0 1.44-.792 1.44-3.024s-.648-2.976-1.44-2.976c-.792 0-1.44.744-1.44 2.976s.648 3.024 1.44 3.024zm.528 8.256l8.448-16.224h2.04l-8.448 16.224h-2.04zm11.016 0c-2.256 0-3.888-1.848-3.888-4.992 0-3.12 1.632-4.944 3.888-4.944 2.256 0 3.912 1.824 3.912 4.944 0 3.144-1.656 4.992-3.912 4.992zm0-1.968c.792 0 1.44-.792 1.44-3.024s-.648-2.976-1.44-2.976c-.792 0-1.44.744-1.44 2.976s.648 3.024 1.44 3.024z"/></g></g></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/convdev/convdev_overview.svg b/app/assets/images/illustrations/convdev/convdev_overview.svg new file mode 100644 index 00000000000..a06d70812ca --- /dev/null +++ b/app/assets/images/illustrations/convdev/convdev_overview.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="208" height="127" viewBox="0 0 208 127" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><rect id="a" width="58" height="98" y="17" rx="6"/><rect id="b" width="58" height="98" x="3.5" y="17" rx="6"/><rect id="c" width="58" height="98.394" rx="6"/></defs><g fill="none" fill-rule="evenodd" transform="translate(1)"><path fill="#000" fill-opacity=".06" fill-rule="nonzero" d="M16 11.06c0-1.39.56-2.69 1.534-3.635.398-.386.41-1.025.027-1.426a.993.993 0 0 0-1.413-.028A7.075 7.075 0 0 0 14 11.062c0 .556.448 1.007 1 1.007s1-.452 1-1.01zm6.432-5.043h4.8c.552 0 1-.452 1-1.01 0-.556-.448-1.007-1-1.007h-4.8c-.552 0-1 .45-1 1.008 0 .557.448 1.01 1 1.01zm10.8 0h4.8c.552 0 1-.452 1-1.01 0-.556-.448-1.007-1-1.007h-4.8c-.552 0-1 .45-1 1.008 0 .557.448 1.01 1 1.01zm10.8 0h4.8c.552 0 1-.452 1-1.01 0-.556-.448-1.007-1-1.007h-4.8c-.552 0-1 .45-1 1.008 0 .557.448 1.01 1 1.01zm10.8 0h4.8c.552 0 1-.452 1-1.01 0-.556-.448-1.007-1-1.007h-4.8c-.552 0-1 .45-1 1.008 0 .557.448 1.01 1 1.01zm10.8 0h4.8c.552 0 1-.452 1-1.01 0-.556-.448-1.007-1-1.007h-4.8c-.552 0-1 .45-1 1.008 0 .557.448 1.01 1 1.01zm10.8 0h4.8c.552 0 1-.452 1-1.01 0-.556-.448-1.007-1-1.007h-4.8c-.552 0-1 .45-1 1.008 0 .557.448 1.01 1 1.01zm10.8 0h4.8c.552 0 1-.452 1-1.01 0-.556-.448-1.007-1-1.007h-4.8c-.552 0-1 .45-1 1.008 0 .557.448 1.01 1 1.01zm10.8 0h4.8c.552 0 1-.452 1-1.01 0-.556-.448-1.007-1-1.007h-4.8c-.552 0-1 .45-1 1.008 0 .557.448 1.01 1 1.01zm10.8 0h4.8c.552 0 1-.452 1-1.01 0-.556-.448-1.007-1-1.007h-4.8c-.552 0-1 .45-1 1.008 0 .557.448 1.01 1 1.01zm10.8 0h4.8c.552 0 1-.452 1-1.01 0-.556-.448-1.007-1-1.007h-4.8c-.552 0-1 .45-1 1.008 0 .557.448 1.01 1 1.01zm10.8 0h4.8c.552 0 1-.452 1-1.01 0-.556-.448-1.007-1-1.007h-4.8c-.552 0-1 .45-1 1.008 0 .557.448 1.01 1 1.01zm10.8 0h4.8c.552 0 1-.452 1-1.01 0-.556-.448-1.007-1-1.007h-4.8c-.552 0-1 .45-1 1.008 0 .557.448 1.01 1 1.01zm10.8 0h4.8c.552 0 1-.452 1-1.01 0-.556-.448-1.007-1-1.007h-4.8c-.552 0-1 .45-1 1.008 0 .557.448 1.01 1 1.01zm10.8 0h4.8c.552 0 1-.452 1-1.01 0-.556-.448-1.007-1-1.007h-4.8c-.552 0-1 .45-1 1.008 0 .557.448 1.01 1 1.01zm10.8 0h4.8c.552 0 1-.452 1-1.01 0-.556-.448-1.007-1-1.007h-4.8c-.552 0-1 .45-1 1.008 0 .557.448 1.01 1 1.01zm10.8 0H185a4.95 4.95 0 0 1 3.254 1.215.995.995 0 0 0 1.41-.108c.36-.423.312-1.06-.107-1.422A6.944 6.944 0 0 0 185 4h-.568c-.552 0-1 .45-1 1.008 0 .557.448 1.01 1 1.01zM190 11.932v4.84c0 .557.448 1.008 1 1.008s1-.45 1-1.008v-4.84c0-.556-.448-1.008-1-1.008s-1 .452-1 1.008zm0 10.89v4.84c0 .556.448 1.008 1 1.008s1-.452 1-1.01v-4.838c0-.557-.448-1.01-1-1.01s-1 .453-1 1.01zm0 10.89v4.84c0 .555.448 1.007 1 1.007s1-.453 1-1.01v-4.84c0-.556-.448-1.007-1-1.007s-1 .45-1 1.008zm0 10.888v4.84c0 .557.448 1.008 1 1.008s1-.45 1-1.008V44.6c0-.557-.448-1.008-1-1.008s-1 .45-1 1.008zm0 10.89v4.84c0 .556.448 1.007 1 1.007s1-.45 1-1.008v-4.84c0-.557-.448-1.01-1-1.01s-1 .453-1 1.01zm0 10.89v4.838c0 .557.448 1.01 1 1.01s1-.453 1-1.01v-4.84c0-.556-.448-1.008-1-1.008s-1 .452-1 1.01zm0 10.888v4.84c0 .556.448 1.008 1 1.008s1-.452 1-1.008v-4.84c0-.557-.448-1.008-1-1.008s-1 .45-1 1.008zm0 10.89v4.84c0 .556.448 1.007 1 1.007s1-.45 1-1.008v-4.84c0-.557-.448-1.008-1-1.008s-1 .45-1 1.007zm0 10.888v4.84c0 .557.448 1.008 1 1.008s1-.45 1-1.008v-4.84c0-.556-.448-1.008-1-1.008s-1 .452-1 1.008zm-.24 21.446a5.06 5.06 0 0 1-2.572 2.985 1.01 1.01 0 0 0-.46 1.348c.24.5.84.708 1.336.464a7.06 7.06 0 0 0 3.598-4.178c.17-.53-.12-1.098-.644-1.27a1 1 0 0 0-1.26.65zm-8.063 3.49h-4.8c-.552 0-1 .453-1 1.01 0 .557.448 1.008 1 1.008h4.8c.553 0 1-.45 1-1.008 0-.557-.447-1.01-1-1.01zm-10.8 0h-4.8c-.552 0-1 .453-1 1.01 0 .557.448 1.008 1 1.008h4.8c.553 0 1-.45 1-1.008 0-.557-.447-1.01-1-1.01zm-10.8 0h-4.8c-.552 0-1 .453-1 1.01 0 .557.448 1.008 1 1.008h4.8c.553 0 1-.45 1-1.008 0-.557-.447-1.01-1-1.01zm-10.8 0h-4.8c-.552 0-1 .453-1 1.01 0 .557.448 1.008 1 1.008h4.8c.553 0 1-.45 1-1.008 0-.557-.447-1.01-1-1.01zm-10.8 0h-4.8c-.552 0-1 .453-1 1.01 0 .557.448 1.008 1 1.008h4.8c.553 0 1-.45 1-1.008 0-.557-.447-1.01-1-1.01zm-10.8 0h-4.8c-.552 0-1 .453-1 1.01 0 .557.448 1.008 1 1.008h4.8c.553 0 1-.45 1-1.008 0-.557-.447-1.01-1-1.01zm-10.8 0h-4.8c-.552 0-1 .453-1 1.01 0 .557.448 1.008 1 1.008h4.8c.553 0 1-.45 1-1.008 0-.557-.447-1.01-1-1.01zm-10.8 0h-4.8c-.552 0-1 .453-1 1.01 0 .557.448 1.008 1 1.008h4.8c.553 0 1-.45 1-1.008 0-.557-.447-1.01-1-1.01zm-10.8 0h-4.8c-.552 0-1 .453-1 1.01 0 .557.448 1.008 1 1.008h4.8c.553 0 1-.45 1-1.008 0-.557-.447-1.01-1-1.01zm-10.8 0h-4.8c-.552 0-1 .453-1 1.01 0 .557.448 1.008 1 1.008h4.8c.553 0 1-.45 1-1.008 0-.557-.447-1.01-1-1.01zm-10.8 0h-4.8c-.552 0-1 .453-1 1.01 0 .557.448 1.008 1 1.008h4.8c.553 0 1-.45 1-1.008 0-.557-.447-1.01-1-1.01zm-10.8 0h-4.8c-.552 0-1 .453-1 1.01 0 .557.448 1.008 1 1.008h4.8c.553 0 1-.45 1-1.008 0-.557-.447-1.01-1-1.01zm-10.8 0h-4.8c-.552 0-1 .453-1 1.01 0 .557.448 1.008 1 1.008h4.8c.553 0 1-.45 1-1.008 0-.557-.447-1.01-1-1.01zm-10.8 0h-4.8c-.552 0-1 .453-1 1.01 0 .557.448 1.008 1 1.008h4.8c.553 0 1-.45 1-1.008 0-.557-.447-1.01-1-1.01zm-10.8 0h-4.8c-.552 0-1 .453-1 1.01 0 .557.448 1.008 1 1.008h4.8c.553 0 1-.45 1-1.008 0-.557-.447-1.01-1-1.01zm-10.577-.116a5.009 5.009 0 0 1-3.19-2.3.994.994 0 0 0-1.373-.333c-.472.29-.62.91-.332 1.386.99 1.632 2.6 2.8 4.465 3.215a1 1 0 0 0 1.192-.768 1.005 1.005 0 0 0-.762-1.2zM16 105.292v-4.84c0-.556-.448-1.008-1-1.008s-1 .452-1 1.01v4.838c0 .557.448 1.01 1 1.01s1-.453 1-1.01zm0-10.89v-4.84c0-.555-.448-1.007-1-1.007s-1 .452-1 1.008v4.84c0 .557.448 1.008 1 1.008s1-.45 1-1.007zm0-10.888v-4.84c0-.557-.448-1.008-1-1.008s-1 .45-1 1.008v4.84c0 .557.448 1.008 1 1.008s1-.45 1-1.008zm0-10.89v-4.84c0-.556-.448-1.007-1-1.007s-1 .45-1 1.008v4.84c0 .556.448 1.008 1 1.008s1-.452 1-1.008zm0-10.89v-4.838c0-.557-.448-1.01-1-1.01s-1 .453-1 1.01v4.84c0 .556.448 1.008 1 1.008s1-.452 1-1.01zm0-11.888v-4.84c0-.556-.448-1.008-1-1.008s-1 .452-1 1.008v4.84c0 .557.448 1.008 1 1.008s1-.45 1-1.008zm0-9.89v-4.84c0-.556-.448-1.007-1-1.007s-1 .45-1 1.007v4.84c0 .557.448 1.008 1 1.008s1-.45 1-1.008zm0-10.888v-4.84c0-.557-.448-1.008-1-1.008s-1 .45-1 1.008v4.84c0 .556.448 1.008 1 1.008s1-.452 1-1.008zm0-10.89v-4.84c0-.556-.448-1.008-1-1.008s-1 .452-1 1.01v4.838c0 .557.448 1.01 1 1.01s1-.453 1-1.01z"/><g transform="translate(74)"><rect width="58" height="98" y="20" fill="#000" fill-opacity=".02" rx="6"/><use fill="#FFF" xlink:href="#a"/><rect width="56" height="96" x="1" y="18" stroke="#EEE" stroke-width="2" rx="6"/><g transform="translate(16 45.185)"><path fill="#333" d="M.59 33.815h5.655V32.15H4.58v-7.225H3.066c-.63.378-1.246.63-2.212.812v1.274H2.52v5.14H.59v1.665zm10.093.168c-1.778 0-3.094-.994-3.094-2.436 0-1.078.67-1.736 1.51-2.184v-.056c-.685-.518-1.19-1.162-1.19-2.1 0-1.512 1.19-2.45 2.843-2.45 1.624 0 2.702.966 2.702 2.436 0 .854-.546 1.54-1.162 1.946v.055c.854.462 1.54 1.148 1.54 2.324 0 1.4-1.26 2.463-3.15 2.463zm.56-5.348c.35-.406.546-.84.546-1.302 0-.686-.407-1.148-1.08-1.148-.545 0-.993.336-.993 1.022 0 .728.616 1.078 1.526 1.428zm-.518 3.92c.686 0 1.19-.364 1.19-1.106 0-.785-.756-1.08-1.876-1.555-.393.364-.687.868-.687 1.414 0 .783.63 1.245 1.372 1.245zm6.3-2.24c-1.316 0-2.268-1.078-2.268-2.912 0-1.82.952-2.884 2.268-2.884 1.316 0 2.282 1.063 2.282 2.883 0 1.834-.966 2.912-2.282 2.912zm0-1.148c.462 0 .84-.462.84-1.764s-.378-1.736-.84-1.736c-.462 0-.84.434-.84 1.736s.378 1.764.84 1.764zm.308 4.816l4.928-9.464h1.19l-4.927 9.463h-1.19zm6.426 0c-1.317 0-2.27-1.078-2.27-2.912 0-1.82.953-2.883 2.27-2.883 1.315 0 2.28 1.064 2.28 2.884 0 1.835-.965 2.913-2.28 2.913zm0-1.148c.46 0 .84-.462.84-1.764 0-1.3-.38-1.735-.84-1.735-.463 0-.84.434-.84 1.736 0 1.303.377 1.765.84 1.765z"/><rect width="13" height="2" x="6" y=".815" fill="#FB722E" rx="1"/><path fill="#F0EDF8" d="M3 47.815c0-.552.455-1 .992-1h18.016c.548 0 .992.444.992 1 0 .553-.455 1-.992 1H3.992a.994.994 0 0 1-.992-1zm0 6c0-.552.455-1 .992-1h18.016c.548 0 .992.444.992 1 0 .553-.455 1-.992 1H3.992a.994.994 0 0 1-.992-1z"/><rect width="20" height="2" x="3" y="6.815" fill="#FEE1D3" rx="1"/></g><g transform="translate(10.81)"><circle cx="18.19" cy="18" r="18" fill="#FFF"/><path fill="#F0EDF8" fill-rule="nonzero" d="M18.19 34c8.837 0 16-7.163 16-16s-7.163-16-16-16-16 7.163-16 16 7.163 16 16 16zm0 2c-9.94 0-18-8.06-18-18s8.06-18 18-18 18 8.06 18 18-8.06 18-18 18z"/><g transform="translate(10 11)"><path fill="#C3B8E3" fill-rule="nonzero" d="M2.19 13.32L5.397 11h7.783a.998.998 0 0 0 1.01-1V3c0-.55-.45-1-1.01-1H3.2a.998.998 0 0 0-1.01 1v10.32zM6.045 13l-3.422 2.476C1.28 16.45.19 15.892.19 14.23V3c0-1.657 1.337-3 3.01-3h9.98a3.004 3.004 0 0 1 3.01 3v7c0 1.657-1.337 3-3.01 3H6.045z"/><rect width="4" height="2" x="5.19" y="4" fill="#6B4FBB" rx="1"/><rect width="6" height="2" x="5.19" y="7" fill="#6B4FBB" rx="1"/></g></g></g><g transform="translate(144.5)"><rect width="58" height="98" x=".5" y="20" fill="#000" fill-opacity=".02" rx="6"/><use fill="#FFF" xlink:href="#b"/><rect width="56" height="96" x="4.5" y="18" stroke="#EEE" stroke-width="2" rx="6"/><g transform="translate(19 46.185)"><path fill="#333" d="M4.01 33.746c1.793 0 3.305-.938 3.305-2.59 0-1.148-.742-1.876-1.764-2.17v-.056c.953-.406 1.485-1.05 1.485-1.974 0-1.554-1.232-2.436-3.066-2.436-1.093 0-1.99.434-2.8 1.134l1.035 1.26c.56-.49 1.036-.784 1.666-.784.7 0 1.093.364 1.093.98 0 .714-.504 1.19-2.1 1.19v1.456c1.932 0 2.394.49 2.394 1.274 0 .672-.574 1.05-1.442 1.05-.756 0-1.414-.378-1.946-.896l-.953 1.302c.644.756 1.652 1.26 3.094 1.26zm4.51-.168h6.257v-1.736h-1.792c-.42 0-1.036.056-1.484.112 1.443-1.512 2.843-3.108 2.843-4.606 0-1.708-1.19-2.828-2.94-2.828-1.274 0-2.1.476-2.982 1.414l1.12 1.106c.45-.476.94-.91 1.583-.91.77 0 1.26.476 1.26 1.344 0 1.26-1.596 2.786-3.864 4.928v1.176zm9.505-3.5c-1.316 0-2.268-1.078-2.268-2.912 0-1.82.952-2.884 2.268-2.884 1.316 0 2.282 1.064 2.282 2.884 0 1.834-.966 2.912-2.282 2.912zm0-1.148c.462 0 .84-.462.84-1.764s-.378-1.736-.84-1.736c-.462 0-.84.434-.84 1.736s.378 1.764.84 1.764zm.308 4.816l4.928-9.464h1.19l-4.927 9.464h-1.19zm6.426 0c-1.317 0-2.27-1.078-2.27-2.912 0-1.82.953-2.884 2.27-2.884 1.315 0 2.28 1.064 2.28 2.884 0 1.834-.965 2.912-2.28 2.912zm0-1.148c.46 0 .84-.462.84-1.764s-.38-1.736-.84-1.736c-.463 0-.84.434-.84 1.736s.377 1.764.84 1.764z"/><rect width="13" height="2.008" x="7.5" fill="#FB722E" rx="1.004"/><path fill="#F0EDF8" d="M3.5 47.19c0-.556.455-1.005 1.006-1.005h17.988c.556 0 1.006.445 1.006 1.004 0 .553-.455 1.003-1.006 1.003H4.506A1.003 1.003 0 0 1 3.5 47.188zm0 6.023c0-.555.455-1.004 1.006-1.004h17.988c.556 0 1.006.444 1.006 1.003 0 .554-.455 1.004-1.006 1.004H4.506A1.003 1.003 0 0 1 3.5 53.212z"/><rect width="20" height="2.008" x="4" y="6.024" fill="#FEE1D3" rx="1.004"/></g><g transform="translate(14.413)"><circle cx="18.087" cy="18" r="18" fill="#FFF"/><path fill="#F0EDF8" fill-rule="nonzero" d="M18.087 34c8.836 0 16-7.163 16-16s-7.164-16-16-16c-8.837 0-16 7.163-16 16s7.163 16 16 16zm0 2c-9.942 0-18-8.06-18-18s8.058-18 18-18c9.94 0 18 8.06 18 18s-8.06 18-18 18z"/><path fill="#C3B8E3" fill-rule="nonzero" d="M18.087 24a6 6 0 1 0 0-12 6 6 0 0 0 0 12zm0 2c-4.42 0-8-3.582-8-8s3.58-8 8-8a8 8 0 0 1 0 16z"/><path fill="#6B4FBB" d="M19.087 17v-2c0-.556-.448-1-1-1-.557 0-1 .448-1 1v3a.997.997 0 0 0 .998 1h3c.557 0 1-.448 1-1 0-.556-.447-1-1-1h-2z"/></g></g><rect width="58" height="98" x="3" y="20" fill="#000" fill-opacity=".02" rx="6"/><g transform="translate(0 16.754)"><use fill="#FFF" xlink:href="#c"/><rect width="56" height="96.394" x="1" y="1" stroke="#EEE" stroke-width="2" rx="6"/><g transform="translate(16 29.618)"><path fill="#333" d="M3.137 27.84c.462 0 .98-.253 1.33-.883-.182-1.4-.756-1.848-1.386-1.848-.6 0-1.12.433-1.12 1.44 0 .94.505 1.29 1.177 1.29zm-.322 4.955A3.626 3.626 0 0 1 .21 31.73l1.093-1.23c.294.335.854.63 1.372.63.994 0 1.764-.7 1.834-2.773-.463.588-1.233.938-1.78.938-1.51 0-2.645-.868-2.645-2.744 0-1.847 1.344-2.98 2.954-2.98 1.72 0 3.373 1.287 3.373 4.41 0 3.317-1.736 4.815-3.598 4.815zm8.12 0c-1.722 0-3.36-1.288-3.36-4.41 0-3.318 1.722-4.816 3.598-4.816 1.176 0 2.03.49 2.59 1.063l-1.078 1.232c-.308-.336-.868-.63-1.386-.63-.98 0-1.765.7-1.835 2.772.462-.588 1.232-.938 1.778-.938 1.526 0 2.646.867 2.646 2.743 0 1.848-1.345 2.982-2.955 2.982zm-.042-1.54c.616 0 1.12-.434 1.12-1.442 0-.938-.49-1.288-1.162-1.288-.46 0-.98.252-1.343.882.182 1.4.77 1.848 1.386 1.848zm6.132-2.128c-1.316 0-2.268-1.078-2.268-2.912 0-1.82.952-2.884 2.268-2.884 1.316 0 2.282 1.065 2.282 2.885 0 1.834-.966 2.912-2.282 2.912zm0-1.148c.462 0 .84-.463.84-1.765 0-1.302-.378-1.736-.84-1.736-.462 0-.84.433-.84 1.735s.378 1.764.84 1.764zm.308 4.815l4.928-9.464h1.19l-4.927 9.465h-1.19zm6.426 0c-1.317 0-2.27-1.078-2.27-2.912 0-1.82.953-2.884 2.27-2.884 1.315 0 2.28 1.063 2.28 2.883 0 1.834-.965 2.912-2.28 2.912zm0-1.148c.46 0 .84-.462.84-1.764s-.38-1.736-.84-1.736c-.463 0-.84.434-.84 1.736s.377 1.764.84 1.764z"/><rect width="13" height="2.008" x="6.5" y=".314" fill="#FEE1D3" rx="1.004"/><path fill="#F0EDF8" d="M3 46.627c0-.552.455-1 .992-1h18.016c.548 0 .992.444.992 1 0 .553-.455 1-.992 1H3.992a.994.994 0 0 1-.992-1zm0 6c0-.552.455-1 .992-1h18.016c.548 0 .992.444.992 1 0 .553-.455 1-.992 1H3.992a.994.994 0 0 1-.992-1z"/><rect width="20" height="2" x="3" y="5.627" fill="#FB722E" rx="1"/></g></g><g transform="translate(10.41)"><circle cx="18.589" cy="18" r="18" fill="#FFF"/><path fill="#F0EDF8" fill-rule="nonzero" d="M18.59 34c8.836 0 16-7.163 16-16s-7.164-16-16-16c-8.837 0-16 7.163-16 16s7.163 16 16 16zm0 2c-9.942 0-18-8.06-18-18s8.058-18 18-18c9.94 0 18 8.06 18 18s-8.06 18-18 18z"/><path fill="#C3B8E3" d="M17.05 19.262h3.367l.248-2.808H17.3l-.25 2.808zm-.177 2.008l-.144 1.627c-.06.662-.646 1.2-1.3 1.2h.25c-.658 0-1.144-.534-1.085-1.2l.144-1.627H13.59a1.001 1.001 0 0 1-1.003-1.004c0-.555.455-1.004 1.002-1.004h1.325l.248-2.808h-1.15a1 1 0 0 1-1.004-1.004 1.01 1.01 0 0 1 1.004-1.004h1.33l.106-1.2c.058-.66.644-1.198 1.298-1.198h-.25c.66 0 1.145.533 1.086 1.2l-.106 1.198h3.365l.107-1.2c.058-.66.644-1.198 1.298-1.198h-.25c.66 0 1.145.533 1.086 1.2l-.106 1.198h1.03c.554 0 1.003.446 1.003 1.004 0 .555-.455 1.004-1 1.004H22.8l-.25 2.808h1.037a1 1 0 0 1 1.002 1.004c0 .554-.456 1.004-1.003 1.004h-1.214l-.144 1.627c-.06.662-.646 1.2-1.3 1.2h.25c-.658 0-1.144-.534-1.085-1.2l.144-1.627H16.87z"/><path fill="#6B4FBB" d="M17.05 19.262l-.177 2.008H14.74l.177-2.008h2.134zm-1.707-4.816h2.135l-.178 2.008h-2.135l.178-2.008zm5.5 0h2.135l-.178 2.008h-2.135l.178-2.008zm1.708 4.816l-.177 2.008H20.24l.177-2.008h2.134z"/></g></g></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/convdev/i2p_step_1.svg b/app/assets/images/illustrations/convdev/i2p_step_1.svg new file mode 100644 index 00000000000..67467b1513d --- /dev/null +++ b/app/assets/images/illustrations/convdev/i2p_step_1.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M45.688 18.854c-4.869-1.989-10.488-1.975-15.29-.001a20.014 20.014 0 0 0-6.493 4.268 19.798 19.798 0 0 0-4.346 6.381 19.135 19.135 0 0 0-1.525 7.537c0 2.066.33 4.118.983 6.104a20.142 20.142 0 0 0 1.83 3.937 5.983 5.983 0 0 0-2.086 4.538c0 3.309 2.691 6 6 6s6-2.691 6-6-2.691-6-6-6c-.779 0-1.522.154-2.205.425a18.13 18.13 0 0 1-1.642-3.533 17.467 17.467 0 0 1-.881-5.472c0-2.351.459-4.623 1.391-6.814a17.721 17.721 0 0 1 3.88-5.675 18.057 18.057 0 0 1 5.85-3.845c4.329-1.778 9.392-1.79 13.78.002a18.077 18.077 0 0 1 5.843 3.84c3.39 3.34 5.257 7.776 5.257 12.493a17.463 17.463 0 0 1-.878 5.481 17.451 17.451 0 0 1-2.569 4.923c-2.134 2.866-3.818 4.698-5.174 6.173-2.424 2.643-3.98 4.599-4.383 8.384H32.215a1 1 0 1 0 0 2h11.739a1 1 0 0 0 .999-.947c.19-3.645 1.345-5.263 3.934-8.09 1.385-1.506 3.107-3.381 5.304-6.331a19.422 19.422 0 0 0 2.864-5.489c.651-1.98.98-4.04.979-6.109 0-5.256-2.078-10.198-5.856-13.92a20.079 20.079 0 0 0-6.49-4.265M28.761 51.612c0 2.206-1.794 4-4 4s-4-1.794-4-4 1.794-4 4-4 4 1.794 4 4M40 74h-4a1 1 0 1 0 0 2h4a1 1 0 1 0 0-2M42 70h-8a1 1 0 1 0 0 2h8a1 1 0 1 0 0-2M38 10a1 1 0 0 0 1-1V1a1 1 0 1 0-2 0v8a1 1 0 0 0 1 1M20.828 15.828a.999.999 0 0 0 .707-1.707l-5.656-5.656a.999.999 0 1 0-1.414 1.414l5.656 5.656a.997.997 0 0 0 .707.293M10 33H2a1 1 0 1 0 0 2h8a1 1 0 1 0 0-2M60.12 8.465l-5.656 5.656a.999.999 0 1 0 1.414 1.414l5.656-5.656a.999.999 0 1 0-1.414-1.414M74 33h-8a1 1 0 1 0 0 2h8a1 1 0 1 0 0-2M43 66H33a1 1 0 1 0 0 2h10a1 1 0 1 0 0-2"/></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/convdev/i2p_step_10.svg b/app/assets/images/illustrations/convdev/i2p_step_10.svg new file mode 100644 index 00000000000..588ecd81414 --- /dev/null +++ b/app/assets/images/illustrations/convdev/i2p_step_10.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M5 43a1 1 0 1 0 2 0v-4h4a1 1 0 1 0 0-2H7v-4a1 1 0 1 0-2 0v4H1a1 1 0 1 0 0 2h4v4M75 37h-4v-4a1 1 0 1 0-2 0v4h-4a1 1 0 1 0 0 2h4v4a1 1 0 1 0 2 0v-4h4a1 1 0 1 0 0-2M21 38a1 1 0 0 0 .47.848l8 5a.999.999 0 0 0 1.061-1.696L23.887 38l6.644-4.152a1 1 0 1 0-1.061-1.695l-8 5A.998.998 0 0 0 21 38M55 38a1 1 0 0 0-.47-.848l-8-5a.999.999 0 1 0-1.061 1.695L52.113 38l-6.644 4.152a1 1 0 1 0 1.061 1.696l8-5A1 1 0 0 0 55 38M41.803 26.05a1 1 0 0 0-1.256.65l-7 22a1.001 1.001 0 0 0 .953 1.303 1 1 0 0 0 .953-.697l7-22a1.001 1.001 0 0 0-.65-1.256M62 7c3.859 0 7 3.141 7 7v11a1 1 0 1 0 2 0V14c0-4.963-4.04-9-9-9H45.91c-.479-2.833-2.943-5-5.91-5-3.309 0-6 2.691-6 6s2.691 6 6 6c2.967 0 5.431-2.167 5.91-5H62m-22 3c-2.206 0-4-1.794-4-4s1.794-4 4-4 4 1.794 4 4-1.794 4-4 4M6 26a1 1 0 0 0 1-1V14c0-3.859 3.141-7 7-7h11.09l-3.293 3.293a.999.999 0 1 0 1.414 1.414l5-5a.999.999 0 0 0 0-1.414l-5-5a.999.999 0 1 0-1.414 1.414L25.09 5H14c-4.963 0-9 4.04-9 9v11a1 1 0 0 0 1 1M36 64c-2.967 0-5.431 2.167-5.91 5H14c-3.859 0-7-3.141-7-7V51a1 1 0 1 0-2 0v11c0 4.963 4.04 9 9 9h16.09c.478 2.833 2.942 5 5.91 5 3.309 0 6-2.691 6-6s-2.691-6-6-6m0 10c-2.206 0-4-1.794-4-4s1.794-4 4-4 4 1.794 4 4-1.794 4-4 4M70 50a1 1 0 0 0-1 1v11c0 3.859-3.141 7-7 7H50.91l3.293-3.293a.999.999 0 1 0-1.414-1.414l-5 5a.999.999 0 0 0 0 1.414l5 5a.997.997 0 0 0 1.414 0 .999.999 0 0 0 0-1.414L50.91 71H62c4.963 0 9-4.04 9-9V51a1 1 0 0 0-1-1"/></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/convdev/i2p_step_2.svg b/app/assets/images/illustrations/convdev/i2p_step_2.svg new file mode 100644 index 00000000000..4280024c23c --- /dev/null +++ b/app/assets/images/illustrations/convdev/i2p_step_2.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M42.26 40.44a.989.989 0 0 0 1.109-.877l2.625-22.444a.997.997 0 0 0-.993-1.117h-14a1 1 0 0 0-.994 1.108l3.454 31.575a6.981 6.981 0 0 0-2.46 5.317c0 3.859 3.141 7 7 7s7-3.141 7-7-3.141-7-7-7c-.94 0-1.835.189-2.655.527l-3.23-29.527h11.761L41.383 39.33a1 1 0 0 0 .877 1.11m.741 13.562c0 2.757-2.243 5-5 5s-5-2.243-5-5 2.243-5 5-5 5 2.243 5 5"/><path d="M73.236 23.749a1 1 0 0 0-1.854.75A35.788 35.788 0 0 1 74 38c0 19.851-16.149 36-36 36S2 57.851 2 38 18.149 2 38 2c7.6 0 14.83 2.332 20.965 6.74A5.955 5.955 0 0 0 58 12c0 1.603.624 3.109 1.758 4.242A5.956 5.956 0 0 0 64 18a5.956 5.956 0 0 0 4.242-1.758C69.376 15.109 70 13.603 70 12s-.624-3.109-1.758-4.242A5.956 5.956 0 0 0 64 6a5.943 5.943 0 0 0-3.668 1.259C53.812 2.512 46.104 0 38 0 17.047 0 0 17.047 0 38s17.047 38 38 38 38-17.047 38-38c0-4.93-.93-9.725-2.764-14.251zM64 8c1.068 0 2.072.416 2.828 1.172S68 10.932 68 12s-.416 2.072-1.172 2.828c-1.512 1.512-4.145 1.512-5.656 0C60.416 14.072 60 13.068 60 12s.416-2.072 1.172-2.828S62.932 8 64 8z"/></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/convdev/i2p_step_3.svg b/app/assets/images/illustrations/convdev/i2p_step_3.svg new file mode 100644 index 00000000000..7690f91b420 --- /dev/null +++ b/app/assets/images/illustrations/convdev/i2p_step_3.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M12 8c0-3.309-2.691-6-6-6S0 4.691 0 8c0 2.967 2.167 5.431 5 5.91v8.181c-2.833.478-5 2.942-5 5.909s2.167 5.431 5 5.91v8.181c-2.833.478-5 2.942-5 5.909s2.167 5.431 5 5.91v8.181c-2.833.478-5 2.942-5 5.909 0 3.309 2.691 6 6 6s6-2.691 6-6c0-2.967-2.167-5.431-5-5.91v-8.18c2.833-.478 5-2.942 5-5.91s-2.167-5.431-5-5.91v-8.18c2.833-.478 5-2.942 5-5.91s-2.167-5.431-5-5.91v-8.18c2.833-.479 5-2.943 5-5.91M2 8c0-2.206 1.794-4 4-4s4 1.794 4 4-1.794 4-4 4-4-1.794-4-4m8 60c0 2.206-1.794 4-4 4s-4-1.794-4-4 1.794-4 4-4 4 1.794 4 4m0-20c0 2.206-1.794 4-4 4s-4-1.794-4-4 1.794-4 4-4 4 1.794 4 4m0-20c0 2.206-1.794 4-4 4s-4-1.794-4-4 1.794-4 4-4 4 1.794 4 4M21 6h54a1 1 0 1 0 0-2H21a1 1 0 1 0 0 2M21 12h35a1 1 0 1 0 0-2H21a1 1 0 1 0 0 2M75 24H21a1 1 0 1 0 0 2h54a1 1 0 1 0 0-2M21 32h34a1 1 0 1 0 0-2H21a1 1 0 1 0 0 2M75 44H21a1 1 0 1 0 0 2h54a1 1 0 1 0 0-2M21 52h34a1 1 0 1 0 0-2H21a1 1 0 1 0 0 2M75 64H21a1 1 0 1 0 0 2h54a1 1 0 1 0 0-2M55 70H21a1 1 0 1 0 0 2h34a1 1 0 1 0 0-2"/></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/convdev/i2p_step_4.svg b/app/assets/images/illustrations/convdev/i2p_step_4.svg new file mode 100644 index 00000000000..ba21b9e2c3a --- /dev/null +++ b/app/assets/images/illustrations/convdev/i2p_step_4.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M67.7 10h-6.751C60.442 4.402 55.728 0 50 0c-6.06 0-11 4.935-11 11s4.935 11 11 11c5.728 0 10.442-4.402 10.949-10H67.7c1.269 0 2.3.987 2.3 2.2v57.6c0 1.213-1.031 2.2-2.3 2.2H8.3C7.031 74 6 73.013 6 71.8V14.2C6 12.987 7.031 12 8.3 12h15.15a1 1 0 1 0 0-2H8.3C5.929 10 4 11.884 4 14.2v57.6C4 74.116 5.929 76 8.3 76h59.4c2.371 0 4.3-1.884 4.3-4.2V14.2c0-2.316-1.929-4.2-4.3-4.2M50 20c-4.963 0-9-4.04-9-9s4.04-9 9-9 9 4.04 9 9-4.04 9-9 9"/><path d="M21.293 29.29a.999.999 0 0 0 0 1.414l12.975 12.975-12.975 12.974a.999.999 0 1 0 1.414 1.414l13.682-13.682a.999.999 0 0 0 0-1.414L22.707 29.29a.999.999 0 0 0-1.414 0M54 59a1 1 0 1 0 0-2H42a1 1 0 1 0 0 2h12"/></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/convdev/i2p_step_5.svg b/app/assets/images/illustrations/convdev/i2p_step_5.svg new file mode 100644 index 00000000000..3c8f8422a97 --- /dev/null +++ b/app/assets/images/illustrations/convdev/i2p_step_5.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M48.949 37C48.442 31.402 43.728 27 38 27s-10.442 4.402-10.949 10h-13.05a1 1 0 1 0 0 2h13.05c.507 5.598 5.221 10 10.949 10s10.442-4.402 10.949-10h12.24a1 1 0 1 0 0-2h-12.24M38 47c-4.963 0-9-4.04-9-9s4.04-9 9-9 9 4.04 9 9-4.04 9-9 9"/><path d="M73.236 23.749a1 1 0 0 0-1.854.75A35.788 35.788 0 0 1 74 38c0 19.851-16.149 36-36 36S2 57.851 2 38 18.149 2 38 2c7.6 0 14.83 2.332 20.965 6.74A5.955 5.955 0 0 0 58 12c0 1.603.624 3.109 1.758 4.242A5.956 5.956 0 0 0 64 18a5.956 5.956 0 0 0 4.242-1.758C69.376 15.109 70 13.603 70 12s-.624-3.109-1.758-4.242A5.956 5.956 0 0 0 64 6a5.943 5.943 0 0 0-3.668 1.259C53.812 2.512 46.104 0 38 0 17.047 0 0 17.047 0 38s17.047 38 38 38 38-17.047 38-38c0-4.93-.93-9.725-2.764-14.251zM64 8c1.068 0 2.072.416 2.828 1.172S68 10.932 68 12s-.416 2.072-1.172 2.828c-1.512 1.512-4.145 1.512-5.656 0C60.416 14.072 60 13.068 60 12s.416-2.072 1.172-2.828S62.932 8 64 8z"/></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/convdev/i2p_step_6.svg b/app/assets/images/illustrations/convdev/i2p_step_6.svg new file mode 100644 index 00000000000..933860798ad --- /dev/null +++ b/app/assets/images/illustrations/convdev/i2p_step_6.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M14.267 7.32l-4.896 5.277-1.702-1.533a.999.999 0 1 0-1.338 1.486l2.434 2.192c.064.058.139.091.212.13.035.018.065.048.101.062a.99.99 0 0 0 .752-.016c.044-.019.077-.058.118-.084.076-.047.155-.086.219-.154l5.566-6a1 1 0 0 0-1.466-1.36M31 9h44a1 1 0 1 0 0-2H31a1 1 0 1 0 0 2M31 15h24a1 1 0 1 0 0-2H31a1 1 0 1 0 0 2"/><path d="M11 0C4.93 0 0 4.935 0 11s4.935 11 11 11 11-4.935 11-11S17.065 0 11 0m0 20c-4.963 0-9-4.04-9-9s4.04-9 9-9 9 4.04 9 9-4.04 9-9 9M14.267 34.32l-4.896 5.277-1.702-1.533a1 1 0 1 0-1.338 1.486l2.434 2.192c.064.058.139.091.212.13.035.018.065.048.101.062a.99.99 0 0 0 .752-.016c.044-.019.077-.058.118-.084.076-.047.155-.086.219-.154l5.566-6a1 1 0 0 0-1.466-1.36M75 34H31a1 1 0 1 0 0 2h44a1 1 0 1 0 0-2M31 42h24a1 1 0 1 0 0-2H31a1 1 0 1 0 0 2"/><path d="M11 27C4.93 27 0 31.935 0 38s4.935 11 11 11 11-4.935 11-11-4.935-11-11-11m0 20c-4.963 0-9-4.04-9-9s4.04-9 9-9 9 4.04 9 9-4.04 9-9 9M14.267 61.32l-4.896 5.277-1.702-1.533a1 1 0 1 0-1.338 1.486l2.434 2.192c.064.058.139.091.212.13.035.018.065.048.101.062a.99.99 0 0 0 .752-.016c.044-.019.077-.058.118-.084.076-.047.155-.086.219-.154l5.566-6a1 1 0 0 0-1.466-1.36"/><path d="M11 54C4.93 54 0 58.935 0 65s4.935 11 11 11 11-4.935 11-11-4.935-11-11-11m0 20c-4.963 0-9-4.04-9-9s4.04-9 9-9 9 4.04 9 9-4.04 9-9 9M75 61H31a1 1 0 1 0 0 2h44a1 1 0 1 0 0-2M55 67H31a1 1 0 1 0 0 2h24a1 1 0 1 0 0-2"/></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/convdev/i2p_step_7.svg b/app/assets/images/illustrations/convdev/i2p_step_7.svg new file mode 100644 index 00000000000..d97c8f7c2d4 --- /dev/null +++ b/app/assets/images/illustrations/convdev/i2p_step_7.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M73.236 23.749a1 1 0 1 0-1.854.75A35.788 35.788 0 0 1 74 38c0 19.851-16.149 36-36 36S2 57.851 2 38 18.149 2 38 2c7.6 0 14.83 2.332 20.965 6.74A5.955 5.955 0 0 0 58 12c0 1.603.624 3.109 1.758 4.242A5.956 5.956 0 0 0 64 18a5.956 5.956 0 0 0 4.242-1.758C69.376 15.109 70 13.603 70 12s-.624-3.109-1.758-4.242A5.956 5.956 0 0 0 64 6a5.943 5.943 0 0 0-3.668 1.259C53.812 2.512 46.104 0 38 0 17.047 0 0 17.047 0 38s17.047 38 38 38 38-17.047 38-38c0-4.93-.93-9.725-2.764-14.251zM64 8c1.068 0 2.072.416 2.828 1.172S68 10.932 68 12s-.416 2.072-1.172 2.828c-1.512 1.512-4.145 1.512-5.656 0C60.416 14.072 60 13.068 60 12s.416-2.072 1.172-2.828S62.932 8 64 8z"/><path d="M27.19 32.17a.997.997 0 0 0-1.366-.364L13.17 39.132a1 1 0 0 0 0 1.73l12.654 7.326a1 1 0 0 0 1.002-1.73l-11.159-6.461 11.159-6.461a.998.998 0 0 0 .364-1.366M48.808 47.827a1 1 0 0 0 1.366.364l12.654-7.326a1 1 0 0 0 0-1.73l-12.654-7.326a1 1 0 0 0-1.002 1.73L60.331 40l-11.159 6.461a.998.998 0 0 0-.364 1.366M42.71 23.06L31.398 56.29a1 1 0 0 0 1.892.645l11.312-33.23a1 1 0 0 0-1.892-.645"/></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/convdev/i2p_step_8.svg b/app/assets/images/illustrations/convdev/i2p_step_8.svg new file mode 100644 index 00000000000..919bbeff319 --- /dev/null +++ b/app/assets/images/illustrations/convdev/i2p_step_8.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M62.44 54.765l-9.912-11.09c.315-3.881.481-7.241.508-10.271-.029-13.871-3.789-23.05-13.413-32.746-.855-.859-2.411-.828-3.294.059-7.594 7.65-11.139 13.934-12.575 22.3a6.94 6.94 0 0 0-4.699 2.039c-1.321 1.321-2.05 3.079-2.05 4.949s.729 3.628 2.051 4.949c1.321 1.322 3.079 2.051 4.949 2.051s3.628-.729 4.949-2.051a6.951 6.951 0 0 0 2.051-4.949 6.955 6.955 0 0 0-2.051-4.949c-.9-.9-2-1.517-3.205-1.824 1.373-7.859 4.764-13.818 11.999-21.11.128-.13.356-.158.456-.059 9.207 9.274 12.805 18.06 12.832 31.33-.026 3.079-.202 6.527-.536 10.54a.997.997 0 0 0 .25.749l10.166 11.379c.062.076.109.23.093.32l-4.547 17.407c-.004.015-.009.036-.079.106a.403.403 0 0 1-.2.106l-3.577.002c-.144-.009-.265-.077-.309-.153l-5.425-10.328a1.002 1.002 0 0 0-.886-.535H30.024c-.371 0-.713.206-.886.535l-5.407 10.303-.069.072a.366.366 0 0 1-.199.105l-3.588.001c-.179-.009-.304-.123-.33-.227l-4.531-17.338a.525.525 0 0 1 .049-.34L25.26 44.682a1 1 0 0 0-1.492-1.332L13.539 54.803c-.448.554-.63 1.312-.474 2.084l4.544 17.396c.253.963 1.146 1.669 2.218 1.719h3.636c.581 0 1.187-.261 1.615-.693.114-.114.286-.286.406-.528l5.144-9.793h14.754l5.16 9.822c.396.697 1.124 1.143 2.01 1.192l3.712-.003a2.396 2.396 0 0 0 1.544-.694c.313-.316.504-.646.598-1.022l4.557-17.451a2.502 2.502 0 0 0-.518-2.066M29.01 30.001c0 1.335-.521 2.591-1.465 3.535s-2.2 1.465-3.535 1.465-2.591-.521-3.535-1.465-1.465-2.2-1.465-3.535.521-2.591 1.465-3.535 2.2-1.465 3.535-1.465 2.591.521 3.535 1.465 1.465 2.2 1.465 3.535"/></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/convdev/i2p_step_9.svg b/app/assets/images/illustrations/convdev/i2p_step_9.svg new file mode 100644 index 00000000000..2d1b10d430d --- /dev/null +++ b/app/assets/images/illustrations/convdev/i2p_step_9.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M68 67c-1.725 0-3.36.541-4.723 1.545A12.998 12.998 0 0 0 52 62c-2.734 0-5.359.853-7.555 2.43L42.159 49h1.228l3.829 7.645c.339.598.962.979 1.724 1.022l2.812-.003a2.07 2.07 0 0 0 1.316-.595c.264-.266.433-.559.514-.882l3.433-13.145a2.138 2.138 0 0 0-.449-1.763l-7.385-8.268c.231-2.875.354-5.376.374-7.641C49.532 14.863 46.684 7.908 39.393.564c-.737-.742-2.072-.715-2.829.044-5.617 5.659-8.309 10.336-9.446 16.463a5.95 5.95 0 0 0-3.36 1.686C22.624 19.891 22 21.397 22 23s.624 3.109 1.758 4.242C24.891 28.376 26.397 29 28 29s3.109-.624 4.242-1.758C33.376 26.109 34 24.603 34 23s-.624-3.109-1.758-4.242a5.952 5.952 0 0 0-3.098-1.648c1.095-5.538 3.637-9.855 8.83-15.14 6.874 6.924 9.561 13.485 9.581 23.392-.021 2.316-.151 4.903-.402 7.91a.999.999 0 0 0 .25.749l7.663 8.572-3.391 13.07-2.695.036-4.081-8.15a1.001 1.001 0 0 0-.895-.553h-12.01c-.379 0-.725.214-.895.553l-4.04 8.114-2.707.015-3.427-13.07 7.671-8.588a1 1 0 0 0-1.492-1.332l-7.7 8.623c-.383.47-.54 1.116-.406 1.787l3.419 13.08c.216.829.98 1.438 1.907 1.48h2.735c.508 0 1.016-.218 1.391-.595.091-.09.242-.241.358-.475l3.804-7.597h1.228l-2.286 15.43a12.914 12.914 0 0 0-7.555-2.43c-4.685 0-8.979 2.53-11.277 6.545a7.943 7.943 0 0 0-4.723-1.545c-4.411 0-8 3.589-8 8a1 1 0 0 0 1 1h74a1 1 0 0 0 1-1c0-4.411-3.589-8-8-8m-36-44a3.973 3.973 0 0 1-1.172 2.828c-1.512 1.512-4.145 1.512-5.656 0-.756-.756-1.172-1.76-1.172-2.828s.416-2.072 1.172-2.828 1.76-1.172 2.828-1.172 2.072.416 2.828 1.172 1.172 1.76 1.172 2.828m-29.917 51a6.01 6.01 0 0 1 5.917-5c1.638 0 3.17.652 4.313 1.836a.998.998 0 0 0 1.634-.289 11.011 11.011 0 0 1 10.05-6.547c2.836 0 5.532 1.085 7.593 3.055a1.001 1.001 0 0 0 1.681-.576l2.588-17.479h4.275l2.589 17.479a.999.999 0 1 0 1.681.576 10.945 10.945 0 0 1 7.593-3.055c4.343 0 8.288 2.57 10.05 6.547a.998.998 0 0 0 1.634.289 5.948 5.948 0 0 1 4.313-1.836 6.01 6.01 0 0 1 5.917 5H2.076"/></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/logos/go_logo.svg b/app/assets/images/illustrations/logos/go_logo.svg new file mode 100644 index 00000000000..7fd49118006 --- /dev/null +++ b/app/assets/images/illustrations/logos/go_logo.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 16 16"><g fill-rule="evenodd"><path d="M14 16.01h1V7.99C15 4.128 11.866.999 8 .999c-3.858 0-7 3.13-7 6.991v8.02h1V7.99c0-3.306 2.691-5.991 6-5.991 3.314 0 6 2.682 6 5.991v8.02M3.48 2.656a2 2 0 1 0-2.155 3.228c.102-.321.226-.631.371-.93a1.001 1.001 0 1 1 1.069-1.599 6.96 6.96 0 0 1 .717-.699m9.04-.002a2 2 0 1 1 2.155 3.23 6.835 6.835 0 0 0-.37-.931 1 1 0 1 0-1.068-1.599 6.96 6.96 0 0 0-.717-.699"/><path d="M5.726 8.04h1.557v.124c0 .283-.033.534-.1.752a1.583 1.583 0 0 1-.33.566c-.35.394-.795.591-1.335.591-.527 0-.979-.19-1.355-.571a1.893 1.893 0 0 1-.564-1.377c0-.547.191-1.01.574-1.391a1.902 1.902 0 0 1 1.396-.574c.295 0 .57.06.825.181.244.12.484.316.72.586l-.405.388c-.309-.412-.686-.618-1.13-.618-.399 0-.733.138-1 .413-.27.27-.405.609-.405 1.015 0 .42.151.766.452 1.037.282.252.587.378.915.378.28 0 .531-.094.754-.283.223-.19.347-.418.373-.683h-.94v-.535m2.884.061c0-.53.194-.986.583-1.367a1.919 1.919 0 0 1 1.396-.571c.537 0 .998.192 1.382.576.386.384.578.845.578 1.384 0 .542-.194 1-.581 1.379a1.944 1.944 0 0 1-1.408.569c-.487 0-.923-.168-1.311-.505-.426-.373-.64-.861-.64-1.465m.574.007c0 .417.14.759.42 1.028.278.269.6.403.964.403.395 0 .729-.137 1-.41.272-.277.408-.613.408-1.01 0-.402-.134-.739-.403-1.01a1.33 1.33 0 0 0-.991-.41c-.392 0-.723.137-.993.41a1.36 1.36 0 0 0-.405 1m-.184 3.918c.525.026.812.063.812.063.271.025.324-.096.116-.273 0 0-.775-.813-1.933-.813-1.159 0-1.923.813-1.923.813-.211.174-.153.3.12.273 0 0 .286-.037.81-.063v.477c0 .268.224.5.5.5.268 0 .5-.223.5-.498v-.252.25c0 .268.224.5.5.5.268 0 .5-.223.5-.498v-.478m-1-1.023c.552 0 1-.224 1-.5s-.448-.5-1-.5-1 .224-1 .5.448.5 1 .5"/></g></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/logos/mattermost_logo.svg b/app/assets/images/illustrations/logos/mattermost_logo.svg new file mode 100644 index 00000000000..b577c0599aa --- /dev/null +++ b/app/assets/images/illustrations/logos/mattermost_logo.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" version="1" viewBox="0 0 501 501"><path d="M236 .7C137.7 7.5 54 68.2 18.2 158.5c-32 81-19.6 172.8 33 242.5 39.8 53 97.2 87 164.3 97 16.5 2.7 48 3.2 63.5 1.2 48.7-6.3 92.2-24.6 129-54.2 13-10.5 33-31.2 42.2-43.7 26.4-35.5 42.8-75.8 49-120.3 1.6-12.3 1.6-48.7 0-61-4-28.3-12-54.8-24.2-79.5-12.8-26-26.5-45.3-46.8-65.8C417.8 64 400.2 49 398.4 49c-.6 0-.4 10.5.3 26l1.3 26 7 8.7c19 23.7 32.8 53.5 38.2 83 2.5 14 3 43 1 55.8-4.5 27.8-15.2 54-31 76.5-8.6 12.2-28 31.6-40.2 40.2-24 17-50 27.6-80 33-10 1.8-49 1.8-59 0-43-7.7-78.8-26-107.2-54.8-29.3-29.7-46.5-64-52.4-104.4-2-14-1.5-42 1-55C90 121.4 132 72 192 49.7c8-3 18.4-5.8 29.5-8.2 1.7-.4 34.4-38 35.3-40.6.3-1-10.2-1-20.8-.4z"/><path d="M322.2 24.6c-1.3.8-8.4 9.3-16 18.7-7.4 9.5-22.4 28-33.2 41.2-51 62.2-66 81.6-70.6 91-6 12-8.4 21-9 33-1.2 19.8 5 36 19 50C222 268 230 273 243 277.2c9 3 10.4 3.2 24 3.2 13.8 0 15 0 22.6-3 23.2-9 39-28.4 45-55.7 2-8.2 2-28.7.4-79.7l-2-72c-1-36.8-1.4-41.8-3-44-2-3-4.8-3.6-7.8-1.4z"/></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/merge_request_changes_empty.svg b/app/assets/images/illustrations/merge_request_changes_empty.svg new file mode 100644 index 00000000000..707efa736e4 --- /dev/null +++ b/app/assets/images/illustrations/merge_request_changes_empty.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 374 268" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><rect id="d" width="230" height="176" rx="10" fill="#fff"/><rect id="e" width="14" rx="2" height="4"/><rect id="f" width="14" x="40" rx="2" height="4"/><rect id="g" width="14" x="40" y="24" rx="2" height="4"/><rect id="h" width="7" x="20" y="12" rx="2" height="4"/><rect id="i" width="7" y="24" rx="2" height="4"/><rect id="j" width="7" x="33" y="12" rx="2" height="4"/><circle id="l" cx="31" cy="31" r="31"/><circle id="c" cx="35" cy="35" r="35"/><circle id="a" cx="44" cy="44" r="44"/><circle id="b" cx="31" cy="31" r="31"/></defs><g fill="none" fill-rule="evenodd"><g transform="translate(0 94)"><circle cx="57" cy="57" r="44" fill="#f9f9f9"/><g transform="rotate(-7.999 120.507 -22.508)"><use fill="#fff" xlink:href="#a"/><circle cx="44" cy="44" r="42" stroke="#eee" stroke-width="4"/><path fill="#fee1d3" fill-rule="nonzero" d="M34.394 55.736A4 4 0 0 1 36.706 55H56a6 6 0 0 0 6-6V35a6 6 0 0 0-6-6H34a6 6 0 0 0-6 6v25.26l6.394-4.529m2.312 3.264l-7.972 5.647A3.001 3.001 0 0 1 24 62.194v-27.2c0-5.523 4.477-10 10-10h22c5.523 0 10 4.477 10 10v14c0 5.523-4.477 10-10 10H36.706"/><path fill="#fc6d26" d="M38 40a2 2 0 1 1 .001 3.999A2 2 0 0 1 38 40m7 0a2 2 0 1 1 .001 3.999A2 2 0 0 1 45 40m7 0a2 2 0 1 1 .001 3.999A2 2 0 0 1 52 40"/></g></g><g transform="translate(48)"><circle cx="41" cy="41" r="31" fill="#f9f9f9"/><g transform="rotate(-7.999 84.554 -15.551)"><use fill="#fff" xlink:href="#b"/><circle cx="31" cy="31" r="29" stroke="#eee" stroke-width="4"/><rect width="20" height="4" x="21" y="29" fill="#6b4fbb" rx="2"/></g></g><path fill="#f9f9f9" d="M235.58 229H102c-6.627 0-12-5.373-12-12V65c0-6.627 5.373-12 12-12h206c6.627 0 12 5.373 12 12v18.399A34.834 34.834 0 0 1 337 79c19.33 0 35 15.67 35 35s-15.67 35-35 35a34.831 34.831 0 0 1-17-4.399v72.4c0 6.627-5.373 12-12 12h-11.58c.381 1.941.58 3.947.58 6 0 17.12-13.879 31-31 31-17.12 0-31-13.879-31-31 0-2.053.2-4.059.58-6"/><g transform="translate(87 50)"><g transform="rotate(7.999 -44.933 1563.894)"><use fill="#fff" xlink:href="#c"/><circle cx="35" cy="35" r="33" stroke="#eee" stroke-width="4"/><g transform="translate(20 19)"><circle cx="15" cy="16" r="15" fill="#f4f1fa" stroke="#6b4fbb" stroke-width="3"/><g fill="#6b4fbb"><path d="M19.419 6.996h-.007L16.959 4l-2.454 2.997H14.5L12.046 4 9.591 6.998h-.003L7.133 4 4.677 6.999H2.001c2.605-4.204 7.231-7 12.502-7 5.269 0 9.892 2.793 12.498 6.994h-2.676l-2.452-2.994-2.453 2.996"/><circle cx="9.5" cy="17.5" r="1.5"/><circle cx="20.5" cy="17.5" r="1.5"/></g></g></g><use xlink:href="#d"/><rect width="226" height="172" x="2" y="2" stroke="#eee" stroke-width="4" rx="10"/><rect width="4" height="122" x="33" y="42" fill="#eee" rx="2"/><g transform="translate(13 59)"><rect width="10" height="4" fill="#fee1d3" rx="2"/><rect width="10" height="4" y="12" fill="#f0edf8" rx="2"/><rect width="10" height="4" y="24" fill="#fef0e9" rx="2"/><rect width="10" height="4" y="36" fill="#fee1d3" rx="2"/><rect width="10" height="4" y="48" fill="#e1dbf1" rx="2"/><rect width="10" height="4" y="60" fill="#f0edf8" rx="2"/><rect width="10" height="4" y="72" fill="#fef0e9" rx="2"/><rect width="10" height="4" y="84" fill="#fee1d3" rx="2"/></g><g transform="translate(55 59)"><use fill="#6b4fbb" xlink:href="#e"/><rect width="14" height="4" x="20" fill="#f0edf8" rx="2"/><use fill="#fef0e9" xlink:href="#f"/><rect width="14" height="4" y="12" fill="#f0edf8" rx="2"/><use fill="#fef0e9" xlink:href="#g"/><rect width="14" height="4" y="48" fill="#e1dbf1" rx="2"/><rect width="14" height="4" x="40" y="36" fill="#fef0e9" rx="2"/><use fill="#fee1d3" xlink:href="#h"/><rect width="7" height="4" x="27" y="36" fill="#6b4fbb" rx="2"/><rect width="7" height="4" x="20" y="48" fill="#fee1d3" rx="2"/><use fill="#fc6d26" xlink:href="#i"/><rect width="21" height="4" x="13" y="24" fill="#e1dbf1" rx="2"/><rect width="21" height="4" y="36" fill="#eee" rx="2"/><use fill="#6b4fbb" xlink:href="#j"/><g transform="translate(98)"><use fill="#fee1d3" xlink:href="#e"/><rect width="14" height="4" x="20" fill="#f0edf8" rx="2"/><use fill="#fc6d26" xlink:href="#f"/><rect width="14" height="4" y="12" fill="#fef0e9" rx="2" id="k"/><use fill="#e1dbf1" xlink:href="#g"/><rect width="14" height="4" y="48" fill="#f0edf8" rx="2"/><rect width="14" height="4" x="40" y="36" fill="#fee1d3" rx="2"/><use fill="#fc6d26" xlink:href="#h"/><rect width="7" height="4" x="27" y="36" fill="#6b4fbb" rx="2"/><rect width="7" height="4" x="20" y="48" fill="#fc6d26" rx="2"/><use fill="#6b4fbb" xlink:href="#i"/><rect width="21" height="4" x="13" y="24" fill="#fee1d3" rx="2"/><rect width="21" height="4" y="36" fill="#fef0e9" rx="2"/><use fill="#6b4fbb" xlink:href="#j"/></g><g transform="translate(0 60)"><use fill="#f0edf8" xlink:href="#e"/><rect width="14" height="4" x="20" fill="#6b4fbb" rx="2"/><use fill="#e1dbf1" xlink:href="#f"/><use xlink:href="#k"/><use fill="#fee1d3" xlink:href="#g"/><use fill="#eee" xlink:href="#h"/><use fill="#6b4fbb" xlink:href="#i"/><rect width="21" height="4" x="13" y="24" fill="#fef0e9" rx="2"/><use fill="#fc6d26" xlink:href="#j"/></g><rect width="4" height="63" x="74" y="13" fill="#eee" rx="2"/></g><rect width="230" height="4" y="27" fill="#eee" rx="2"/></g><g transform="rotate(7.999 -1289.786 1797.583)"><use fill="#fff" xlink:href="#l"/><circle cx="31" cy="31" r="29" stroke="#eee" stroke-width="4"/><path fill="#fc6d26" d="M29 29h-6a2 2 0 1 0 0 4h6v6a2 2 0 1 0 4 0v-6h6a2 2 0 1 0 0-4h-6v-6a2 2 0 1 0-4 0v6"/></g></g></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/monitoring/getting_started.svg b/app/assets/images/illustrations/monitoring/getting_started.svg index db7a1c2e708..ff783bdd388 100644 --- a/app/assets/images/illustrations/monitoring/getting_started.svg +++ b/app/assets/images/illustrations/monitoring/getting_started.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 406 305" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><rect id="0" width="159.8" height="127.81" x=".196" y="5" rx="10"/><rect id="2" width="160" height="128" x=".666" y=".41" rx="10"/><rect id="4" width="160.19" height="128.19" x=".339" y=".59" rx="10"/><mask id="1" width="159.8" height="127.81" x="0" y="0" fill="#fff"><use xlink:href="#0"/></mask><mask id="3" width="160" height="128" x="0" y="0" fill="#fff"><use xlink:href="#2"/></mask><mask id="5" width="160.19" height="128.19" x="0" y="0" fill="#fff"><use xlink:href="#4"/></mask></defs><g fill="none" fill-rule="evenodd" transform="translate(12 3)"><rect width="160" height="128" x="122.08" y="146.08" fill="#f9f9f9" transform="matrix(.99619.08716-.08716.99619 19.08-16.813)" rx="10"/><g transform="matrix(.96593.25882-.25882.96593 227.1 57.47)"><rect width="159.8" height="127.81" x="1.64" y="10.06" fill="#f9f9f9" rx="8"/><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#1)" xlink:href="#0"/><g transform="translate(24.368 36.951)"><path fill="#d2caea" fill-rule="nonzero" d="m71.785 44.2c.761.296 1.625.099 2.184-.496l35.956-38.34c.756-.806.715-2.071-.091-2.827-.806-.756-2.071-.715-2.827.091l-35.03 37.36-41.888-16.285c-.749-.291-1.6-.106-2.16.471l-26.368 27.16c-.769.793-.751 2.059.042 2.828.793.769 2.059.751 2.828-.042l25.444-26.21 41.911 16.294"/><g fill="#fff"><circle cx="5.716" cy="5.104" r="5" stroke="#6b4fbb" stroke-width="4" transform="translate(65.917 34.945)"/><g stroke="#fb722e"><ellipse cx="4.632" cy="50.05" stroke-width="3.2" rx="4" ry="3.999"/><g stroke-width="4"><ellipse cx="29.632" cy="27.05" rx="4" ry="3.999"/><ellipse cx="107.63" cy="4.048" rx="4" ry="3.999"/></g></g></g></g></g><rect width="160.19" height="128.19" x="36.28" y="86.74" fill="#f9f9f9" transform="matrix(.99619-.08716.08716.99619-12.703 10.717)" rx="10"/><g transform="matrix(.99619.08716-.08716.99619 126.61 137.8)"><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#3)" xlink:href="#2"/><path fill="#6b4fbb" stroke="#6b4fbb" stroke-width="3.2" d="m84.67 28.41c18.225 0 33 15.07 33 33.651h-33v-33.651" stroke-linecap="round" stroke-linejoin="round"/><path fill="#d2caea" fill-rule="nonzero" d="m78.67 66.41h30c1.105 0 2 .895 2 2 0 18.778-15.222 34-34 34-18.778 0-34-15.222-34-34 0-18.778 15.222-34 34-34 1.105 0 2 .895 2 2v30m-32 2c0 16.569 13.431 30 30 30 15.896 0 28.905-12.364 29.934-28h-29.934c-1.105 0-2-.895-2-2v-29.934c-15.636 1.029-28 14.04-28 29.934"/></g><g transform="matrix(.99619-.08716.08716.99619 30 88.03)"><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#5)" xlink:href="#4"/><g transform="translate(42 34)"><path fill="#fef0ea" d="m0 13.391c0-.768.628-1.391 1.4-1.391h9.2c.773 0 1.4.626 1.4 1.391v49.609h-12v-49.609"/><path fill="#fb722e" d="m66 21.406c0-.777.628-1.406 1.4-1.406h9.2c.773 0 1.4.624 1.4 1.406v41.594h-12v-41.594"/><path fill="#6b4fbb" d="m22 1.404c0-.776.628-1.404 1.4-1.404h9.2c.773 0 1.4.624 1.4 1.404v61.6h-12v-61.6"/><path fill="#d2caea" d="m44 39.4c0-.772.628-1.398 1.4-1.398h9.2c.773 0 1.4.618 1.4 1.398v23.602h-12v-23.602"/></g></g><g fill="#fee8dc"><path d="m6.226 94.95l-2.84.631c-1.075.239-1.752-.445-1.515-1.515l.631-2.84-.631-2.84c-.239-1.075.445-1.752 1.515-1.515l2.84.631 2.84-.631c1.075-.239 1.752.445 1.515 1.515l-.631 2.84.631 2.84c.239 1.075-.445 1.752-1.515 1.515l-2.84-.631" transform="matrix(.70711.70711-.70711.70711 66.33 22.317)"/><path d="m312.78 53.43l-3.634.807c-1.296.288-2.115-.52-1.825-1.825l.807-3.634-.807-3.634c-.288-1.296.52-2.115 1.825-1.825l3.634.807 3.634-.807c1.296-.288 2.115.52 1.825 1.825l-.807 3.634.807 3.634c.288 1.296-.52 2.115-1.825 1.825l-3.634-.807" transform="matrix(.70711.70711-.70711.70711 126.1-206.88)"/></g><path fill="#e1dcf1" d="m124.78 12.43l-3.617.804c-1.306.29-2.129-.53-1.839-1.839l.804-3.617-.804-3.617c-.29-1.306.53-2.129 1.839-1.839l3.617.804 3.617-.804c1.306-.29 2.129.53 1.839 1.839l-.804 3.617.804 3.617c.29 1.306-.53 2.129-1.839 1.839l-3.617-.804" transform="matrix(.70711-.70711.70711.70711 31.05 90.51)"/><path fill="#d2caea" d="m374.78 244.43l-3.617.804c-1.306.29-2.129-.53-1.839-1.839l.804-3.617-.804-3.617c-.29-1.306.53-2.129 1.839-1.839l3.617.804 3.617-.804c1.306-.29 2.129.53 1.839 1.839l-.804 3.617.804 3.617c.29 1.306-.53 2.129-1.839 1.839l-3.617-.804" transform="matrix(.70711-.70711.70711.70711-59.779 335.24)"/></g></svg>
\ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 406 305" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><rect id="a" width="159.8" height="127.81" x=".196" y="5" rx="10"/><rect id="b" width="160" height="128" x=".666" y=".41" rx="10"/><rect id="c" width="160.19" height="128.19" x=".339" y=".59" rx="10"/><mask id="d" width="159.8" height="127.81" x="0" y="0" fill="#fff"><use xlink:href="#a"/></mask><mask id="e" width="160" height="128" x="0" y="0" fill="#fff"><use xlink:href="#b"/></mask><mask id="f" width="160.19" height="128.19" x="0" y="0" fill="#fff"><use xlink:href="#c"/></mask></defs><g fill="none" fill-rule="evenodd" transform="translate(12 3)"><rect width="160" height="128" x="122.08" y="146.08" fill="#f9f9f9" transform="rotate(5 202.071 210.085)" rx="10"/><g transform="rotate(15 -104.714 891.23)"><rect width="159.8" height="127.81" x="1.64" y="10.06" fill="#f9f9f9" rx="8"/><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#d)" xlink:href="#a"/><path fill="#d2caea" fill-rule="nonzero" d="M96.153 81.151a2.001 2.001 0 0 0 2.184-.496l35.956-38.34a2 2 0 1 0-2.918-2.736l-35.03 37.36-41.888-16.285a2 2 0 0 0-2.16.471l-26.368 27.16a2 2 0 1 0 2.87 2.786l25.444-26.21 41.911 16.294"/><g fill="#fff" transform="translate(24.368 36.951)"><circle cx="5.716" cy="5.104" r="5" stroke="#6b4fbb" stroke-width="4" transform="translate(65.917 34.945)"/><g stroke="#fb722e"><ellipse cx="4.632" cy="50.05" stroke-width="3.2" rx="4" ry="3.999"/><g stroke-width="4"><ellipse cx="29.632" cy="27.05" rx="4" ry="3.999"/><ellipse cx="107.63" cy="4.048" rx="4" ry="3.999"/></g></g></g></g><rect width="160.19" height="128.19" x="36.28" y="86.74" fill="#f9f9f9" transform="rotate(-5 116.372 150.825)" rx="10"/><g transform="rotate(5 -1514.687 1518.752)"><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#e)" xlink:href="#b"/><path fill="#6b4fbb" stroke="#6b4fbb" stroke-width="3.2" d="M84.67 28.41c18.225 0 33 15.07 33 33.651h-33V28.41" stroke-linecap="round" stroke-linejoin="round"/><path fill="#d2caea" fill-rule="nonzero" d="M78.67 66.41h30a2 2 0 0 1 2 2c0 18.778-15.222 34-34 34s-34-15.222-34-34 15.222-34 34-34a2 2 0 0 1 2 2v30m-32 2c0 16.569 13.431 30 30 30 15.896 0 28.905-12.364 29.934-28H76.67a2 2 0 0 1-2-2V38.476c-15.636 1.029-28 14.04-28 29.934"/></g><g transform="rotate(-5 1023.06 -299.524)"><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#f)" xlink:href="#c"/><path fill="#fef0ea" d="M42 47.391c0-.768.628-1.391 1.4-1.391h9.2c.773 0 1.4.626 1.4 1.391V97H42V47.391"/><path fill="#fb722e" d="M108 55.406c0-.777.628-1.406 1.4-1.406h9.2a1.4 1.4 0 0 1 1.4 1.406V97h-12V55.406"/><path fill="#6b4fbb" d="M64 35.404c0-.776.628-1.404 1.4-1.404h9.2a1.4 1.4 0 0 1 1.4 1.404v61.6H64v-61.6"/><path fill="#d2caea" d="M86 73.4a1.4 1.4 0 0 1 1.4-1.398h9.2c.773 0 1.4.618 1.4 1.398v23.602H86V73.4"/></g><g fill="#fee8dc"><path d="M3.592 93.86l-2.454-1.562c-.93-.592-.924-1.554 0-2.143l2.454-1.562 1.562-2.454c.592-.93 1.554-.925 2.143 0l1.562 2.454 2.454 1.562c.93.591.924 1.554 0 2.143L8.86 93.86l-1.562 2.454c-.591.93-1.554.924-2.143 0L3.592 93.86M309.489 52.07l-3.14-1.998c-1.12-.713-1.128-1.863 0-2.581l3.14-2 1.999-3.14c.713-1.12 1.863-1.127 2.58 0l2 3.14 3.14 2c1.12.713 1.128 1.863 0 2.58l-3.14 2-2 3.14c-.712 1.12-1.862 1.128-2.58 0l-1.999-3.14"/></g><path fill="#e1dcf1" d="M128.073 11.066l-1.99 3.126c-.718 1.129-1.88 1.131-2.6 0l-1.99-3.126-3.126-1.989c-1.128-.718-1.13-1.88 0-2.6l3.127-1.99 1.989-3.126c.718-1.128 1.88-1.13 2.6 0l1.99 3.126 3.126 1.99c1.128.718 1.13 1.88 0 2.6l-3.126 1.99"/><path fill="#d2caea" d="M378.07 243.068l-1.989 3.126c-.718 1.129-1.88 1.131-2.6 0l-1.99-3.126-3.126-1.989c-1.128-.718-1.13-1.88 0-2.6l3.127-1.99 1.989-3.126c.718-1.128 1.88-1.13 2.6 0l1.99 3.126 3.126 1.99c1.128.718 1.13 1.88 0 2.6l-3.126 1.99"/></g></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/monitoring/loading.svg b/app/assets/images/illustrations/monitoring/loading.svg index 6bbd7a6c5b9..1e196fc8ad1 100644 --- a/app/assets/images/illustrations/monitoring/loading.svg +++ b/app/assets/images/illustrations/monitoring/loading.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 406 305" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><rect id="C" width="161" height="100" x="92" y="181" rx="10"/><rect id="E" width="151" height="32" x="20" rx="10"/><rect id="G" width="191" height="62" y="10" rx="10"/><circle id="I" cx="23" cy="41" r="9"/><circle id="4" cx="36.5" cy="36.5" r="36.5"/><circle id="8" cx="262.5" cy="169.5" r="15.5"/><circle id="A" cx="79.5" cy="169.5" r="15.5"/><circle id="K" cx="45" cy="41" r="9"/><circle id="0" cx="30.5" cy="30.5" r="30.5"/><circle id="2" cx="18" cy="34" r="3"/><ellipse id="6" cx="43.5" cy="43.5" rx="43.5" ry="43.5"/><mask id="H" width="191" height="62" x="0" y="0" fill="#fff"><use xlink:href="#G"/></mask><mask id="J" width="18" height="18" x="0" y="0" fill="#fff"><use xlink:href="#I"/></mask><mask id="D" width="161" height="100" x="0" y="0" fill="#fff"><use xlink:href="#C"/></mask><mask id="F" width="151" height="32" x="0" y="0" fill="#fff"><use xlink:href="#E"/></mask><mask id="9" width="31" height="31" x="0" y="0" fill="#fff"><use xlink:href="#8"/></mask><mask id="1" width="61" height="61" x="0" y="0" fill="#fff"><use xlink:href="#0"/></mask><mask id="B" width="31" height="31" x="0" y="0" fill="#fff"><use xlink:href="#A"/></mask><mask id="3" width="6" height="6" x="0" y="0" fill="#fff"><use xlink:href="#2"/></mask><mask id="7" width="87" height="87" x="0" y="0" fill="#fff"><use xlink:href="#6"/></mask><mask id="L" width="18" height="18" x="0" y="0" fill="#fff"><use xlink:href="#K"/></mask><mask id="5" width="73" height="73" x="0" y="0" fill="#fff"><use xlink:href="#4"/></mask></defs><g fill="none" fill-rule="evenodd" transform="translate(28 2)"><g transform="translate(133 87)"><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#1)" xlink:href="#0"/><path stroke="#d2caea" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" d="m19 32l2-9 5 17 4-12 4 5 6-10 3 5"/><g fill="#fff" stroke="#fb722e"><use stroke-width="4" mask="url(#3)" xlink:href="#2"/><circle cx="44" cy="30" r="2" stroke-width="2"/></g></g><g transform="translate(188 29)"><circle cx="36.5" cy="41.5" r="36.5" fill="#f9f9f9"/><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#5)" xlink:href="#4"/><rect width="27" height="4" x="23" y="27" fill="#d2caea" rx="2"/><rect width="10.5" height="4" x="23" y="27" fill="#6b4fbb" rx="2"/><rect width="27" height="4" x="23" y="36" fill="#d2caea" rx="2"/><rect width="19" height="4" x="23" y="36" fill="#6b4fbb" rx="2"/><rect width="27" height="4" x="23" y="45" fill="#d2caea" rx="2"/><rect width="7" height="4" x="23" y="45" fill="#6b4fbb" rx="2"/></g><path fill="#eee" fill-rule="nonzero" d="m247 292v1c0 5.519-4.469 9.993-10.01 9.993h-125.99c-5.177 0-9.436-3.927-9.954-8.96 1.348.998 2.957 1.666 4.705 1.883 1.027 1.835 2.992 3.077 5.248 3.077h125.99c2.485 0 4.611-1.497 5.526-3.637 1.796-.675 3.347-1.852 4.48-3.359m1.947-8.962c-.518 5.03-4.774 8.958-9.95 8.958h-131.99c-4.929 0-9.03-3.563-9.851-8.25 1.382.767 2.964 1.216 4.649 1.248 1.037 1.794 2.978 3 5.202 3h131.99c2.255 0 4.219-1.241 5.245-3.076 1.748-.216 3.356-.883 4.705-1.882"/><g transform="translate(79)"><ellipse cx="43.5" cy="47.5" fill="#f9f9f9" rx="43.5" ry="43.5"/><g fill="#fff"><g stroke="#eee"><use stroke-width="8" mask="url(#7)" xlink:href="#6"/><path stroke-width="4" d="m18.595 49c2.515 11.44 12.71 20 24.905 20 14.08 0 25.5-11.417 25.5-25.5 0-12.195-8.56-22.391-20-24.905v15.959c3 1.848 5 5.164 5 8.946 0 5.799-4.701 10.5-10.5 10.5-3.782 0-7.098-2-8.946-5h-15.959" stroke-linejoin="round"/></g><path stroke="#d2caea" stroke-width="4" d="m18 44c-.003-.166-.005-.333-.005-.5 0-14.08 11.417-25.5 25.5-25.5.167 0 .334.002.5.005v15.01c-.166-.008-.332-.012-.5-.012-5.799 0-10.5 4.701-10.5 10.5 0 .168.004.334.012.5h-15.01" stroke-linejoin="round"/></g></g><g fill="#fff" stroke="#eee" stroke-width="8"><use mask="url(#9)" xlink:href="#8"/><use mask="url(#B)" xlink:href="#A"/><use mask="url(#D)" xlink:href="#C"/></g><g fill="#eee"><rect width="15" height="2" x="226" y="247" rx="1"/><rect width="15" height="2" x="226" y="242" rx="1"/><rect width="15" height="2" x="226" y="252" rx="1"/></g><rect width="10" height="52" x="118" y="196" fill="#d2caea" rx="2"/><rect width="10" height="47" x="154" y="196" fill="#6b4fbb" rx="2"/><rect width="10" height="37" x="190" y="196" fill="#d2caea" rx="2"/><g fill="#fee8dc"><rect width="10" height="52" x="132" y="185" rx="2"/><rect width="10" height="38" x="168" y="185" rx="2"/></g><rect width="10" height="58" x="204" y="185" fill="#fb722e" rx="2"/><g transform="translate(76 128)"><g fill="#fff" stroke="#eee" stroke-width="8"><use mask="url(#F)" xlink:href="#E"/><use mask="url(#H)" xlink:href="#G"/></g><g fill="#d2caea"><rect width="16" height="4" x="156" y="35" rx="2"/><rect width="16" height="4" x="156" y="43" rx="2"/></g><g fill="#fff" stroke-width="8"><use stroke="#fee8dc" mask="url(#J)" xlink:href="#I"/><use stroke="#fb722e" mask="url(#L)" xlink:href="#K"/></g></g><g fill="#fb722e"><path d="m6.226 220.95l-2.84.631c-1.075.239-1.752-.445-1.515-1.515l.631-2.84-.631-2.84c-.239-1.075.445-1.752 1.515-1.515l2.84.631 2.84-.631c1.075-.239 1.752.445 1.515 1.515l-.631 2.84.631 2.84c.239 1.075-.445 1.752-1.515 1.515l-2.84-.631" opacity=".2" transform="matrix(.70711.70711-.70711.70711 155.43 59.22)"/><path d="m256.23 9.95l-2.84.631c-1.075.239-1.752-.445-1.515-1.515l.631-2.84-.631-2.84c-.239-1.075.445-1.752 1.515-1.515l2.84.631 2.84-.631c1.075-.239 1.752.445 1.515 1.515l-.631 2.84.631 2.84c.239 1.075-.445 1.752-1.515 1.515l-2.84-.631" opacity=".2" transform="matrix(.70711.70711-.70711.70711 79.45-179.36)"/></g><path fill="#fee8dc" d="m312.78 150.43l-3.634.807c-1.296.288-2.115-.52-1.825-1.825l.807-3.634-.807-3.634c-.288-1.296.52-2.115 1.825-1.825l3.634.807 3.634-.807c1.296-.288 2.115.52 1.825 1.825l-.807 3.634.807 3.634c.288 1.296-.52 2.115-1.825 1.825l-3.634-.807" transform="matrix(.70711.70711-.70711.70711 194.69-178.47)"/><path fill="#6b4fbb" d="m43.778 80.43l-3.617.804c-1.306.29-2.129-.53-1.839-1.839l.804-3.617-.804-3.617c-.29-1.306.53-2.129 1.839-1.839l3.617.804 3.617-.804c1.306-.29 2.129.53 1.839 1.839l-.804 3.617.804 3.617c.29 1.306-.53 2.129-1.839 1.839l-3.617-.804" opacity=".2" transform="matrix(.70711-.70711.70711.70711-40.761 53.15)"/></g></svg>
\ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 406 305" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><rect id="c" width="161" height="100" x="92" y="181" rx="10"/><rect id="d" width="151" height="32" x="20" rx="10"/><rect id="a" width="191" height="62" y="10" rx="10"/><circle id="b" cx="23" cy="41" r="9"/><circle id="k" cx="36.5" cy="36.5" r="36.5"/><circle id="e" cx="262.5" cy="169.5" r="15.5"/><circle id="g" cx="79.5" cy="169.5" r="15.5"/><circle id="j" cx="45" cy="41" r="9"/><circle id="f" cx="30.5" cy="30.5" r="30.5"/><circle id="h" cx="18" cy="34" r="3"/><ellipse id="i" cx="43.5" cy="43.5" rx="43.5" ry="43.5"/><mask id="t" width="191" height="62" x="0" y="0" fill="#fff"><use xlink:href="#a"/></mask><mask id="u" width="18" height="18" x="0" y="0" fill="#fff"><use xlink:href="#b"/></mask><mask id="r" width="161" height="100" x="0" y="0" fill="#fff"><use xlink:href="#c"/></mask><mask id="s" width="151" height="32" x="0" y="0" fill="#fff"><use xlink:href="#d"/></mask><mask id="p" width="31" height="31" x="0" y="0" fill="#fff"><use xlink:href="#e"/></mask><mask id="l" width="61" height="61" x="0" y="0" fill="#fff"><use xlink:href="#f"/></mask><mask id="q" width="31" height="31" x="0" y="0" fill="#fff"><use xlink:href="#g"/></mask><mask id="m" width="6" height="6" x="0" y="0" fill="#fff"><use xlink:href="#h"/></mask><mask id="o" width="87" height="87" x="0" y="0" fill="#fff"><use xlink:href="#i"/></mask><mask id="v" width="18" height="18" x="0" y="0" fill="#fff"><use xlink:href="#j"/></mask><mask id="n" width="73" height="73" x="0" y="0" fill="#fff"><use xlink:href="#k"/></mask></defs><g fill="none" fill-rule="evenodd" transform="translate(28 2)"><g transform="translate(133 87)"><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#l)" xlink:href="#f"/><path stroke="#d2caea" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" d="M19 32l2-9 5 17 4-12 4 5 6-10 3 5"/><g fill="#fff" stroke="#fb722e"><use stroke-width="4" mask="url(#m)" xlink:href="#h"/><circle cx="44" cy="30" r="2" stroke-width="2"/></g></g><g transform="translate(188 29)"><circle cx="36.5" cy="41.5" r="36.5" fill="#f9f9f9"/><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#n)" xlink:href="#k"/><rect width="27" height="4" x="23" y="27" fill="#d2caea" rx="2"/><rect width="10.5" height="4" x="23" y="27" fill="#6b4fbb" rx="2"/><rect width="27" height="4" x="23" y="36" fill="#d2caea" rx="2"/><rect width="19" height="4" x="23" y="36" fill="#6b4fbb" rx="2"/><rect width="27" height="4" x="23" y="45" fill="#d2caea" rx="2"/><rect width="7" height="4" x="23" y="45" fill="#6b4fbb" rx="2"/></g><path fill="#eee" fill-rule="nonzero" d="M247 292v1c0 5.519-4.469 9.993-10.01 9.993H111c-5.177 0-9.436-3.927-9.954-8.96a9.96 9.96 0 0 0 4.705 1.883 6.008 6.008 0 0 0 5.248 3.077h125.99a6 6 0 0 0 5.526-3.637 10.027 10.027 0 0 0 4.48-3.359m1.947-8.962a10.001 10.001 0 0 1-9.95 8.958h-131.99a10 10 0 0 1-9.851-8.25 9.942 9.942 0 0 0 4.649 1.248 6 6 0 0 0 5.202 3h131.99a6.002 6.002 0 0 0 5.245-3.076 9.943 9.943 0 0 0 4.705-1.882"/><g transform="translate(79)"><ellipse cx="43.5" cy="47.5" fill="#f9f9f9" rx="43.5" ry="43.5"/><g fill="#fff"><g stroke="#eee"><use stroke-width="8" mask="url(#o)" xlink:href="#i"/><path stroke-width="4" d="M18.595 49C21.11 60.44 31.305 69 43.5 69 57.58 69 69 57.583 69 43.5c0-12.195-8.56-22.391-20-24.905v15.959c3 1.848 5 5.164 5 8.946C54 49.299 49.299 54 43.5 54c-3.782 0-7.098-2-8.946-5H18.595" stroke-linejoin="round"/></g><path stroke="#d2caea" stroke-width="4" d="M18 44a27.69 27.69 0 0 1-.005-.5c0-14.08 11.417-25.5 25.5-25.5.167 0 .334.002.5.005v15.01a10.365 10.365 0 0 0-.5-.012c-5.799 0-10.5 4.701-10.5 10.5 0 .168.004.334.012.5h-15.01" stroke-linejoin="round"/></g></g><g fill="#fff" stroke="#eee" stroke-width="8"><use mask="url(#p)" xlink:href="#e"/><use mask="url(#q)" xlink:href="#g"/><use mask="url(#r)" xlink:href="#c"/></g><g fill="#eee"><rect width="15" height="2" x="226" y="247" rx="1"/><rect width="15" height="2" x="226" y="242" rx="1"/><rect width="15" height="2" x="226" y="252" rx="1"/></g><rect width="10" height="52" x="118" y="196" fill="#d2caea" rx="2"/><rect width="10" height="47" x="154" y="196" fill="#6b4fbb" rx="2"/><rect width="10" height="37" x="190" y="196" fill="#d2caea" rx="2"/><g fill="#fee8dc"><rect width="10" height="52" x="132" y="185" rx="2"/><rect width="10" height="38" x="168" y="185" rx="2"/></g><rect width="10" height="58" x="204" y="185" fill="#fb722e" rx="2"/><g fill="#fff" stroke="#eee" stroke-width="8" transform="translate(76 128)"><use mask="url(#s)" xlink:href="#d"/><use mask="url(#t)" xlink:href="#a"/></g><g fill="#d2caea" transform="translate(76 128)"><rect width="16" height="4" x="156" y="35" rx="2"/><rect width="16" height="4" x="156" y="43" rx="2"/></g><g fill="#fff" stroke-width="8" transform="translate(76 128)"><use stroke="#fee8dc" mask="url(#u)" xlink:href="#b"/><use stroke="#fb722e" mask="url(#v)" xlink:href="#j"/></g><g fill="#fb722e"><path d="M3.597 219.858l-2.455-1.562c-.929-.59-.924-1.553 0-2.142l2.455-1.562 1.562-2.455c.59-.929 1.553-.924 2.142 0l1.562 2.455 2.454 1.562c.93.591.925 1.553 0 2.142l-2.454 1.562-1.562 2.455c-.591.929-1.553.924-2.142 0l-1.562-2.455M253.597 8.859l-2.454-1.562c-.93-.592-.925-1.554 0-2.143l2.454-1.562 1.562-2.454c.591-.93 1.554-.925 2.143 0l1.562 2.454 2.454 1.562c.93.591.924 1.554 0 2.143l-2.454 1.562-1.562 2.454c-.592.93-1.554.924-2.143 0l-1.562-2.454" opacity=".2"/></g><path fill="#fee8dc" d="M309.49 149.07l-3.141-1.999c-1.12-.712-1.128-1.863 0-2.58l3.14-2 2-3.14c.712-1.12 1.863-1.128 2.58 0l2 3.14 3.14 2c1.12.712 1.127 1.863 0 2.58l-3.14 2-2 3.14c-.713 1.12-1.863 1.128-2.58 0l-2-3.14"/><path fill="#6b4fbb" d="M47.068 79.067l-1.99 3.126c-.718 1.129-1.88 1.13-2.6 0l-1.99-3.126-3.125-1.99c-1.129-.718-1.131-1.88 0-2.6l3.126-1.989 1.989-3.126c.718-1.129 1.88-1.13 2.6 0l1.99 3.126 3.126 1.99c1.128.718 1.13 1.88 0 2.6l-3.126 1.989" opacity=".2"/></g></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/monitoring/unable_to_connect.svg b/app/assets/images/illustrations/monitoring/unable_to_connect.svg index 62537d87d5d..314c052f931 100644 --- a/app/assets/images/illustrations/monitoring/unable_to_connect.svg +++ b/app/assets/images/illustrations/monitoring/unable_to_connect.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 406 305" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><use id="0" xlink:href="#E"/><use id="2" xlink:href="#E"/><use id="4" xlink:href="#E"/><path id="6" d="m74 93h26v47h-26z"/><path id="8" d="m74 93h26v47h-26z"/><rect id="A" width="65" height="14" x="55" y="135" rx="4"/><rect id="C" width="175" height="118" rx="10"/><rect id="E" width="159" rx="10" height="56"/><rect id="F" width="160" y="2" rx="10" height="56" fill="#f9f9f9"/><mask id="B" width="65" height="14" x="0" y="0" fill="#fff"><use xlink:href="#A"/></mask><mask id="9" width="26" height="47" x="0" y="0" fill="#fff"><use xlink:href="#8"/></mask><mask id="D" width="175" height="118" x="0" y="0" fill="#fff"><use xlink:href="#C"/></mask><mask id="7" width="26" height="47" x="0" y="0" fill="#fff"><use xlink:href="#6"/></mask><mask id="3" width="159" height="56" x="0" y="0" fill="#fff"><use xlink:href="#2"/></mask><mask id="1" width="159" height="56" x="0" y="0" fill="#fff"><use xlink:href="#0"/></mask><mask id="5" width="159" height="56" x="0" y="0" fill="#fff"><use xlink:href="#4"/></mask></defs><g fill="none" fill-rule="evenodd" transform="translate(1 65)"><g transform="translate(244)"><use xlink:href="#F"/><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#1)" xlink:href="#0"/><g fill-rule="nonzero"><path fill="#fb722e" d="m134 31c1.105 0 2-.895 2-2 0-1.105-.895-2-2-2-1.105 0-2 .895-2 2 0 1.105.895 2 2 2m0 4c-3.314 0-6-2.686-6-6 0-3.314 2.686-6 6-6 3.314 0 6 2.686 6 6 0 3.314-2.686 6-6 6"/><path fill="#fee8dc" d="m117 31c1.105 0 2-.895 2-2 0-1.105-.895-2-2-2-1.105 0-2 .895-2 2 0 1.105.895 2 2 2m0 4c-3.314 0-6-2.686-6-6 0-3.314 2.686-6 6-6 3.314 0 6 2.686 6 6 0 3.314-2.686 6-6 6m-17-4c1.105 0 2-.895 2-2 0-1.105-.895-2-2-2-1.105 0-2 .895-2 2 0 1.105.895 2 2 2m0 4c-3.314 0-6-2.686-6-6 0-3.314 2.686-6 6-6 3.314 0 6 2.686 6 6 0 3.314-2.686 6-6 6"/></g><g fill="#d2caea"><rect width="50" height="4" x="19" y="20" rx="2"/><rect width="50" height="4" x="19" y="34" rx="2"/></g><g transform="translate(0 59)"><use xlink:href="#F"/><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#3)" xlink:href="#2"/><g fill-rule="nonzero"><path fill="#fee8dc" d="m134 30c1.105 0 2-.895 2-2 0-1.105-.895-2-2-2-1.105 0-2 .895-2 2 0 1.105.895 2 2 2m0 4c-3.314 0-6-2.686-6-6 0-3.314 2.686-6 6-6 3.314 0 6 2.686 6 6 0 3.314-2.686 6-6 6"/><path fill="#fb722e" d="m117 30c1.105 0 2-.895 2-2 0-1.105-.895-2-2-2-1.105 0-2 .895-2 2 0 1.105.895 2 2 2m0 4c-3.314 0-6-2.686-6-6 0-3.314 2.686-6 6-6 3.314 0 6 2.686 6 6 0 3.314-2.686 6-6 6"/><path fill="#fee8dc" d="m100 30c1.105 0 2-.895 2-2 0-1.105-.895-2-2-2-1.105 0-2 .895-2 2 0 1.105.895 2 2 2m0 4c-3.314 0-6-2.686-6-6 0-3.314 2.686-6 6-6 3.314 0 6 2.686 6 6 0 3.314-2.686 6-6 6"/></g><rect width="50" height="4" x="19" y="19" fill="#d2caea" rx="2" id="G"/><rect width="50" height="4" x="19" y="33" fill="#d2caea" rx="2" id="H"/></g><g transform="translate(0 118)"><use xlink:href="#F"/><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#5)" xlink:href="#4"/><g fill-rule="nonzero"><path fill="#fb722e" d="m134 30c1.105 0 2-.895 2-2 0-1.105-.895-2-2-2-1.105 0-2 .895-2 2 0 1.105.895 2 2 2m0 4c-3.314 0-6-2.686-6-6 0-3.314 2.686-6 6-6 3.314 0 6 2.686 6 6 0 3.314-2.686 6-6 6"/><path fill="#fee8dc" d="m117 30c1.105 0 2-.895 2-2 0-1.105-.895-2-2-2-1.105 0-2 .895-2 2 0 1.105.895 2 2 2m0 4c-3.314 0-6-2.686-6-6 0-3.314 2.686-6 6-6 3.314 0 6 2.686 6 6 0 3.314-2.686 6-6 6m-17-4c1.105 0 2-.895 2-2 0-1.105-.895-2-2-2-1.105 0-2 .895-2 2 0 1.105.895 2 2 2m0 4c-3.314 0-6-2.686-6-6 0-3.314 2.686-6 6-6 3.314 0 6 2.686 6 6 0 3.314-2.686 6-6 6"/></g><use xlink:href="#G"/><use xlink:href="#H"/></g></g><g transform="translate(163 55)"><g fill="#eee"><rect width="29" height="4" y="29" rx="2"/><rect width="28" height="4" x="55" y="29" rx="2"/></g><g transform="translate(16)"><circle cx="30" cy="30" r="24" fill="#fef0ea"/><g fill="#fb722e"><circle cx="30.5" cy="30.5" r="30.5" opacity=".1"/><circle cx="30.5" cy="30.5" r="19.5" opacity=".1"/></g><circle cx="30.5" cy="30.5" r="13.5" fill="#fff"/><path fill="#fb722e" d="m32.621 30.5l2.481-2.481c.586-.586.58-1.529-.006-2.115-.59-.59-1.533-.589-2.115-.006l-2.481 2.481-2.481-2.481c-.586-.586-1.529-.58-2.115.006-.59.59-.589 1.533-.006 2.115l2.481 2.481-2.481 2.481c-.586.586-.58 1.529.006 2.115.59.59 1.533.589 2.115.006l2.481-2.481 2.481 2.481c.586.586 1.529.58 2.115-.006.59-.59.589-1.533.006-2.115l-2.481-2.481"/></g></g><g transform="translate(0 13)"><rect width="65" height="14" x="55" y="137" fill="#f9f9f9" rx="4"/><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#7)" xlink:href="#6"/><rect width="175" height="118" y="3" fill="#f9f9f9" rx="10"/><g fill="#fff" stroke="#eee" stroke-width="8"><use mask="url(#9)" xlink:href="#8"/><use mask="url(#B)" xlink:href="#A"/><use mask="url(#D)" xlink:href="#C"/></g><g fill-rule="nonzero"><path fill="#eee" d="m163 105v-93h-152v93h152m-156-93.01c0-2.204 1.797-3.99 3.995-3.99h152.01c2.206 0 3.995 1.796 3.995 3.99v93.02c0 2.204-1.797 3.99-3.995 3.99h-152.01c-2.206 0-3.995-1.796-3.995-3.99v-93.02"/><path fill="#d2caea" d="m86 92c-11.598 0-21-9.402-21-21 0-11.598 9.402-21 21-21 11.598 0 21 9.402 21 21 0 11.598-9.402 21-21 21m0-4c9.389 0 17-7.611 17-17 0-9.389-7.611-17-17-17-9.389 0-17 7.611-17 17 0 9.389 7.611 17 17 17"/></g><path fill="#6b4fbb" d="m83 63c0-1.659 1.347-3 3-3 1.657 0 3 1.342 3 3v7.993c0 1.659-1.347 3-3 3-1.657 0-3-1.342-3-3v-7.993m3 18.997c-1.657 0-3-1.343-3-3 0-1.657 1.343-3 3-3 1.657 0 3 1.343 3 3 0 1.657-1.343 3-3 3"/><g fill="#eee"><rect width="134" height="4" x="20" y="30" rx="2"/><rect width="14" height="4" x="20" y="20" rx="2"/><circle cx="87" cy="21" r="5"/></g></g></g></svg>
\ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 406 305" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><use id="g" xlink:href="#a"/><use id="f" xlink:href="#a"/><use id="h" xlink:href="#a"/><path id="e" d="M74 93h26v47H74z"/><path id="c" d="M74 93h26v47H74z"/><rect id="b" width="65" height="14" x="55" y="135" rx="4"/><rect id="d" width="175" height="118" rx="10"/><rect id="a" width="159" rx="10" height="56"/><rect id="i" width="160" y="2" rx="10" height="56" fill="#f9f9f9"/><mask id="q" width="65" height="14" x="0" y="0" fill="#fff"><use xlink:href="#b"/></mask><mask id="p" width="26" height="47" x="0" y="0" fill="#fff"><use xlink:href="#c"/></mask><mask id="r" width="175" height="118" x="0" y="0" fill="#fff"><use xlink:href="#d"/></mask><mask id="o" width="26" height="47" x="0" y="0" fill="#fff"><use xlink:href="#e"/></mask><mask id="k" width="159" height="56" x="0" y="0" fill="#fff"><use xlink:href="#f"/></mask><mask id="j" width="159" height="56" x="0" y="0" fill="#fff"><use xlink:href="#g"/></mask><mask id="l" width="159" height="56" x="0" y="0" fill="#fff"><use xlink:href="#h"/></mask></defs><g fill="none" fill-rule="evenodd"><g transform="translate(245 65)"><use xlink:href="#i"/><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#j)" xlink:href="#g"/><g fill-rule="nonzero"><path fill="#fb722e" d="M134 31a2 2 0 1 0 .001-3.999A2 2 0 0 0 134 31m0 4a6 6 0 1 1 0-12 6 6 0 0 1 0 12"/><path fill="#fee8dc" d="M117 31a2 2 0 1 0 .001-3.999A2 2 0 0 0 117 31m0 4a6 6 0 1 1 0-12 6 6 0 0 1 0 12m-17-4a2 2 0 1 0 .001-3.999A2 2 0 0 0 100 31m0 4a6 6 0 1 1 0-12 6 6 0 0 1 0 12"/></g><g fill="#d2caea"><rect width="50" height="4" x="19" y="20" rx="2"/><rect width="50" height="4" x="19" y="34" rx="2"/></g><g transform="translate(0 59)"><use xlink:href="#i"/><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#k)" xlink:href="#f"/><g fill-rule="nonzero"><path fill="#fee8dc" d="M134 30a2 2 0 1 0 .001-3.999A2 2 0 0 0 134 30m0 4a6 6 0 1 1 0-12 6 6 0 0 1 0 12"/><path fill="#fb722e" d="M117 30a2 2 0 1 0 .001-3.999A2 2 0 0 0 117 30m0 4a6 6 0 1 1 0-12 6 6 0 0 1 0 12"/><path fill="#fee8dc" d="M100 30a2 2 0 1 0 .001-3.999A2 2 0 0 0 100 30m0 4a6 6 0 1 1 0-12 6 6 0 0 1 0 12"/></g><rect width="50" height="4" x="19" y="19" fill="#d2caea" rx="2" id="m"/><rect width="50" height="4" x="19" y="33" fill="#d2caea" rx="2" id="n"/></g><g transform="translate(0 118)"><use xlink:href="#i"/><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#l)" xlink:href="#h"/><g fill-rule="nonzero"><path fill="#fb722e" d="M134 30a2 2 0 1 0 .001-3.999A2 2 0 0 0 134 30m0 4a6 6 0 1 1 0-12 6 6 0 0 1 0 12"/><path fill="#fee8dc" d="M117 30a2 2 0 1 0 .001-3.999A2 2 0 0 0 117 30m0 4a6 6 0 1 1 0-12 6 6 0 0 1 0 12m-17-4a2 2 0 1 0 .001-3.999A2 2 0 0 0 100 30m0 4a6 6 0 1 1 0-12 6 6 0 0 1 0 12"/></g><use xlink:href="#m"/><use xlink:href="#n"/></g></g><g fill="#eee" transform="translate(164 120)"><rect width="29" height="4" y="29" rx="2"/><rect width="28" height="4" x="55" y="29" rx="2"/></g><g transform="translate(180 120)"><circle cx="30" cy="30" r="24" fill="#fef0ea"/><g fill="#fb722e"><circle cx="30.5" cy="30.5" r="30.5" opacity=".1"/><circle cx="30.5" cy="30.5" r="19.5" opacity=".1"/></g><circle cx="30.5" cy="30.5" r="13.5" fill="#fff"/><path fill="#fb722e" d="M32.621 30.5l2.481-2.481a1.492 1.492 0 0 0-.006-2.115 1.491 1.491 0 0 0-2.115-.006L30.5 28.379l-2.481-2.481a1.492 1.492 0 0 0-2.115.006 1.491 1.491 0 0 0-.006 2.115l2.481 2.481-2.481 2.481a1.492 1.492 0 0 0 .006 2.115c.59.59 1.533.589 2.115.006l2.481-2.481 2.481 2.481c.586.586 1.529.58 2.115-.006.59-.59.589-1.533.006-2.115L32.621 30.5"/></g><g transform="translate(1 78)"><rect width="65" height="14" x="55" y="137" fill="#f9f9f9" rx="4"/><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#o)" xlink:href="#e"/><rect width="175" height="118" y="3" fill="#f9f9f9" rx="10"/><g fill="#fff" stroke="#eee" stroke-width="8"><use mask="url(#p)" xlink:href="#c"/><use mask="url(#q)" xlink:href="#b"/><use mask="url(#r)" xlink:href="#d"/></g><g fill-rule="nonzero"><path fill="#eee" d="M163 105V12H11v93h152M7 11.99A3.998 3.998 0 0 1 10.995 8h152.01A3.999 3.999 0 0 1 167 11.99v93.02a3.998 3.998 0 0 1-3.995 3.99H10.995A3.999 3.999 0 0 1 7 105.01V11.99"/><path fill="#d2caea" d="M86 92c-11.598 0-21-9.402-21-21s9.402-21 21-21 21 9.402 21 21-9.402 21-21 21m0-4c9.389 0 17-7.611 17-17s-7.611-17-17-17-17 7.611-17 17 7.611 17 17 17"/></g><path fill="#6b4fbb" d="M83 63a3.001 3.001 0 0 1 6 0v7.993a3.001 3.001 0 0 1-6 0V63m3 18.997a3 3 0 1 1 0-6 3 3 0 0 1 0 6"/><g fill="#eee"><rect width="134" height="4" x="20" y="30" rx="2"/><rect width="14" height="4" x="20" y="20" rx="2"/><circle cx="87" cy="21" r="5"/></g></g></g></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/no_commits.svg b/app/assets/images/illustrations/no_commits.svg new file mode 100644 index 00000000000..76fa25156dd --- /dev/null +++ b/app/assets/images/illustrations/no_commits.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 168 107" xmlns:xlink="http://www.w3.org/1999/xlink"><g fill="#eee" fill-rule="evenodd"><path d="M4.01 2h1.102a1 1 0 0 0 0-2H4.01A4.001 4.001 0 0 0 0 4a1 1 0 0 0 2 0c0-1.108.892-2 2.01-2m12.702 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7M164 2c.822 0 1.554.503 1.86 1.254a1 1 0 1 0 1.853-.753 4.01 4.01 0 0 0-3.712-2.5h-2.188a1 1 0 0 0 0 2h2.188m2.01 12.518a1 1 0 0 0 2 0v-5.7a1 1 0 0 0-2 0v5.7m0 11.6a1 1 0 0 0 2 0v-5.7a1 1 0 0 0-2 0v5.7m0 11.6a1 1 0 0 0 2 0v-5.7a1 1 0 0 0-2 0v5.7m0 6.282c0 1.108-.892 2-2.01 2h-.72a1 1 0 0 0 0 2h.72a4.001 4.001 0 0 0 4.01-4v-.382a1 1 0 0 0-2 0v.382m-14.325 2a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-8.47 0a2.01 2.01 0 0 1-1.782-1.085 1 1 0 0 0-1.775.923 4.007 4.007 0 0 0 3.556 2.162h2.57a1 1 0 0 0 0-2h-2.57m-2.01-12.136a1 1 0 0 0-2 0v5.7a1 1 0 0 0 2 0v-5.7m0-11.6a1 1 0 0 0-2 0v5.7a1 1 0 0 0 2 0v-5.7m0-11.6a1 1 0 0 0-2 0v5.7a1 1 0 0 0 2 0v-5.7m0-6.664a1 1 0 0 0-2 0v.764a1 1 0 0 0 2 0v-.764" id="a"/><circle cx="21" cy="24" r="10"/><rect width="33" height="3" x="37" y="18" rx="1.5" id="b"/><rect width="53" height="3" x="37" y="27" rx="1.5" id="c"/><path d="M131 29c0 .552.447.999.996.999h22.01c.545 0 .996-.451.996-.999v-9a.998.998 0 0 0-.996-.999h-22.01c-.545 0-.996.451-.996.999v9m.996-12h22.01a2.998 2.998 0 0 1 2.996 2.999v9a3.003 3.003 0 0 1-2.996 2.999h-22.01A2.998 2.998 0 0 1 129 28.999v-9A3.003 3.003 0 0 1 131.996 17" id="d"/><g transform="translate(0 59)"><use xlink:href="#a"/><circle cx="21" cy="24" r="10"/><use xlink:href="#b"/><use xlink:href="#c"/><use xlink:href="#d"/></g></g></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/welcome/add_new_group.svg b/app/assets/images/illustrations/welcome/add_new_group.svg new file mode 100644 index 00000000000..b10a3ae8812 --- /dev/null +++ b/app/assets/images/illustrations/welcome/add_new_group.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"><g fill="none" fill-rule="evenodd"><path fill="#000" fill-opacity=".03" d="M2.12 42C2.04 43 2 44 2 45c0 20.43 16.57 37 37 37s37-16.57 37-37c0-1-.04-2-.12-3C74.35 61.03 58.42 76 39 76S3.65 61.03 2.12 42z"/><path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/><path fill="#E1DBF2" fill-rule="nonzero" d="M59.65 32.65H60l-2-2.42-2 2.4-2-2.4-2 2.4-2-2.4-2 2.4-2-2.4-2 2.42h.77C45.57 34.6 46 36.75 46 39c0 2.84-.7 5.5-1.92 7.86 1.97 2.28 4.83 3.64 7.92 3.64 5.8 0 10.5-4.74 10.5-10.6 0-2.8-1.08-5.36-2.85-7.25zM43.18 29.6c2.4-2.1 5.52-3.3 8.82-3.3 7.46 0 13.5 6.1 13.5 13.6S59.46 53.5 52 53.5c-3.68 0-7.1-1.5-9.6-4.04C39.3 53.44 34.44 56 29 56c-9.4 0-17-7.6-17-17s7.6-17 17-17c3.22 0 6.23.9 8.8 2.45 2.13 1.3 3.97 3.05 5.38 5.16zM17 34c-.65 1.54-1 3.23-1 5 0 7.18 5.82 13 13 13s13-5.82 13-13c0-1.77-.35-3.46-1-5h-9c-.53 0-1.04-.2-1.4-.6L29 31.84l-1.6 1.58c-.36.4-.87.6-1.4.6h-9zm21.38-4a12.996 12.996 0 0 0-18.76 0h5.55l2.42-2.4c.74-.8 2-.8 2.8 0l2.4 2.4h5.54z"/><path fill="#6B4FBB" d="M47.6 42.32c-.66 0-1.2-.54-1.2-1.2 0-.68.54-1.22 1.2-1.22.66 0 1.2.54 1.2 1.2 0 .68-.54 1.22-1.2 1.22zm8.8 0c-.66 0-1.2-.54-1.2-1.2 0-.68.54-1.22 1.2-1.22.66 0 1.2.54 1.2 1.2 0 .68-.54 1.22-1.2 1.22zM25 44h8c0 2.2-1.8 4-4 4s-4-1.8-4-4zm-1.5-1c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></g></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/welcome/add_new_project.svg b/app/assets/images/illustrations/welcome/add_new_project.svg new file mode 100644 index 00000000000..4b8dc34c088 --- /dev/null +++ b/app/assets/images/illustrations/welcome/add_new_project.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M2.12 42c-.08.99-.12 1.99-.12 3 0 20.435 16.565 37 37 37s37-16.565 37-37c0-1.01-.04-2.01-.12-3C74.353 61.032 58.425 76 39 76S3.647 61.032 2.12 42z"/><path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/><path fill="#E1DBF2" fill-rule="nonzero" d="M30 24c-2.21 0-4 1.79-4 4v22c0 2.21 1.79 4 4 4h18c2.21 0 4-1.79 4-4V28c0-2.21-1.79-4-4-4H30zm0-4h18a8 8 0 0 1 8 8v22a8 8 0 0 1-8 8H30a8 8 0 0 1-8-8V28a8 8 0 0 1 8-8z"/><path fill="#6B4FBB" d="M33 30h8a2 2 0 1 1 0 4h-8a2 2 0 1 1 0-4zm0 7h12a2 2 0 1 1 0 4H33a2 2 0 1 1 0-4zm0 7h12a2 2 0 1 1 0 4H33a2 2 0 1 1 0-4z"/></g></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/welcome/add_new_user.svg b/app/assets/images/illustrations/welcome/add_new_user.svg new file mode 100644 index 00000000000..d4c184989bf --- /dev/null +++ b/app/assets/images/illustrations/welcome/add_new_user.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"><g fill="none" fill-rule="evenodd"><path fill="#000" fill-opacity=".03" d="M2.12 42C2.04 43 2 44 2 45c0 20.43 16.57 37 37 37s37-16.57 37-37c0-1-.04-2-.12-3C74.35 61.03 58.42 76 39 76S3.65 61.03 2.12 42z"/><path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/><path fill="#E1DBF2" d="M44 31l-2.5-3-2.5 3-2.5-3-2.5 3-2.5-3-2.5 3h-2.72c2.65-4.2 7.36-7 12.72-7s10.07 2.8 12.72 7H49l-2.5-3-2.5 3z"/><path fill="#E1DBF2" fill-rule="nonzero" d="M39 57c-9.4 0-17-7.6-17-17s7.6-17 17-17 17 7.6 17 17-7.6 17-17 17zm0-4c7.18 0 13-5.82 13-13s-5.82-13-13-13-13 5.82-13 13 5.82 13 13 13z"/><path fill="#6B4FBB" d="M35 45h8c0 2.2-1.8 4-4 4s-4-1.8-4-4zm-1.5-2c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></g></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/welcome/configure_server.svg b/app/assets/images/illustrations/welcome/configure_server.svg new file mode 100644 index 00000000000..f9dda816f11 --- /dev/null +++ b/app/assets/images/illustrations/welcome/configure_server.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"><g fill="none" fill-rule="evenodd"><path fill="#000" fill-opacity=".03" d="M2.12 42C2.04 43 2 44 2 45c0 20.43 16.57 37 37 37s37-16.57 37-37c0-1-.04-2-.12-3C74.35 61.03 58.42 76 39 76S3.65 61.03 2.12 42z"/><path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/><path fill="#FEE1D3" fill-rule="nonzero" d="M24.92 35.15a4.012 4.012 0 0 1-.6-5.63l1.26-1.55c1.4-1.72 3.9-2 5.63-.6l.7.56c.7-.4 1.4-.73 2.1-1V26c0-2.2 1.8-4 4-4h2c2.2 0 4 1.8 4 4v.92c.8.28 1.5.62 2.1 1l.7-.55c1.7-1.4 4.3-1.12 5.7.6l1.3 1.55c1.4 1.72 1.2 4.23-.6 5.63l-.7.6c.3.74.4 1.5.5 2.3l.9.2c2.2.5 3.5 2.64 3 4.8L56.4 45c-.5 2.15-2.64 3.5-4.8 3l-.88-.2c-.44.63-.92 1.24-1.46 1.8l.4.82c.9 1.98.1 4.38-1.9 5.35l-1.8.87c-2 .97-4.37.15-5.34-1.84l-.46-.85c-.34.03-.74.05-1.13.05-.4 0-.8-.02-1.2-.05l-.4.85c-.95 2-3.34 2.8-5.33 1.84l-1.8-.87a4.011 4.011 0 0 1-1.83-5.35l.4-.8c-.54-.58-1.02-1.2-1.46-1.83l-.8.2c-2.2.5-4.3-.9-4.8-3l-.4-2c-.5-2.2.85-4.3 3-4.8l.9-.2c.1-.8.3-1.6.5-2.3l-.7-.6zm4.95.77c-.53 1.2-.83 2.47-.87 3.8-.02.9-.66 1.68-1.55 1.9l-2.32.53.45 1.94 2.3-.6c.9-.2 1.8.2 2.23 1 .7 1.1 1.5 2.2 2.5 3 .7.6.9 1.6.5 2.4l-1 2.1 1.8.9 1.1-2.1c.4-.8 1.3-1.3 2.2-1.1.7.1 1.3.2 2 .2s1.3-.1 2-.2c.9-.2 1.8.3 2.2 1.1l1 2.1 1.8-.9-1.2-2c-.4-.8-.2-1.8.5-2.4 1-.85 1.84-1.88 2.45-3.05.4-.82 1.33-1.24 2.2-1.04l2.33.54.45-1.95-2.32-.54c-.9-.2-1.52-.97-1.54-1.88-.03-1.4-.33-2.6-.86-3.8-.4-.9-.2-1.8.5-2.4l1.9-1.5-1.3-1.6-1.8 1.5c-.8.5-1.8.6-2.5 0-1.1-.8-2.3-1.4-3.5-1.7-.9-.2-1.5-1-1.5-1.9V26h-2v2.38c0 .9-.6 1.7-1.5 1.93-1.3.4-2.5 1-3.5 1.7-.8.6-1.8.6-2.5 0l-1.9-1.5-1.26 1.6 1.8 1.5c.7.6.94 1.6.6 2.4z"/><path fill="#FC6D26" fill-rule="nonzero" d="M39 46c-3.3 0-6-2.7-6-6s2.7-6 6-6 6 2.7 6 6-2.7 6-6 6zm0-4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z"/></g></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/welcome/ee_trial.svg b/app/assets/images/illustrations/welcome/ee_trial.svg new file mode 100644 index 00000000000..6d0dcf0020c --- /dev/null +++ b/app/assets/images/illustrations/welcome/ee_trial.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="330" height="132" viewBox="0 0 330 132"><g fill="none" fill-rule="evenodd"><path fill="#000" fill-opacity=".03" d="M174.12 42c-.08 1-.12 2-.12 3 0 20.43 16.57 37 37 37s37-16.57 37-37c0-1-.04-2-.12-3-1.53 19.03-17.46 34-36.88 34s-35.35-14.97-36.88-34z"/><path fill="#EEE" fill-rule="nonzero" d="M211 78c-21.54 0-39-17.46-39-39s17.46-39 39-39 39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S230.33 4 211 4s-35 15.67-35 35 15.67 35 35 35z"/><g fill-rule="nonzero"><path fill="#FEE1D3" d="M211.5 51c-6.42 0-12.26-2.84-17.43-8.4a4.008 4.008 0 0 1-.27-5.13C199 30.57 204.92 27 211.5 27s12.5 3.56 17.7 10.47a3.994 3.994 0 0 1-.27 5.12c-5.17 5.53-11 8.4-17.43 8.4zm0-4c5.25 0 10.05-2.34 14.5-7.13-4.5-5.98-9.3-8.87-14.5-8.87-5.2 0-10 2.9-14.5 8.87 4.45 4.8 9.25 7.13 14.5 7.13z"/><path fill="#FC6D26" d="M211 47c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm0-4c2.2 0 4-1.8 4-4s-1.8-4-4-4-4 1.8-4 4 1.8 4 4 4zm0-1c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3z"/></g><path fill="#000" fill-opacity=".03" d="M88.12 83c-.08 1-.12 2-.12 3 0 20.43 16.57 37 37 37s37-16.57 37-37c0-1-.04-2-.12-3-1.53 19.03-17.46 34-36.88 34s-35.35-14.97-36.88-34z"/><path fill="#EEE" fill-rule="nonzero" d="M125 119c-21.54 0-39-17.46-39-39s17.46-39 39-39 39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35s-15.67-35-35-35-35 15.67-35 35 15.67 35 35 35z"/><path fill="#FEE1D3" fill-rule="nonzero" d="M116 86.34c2.33.83 4 3.05 4 5.66 0 3.3-2.7 6-6 6s-6-2.7-6-6c0-2.6 1.67-4.83 4-5.66V72h4v14.34zM128 66c5.52 0 10 4.48 10 10v12h-4V76c0-3.3-2.7-6-6-6v1.83c0 .55-.45 1-1 1-.24 0-.47-.1-.65-.24l-4.46-3.87c-.46-.36-.5-1-.15-1.4.03-.05.07-.1.1-.12l4.47-3.82c.42-.35 1.05-.3 1.4.1.16.2.25.43.25.66V66zm-14 28c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z"/><path fill="#FC6D26" fill-rule="nonzero" d="M114 74c-3.3 0-6-2.7-6-6s2.7-6 6-6 6 2.7 6 6-2.7 6-6 6zm0-4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm22 28c-3.3 0-6-2.7-6-6s2.7-6 6-6 6 2.7 6 6-2.7 6-6 6zm0-4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z"/><path fill="#000" fill-opacity=".03" d="M2.12 52C2.04 53 2 54 2 55c0 20.43 16.57 37 37 37s37-16.57 37-37c0-1-.04-2-.12-3C74.35 71.03 58.42 86 39 86S3.65 71.03 2.12 52z"/><path fill="#EEE" fill-rule="nonzero" d="M39 88C17.46 88 0 70.54 0 49s17.46-39 39-39 39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 14 39 14 4 29.67 4 49s15.67 35 35 35z"/><path fill="#6B4FBB" fill-rule="nonzero" d="M48 41h-4c0-2.76-2.24-5-5-5s-5 2.24-5 5h-4a9 9 0 0 1 18 0zm-18 0h4v3h-4v-3zm14 0h4v3h-4v-3z"/><path fill="#E1DBF2" fill-rule="nonzero" d="M30 47c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h18c.55 0 1-.45 1-1V48c0-.55-.45-1-1-1H30zm0-4h18c2.76 0 5 2.24 5 5v12c0 2.76-2.24 5-5 5H30c-2.76 0-5-2.24-5-5V48c0-2.76 2.24-5 5-5z"/><path fill="#6B4FBB" d="M38 53.73c-.6-.34-1-1-1-1.73 0-1.1.9-2 2-2s2 .9 2 2c0 .74-.4 1.4-1 1.73V55c0 .55-.45 1-1 1s-1-.45-1-1v-1.27z"/><path fill="#000" fill-opacity=".03" d="M254.12 92c-.08 1-.12 2-.12 3 0 20.43 16.57 37 37 37s37-16.57 37-37c0-1-.04-2-.12-3-1.53 19.03-17.46 34-36.88 34s-35.35-14.97-36.88-34z"/><path fill="#EEE" fill-rule="nonzero" d="M291 128c-21.54 0-39-17.46-39-39s17.46-39 39-39 39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35s-15.67-35-35-35-35 15.67-35 35 15.67 35 35 35z"/><path fill="#6B4BBE" fill-rule="nonzero" d="M292 78c5.52 0 10 4.48 10 10 0 2.28-.76 4.43-2.14 6.18-1.03 1.3-.8 3.2.5 4.22 1.3 1.02 3.2.8 4.2-.5 2.22-2.8 3.44-6.26 3.44-9.9 0-8.84-7.16-16-16-16v-3.13c0-.2-.06-.4-.17-.56-.3-.42-.93-.54-1.38-.23l-9.2 6.13c-.1.06-.2.16-.28.27-.3.45-.18 1.08.28 1.38l9.2 6.13c.16.1.35.17.55.17.55 0 1-.45 1-1V78z"/><path fill="#E1DBF2" fill-rule="nonzero" d="M290 100c-5.52 0-10-4.48-10-10 0-2.25.74-4.38 2.1-6.12 1-1.3.77-3.2-.54-4.2-1.3-1.02-3.2-.78-4.2.53A15.796 15.796 0 0 0 274 90c0 8.84 7.16 16 16 16v3.13c0 .55.45 1 1 1 .2 0 .4-.06.55-.17l9.2-6.13c.46-.3.6-.93.28-1.38-.07-.1-.17-.2-.28-.28l-9.2-6.13c-.45-.3-1.08-.2-1.38.27-.1.2-.17.4-.17.6v3.1z"/></g></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/welcome/globe.svg b/app/assets/images/illustrations/welcome/globe.svg new file mode 100644 index 00000000000..c2daae5f317 --- /dev/null +++ b/app/assets/images/illustrations/welcome/globe.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M2.12 42c-.08.99-.12 1.99-.12 3 0 20.435 16.565 37 37 37s37-16.565 37-37c0-1.01-.04-2.01-.12-3C74.353 61.032 58.425 76 39 76 19.575 76 3.647 61.032 2.12 42z"/><path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/><path fill="#E1DBF2" d="M30.24 27.823A14.98 14.98 0 0 0 24 40c0 2.549.636 4.949 1.757 7.051-.297-2.684.644-4.026 2.823-4.026 3.707 0 2.462 5.365 4.473 5.761 2.01.396 4.175.396 4.267 3.29.04 1.257-.265 2.157-.917 2.7a15.095 15.095 0 0 0 8.555-1.006c.035-1.91.303-4.941 2.21-5.61 2.373-.833-.55-1.431.734-3.368 1.17-1.762-3.297-5.2 0-4.832 3.477.388 5.044-.816 6.024-1.456a14.903 14.903 0 0 0-1.373-4.94c-.873.4-2.19.465-3.702-.538-.757-.502-1.084-3.944-2.107-3.944-3.823 0-4.065 3.17-5.994 3.944-1.076.431-4.193 3.773-5.614 3.596-1.126-.14-1.071-4.417-2.45-5.166-1.359-.738-2.174-1.948-2.447-3.633zM39 59c-10.493 0-19-8.507-19-19s8.507-19 19-19 19 8.507 19 19-8.507 19-19 19z"/></g></svg>
\ No newline at end of file diff --git a/app/assets/images/illustrations/welcome/lightbulb.svg b/app/assets/images/illustrations/welcome/lightbulb.svg new file mode 100644 index 00000000000..fce10312085 --- /dev/null +++ b/app/assets/images/illustrations/welcome/lightbulb.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M2.12 42c-.08.99-.12 1.99-.12 3 0 20.435 16.565 37 37 37s37-16.565 37-37c0-1.01-.04-2.01-.12-3C74.353 61.032 58.425 76 39 76S3.647 61.032 2.12 42z"/><path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/><path fill="#6B4FBB" d="M33 52h12a2 2 0 1 1 0 4H33a2 2 0 1 1 0-4zm1 5h10a2 2 0 1 1 0 4H34a2 2 0 1 1 0-4z"/><path fill="#E1DBF2" fill-rule="nonzero" d="M45.542 46.932l.346-2.36a8.004 8.004 0 0 1 1.566-3.705c3.025-3.946 4.485-7.29 4.547-9.96C52.153 24.41 46.843 20 39 20c-7.777 0-13 4.374-13 11 0 2.4 1.462 5.73 4.573 9.846a8.009 8.009 0 0 1 1.536 3.683l.353 2.456 13.08-.054zm-17.038.624L28.15 45.1a3.997 3.997 0 0 0-.768-1.842C23.794 38.51 22 34.424 22 31c0-9.39 7.61-15 17-15s17.218 5.614 17 15c-.085 3.64-1.875 7.74-5.37 12.3a3.99 3.99 0 0 0-.784 1.853l-.346 2.36a4.003 4.003 0 0 1-3.942 3.42l-13.08.053a4 4 0 0 1-3.974-3.43z"/><path fill="#6B4FBB" d="M41 38.732a2 2 0 1 1 2 0V42a1 1 0 0 1-2 0v-3.268zm-6 0a2 2 0 1 1 2 0V42a1 1 0 0 1-2 0v-3.268z"/></g></svg>
\ No newline at end of file diff --git a/app/assets/javascripts/abuse_reports.js b/app/assets/javascripts/abuse_reports.js index 3de192d56eb..d2d3a257c0d 100644 --- a/app/assets/javascripts/abuse_reports.js +++ b/app/assets/javascripts/abuse_reports.js @@ -1,3 +1,5 @@ +import { truncate } from './lib/utils/text_utility'; + const MAX_MESSAGE_LENGTH = 500; const MESSAGE_CELL_SELECTOR = '.abuse-reports .message'; @@ -15,7 +17,7 @@ export default class AbuseReports { if (reportMessage.length > MAX_MESSAGE_LENGTH) { $messageCellElement.data('original-message', reportMessage); $messageCellElement.data('message-truncated', 'true'); - $messageCellElement.text(window.gl.text.truncate(reportMessage, MAX_MESSAGE_LENGTH)); + $messageCellElement.text(truncate(reportMessage, MAX_MESSAGE_LENGTH)); } } diff --git a/app/assets/javascripts/behaviors/copy_to_clipboard.js b/app/assets/javascripts/behaviors/copy_to_clipboard.js new file mode 100644 index 00000000000..cdea625fc8c --- /dev/null +++ b/app/assets/javascripts/behaviors/copy_to_clipboard.js @@ -0,0 +1,73 @@ +import Clipboard from 'clipboard'; + +function showTooltip(target, title) { + const $target = $(target); + const originalTitle = $target.data('original-title'); + + if (!$target.data('hideTooltip')) { + $target + .attr('title', title) + .tooltip('fixTitle') + .tooltip('show') + .attr('title', originalTitle) + .tooltip('fixTitle'); + } +} + +function genericSuccess(e) { + showTooltip(e.trigger, 'Copied'); + // Clear the selection and blur the trigger so it loses its border + e.clearSelection(); + $(e.trigger).blur(); +} + +/** + * Safari > 10 doesn't support `execCommand`, so instead we inform the user to copy manually. + * See http://clipboardjs.com/#browser-support + */ +function genericError(e) { + let key; + if (/Mac/i.test(navigator.userAgent)) { + key = '⌘'; // Command + } else { + key = 'Ctrl'; + } + showTooltip(e.trigger, `Press ${key}-C to copy`); +} + +export default function initCopyToClipboard() { + const clipboard = new Clipboard('[data-clipboard-target], [data-clipboard-text]'); + clipboard.on('success', genericSuccess); + clipboard.on('error', genericError); + + /** + * This a workaround around ClipboardJS limitations to allow the context-specific copy/pasting + * of plain text or GFM. The Ruby `clipboard_button` helper sneaks a JSON hash with `text` and + * `gfm` keys into the `data-clipboard-text` attribute that ClipboardJS reads from. + * When ClipboardJS creates a new `textarea` (directly inside `body`, with a `readonly` + * attribute`), sets its value to the value of this data attribute, focusses on it, and finally + * programmatically issues the 'Copy' command, this code intercepts the copy command/event at + * the last minute to deconstruct this JSON hash and set the `text/plain` and `text/x-gfm` copy + * data types to the intended values. + */ + $(document).on('copy', 'body > textarea[readonly]', (e) => { + const clipboardData = e.originalEvent.clipboardData; + if (!clipboardData) return; + + const text = e.target.value; + + let json; + try { + json = JSON.parse(text); + } catch (ex) { + return; + } + + if (!json.text || !json.gfm) return; + + e.preventDefault(); + + clipboardData.setData('text/plain', json.text); + clipboardData.setData('text/x-gfm', json.gfm); + }); +} diff --git a/app/assets/javascripts/behaviors/index.js b/app/assets/javascripts/behaviors/index.js index 671532394a9..34e905222b4 100644 --- a/app/assets/javascripts/behaviors/index.js +++ b/app/assets/javascripts/behaviors/index.js @@ -1,6 +1,7 @@ import './autosize'; import './bind_in_out'; import initCopyAsGFM from './copy_as_gfm'; +import initCopyToClipboard from './copy_to_clipboard'; import './details_behavior'; import installGlEmojiElement from './gl_emoji'; import './quick_submit'; @@ -9,3 +10,4 @@ import './toggler_behavior'; installGlEmojiElement(); initCopyAsGFM(); +initCopyToClipboard(); diff --git a/app/assets/javascripts/blob_edit/blob_bundle.js b/app/assets/javascripts/blob_edit/blob_bundle.js index b5500ac116f..6b06344f5ba 100644 --- a/app/assets/javascripts/blob_edit/blob_bundle.js +++ b/app/assets/javascripts/blob_edit/blob_bundle.js @@ -1,7 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, quotes, vars-on-top, no-unused-vars, no-new, max-len */ /* global EditBlob */ -/* global NewCommitForm */ - +import NewCommitForm from '../new_commit_form'; import EditBlob from './edit_blob'; import BlobFileDropzone from '../blob/blob_file_dropzone'; diff --git a/app/assets/javascripts/boards/boards_bundle.js b/app/assets/javascripts/boards/boards_bundle.js index ef4093b59e3..20d23162940 100644 --- a/app/assets/javascripts/boards/boards_bundle.js +++ b/app/assets/javascripts/boards/boards_bundle.js @@ -1,12 +1,13 @@ /* eslint-disable one-var, quote-props, comma-dangle, space-before-function-paren */ -/* global BoardService */ import _ from 'underscore'; import Vue from 'vue'; import VueResource from 'vue-resource'; import Flash from '../flash'; +import { __ } from '../locale'; import FilteredSearchBoards from './filtered_search_boards'; import eventHub from './eventhub'; +import sidebarEventHub from '../sidebar/event_hub'; import './models/issue'; import './models/label'; import './models/list'; @@ -14,7 +15,7 @@ import './models/milestone'; import './models/assignee'; import './stores/boards_store'; import './stores/modal_store'; -import './services/board_service'; +import BoardService from './services/board_service'; import './mixins/modal_mixins'; import './mixins/sortable_default_options'; import './filters/due_date_filters'; @@ -77,11 +78,16 @@ $(() => { }); Store.rootPath = this.boardsEndpoint; - // Listen for updateTokens event eventHub.$on('updateTokens', this.updateTokens); + eventHub.$on('newDetailIssue', this.updateDetailIssue); + eventHub.$on('clearDetailIssue', this.clearDetailIssue); + sidebarEventHub.$on('toggleSubscription', this.toggleSubscription); }, beforeDestroy() { eventHub.$off('updateTokens', this.updateTokens); + eventHub.$off('newDetailIssue', this.updateDetailIssue); + eventHub.$off('clearDetailIssue', this.clearDetailIssue); + sidebarEventHub.$off('toggleSubscription', this.toggleSubscription); }, mounted () { this.filterManager = new FilteredSearchBoards(Store.filter, true); @@ -112,6 +118,46 @@ $(() => { methods: { updateTokens() { this.filterManager.updateTokens(); + }, + updateDetailIssue(newIssue) { + const sidebarInfoEndpoint = newIssue.sidebarInfoEndpoint; + if (sidebarInfoEndpoint && newIssue.subscribed === undefined) { + newIssue.setFetchingState('subscriptions', true); + BoardService.getIssueInfo(sidebarInfoEndpoint) + .then(res => res.json()) + .then((data) => { + newIssue.setFetchingState('subscriptions', false); + newIssue.updateData({ + subscribed: data.subscribed, + }); + }) + .catch(() => { + newIssue.setFetchingState('subscriptions', false); + Flash(__('An error occurred while fetching sidebar data')); + }); + } + + Store.detail.issue = newIssue; + }, + clearDetailIssue() { + Store.detail.issue = {}; + }, + toggleSubscription(id) { + const issue = Store.detail.issue; + if (issue.id === id && issue.toggleSubscriptionEndpoint) { + issue.setFetchingState('subscriptions', true); + BoardService.toggleIssueSubscription(issue.toggleSubscriptionEndpoint) + .then(() => { + issue.setFetchingState('subscriptions', false); + issue.updateData({ + subscribed: !issue.subscribed, + }); + }) + .catch(() => { + issue.setFetchingState('subscriptions', false); + Flash(__('An error occurred when toggling the notification subscription')); + }); + } } }, }); diff --git a/app/assets/javascripts/boards/components/board_card.js b/app/assets/javascripts/boards/components/board_card.vue index 079fb6438b9..0b220a56e0b 100644 --- a/app/assets/javascripts/boards/components/board_card.js +++ b/app/assets/javascripts/boards/components/board_card.vue @@ -1,25 +1,11 @@ +<script> import './issue_card_inner'; +import eventHub from '../eventhub'; const Store = gl.issueBoards.BoardsStore; export default { name: 'BoardsIssueCard', - template: ` - <li class="card" - :class="{ 'user-can-drag': !disabled && issue.id, 'is-disabled': disabled || !issue.id, 'is-active': issueDetailVisible }" - :index="index" - :data-issue-id="issue.id" - @mousedown="mouseDown" - @mousemove="mouseMove" - @mouseup="showIssue($event)"> - <issue-card-inner - :list="list" - :issue="issue" - :issue-link-base="issueLinkBase" - :root-path="rootPath" - :update-filters="true" /> - </li> - `, components: { 'issue-card-inner': gl.issueBoards.IssueCardInner, }, @@ -56,12 +42,30 @@ export default { this.showDetail = false; if (Store.detail.issue && Store.detail.issue.id === this.issue.id) { - Store.detail.issue = {}; + eventHub.$emit('clearDetailIssue'); } else { - Store.detail.issue = this.issue; + eventHub.$emit('newDetailIssue', this.issue); Store.detail.list = this.list; } } }, }, }; +</script> + +<template> + <li class="card" + :class="{ 'user-can-drag': !disabled && issue.id, 'is-disabled': disabled || !issue.id, 'is-active': issueDetailVisible }" + :index="index" + :data-issue-id="issue.id" + @mousedown="mouseDown" + @mousemove="mouseMove" + @mouseup="showIssue($event)"> + <issue-card-inner + :list="list" + :issue="issue" + :issue-link-base="issueLinkBase" + :root-path="rootPath" + :update-filters="true" /> + </li> +</template> diff --git a/app/assets/javascripts/boards/components/board_list.js b/app/assets/javascripts/boards/components/board_list.js index 6159680f1e6..29aeb8e84aa 100644 --- a/app/assets/javascripts/boards/components/board_list.js +++ b/app/assets/javascripts/boards/components/board_list.js @@ -1,6 +1,6 @@ /* global Sortable */ import boardNewIssue from './board_new_issue'; -import boardCard from './board_card'; +import boardCard from './board_card.vue'; import eventHub from '../eventhub'; import loadingIcon from '../../vue_shared/components/loading_icon.vue'; diff --git a/app/assets/javascripts/boards/components/board_sidebar.js b/app/assets/javascripts/boards/components/board_sidebar.js index 9ae5e270a4b..faa76da964f 100644 --- a/app/assets/javascripts/boards/components/board_sidebar.js +++ b/app/assets/javascripts/boards/components/board_sidebar.js @@ -5,12 +5,13 @@ import Vue from 'vue'; import Flash from '../../flash'; import eventHub from '../../sidebar/event_hub'; -import AssigneeTitle from '../../sidebar/components/assignees/assignee_title'; -import Assignees from '../../sidebar/components/assignees/assignees'; +import assigneeTitle from '../../sidebar/components/assignees/assignee_title'; +import assignees from '../../sidebar/components/assignees/assignees'; import DueDateSelectors from '../../due_date_select'; import './sidebar/remove_issue'; import IssuableContext from '../../issuable_context'; import LabelsSelect from '../../labels_select'; +import subscriptions from '../../sidebar/components/subscriptions/subscriptions.vue'; const Store = gl.issueBoards.BoardsStore; @@ -117,11 +118,11 @@ gl.issueBoards.BoardSidebar = Vue.extend({ new DueDateSelectors(); new LabelsSelect(); new Sidebar(); - gl.Subscription.bindAll('.subscription'); }, components: { + assigneeTitle, + assignees, removeBtn: gl.issueBoards.RemoveIssueBtn, - 'assignee-title': AssigneeTitle, - assignees: Assignees, + subscriptions, }, }); diff --git a/app/assets/javascripts/boards/components/modal/footer.js b/app/assets/javascripts/boards/components/modal/footer.js index de9e44cef35..182957113a2 100644 --- a/app/assets/javascripts/boards/components/modal/footer.js +++ b/app/assets/javascripts/boards/components/modal/footer.js @@ -3,6 +3,7 @@ import Vue from 'vue'; import Flash from '../../../flash'; import './lists_dropdown'; +import { pluralize } from '../../../lib/utils/text_utility'; const ModalStore = gl.issueBoards.ModalStore; @@ -21,7 +22,7 @@ gl.issueBoards.ModalFooter = Vue.extend({ submitText() { const count = ModalStore.selectedCount(); - return `Add ${count > 0 ? count : ''} ${gl.text.pluralize('issue', count)}`; + return `Add ${count > 0 ? count : ''} ${pluralize('issue', count)}`; }, }, methods: { diff --git a/app/assets/javascripts/boards/models/issue.js b/app/assets/javascripts/boards/models/issue.js index 407db176446..81edd95bf2b 100644 --- a/app/assets/javascripts/boards/models/issue.js +++ b/app/assets/javascripts/boards/models/issue.js @@ -17,6 +17,12 @@ class ListIssue { this.assignees = []; this.selected = false; this.position = obj.relative_position || Infinity; + this.isFetching = { + subscriptions: true, + }; + this.isLoading = {}; + this.sidebarInfoEndpoint = obj.issue_sidebar_endpoint; + this.toggleSubscriptionEndpoint = obj.toggle_subscription_endpoint; if (obj.milestone) { this.milestone = new ListMilestone(obj.milestone); @@ -73,6 +79,18 @@ class ListIssue { return gl.issueBoards.BoardsStore.state.lists.filter(list => list.findIssue(this.id)); } + updateData(newData) { + Object.assign(this, newData); + } + + setFetchingState(key, value) { + this.isFetching[key] = value; + } + + setLoadingState(key, value) { + this.isLoading[key] = value; + } + update (url) { const data = { issue: { diff --git a/app/assets/javascripts/boards/services/board_service.js b/app/assets/javascripts/boards/services/board_service.js index 97e80afa3f8..fa7ddd25e1f 100644 --- a/app/assets/javascripts/boards/services/board_service.js +++ b/app/assets/javascripts/boards/services/board_service.js @@ -2,7 +2,7 @@ import Vue from 'vue'; -class BoardService { +export default class BoardService { constructor ({ boardsEndpoint, listsEndpoint, bulkUpdatePath, boardId }) { this.boards = Vue.resource(`${boardsEndpoint}{/id}.json`, {}, { issues: { @@ -88,6 +88,14 @@ class BoardService { return this.issues.bulkUpdate(data); } + + static getIssueInfo(endpoint) { + return Vue.http.get(endpoint); + } + + static toggleIssueSubscription(endpoint) { + return Vue.http.post(endpoint); + } } window.BoardService = BoardService; diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js index dc443475952..2cfd6179a25 100644 --- a/app/assets/javascripts/clusters/clusters_bundle.js +++ b/app/assets/javascripts/clusters/clusters_bundle.js @@ -48,6 +48,7 @@ export default class Clusters { this.toggle = this.toggle.bind(this); this.installApplication = this.installApplication.bind(this); + this.showToken = this.showToken.bind(this); this.toggleButton = document.querySelector('.js-toggle-cluster'); this.toggleInput = document.querySelector('.js-toggle-input'); @@ -56,6 +57,8 @@ export default class Clusters { this.creatingContainer = document.querySelector('.js-cluster-creating'); this.errorReasonContainer = this.errorContainer.querySelector('.js-error-reason'); this.successApplicationContainer = document.querySelector('.js-cluster-application-notice'); + this.showTokenButton = document.querySelector('.js-show-cluster-token'); + this.tokenField = document.querySelector('.js-cluster-token'); initSettingsPanels(); this.initApplications(); @@ -97,11 +100,13 @@ export default class Clusters { addListeners() { this.toggleButton.addEventListener('click', this.toggle); + if (this.showTokenButton) this.showTokenButton.addEventListener('click', this.showToken); eventHub.$on('installApplication', this.installApplication); } removeListeners() { this.toggleButton.removeEventListener('click', this.toggle); + if (this.showTokenButton) this.showTokenButton.removeEventListener('click', this.showToken); eventHub.$off('installApplication', this.installApplication); } @@ -145,8 +150,18 @@ export default class Clusters { } toggle() { - this.toggleButton.classList.toggle('checked'); - this.toggleInput.setAttribute('value', this.toggleButton.classList.contains('checked').toString()); + this.toggleButton.classList.toggle('is-checked'); + this.toggleInput.setAttribute('value', this.toggleButton.classList.contains('is-checked').toString()); + } + + showToken() { + const type = this.tokenField.getAttribute('type'); + + if (type === 'password') { + this.tokenField.setAttribute('type', 'text'); + } else { + this.tokenField.setAttribute('type', 'password'); + } } hideAll() { diff --git a/app/assets/javascripts/clusters/clusters_index.js b/app/assets/javascripts/clusters/clusters_index.js new file mode 100644 index 00000000000..6844d1dbd83 --- /dev/null +++ b/app/assets/javascripts/clusters/clusters_index.js @@ -0,0 +1,58 @@ +import Flash from '../flash'; +import { s__ } from '../locale'; +import ClustersService from './services/clusters_service'; +/** + * Toggles loading and disabled classes. + * @param {HTMLElement} button + */ +const toggleLoadingButton = (button) => { + if (button.getAttribute('disabled')) { + button.removeAttribute('disabled'); + } else { + button.setAttribute('disabled', true); + } + + button.classList.toggle('is-loading'); +}; + +/** + * Toggles checked class for the given button + * @param {HTMLElement} button + */ +const toggleValue = (button) => { + button.classList.toggle('is-checked'); +}; + +/** + * Handles toggle buttons in the cluster's table. + * + * When the user clicks the toggle button for each cluster, it: + * - toggles the button + * - shows a loading and disables button + * - Makes a put request to the given endpoint + * Once we receive the response, either: + * 1) Show updated status in case of successfull response + * 2) Show initial status in case of failed response + */ +export default function setClusterTableToggles() { + document.querySelectorAll('.js-toggle-cluster-list') + .forEach(button => button.addEventListener('click', (e) => { + const toggleButton = e.currentTarget; + const endpoint = toggleButton.getAttribute('data-endpoint'); + + toggleValue(toggleButton); + toggleLoadingButton(toggleButton); + + const value = toggleButton.classList.contains('is-checked'); + + ClustersService.updateCluster(endpoint, { cluster: { enabled: value } }) + .then(() => { + toggleLoadingButton(toggleButton); + }) + .catch(() => { + toggleLoadingButton(toggleButton); + toggleValue(toggleButton); + Flash(s__('ClusterIntegration|Something went wrong on our end.')); + }); + })); +} diff --git a/app/assets/javascripts/clusters/services/clusters_service.js b/app/assets/javascripts/clusters/services/clusters_service.js index 0ac8e68187d..755c2981c2e 100644 --- a/app/assets/javascripts/clusters/services/clusters_service.js +++ b/app/assets/javascripts/clusters/services/clusters_service.js @@ -1,10 +1,7 @@ -import axios from 'axios'; -import setAxiosCsrfToken from '../../lib/utils/axios_utils'; +import axios from '../../lib/utils/axios_utils'; export default class ClusterService { constructor(options = {}) { - setAxiosCsrfToken(); - this.options = options; this.appInstallEndpointMap = { helm: this.options.installHelmEndpoint, @@ -18,7 +15,10 @@ export default class ClusterService { } installApplication(appId) { - const endpoint = this.appInstallEndpointMap[appId]; - return axios.post(endpoint); + return axios.post(this.appInstallEndpointMap[appId]); + } + + static updateCluster(endpoint, data) { + return axios.put(endpoint, data); } } diff --git a/app/assets/javascripts/commit/image_file.js b/app/assets/javascripts/commit/image_file.js index e7adf8814b8..50d0cb5c86d 100644 --- a/app/assets/javascripts/commit/image_file.js +++ b/app/assets/javascripts/commit/image_file.js @@ -1,217 +1,208 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-use-before-define, prefer-arrow-callback, no-else-return, consistent-return, prefer-template, quotes, one-var, one-var-declaration-per-line, no-unused-vars, no-return-assign, comma-dangle, quote-props, no-unused-expressions, no-sequences, object-shorthand, max-len */ import 'vendor/jquery.waitforimages'; -(function() { - gl.ImageFile = (function() { - var prepareFrames; - - // Width where images must fits in, for 2-up this gets divided by 2 - ImageFile.availWidth = 900; - - ImageFile.viewModes = ['two-up', 'swipe']; - - function ImageFile(file) { - this.file = file; - this.requestImageInfo($('.two-up.view .frame.deleted img', this.file), (function(_this) { - return function(deletedWidth, deletedHeight) { - return _this.requestImageInfo($('.two-up.view .frame.added img', _this.file), function(width, height) { - _this.initViewModes(); - - // Load two-up view after images are loaded - // so that we can display the correct width and height information - const $images = $('.two-up.view img', _this.file); - - $images.waitForImages(function() { - _this.initView('two-up'); - }); +// Width where images must fits in, for 2-up this gets divided by 2 +const availWidth = 900; +const viewModes = ['two-up', 'swipe']; + +export default class ImageFile { + constructor(file) { + this.file = file; + this.requestImageInfo($('.two-up.view .frame.deleted img', this.file), (function(_this) { + return function(deletedWidth, deletedHeight) { + return _this.requestImageInfo($('.two-up.view .frame.added img', _this.file), function(width, height) { + _this.initViewModes(); + + // Load two-up view after images are loaded + // so that we can display the correct width and height information + const $images = $('.two-up.view img', _this.file); + + $images.waitForImages(function() { + _this.initView('two-up'); + }); + }); + }; + })(this)); + } + + initViewModes() { + const viewMode = viewModes[0]; + $('.view-modes', this.file).removeClass('hide'); + $('.view-modes-menu', this.file).on('click', 'li', (function(_this) { + return function(event) { + if (!$(event.currentTarget).hasClass('active')) { + return _this.activateViewMode(event.currentTarget.className); + } + }; + })(this)); + return this.activateViewMode(viewMode); + } + + activateViewMode(viewMode) { + $('.view-modes-menu li', this.file).removeClass('active').filter("." + viewMode).addClass('active'); + return $(".view:visible:not(." + viewMode + ")", this.file).fadeOut(200, (function(_this) { + return function() { + $(".view." + viewMode, _this.file).fadeIn(200); + return _this.initView(viewMode); + }; + })(this)); + } + + initView(viewMode) { + return this.views[viewMode].call(this); + } + // eslint-disable-next-line class-methods-use-this + initDraggable($el, padding, callback) { + var dragging = false; + var $body = $('body'); + var $offsetEl = $el.parent(); + + $el.off('mousedown').on('mousedown', function() { + dragging = true; + $body.css('user-select', 'none'); + }); + + $body.off('mouseup').off('mousemove').on('mouseup', function() { + dragging = false; + $body.css('user-select', ''); + }) + .on('mousemove', function(e) { + var left; + if (!dragging) return; + + left = e.pageX - ($offsetEl.offset().left + padding); + + callback(e, left); + }); + } + + prepareFrames(view) { + var maxHeight, maxWidth; + maxWidth = 0; + maxHeight = 0; + $('.frame', view).each((function(_this) { + return function(index, frame) { + var height, width; + width = $(frame).width(); + height = $(frame).height(); + maxWidth = width > maxWidth ? width : maxWidth; + return maxHeight = height > maxHeight ? height : maxHeight; + }; + })(this)).css({ + width: maxWidth, + height: maxHeight + }); + return [maxWidth, maxHeight]; + } + + views = { + 'two-up': function() { + return $('.two-up.view .wrap', this.file).each((function(_this) { + return function(index, wrap) { + $('img', wrap).each(function() { + var currentWidth; + currentWidth = $(this).width(); + if (currentWidth > availWidth / 2) { + return $(this).width(availWidth / 2); + } + }); + return _this.requestImageInfo($('img', wrap), function(width, height) { + $('.image-info .meta-width', wrap).text(width + "px"); + $('.image-info .meta-height', wrap).text(height + "px"); + return $('.image-info', wrap).removeClass('hide'); }); }; })(this)); - } + }, + 'swipe': function() { + var maxHeight, maxWidth; + maxWidth = 0; + maxHeight = 0; + return $('.swipe.view', this.file).each((function(_this) { + return function(index, view) { + var $swipeWrap, $swipeBar, $swipeFrame, wrapPadding, ref; + ref = this.prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1]; + $swipeFrame = $('.swipe-frame', view); + $swipeWrap = $('.swipe-wrap', view); + $swipeBar = $('.swipe-bar', view); + + $swipeFrame.css({ + width: maxWidth + 16, + height: maxHeight + 28 + }); + $swipeWrap.css({ + width: maxWidth + 1, + height: maxHeight + 2 + }); + // Set swipeBar left position to match image frame + $swipeBar.css({ + left: 1 + }); - ImageFile.prototype.initViewModes = function() { - var viewMode; - viewMode = ImageFile.viewModes[0]; - $('.view-modes', this.file).removeClass('hide'); - $('.view-modes-menu', this.file).on('click', 'li', (function(_this) { - return function(event) { - if (!$(event.currentTarget).hasClass('active')) { - return _this.activateViewMode(event.currentTarget.className); - } - }; - })(this)); - return this.activateViewMode(viewMode); - }; - - ImageFile.prototype.activateViewMode = function(viewMode) { - $('.view-modes-menu li', this.file).removeClass('active').filter("." + viewMode).addClass('active'); - return $(".view:visible:not(." + viewMode + ")", this.file).fadeOut(200, (function(_this) { - return function() { - $(".view." + viewMode, _this.file).fadeIn(200); - return _this.initView(viewMode); + wrapPadding = parseInt($swipeWrap.css('right').replace('px', ''), 10); + + _this.initDraggable($swipeBar, wrapPadding, function(e, left) { + if (left > 0 && left < $swipeFrame.width() - (wrapPadding * 2)) { + $swipeWrap.width((maxWidth + 1) - left); + $swipeBar.css('left', left); + } + }); }; })(this)); - }; - - ImageFile.prototype.initView = function(viewMode) { - return this.views[viewMode].call(this); - }; - - ImageFile.prototype.initDraggable = function($el, padding, callback) { - var dragging = false; - var $body = $('body'); - var $offsetEl = $el.parent(); - - $el.off('mousedown').on('mousedown', function() { - dragging = true; - $body.css('user-select', 'none'); - }); - - $body.off('mouseup').off('mousemove').on('mouseup', function() { - dragging = false; - $body.css('user-select', ''); - }) - .on('mousemove', function(e) { - var left; - if (!dragging) return; + }, + 'onion-skin': function() { + var dragTrackWidth, maxHeight, maxWidth; + maxWidth = 0; + maxHeight = 0; + dragTrackWidth = $('.drag-track', this.file).width() - $('.dragger', this.file).width(); + return $('.onion-skin.view', this.file).each((function(_this) { + return function(index, view) { + var $frame, $track, $dragger, $frameAdded, framePadding, ref, dragging = false; + ref = this.prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1]; + $frame = $('.onion-skin-frame', view); + $frameAdded = $('.frame.added', view); + $track = $('.drag-track', view); + $dragger = $('.dragger', $track); + + $frame.css({ + width: maxWidth + 16, + height: maxHeight + 28 + }); + $('.swipe-wrap', view).css({ + width: maxWidth + 1, + height: maxHeight + 2 + }); + $dragger.css({ + left: dragTrackWidth + }); - left = e.pageX - ($offsetEl.offset().left + padding); + framePadding = parseInt($frameAdded.css('right').replace('px', ''), 10); - callback(e, left); - }); - }; + _this.initDraggable($dragger, framePadding, function(e, left) { + var opacity = left / dragTrackWidth; - prepareFrames = function(view) { - var maxHeight, maxWidth; - maxWidth = 0; - maxHeight = 0; - $('.frame', view).each((function(_this) { - return function(index, frame) { - var height, width; - width = $(frame).width(); - height = $(frame).height(); - maxWidth = width > maxWidth ? width : maxWidth; - return maxHeight = height > maxHeight ? height : maxHeight; + if (opacity >= 0 && opacity <= 1) { + $dragger.css('left', left); + $frameAdded.css('opacity', opacity); + } + }); }; - })(this)).css({ - width: maxWidth, - height: maxHeight - }); - return [maxWidth, maxHeight]; - }; - - ImageFile.prototype.views = { - 'two-up': function() { - return $('.two-up.view .wrap', this.file).each((function(_this) { - return function(index, wrap) { - $('img', wrap).each(function() { - var currentWidth; - currentWidth = $(this).width(); - if (currentWidth > ImageFile.availWidth / 2) { - return $(this).width(ImageFile.availWidth / 2); - } - }); - return _this.requestImageInfo($('img', wrap), function(width, height) { - $('.image-info .meta-width', wrap).text(width + "px"); - $('.image-info .meta-height', wrap).text(height + "px"); - return $('.image-info', wrap).removeClass('hide'); - }); - }; - })(this)); - }, - 'swipe': function() { - var maxHeight, maxWidth; - maxWidth = 0; - maxHeight = 0; - return $('.swipe.view', this.file).each((function(_this) { - return function(index, view) { - var $swipeWrap, $swipeBar, $swipeFrame, wrapPadding, ref; - ref = prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1]; - $swipeFrame = $('.swipe-frame', view); - $swipeWrap = $('.swipe-wrap', view); - $swipeBar = $('.swipe-bar', view); - - $swipeFrame.css({ - width: maxWidth + 16, - height: maxHeight + 28 - }); - $swipeWrap.css({ - width: maxWidth + 1, - height: maxHeight + 2 - }); - // Set swipeBar left position to match image frame - $swipeBar.css({ - left: 1 - }); - - wrapPadding = parseInt($swipeWrap.css('right').replace('px', ''), 10); - - _this.initDraggable($swipeBar, wrapPadding, function(e, left) { - if (left > 0 && left < $swipeFrame.width() - (wrapPadding * 2)) { - $swipeWrap.width((maxWidth + 1) - left); - $swipeBar.css('left', left); - } - }); - }; - })(this)); - }, - 'onion-skin': function() { - var dragTrackWidth, maxHeight, maxWidth; - maxWidth = 0; - maxHeight = 0; - dragTrackWidth = $('.drag-track', this.file).width() - $('.dragger', this.file).width(); - return $('.onion-skin.view', this.file).each((function(_this) { - return function(index, view) { - var $frame, $track, $dragger, $frameAdded, framePadding, ref, dragging = false; - ref = prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1]; - $frame = $('.onion-skin-frame', view); - $frameAdded = $('.frame.added', view); - $track = $('.drag-track', view); - $dragger = $('.dragger', $track); - - $frame.css({ - width: maxWidth + 16, - height: maxHeight + 28 - }); - $('.swipe-wrap', view).css({ - width: maxWidth + 1, - height: maxHeight + 2 - }); - $dragger.css({ - left: dragTrackWidth - }); - - framePadding = parseInt($frameAdded.css('right').replace('px', ''), 10); - - _this.initDraggable($dragger, framePadding, function(e, left) { - var opacity = left / dragTrackWidth; - - if (opacity >= 0 && opacity <= 1) { - $dragger.css('left', left); - $frameAdded.css('opacity', opacity); - } - }); + })(this)); + } + } + + requestImageInfo(img, callback) { + const domImg = img.get(0); + if (domImg) { + if (domImg.complete) { + return callback.call(this, domImg.naturalWidth, domImg.naturalHeight); + } else { + return img.on('load', (function(_this) { + return function() { + return callback.call(_this, domImg.naturalWidth, domImg.naturalHeight); }; })(this)); } - }; - - ImageFile.prototype.requestImageInfo = function(img, callback) { - var domImg; - domImg = img.get(0); - if (domImg) { - if (domImg.complete) { - return callback.call(this, domImg.naturalWidth, domImg.naturalHeight); - } else { - return img.on('load', (function(_this) { - return function() { - return callback.call(_this, domImg.naturalWidth, domImg.naturalHeight); - }; - })(this)); - } - } - }; - - return ImageFile; - })(); -}).call(window); + } + } +} diff --git a/app/assets/javascripts/commits.js b/app/assets/javascripts/commits.js index ae6b8902032..9b952ea7b60 100644 --- a/app/assets/javascripts/commits.js +++ b/app/assets/javascripts/commits.js @@ -3,6 +3,8 @@ prefer-template, object-shorthand, prefer-arrow-callback */ /* global Pager */ +import { pluralize } from './lib/utils/text_utility'; + export default (function () { const CommitsList = {}; @@ -86,7 +88,7 @@ export default (function () { // Update commits count in the previous commits header. commitsCount += Number($(processedData).nextUntil('li.js-commit-header').first().find('li.commit').length); - $commitsHeadersLast.find('span.commits-count').text(`${commitsCount} ${gl.text.pluralize('commit', commitsCount)}`); + $commitsHeadersLast.find('span.commits-count').text(`${commitsCount} ${pluralize('commit', commitsCount)}`); } gl.utils.localTimeAgo($processedData.find('.js-timeago')); diff --git a/app/assets/javascripts/commons/index.js b/app/assets/javascripts/commons/index.js index 768453b28f1..0d2fe2925d8 100644 --- a/app/assets/javascripts/commons/index.js +++ b/app/assets/javascripts/commons/index.js @@ -3,3 +3,4 @@ import './polyfills'; import './jquery'; import './bootstrap'; import './vue'; +import '../lib/utils/axios_utils'; diff --git a/app/assets/javascripts/commons/polyfills.js b/app/assets/javascripts/commons/polyfills.js index cb5a9a9f6b5..ff9e4485916 100644 --- a/app/assets/javascripts/commons/polyfills.js +++ b/app/assets/javascripts/commons/polyfills.js @@ -10,6 +10,7 @@ import 'core-js/fn/string/from-code-point'; import 'core-js/fn/symbol'; // Browser polyfills +import 'classlist-polyfill'; import './polyfills/custom_event'; import './polyfills/element'; import './polyfills/event'; diff --git a/app/assets/javascripts/copy_to_clipboard.js b/app/assets/javascripts/copy_to_clipboard.js deleted file mode 100644 index 1f3c7e1772d..00000000000 --- a/app/assets/javascripts/copy_to_clipboard.js +++ /dev/null @@ -1,74 +0,0 @@ -/* eslint-disable func-names, space-before-function-paren, one-var, no-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, prefer-arrow-callback, max-len */ - -import Clipboard from 'vendor/clipboard'; - -var genericError, genericSuccess, showTooltip; - -genericSuccess = function(e) { - showTooltip(e.trigger, 'Copied'); - // Clear the selection and blur the trigger so it loses its border - e.clearSelection(); - return $(e.trigger).blur(); -}; - -// Safari doesn't support `execCommand`, so instead we inform the user to -// copy manually. -// -// See http://clipboardjs.com/#browser-support -genericError = function(e) { - var key; - if (/Mac/i.test(navigator.userAgent)) { - key = '⌘'; // Command - } else { - key = 'Ctrl'; - } - return showTooltip(e.trigger, "Press " + key + "-C to copy"); -}; - -showTooltip = function(target, title) { - var $target = $(target); - var originalTitle = $target.data('original-title'); - - if (!$target.data('hideTooltip')) { - $target - .attr('title', 'Copied') - .tooltip('fixTitle') - .tooltip('show') - .attr('title', originalTitle) - .tooltip('fixTitle'); - } -}; - -$(function() { - const clipboard = new Clipboard('[data-clipboard-target], [data-clipboard-text]'); - clipboard.on('success', genericSuccess); - clipboard.on('error', genericError); - - // This a workaround around ClipboardJS limitations to allow the context-specific copy/pasting of plain text or GFM. - // The Ruby `clipboard_button` helper sneaks a JSON hash with `text` and `gfm` keys into the `data-clipboard-text` - // attribute that ClipboardJS reads from. - // When ClipboardJS creates a new `textarea` (directly inside `body`, with a `readonly` attribute`), sets its value - // to the value of this data attribute, focusses on it, and finally programmatically issues the 'Copy' command, - // this code intercepts the copy command/event at the last minute to deconstruct this JSON hash and set the - // `text/plain` and `text/x-gfm` copy data types to the intended values. - $(document).on('copy', 'body > textarea[readonly]', function(e) { - const clipboardData = e.originalEvent.clipboardData; - if (!clipboardData) return; - - const text = e.target.value; - - let json; - try { - json = JSON.parse(text); - } catch (ex) { - return; - } - - if (!json.text || !json.gfm) return; - - e.preventDefault(); - - clipboardData.setData('text/plain', json.text); - clipboardData.setData('text/x-gfm', json.gfm); - }); -}); diff --git a/app/assets/javascripts/create_label.js b/app/assets/javascripts/create_label.js index 3bed0678350..9a4c9bfcc80 100644 --- a/app/assets/javascripts/create_label.js +++ b/app/assets/javascripts/create_label.js @@ -1,5 +1,6 @@ /* eslint-disable func-names, prefer-arrow-callback */ import Api from './api'; +import { humanize } from './lib/utils/text_utility'; export default class CreateLabelDropdown { constructor($el, namespacePath, projectPath) { @@ -107,7 +108,7 @@ export default class CreateLabelDropdown { errors = label.message; } else { errors = Object.keys(label.message).map(key => - `${gl.text.humanize(key)} ${label.message[key].join(', ')}`, + `${humanize(key)} ${label.message[key].join(', ')}`, ).join('<br/>'); } diff --git a/app/assets/javascripts/create_merge_request_dropdown.js b/app/assets/javascripts/create_merge_request_dropdown.js index bf40eb3ee11..23425672b16 100644 --- a/app/assets/javascripts/create_merge_request_dropdown.js +++ b/app/assets/javascripts/create_merge_request_dropdown.js @@ -2,6 +2,7 @@ import Flash from './flash'; import DropLab from './droplab/drop_lab'; import ISetter from './droplab/plugins/input_setter'; +import { __, sprintf } from './locale'; // Todo: Remove this when fixing issue in input_setter plugin const InputSetter = Object.assign({}, ISetter); @@ -12,28 +13,49 @@ const CREATE_BRANCH = 'create-branch'; export default class CreateMergeRequestDropdown { constructor(wrapperEl) { this.wrapperEl = wrapperEl; + this.availableButton = this.wrapperEl.querySelector('.available'); + this.branchInput = this.wrapperEl.querySelector('.js-branch-name'); + this.branchMessage = this.wrapperEl.querySelector('.js-branch-message'); this.createMergeRequestButton = this.wrapperEl.querySelector('.js-create-merge-request'); - this.dropdownToggle = this.wrapperEl.querySelector('.js-dropdown-toggle'); + this.createTargetButton = this.wrapperEl.querySelector('.js-create-target'); this.dropdownList = this.wrapperEl.querySelector('.dropdown-menu'); - this.availableButton = this.wrapperEl.querySelector('.available'); + this.dropdownToggle = this.wrapperEl.querySelector('.js-dropdown-toggle'); + this.refInput = this.wrapperEl.querySelector('.js-ref'); + this.refMessage = this.wrapperEl.querySelector('.js-ref-message'); this.unavailableButton = this.wrapperEl.querySelector('.unavailable'); this.unavailableButtonArrow = this.unavailableButton.querySelector('.fa'); this.unavailableButtonText = this.unavailableButton.querySelector('.text'); - this.createBranchPath = this.wrapperEl.dataset.createBranchPath; + this.branchCreated = false; + this.branchIsValid = true; this.canCreatePath = this.wrapperEl.dataset.canCreatePath; + this.createBranchPath = this.wrapperEl.dataset.createBranchPath; this.createMrPath = this.wrapperEl.dataset.createMrPath; this.droplabInitialized = false; + this.isCreatingBranch = false; this.isCreatingMergeRequest = false; + this.isGettingRef = false; this.mergeRequestCreated = false; - this.isCreatingBranch = false; - this.branchCreated = false; + this.refDebounce = _.debounce((value, target) => this.getRef(value, target), 500); + this.refIsValid = true; + this.refsPath = this.wrapperEl.dataset.refsPath; + this.suggestedRef = this.refInput.value; - this.init(); - } + // These regexps are used to replace + // a backend generated new branch name and its source (ref) + // with user's inputs. + this.regexps = { + branch: { + createBranchPath: new RegExp('(branch_name=)(.+?)(?=&issue)'), + createMrPath: new RegExp('(branch_name=)(.+?)(?=&ref)'), + }, + ref: { + createBranchPath: new RegExp('(ref=)(.+?)$'), + createMrPath: new RegExp('(ref=)(.+?)$'), + }, + }; - init() { - this.checkAbilityToCreateBranch(); + this.init(); } available() { @@ -41,41 +63,13 @@ export default class CreateMergeRequestDropdown { this.unavailableButton.classList.add('hide'); } - unavailable() { - this.availableButton.classList.add('hide'); - this.unavailableButton.classList.remove('hide'); - } - - enable() { - this.createMergeRequestButton.classList.remove('disabled'); - this.createMergeRequestButton.removeAttribute('disabled'); - - this.dropdownToggle.classList.remove('disabled'); - this.dropdownToggle.removeAttribute('disabled'); - } - - disable() { - this.createMergeRequestButton.classList.add('disabled'); - this.createMergeRequestButton.setAttribute('disabled', 'disabled'); - - this.dropdownToggle.classList.add('disabled'); - this.dropdownToggle.setAttribute('disabled', 'disabled'); - } - - hide() { - this.wrapperEl.classList.add('hide'); - } - - setUnavailableButtonState(isLoading = true) { - if (isLoading) { - this.unavailableButtonArrow.classList.add('fa-spinner', 'fa-spin'); - this.unavailableButtonArrow.classList.remove('fa-exclamation-triangle'); - this.unavailableButtonText.textContent = 'Checking branch availability…'; - } else { - this.unavailableButtonArrow.classList.remove('fa-spinner', 'fa-spin'); - this.unavailableButtonArrow.classList.add('fa-exclamation-triangle'); - this.unavailableButtonText.textContent = 'New branch unavailable'; - } + bindEvents() { + this.createMergeRequestButton.addEventListener('click', this.onClickCreateMergeRequestButton.bind(this)); + this.createTargetButton.addEventListener('click', this.onClickCreateMergeRequestButton.bind(this)); + this.branchInput.addEventListener('keyup', this.onChangeInput.bind(this)); + this.dropdownToggle.addEventListener('click', this.onClickSetFocusOnBranchNameInput.bind(this)); + this.refInput.addEventListener('keyup', this.onChangeInput.bind(this)); + this.refInput.addEventListener('keydown', CreateMergeRequestDropdown.processTab.bind(this)); } checkAbilityToCreateBranch() { @@ -107,49 +101,233 @@ export default class CreateMergeRequestDropdown { }); } - initDroplab() { - this.droplab = new DropLab(); + createBranch() { + return $.ajax({ + method: 'POST', + dataType: 'json', + url: this.createBranchPath, + beforeSend: () => (this.isCreatingBranch = true), + }) + .done((data) => { + this.branchCreated = true; + window.location.href = data.url; + }) + .fail(() => new Flash('Failed to create a branch for this issue. Please try again.')); + } - this.droplab.init(this.dropdownToggle, this.dropdownList, [InputSetter], - this.getDroplabConfig()); + createMergeRequest() { + return $.ajax({ + method: 'POST', + dataType: 'json', + url: this.createMrPath, + beforeSend: () => (this.isCreatingMergeRequest = true), + }) + .done((data) => { + this.mergeRequestCreated = true; + window.location.href = data.url; + }) + .fail(() => new Flash('Failed to create Merge Request. Please try again.')); + } + + disable() { + this.disableCreateAction(); + + this.dropdownToggle.classList.add('disabled'); + this.dropdownToggle.setAttribute('disabled', 'disabled'); + } + + disableCreateAction() { + this.createMergeRequestButton.classList.add('disabled'); + this.createMergeRequestButton.setAttribute('disabled', 'disabled'); + + this.createTargetButton.classList.add('disabled'); + this.createTargetButton.setAttribute('disabled', 'disabled'); + } + + enable() { + this.createMergeRequestButton.classList.remove('disabled'); + this.createMergeRequestButton.removeAttribute('disabled'); + + this.createTargetButton.classList.remove('disabled'); + this.createTargetButton.removeAttribute('disabled'); + + this.dropdownToggle.classList.remove('disabled'); + this.dropdownToggle.removeAttribute('disabled'); + } + + static findByValue(objects, ref, returnFirstMatch = false) { + if (!objects || !objects.length) return false; + if (objects.indexOf(ref) > -1) return ref; + if (returnFirstMatch) return objects.find(item => new RegExp(`^${ref}`).test(item)); + + return false; } getDroplabConfig() { return { - InputSetter: [{ - input: this.createMergeRequestButton, - valueAttribute: 'data-value', - inputAttribute: 'data-action', - }, { - input: this.createMergeRequestButton, - valueAttribute: 'data-text', - }], + addActiveClassToDropdownButton: true, + InputSetter: [ + { + input: this.createMergeRequestButton, + valueAttribute: 'data-value', + inputAttribute: 'data-action', + }, + { + input: this.createMergeRequestButton, + valueAttribute: 'data-text', + }, + { + input: this.createTargetButton, + valueAttribute: 'data-value', + inputAttribute: 'data-action', + }, + { + input: this.createTargetButton, + valueAttribute: 'data-text', + }, + ], }; } - bindEvents() { - this.createMergeRequestButton - .addEventListener('click', this.onClickCreateMergeRequestButton.bind(this)); + static getInputSelectedText(input) { + const start = input.selectionStart; + const end = input.selectionEnd; + + return input.value.substr(start, end - start); + } + + getRef(ref, target = 'all') { + if (!ref) return false; + + return $.ajax({ + method: 'GET', + dataType: 'json', + url: this.refsPath + ref, + beforeSend: () => { + this.isGettingRef = true; + }, + }) + .always(() => { + this.isGettingRef = false; + }) + .done((data) => { + const branches = data[Object.keys(data)[0]]; + const tags = data[Object.keys(data)[1]]; + let result; + + if (target === 'branch') { + result = CreateMergeRequestDropdown.findByValue(branches, ref); + } else { + result = CreateMergeRequestDropdown.findByValue(branches, ref, true) || + CreateMergeRequestDropdown.findByValue(tags, ref, true); + this.suggestedRef = result; + } + + return this.updateInputState(target, ref, result); + }) + .fail(() => { + this.unavailable(); + this.disable(); + new Flash('Failed to get ref.'); + + return false; + }); + } + + getTargetData(target) { + return { + input: this[`${target}Input`], + message: this[`${target}Message`], + }; + } + + hide() { + this.wrapperEl.classList.add('hide'); + } + + init() { + this.checkAbilityToCreateBranch(); + } + + initDroplab() { + this.droplab = new DropLab(); + + this.droplab.init( + this.dropdownToggle, + this.dropdownList, + [InputSetter], + this.getDroplabConfig(), + ); + } + + inputsAreValid() { + return this.branchIsValid && this.refIsValid; } isBusy() { return this.isCreatingMergeRequest || this.mergeRequestCreated || this.isCreatingBranch || - this.branchCreated; + this.branchCreated || + this.isGettingRef; } - onClickCreateMergeRequestButton(e) { + onChangeInput(event) { + let target; + let value; + + if (event.srcElement === this.branchInput) { + target = 'branch'; + value = this.branchInput.value; + } else if (event.srcElement === this.refInput) { + target = 'ref'; + value = event.srcElement.value.slice(0, event.srcElement.selectionStart) + + event.srcElement.value.slice(event.srcElement.selectionEnd); + } else { + return false; + } + + if (this.isGettingRef) return false; + + // `ENTER` key submits the data. + if (event.keyCode === 13 && this.inputsAreValid()) { + event.preventDefault(); + return this.createMergeRequestButton.click(); + } + + // If the input is empty, use the original value generated by the backend. + if (!value) { + this.createBranchPath = this.wrapperEl.dataset.createBranchPath; + this.createMrPath = this.wrapperEl.dataset.createMrPath; + + if (target === 'branch') { + this.branchIsValid = true; + } else { + this.refIsValid = true; + } + + this.enable(); + this.showAvailableMessage(target); + return true; + } + + this.showCheckingMessage(target); + this.refDebounce(value, target); + + return true; + } + + onClickCreateMergeRequestButton(event) { let xhr = null; - e.preventDefault(); + event.preventDefault(); if (this.isBusy()) { return; } - if (e.target.dataset.action === CREATE_MERGE_REQUEST) { + if (event.target.dataset.action === CREATE_MERGE_REQUEST) { xhr = this.createMergeRequest(); - } else if (e.target.dataset.action === CREATE_BRANCH) { + } else if (event.target.dataset.action === CREATE_BRANCH) { xhr = this.createBranch(); } @@ -163,31 +341,131 @@ export default class CreateMergeRequestDropdown { this.disable(); } - createMergeRequest() { - return $.ajax({ - method: 'POST', - dataType: 'json', - url: this.createMrPath, - beforeSend: () => (this.isCreatingMergeRequest = true), - }) - .done((data) => { - this.mergeRequestCreated = true; - window.location.href = data.url; - }) - .fail(() => new Flash('Failed to create Merge Request. Please try again.')); + onClickSetFocusOnBranchNameInput() { + this.branchInput.focus(); } - createBranch() { - return $.ajax({ - method: 'POST', - dataType: 'json', - url: this.createBranchPath, - beforeSend: () => (this.isCreatingBranch = true), - }) - .done((data) => { - this.branchCreated = true; - window.location.href = data.url; - }) - .fail(() => new Flash('Failed to create a branch for this issue. Please try again.')); + // `TAB` autocompletes the source. + static processTab(event) { + if (event.keyCode !== 9 || this.isGettingRef) return; + + const selectedText = CreateMergeRequestDropdown.getInputSelectedText(this.refInput); + + // if nothing selected, we don't need to autocomplete anything. Do the default TAB action. + // If a user manually selected text, don't autocomplete anything. Do the default TAB action. + if (!selectedText || this.refInput.dataset.value === this.suggestedRef) return; + + event.preventDefault(); + window.getSelection().removeAllRanges(); + } + + removeMessage(target) { + const { input, message } = this.getTargetData(target); + const inputClasses = ['gl-field-error-outline', 'gl-field-success-outline']; + const messageClasses = ['gl-field-hint', 'gl-field-error-message', 'gl-field-success-message']; + + inputClasses.forEach(cssClass => input.classList.remove(cssClass)); + messageClasses.forEach(cssClass => message.classList.remove(cssClass)); + message.style.display = 'none'; + } + + setUnavailableButtonState(isLoading = true) { + if (isLoading) { + this.unavailableButtonArrow.classList.add('fa-spin'); + this.unavailableButtonArrow.classList.add('fa-spinner'); + this.unavailableButtonArrow.classList.remove('fa-exclamation-triangle'); + this.unavailableButtonText.textContent = __('Checking branch availability...'); + } else { + this.unavailableButtonArrow.classList.remove('fa-spin'); + this.unavailableButtonArrow.classList.remove('fa-spinner'); + this.unavailableButtonArrow.classList.add('fa-exclamation-triangle'); + this.unavailableButtonText.textContent = __('New branch unavailable'); + } + } + + showAvailableMessage(target) { + const { input, message } = this.getTargetData(target); + const text = target === 'branch' ? __('Branch name') : __('Source'); + + this.removeMessage(target); + input.classList.add('gl-field-success-outline'); + message.classList.add('gl-field-success-message'); + message.textContent = sprintf(__('%{text} is available'), { text }); + message.style.display = 'inline-block'; + } + + showCheckingMessage(target) { + const { message } = this.getTargetData(target); + const text = target === 'branch' ? __('branch name') : __('source'); + + this.removeMessage(target); + message.classList.add('gl-field-hint'); + message.textContent = sprintf(__('Checking %{text} availability…'), { text }); + message.style.display = 'inline-block'; + } + + showNotAvailableMessage(target) { + const { input, message } = this.getTargetData(target); + const text = target === 'branch' ? __('Branch is already taken') : __('Source is not available'); + + this.removeMessage(target); + input.classList.add('gl-field-error-outline'); + message.classList.add('gl-field-error-message'); + message.textContent = text; + message.style.display = 'inline-block'; + } + + unavailable() { + this.availableButton.classList.add('hide'); + this.unavailableButton.classList.remove('hide'); + } + + updateInputState(target, ref, result) { + // target - 'branch' or 'ref' - which the input field we are searching a ref for. + // ref - string - what a user typed. + // result - string - what has been found on backend. + + const pathReplacement = `$1${ref}`; + + // If a found branch equals exact the same text a user typed, + // that means a new branch cannot be created as it already exists. + if (ref === result) { + if (target === 'branch') { + this.branchIsValid = false; + this.showNotAvailableMessage('branch'); + } else { + this.refIsValid = true; + this.refInput.dataset.value = ref; + this.showAvailableMessage('ref'); + this.createBranchPath = this.createBranchPath.replace(this.regexps.ref.createBranchPath, + pathReplacement); + this.createMrPath = this.createMrPath.replace(this.regexps.ref.createMrPath, + pathReplacement); + } + } else if (target === 'branch') { + this.branchIsValid = true; + this.showAvailableMessage('branch'); + this.createBranchPath = this.createBranchPath.replace(this.regexps.branch.createBranchPath, + pathReplacement); + this.createMrPath = this.createMrPath.replace(this.regexps.branch.createMrPath, + pathReplacement); + } else { + this.refIsValid = false; + this.refInput.dataset.value = ref; + this.disableCreateAction(); + this.showNotAvailableMessage('ref'); + + // Show ref hint. + if (result) { + this.refInput.value = result; + this.refInput.setSelectionRange(ref.length, result.length); + } + } + + if (this.inputsAreValid()) { + this.enable(); + } else { + this.disableCreateAction(); + } } } diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js b/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js index 8bf9ae17de0..a8cd8c20f8f 100644 --- a/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js +++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js @@ -1,7 +1,7 @@ /* eslint-disable no-param-reassign */ import { __ } from '../locale'; -import '../lib/utils/text_utility'; +import { dasherize } from '../lib/utils/text_utility'; import DEFAULT_EVENT_OBJECTS from './default_event_objects'; const EMPTY_STAGE_TEXTS = { @@ -36,7 +36,7 @@ export default { }); newData.stages.forEach((item) => { - const stageSlug = gl.text.dasherize(item.name.toLowerCase()); + const stageSlug = dasherize(item.name.toLowerCase()); item.active = false; item.isUserAllowed = data.permissions[stageSlug]; item.emptyStageText = EMPTY_STAGE_TEXTS[stageSlug]; diff --git a/app/assets/javascripts/deploy_keys/components/action_btn.vue b/app/assets/javascripts/deploy_keys/components/action_btn.vue index 3f993213dd0..f9f2f9bf693 100644 --- a/app/assets/javascripts/deploy_keys/components/action_btn.vue +++ b/app/assets/javascripts/deploy_keys/components/action_btn.vue @@ -32,7 +32,9 @@ doAction() { this.isLoading = true; - eventHub.$emit(`${this.type}.key`, this.deployKey); + eventHub.$emit(`${this.type}.key`, this.deployKey, () => { + this.isLoading = false; + }); }, }, computed: { @@ -50,6 +52,9 @@ :disabled="isLoading" @click="doAction"> {{ text }} - <loading-icon v-if="isLoading" /> + <loading-icon + v-if="isLoading" + :inline="true" + /> </button> </template> diff --git a/app/assets/javascripts/deploy_keys/components/app.vue b/app/assets/javascripts/deploy_keys/components/app.vue index 54e13b79a4f..fe046449054 100644 --- a/app/assets/javascripts/deploy_keys/components/app.vue +++ b/app/assets/javascripts/deploy_keys/components/app.vue @@ -47,12 +47,15 @@ .then(() => this.fetchKeys()) .catch(() => new Flash('Error enabling deploy key')); }, - disableKey(deployKey) { + disableKey(deployKey, callback) { // eslint-disable-next-line no-alert if (confirm('You are going to remove this deploy key. Are you sure?')) { this.service.disableKey(deployKey.id) .then(() => this.fetchKeys()) + .then(callback) .catch(() => new Flash('Error removing deploy key')); + } else { + callback(); } }, }, diff --git a/app/assets/javascripts/diff_notes/diff_notes_bundle.js b/app/assets/javascripts/diff_notes/diff_notes_bundle.js index 0863c3406bd..e0422057090 100644 --- a/app/assets/javascripts/diff_notes/diff_notes_bundle.js +++ b/app/assets/javascripts/diff_notes/diff_notes_bundle.js @@ -16,7 +16,8 @@ import './components/diff_note_avatars'; import './components/new_issue_for_discussion'; $(() => { - const projectPath = document.querySelector('.merge-request').dataset.projectPath; + const projectPathHolder = document.querySelector('.merge-request') || document.querySelector('.commit-box'); + const projectPath = projectPathHolder.dataset.projectPath; const COMPONENT_SELECTOR = 'resolve-btn, resolve-discussion-btn, jump-to-discussion, comment-and-resolve-btn, new-issue-for-discussion-btn'; window.gl = window.gl || {}; diff --git a/app/assets/javascripts/diff_notes/services/resolve.js b/app/assets/javascripts/diff_notes/services/resolve.js index 6eae54f830b..96fe23640af 100644 --- a/app/assets/javascripts/diff_notes/services/resolve.js +++ b/app/assets/javascripts/diff_notes/services/resolve.js @@ -43,7 +43,7 @@ class ResolveServiceClass { discussion.resolveAllNotes(resolvedBy); } - gl.mrWidget.checkStatus(); + if (gl.mrWidget) gl.mrWidget.checkStatus(); discussion.updateHeadline(data); }) .catch(() => new Flash('An error occurred when trying to resolve a discussion. Please try again.')); diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index 44606989395..678af8f7b7a 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -1,12 +1,12 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, wrap-iife, no-shadow, consistent-return, one-var, one-var-declaration-per-line, camelcase, default-case, no-new, quotes, no-duplicate-case, no-case-declarations, no-fallthrough, max-len */ import { s__ } from './locale'; -/* global ProjectSelect */ +import projectSelect from './project_select'; import IssuableIndex from './issuable_index'; -/* global Milestone */ +import Milestone from './milestone'; import IssuableForm from './issuable_form'; import LabelsSelect from './labels_select'; /* global MilestoneSelect */ -/* global NewBranchForm */ +import NewBranchForm from './new_branch_form'; /* global NotificationsForm */ /* global NotificationsDropdown */ import groupAvatar from './group_avatar'; @@ -18,21 +18,19 @@ import groupsSelect from './groups_select'; /* global Search */ /* global Admin */ import NamespaceSelect from './namespace_select'; -/* global NewCommitForm */ -/* global NewBranchForm */ -/* global Project */ -/* global ProjectAvatar */ +import NewCommitForm from './new_commit_form'; +import Project from './project'; +import projectAvatar from './project_avatar'; /* global MergeRequest */ /* global Compare */ /* global CompareAutocomplete */ /* global ProjectFindFile */ -/* global ProjectNew */ -/* global ProjectShow */ -/* global ProjectImport */ +import ProjectNew from './project_new'; +import projectImport from './project_import'; import Labels from './labels'; import LabelManager from './label_manager'; /* global Sidebar */ - +import IssuableTemplateSelectors from './templates/issuable_template_selectors'; import Flash from './flash'; import CommitsList from './commits'; import Issue from './issue'; @@ -91,6 +89,8 @@ import Members from './members'; import memberExpirationDate from './member_expiration_date'; import DueDateSelectors from './due_date_select'; import Diff from './diff'; +import ProjectLabelSubscription from './project_label_subscription'; +import ProjectVariables from './project_variables'; (function() { var Dispatcher; @@ -187,7 +187,7 @@ import Diff from './diff'; initIssuableSidebar(); break; case 'dashboard:milestones:index': - new ProjectSelect(); + projectSelect(); break; case 'projects:milestones:show': case 'groups:milestones:show': @@ -197,7 +197,7 @@ import Diff from './diff'; break; case 'dashboard:issues': case 'dashboard:merge_requests': - new ProjectSelect(); + projectSelect(); initLegacyFilters(); break; case 'groups:issues': @@ -206,7 +206,7 @@ import Diff from './diff'; const filteredSearchManager = new gl.FilteredSearchManager(page === 'groups:issues' ? 'issues' : 'merge_requests'); filteredSearchManager.setup(); } - new ProjectSelect(); + projectSelect(); break; case 'dashboard:todos:index': new Todos(); @@ -264,7 +264,7 @@ import Diff from './diff'; new IssuableForm($('.issue-form')); new LabelsSelect(); new MilestoneSelect(); - new gl.IssuableTemplateSelectors(); + new IssuableTemplateSelectors(); break; case 'projects:merge_requests:creations:new': const mrNewCompareNode = document.querySelector('.js-merge-request-new-compare'); @@ -288,7 +288,7 @@ import Diff from './diff'; new IssuableForm($('.merge-request-form')); new LabelsSelect(); new MilestoneSelect(); - new gl.IssuableTemplateSelectors(); + new IssuableTemplateSelectors(); new AutoWidthDropdownSelect($('.js-target-branch-select')).init(); break; case 'projects:tags:new': @@ -298,18 +298,21 @@ import Diff from './diff'; break; case 'projects:snippets:show': initNotes(); + new ZenMode(); break; case 'projects:snippets:new': case 'projects:snippets:edit': case 'projects:snippets:create': case 'projects:snippets:update': new GLForm($('.snippet-form'), true); + new ZenMode(); break; case 'snippets:new': case 'snippets:edit': case 'snippets:create': case 'snippets:update': new GLForm($('.snippet-form'), false); + new ZenMode(); break; case 'projects:releases:edit': new ZenMode(); @@ -317,7 +320,6 @@ import Diff from './diff'; break; case 'projects:merge_requests:show': new Diff(); - shortcut_handler = new ShortcutsIssuable(true); new ZenMode(); initIssuableSidebar(); @@ -327,6 +329,8 @@ import Diff from './diff'; window.mergeRequest = new MergeRequest({ action: mrShowNode.dataset.mrAction, }); + + shortcut_handler = new ShortcutsIssuable(true); break; case 'dashboard:activity': new gl.Activities(); @@ -339,7 +343,8 @@ import Diff from './diff'; container: '.js-commit-pipeline-graph', }).bindEvents(); initNotes(); - initChangesDropdown(); + const stickyBarPaddingTop = 16; + initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight - stickyBarPaddingTop); $('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath); break; case 'projects:commit:pipelines': @@ -378,9 +383,10 @@ import Diff from './diff'; initSettingsPanels(); break; case 'projects:imports:show': - new ProjectImport(); + projectImport(); break; case 'projects:pipelines:new': + case 'projects:pipelines:create': new NewBranchForm($('.js-new-pipeline-form')); break; case 'projects:pipelines:builds': @@ -484,7 +490,7 @@ import Diff from './diff'; if ($el.find('.dropdown-group-label').length) { new GroupLabelSubscription($el); } else { - new gl.ProjectLabelSubscription($el); + new ProjectLabelSubscription($el); } }); break; @@ -520,7 +526,7 @@ import Diff from './diff'; // Initialize expandable settings panels initSettingsPanels(); case 'groups:settings:ci_cd:show': - new gl.ProjectVariables(); + new ProjectVariables(); break; case 'ci:lints:create': case 'ci:lints:show': @@ -536,6 +542,7 @@ import Diff from './diff'; new LineHighlighter(); new BlobViewer(); initNotes(); + new ZenMode(); break; case 'import:fogbugz:new_user_map': new UsersSelect(); @@ -548,7 +555,15 @@ import Diff from './diff'; import(/* webpackChunkName: "clusters" */ './clusters/clusters_bundle') .then(cluster => new cluster.default()) // eslint-disable-line new-cap .catch((err) => { - Flash(s__('ClusterIntegration|Problem setting up the cluster JavaScript')); + Flash(s__('ClusterIntegration|Problem setting up the cluster')); + throw err; + }); + break; + case 'projects:clusters:index': + import(/* webpackChunkName: "clusters_index" */ './clusters/clusters_index') + .then(clusterIndex => clusterIndex.default()) + .catch((err) => { + Flash(s__('ClusterIntegration|Problem setting up the clusters list')); throw err; }); break; @@ -604,7 +619,7 @@ import Diff from './diff'; break; case 'projects': new Project(); - new ProjectAvatar(); + projectAvatar(); switch (path[1]) { case 'compare': new CompareAutocomplete(); @@ -623,7 +638,6 @@ import Diff from './diff'; case 'show': new Star(); new ProjectNew(); - new ProjectShow(); new NotificationsDropdown(); break; case 'wikis': diff --git a/app/assets/javascripts/droplab/constants.js b/app/assets/javascripts/droplab/constants.js index 868d47e91b3..673e9bb4c0f 100644 --- a/app/assets/javascripts/droplab/constants.js +++ b/app/assets/javascripts/droplab/constants.js @@ -3,6 +3,7 @@ const DATA_DROPDOWN = 'data-dropdown'; const SELECTED_CLASS = 'droplab-item-selected'; const ACTIVE_CLASS = 'droplab-item-active'; const IGNORE_CLASS = 'droplab-item-ignore'; +const IGNORE_HIDING_CLASS = 'droplab-item-ignore-hiding'; // Matches `{{anything}}` and `{{ everything }}`. const TEMPLATE_REGEX = /\{\{(.+?)\}\}/g; @@ -13,4 +14,5 @@ export { ACTIVE_CLASS, TEMPLATE_REGEX, IGNORE_CLASS, + IGNORE_HIDING_CLASS, }; diff --git a/app/assets/javascripts/droplab/drop_down.js b/app/assets/javascripts/droplab/drop_down.js index 3901bb177fe..5eb0a339a1c 100644 --- a/app/assets/javascripts/droplab/drop_down.js +++ b/app/assets/javascripts/droplab/drop_down.js @@ -1,15 +1,18 @@ import utils from './utils'; -import { SELECTED_CLASS, IGNORE_CLASS } from './constants'; +import { SELECTED_CLASS, IGNORE_CLASS, IGNORE_HIDING_CLASS } from './constants'; class DropDown { - constructor(list) { + constructor(list, config = {}) { this.currentIndex = 0; this.hidden = true; this.list = typeof list === 'string' ? document.querySelector(list) : list; this.items = []; - this.eventWrapper = {}; + if (config.addActiveClassToDropdownButton) { + this.dropdownToggle = this.list.parentNode.querySelector('.js-dropdown-toggle'); + } + this.getItems(); this.initTemplateString(); this.addEvents(); @@ -42,7 +45,7 @@ class DropDown { this.addSelectedClass(selected); e.preventDefault(); - this.hide(); + if (!e.target.classList.contains(IGNORE_HIDING_CLASS)) this.hide(); const listEvent = new CustomEvent('click.dl', { detail: { @@ -67,7 +70,20 @@ class DropDown { addEvents() { this.eventWrapper.clickEvent = this.clickEvent.bind(this); + this.eventWrapper.closeDropdown = this.closeDropdown.bind(this); + this.list.addEventListener('click', this.eventWrapper.clickEvent); + this.list.addEventListener('keyup', this.eventWrapper.closeDropdown); + } + + closeDropdown(event) { + // `ESC` key closes the dropdown. + if (event.keyCode === 27) { + event.preventDefault(); + return this.toggle(); + } + + return true; } setData(data) { @@ -110,6 +126,8 @@ class DropDown { this.list.style.display = 'block'; this.currentIndex = 0; this.hidden = false; + + if (this.dropdownToggle) this.dropdownToggle.classList.add('active'); } hide() { @@ -117,6 +135,8 @@ class DropDown { this.list.style.display = 'none'; this.currentIndex = 0; this.hidden = true; + + if (this.dropdownToggle) this.dropdownToggle.classList.remove('active'); } toggle() { @@ -128,6 +148,7 @@ class DropDown { destroy() { this.hide(); this.list.removeEventListener('click', this.eventWrapper.clickEvent); + this.list.removeEventListener('keyup', this.eventWrapper.closeDropdown); } static setImagesSrc(template) { diff --git a/app/assets/javascripts/droplab/hook.js b/app/assets/javascripts/droplab/hook.js index cf78165b0d8..8a8dcde9f88 100644 --- a/app/assets/javascripts/droplab/hook.js +++ b/app/assets/javascripts/droplab/hook.js @@ -3,7 +3,7 @@ import DropDown from './drop_down'; class Hook { constructor(trigger, list, plugins, config) { this.trigger = trigger; - this.list = new DropDown(list); + this.list = new DropDown(list, config); this.type = 'Hook'; this.event = 'click'; this.plugins = plugins || []; diff --git a/app/assets/javascripts/dropzone_input.js b/app/assets/javascripts/dropzone_input.js index b7747ee3f83..c84be42649a 100644 --- a/app/assets/javascripts/dropzone_input.js +++ b/app/assets/javascripts/dropzone_input.js @@ -36,7 +36,10 @@ export default function dropzoneInput(form) { $formDropzone.append(divHover); $formDropzone.find('.div-dropzone-hover').append(iconPaperclip); - if (!uploadsPath) return; + if (!uploadsPath) { + $formDropzone.addClass('js-invalid-dropzone'); + return; + } const dropzone = $formDropzone.dropzone({ url: uploadsPath, diff --git a/app/assets/javascripts/emoji/support/is_emoji_unicode_supported.js b/app/assets/javascripts/emoji/support/is_emoji_unicode_supported.js index 3fd23efa9f8..e9defb62cf8 100644 --- a/app/assets/javascripts/emoji/support/is_emoji_unicode_supported.js +++ b/app/assets/javascripts/emoji/support/is_emoji_unicode_supported.js @@ -7,6 +7,17 @@ function isFlagEmoji(emojiUnicode) { return emojiUnicode.length === 4 && cp >= flagACodePoint && cp <= flagZCodePoint; } +// Tested on mac OS 10.12.6 and Windows 10 FCU, it renders as two separate characters +const baseFlagCodePoint = 127987; // parseInt('1F3F3', 16) +const rainbowCodePoint = 127752; // parseInt('1F308', 16) +function isRainbowFlagEmoji(emojiUnicode) { + const characters = Array.from(emojiUnicode); + // Length 4 because flags are made of 2 characters which are surrogate pairs + return emojiUnicode.length === 4 && + characters[0].codePointAt(0) === baseFlagCodePoint && + characters[1].codePointAt(0) === rainbowCodePoint; +} + // Chrome <57 renders keycaps oddly // See https://bugs.chromium.org/p/chromium/issues/detail?id=632294 // Same issue on Windows also fixed in Chrome 57, http://i.imgur.com/rQF7woO.png @@ -57,9 +68,11 @@ function isPersonZwjEmoji(emojiUnicode) { // in `isEmojiUnicodeSupported` logic function checkFlagEmojiSupport(unicodeSupportMap, emojiUnicode) { const isFlagResult = isFlagEmoji(emojiUnicode); + const isRainbowFlagResult = isRainbowFlagEmoji(emojiUnicode); return ( (unicodeSupportMap.flag && isFlagResult) || - !isFlagResult + (unicodeSupportMap.rainbowFlag && isRainbowFlagResult) || + (!isFlagResult && !isRainbowFlagResult) ); } @@ -113,6 +126,7 @@ function isEmojiUnicodeSupported(unicodeSupportMap = {}, emojiUnicode, unicodeVe export { isEmojiUnicodeSupported as default, isFlagEmoji, + isRainbowFlagEmoji, isKeycapEmoji, isSkinToneComboEmoji, isHorceRacingSkinToneComboEmoji, diff --git a/app/assets/javascripts/emoji/support/unicode_support_map.js b/app/assets/javascripts/emoji/support/unicode_support_map.js index 755381c2f95..c18d07dad43 100644 --- a/app/assets/javascripts/emoji/support/unicode_support_map.js +++ b/app/assets/javascripts/emoji/support/unicode_support_map.js @@ -1,5 +1,7 @@ import AccessorUtilities from '../../lib/utils/accessor'; +const GL_EMOJI_VERSION = '0.2.0'; + const unicodeSupportTestMap = { // man, student (emojione does not have any of these yet), http://emojipedia.org/emoji-zwj-sequences/ // occupationZwj: '\u{1F468}\u{200D}\u{1F393}', @@ -13,6 +15,7 @@ const unicodeSupportTestMap = { horseRacing: '\u{1F3C7}\u{1F3FF}', // US flag, http://emojipedia.org/flags/ flag: '\u{1F1FA}\u{1F1F8}', + rainbowFlag: '\u{1F3F3}\u{1F308}', // http://emojipedia.org/modifiers/ skinToneModifier: [ // spy_tone5 @@ -141,23 +144,31 @@ function generateUnicodeSupportMap(testMap) { } export default function getUnicodeSupportMap() { - let unicodeSupportMap; - let userAgentFromCache; - const isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe(); - if (isLocalStorageAvailable) userAgentFromCache = window.localStorage.getItem('gl-emoji-user-agent'); + let glEmojiVersionFromCache; + let userAgentFromCache; + if (isLocalStorageAvailable) { + glEmojiVersionFromCache = window.localStorage.getItem('gl-emoji-version'); + userAgentFromCache = window.localStorage.getItem('gl-emoji-user-agent'); + } + let unicodeSupportMap; try { unicodeSupportMap = JSON.parse(window.localStorage.getItem('gl-emoji-unicode-support-map')); } catch (err) { // swallow } - if (!unicodeSupportMap || userAgentFromCache !== navigator.userAgent) { + if ( + !unicodeSupportMap || + glEmojiVersionFromCache !== GL_EMOJI_VERSION || + userAgentFromCache !== navigator.userAgent + ) { unicodeSupportMap = generateUnicodeSupportMap(unicodeSupportTestMap); if (isLocalStorageAvailable) { + window.localStorage.setItem('gl-emoji-version', GL_EMOJI_VERSION); window.localStorage.setItem('gl-emoji-user-agent', navigator.userAgent); window.localStorage.setItem('gl-emoji-unicode-support-map', JSON.stringify(unicodeSupportMap)); } diff --git a/app/assets/javascripts/environments/components/container.vue b/app/assets/javascripts/environments/components/container.vue new file mode 100644 index 00000000000..3236077c3cf --- /dev/null +++ b/app/assets/javascripts/environments/components/container.vue @@ -0,0 +1,71 @@ +<script> + import loadingIcon from '../../vue_shared/components/loading_icon.vue'; + import tablePagination from '../../vue_shared/components/table_pagination.vue'; + import environmentTable from '../components/environments_table.vue'; + + export default { + props: { + isLoading: { + type: Boolean, + required: true, + }, + environments: { + type: Array, + required: true, + }, + pagination: { + type: Object, + required: true, + }, + canCreateDeployment: { + type: Boolean, + required: true, + }, + canReadEnvironment: { + type: Boolean, + required: true, + }, + }, + components: { + environmentTable, + loadingIcon, + tablePagination, + }, + + methods: { + onChangePage(page) { + this.$emit('onChangePage', page); + }, + }, + }; +</script> + +<template> + <div class="environments-container"> + + <loading-icon + label="Loading environments" + v-if="isLoading" + size="3" + /> + + <slot name="emptyState"></slot> + + <div + class="table-holder" + v-if="!isLoading && environments.length > 0"> + + <environment-table + :environments="environments" + :can-create-deployment="canCreateDeployment" + :can-read-environment="canReadEnvironment" + /> + + <table-pagination + v-if="pagination && pagination.totalPages > 1" + :change="onChangePage" + :pageInfo="pagination" + /> + </div> + </div> +</template> diff --git a/app/assets/javascripts/environments/components/empty_state.vue b/app/assets/javascripts/environments/components/empty_state.vue new file mode 100644 index 00000000000..2646f08c8e6 --- /dev/null +++ b/app/assets/javascripts/environments/components/empty_state.vue @@ -0,0 +1,42 @@ +<script> + export default { + name: 'environmentsEmptyState', + props: { + newPath: { + type: String, + required: true, + }, + canCreateEnvironment: { + type: Boolean, + required: true, + }, + helpPath: { + type: String, + required: true, + }, + }, + }; +</script> +<template> + <div class="blank-state-row"> + <div class="blank-state-center"> + <h2 class="blank-state-title js-blank-state-title"> + {{s__("Environments|You don't have any environments right now.")}} + </h2> + <p class="blank-state-text"> + {{s__("Environments|Environments are places where code gets deployed, such as staging or production.")}} + <br /> + <a :href="helpPath"> + {{s__("Environments|Read more about environments")}} + </a> + </p> + + <a + v-if="canCreateEnvironment" + :href="newPath" + class="btn btn-create js-new-environment-button"> + {{s__("Environments|New environment")}} + </a> + </div> + </div> +</template> diff --git a/app/assets/javascripts/environments/components/environment.vue b/app/assets/javascripts/environments/components/environment.vue deleted file mode 100644 index c039ae85cfb..00000000000 --- a/app/assets/javascripts/environments/components/environment.vue +++ /dev/null @@ -1,268 +0,0 @@ -<script> -import Visibility from 'visibilityjs'; -import Flash from '../../flash'; -import EnvironmentsService from '../services/environments_service'; -import environmentTable from './environments_table.vue'; -import EnvironmentsStore from '../stores/environments_store'; -import loadingIcon from '../../vue_shared/components/loading_icon.vue'; -import tablePagination from '../../vue_shared/components/table_pagination.vue'; -import { convertPermissionToBoolean, getParameterByName, setParamInURL } from '../../lib/utils/common_utils'; -import eventHub from '../event_hub'; -import Poll from '../../lib/utils/poll'; -import environmentsMixin from '../mixins/environments_mixin'; - -export default { - - components: { - environmentTable, - tablePagination, - loadingIcon, - }, - - mixins: [ - environmentsMixin, - ], - - data() { - const environmentsData = document.querySelector('#environments-list-view').dataset; - const store = new EnvironmentsStore(); - - return { - store, - state: store.state, - visibility: 'available', - isLoading: false, - cssContainerClass: environmentsData.cssClass, - endpoint: environmentsData.environmentsDataEndpoint, - canCreateDeployment: environmentsData.canCreateDeployment, - canReadEnvironment: environmentsData.canReadEnvironment, - canCreateEnvironment: environmentsData.canCreateEnvironment, - projectEnvironmentsPath: environmentsData.projectEnvironmentsPath, - projectStoppedEnvironmentsPath: environmentsData.projectStoppedEnvironmentsPath, - newEnvironmentPath: environmentsData.newEnvironmentPath, - helpPagePath: environmentsData.helpPagePath, - isMakingRequest: false, - - // Pagination Properties, - paginationInformation: {}, - pageNumber: 1, - }; - }, - - computed: { - scope() { - return getParameterByName('scope'); - }, - - canReadEnvironmentParsed() { - return convertPermissionToBoolean(this.canReadEnvironment); - }, - - canCreateDeploymentParsed() { - return convertPermissionToBoolean(this.canCreateDeployment); - }, - - canCreateEnvironmentParsed() { - return convertPermissionToBoolean(this.canCreateEnvironment); - }, - }, - - /** - * Fetches all the environments and stores them. - * Toggles loading property. - */ - created() { - const scope = getParameterByName('scope') || this.visibility; - const page = getParameterByName('page') || this.pageNumber; - - this.service = new EnvironmentsService(this.endpoint); - - const poll = new Poll({ - resource: this.service, - method: 'get', - data: { scope, page }, - successCallback: this.successCallback, - errorCallback: this.errorCallback, - notificationCallback: (isMakingRequest) => { - this.isMakingRequest = isMakingRequest; - }, - }); - - if (!Visibility.hidden()) { - this.isLoading = true; - poll.makeRequest(); - } - - Visibility.change(() => { - if (!Visibility.hidden()) { - poll.restart(); - } else { - poll.stop(); - } - }); - - eventHub.$on('toggleFolder', this.toggleFolder); - eventHub.$on('postAction', this.postAction); - }, - - beforeDestroy() { - eventHub.$off('toggleFolder'); - eventHub.$off('postAction'); - }, - - methods: { - toggleFolder(folder) { - this.store.toggleFolder(folder); - - if (!folder.isOpen) { - this.fetchChildEnvironments(folder, true); - } - }, - - /** - * Will change the page number and update the URL. - * - * @param {Number} pageNumber desired page to go to. - * @return {String} - */ - changePage(pageNumber) { - const param = setParamInURL('page', pageNumber); - - gl.utils.visitUrl(param); - return param; - }, - - fetchEnvironments() { - const scope = getParameterByName('scope') || this.visibility; - const page = getParameterByName('page') || this.pageNumber; - - this.isLoading = true; - - return this.service.get({ scope, page }) - .then(this.successCallback) - .catch(this.errorCallback); - }, - - fetchChildEnvironments(folder, showLoader = false) { - this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', showLoader); - - this.service.getFolderContent(folder.folder_path) - .then(resp => resp.json()) - .then(response => this.store.setfolderContent(folder, response.environments)) - .then(() => this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', false)) - .catch(() => { - // eslint-disable-next-line no-new - new Flash('An error occurred while fetching the environments.'); - this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', false); - }); - }, - - postAction(endpoint) { - if (!this.isMakingRequest) { - this.isLoading = true; - - this.service.postAction(endpoint) - .then(() => this.fetchEnvironments()) - .catch(() => new Flash('An error occurred while making the request.')); - } - }, - - successCallback(resp) { - this.saveData(resp); - - // We need to verify if any folder is open to also update it - const openFolders = this.store.getOpenFolders(); - if (openFolders.length) { - openFolders.forEach(folder => this.fetchChildEnvironments(folder)); - } - }, - - errorCallback() { - this.isLoading = false; - // eslint-disable-next-line no-new - new Flash('An error occurred while fetching the environments.'); - }, - }, -}; -</script> -<template> - <div :class="cssContainerClass"> - <div class="top-area"> - <ul - v-if="!isLoading" - class="nav-links"> - <li :class="{ active: scope === null || scope === 'available' }"> - <a :href="projectEnvironmentsPath"> - Available - <span class="badge js-available-environments-count"> - {{state.availableCounter}} - </span> - </a> - </li> - <li :class="{ active : scope === 'stopped' }"> - <a :href="projectStoppedEnvironmentsPath"> - Stopped - <span class="badge js-stopped-environments-count"> - {{state.stoppedCounter}} - </span> - </a> - </li> - </ul> - <div - v-if="canCreateEnvironmentParsed && !isLoading" - class="nav-controls"> - <a - :href="newEnvironmentPath" - class="btn btn-create"> - New environment - </a> - </div> - </div> - - <div class="environments-container"> - <loading-icon - label="Loading environments" - size="3" - v-if="isLoading" - /> - - <div - class="blank-state blank-state-no-icon" - v-if="!isLoading && state.environments.length === 0"> - <h2 class="blank-state-title js-blank-state-title"> - You don't have any environments right now. - </h2> - <p class="blank-state-text"> - Environments are places where code gets deployed, such as staging or production. - <br /> - <a :href="helpPagePath"> - Read more about environments - </a> - </p> - - <a - v-if="canCreateEnvironmentParsed" - :href="newEnvironmentPath" - class="btn btn-create js-new-environment-button"> - New environment - </a> - </div> - - <div - class="table-holder" - v-if="!isLoading && state.environments.length > 0"> - - <environment-table - :environments="state.environments" - :can-create-deployment="canCreateDeploymentParsed" - :can-read-environment="canReadEnvironmentParsed" - /> - </div> - - <table-pagination - v-if="state.paginationInformation && state.paginationInformation.totalPages > 1" - :change="changePage" - :pageInfo="state.paginationInformation" /> - </div> - </div> -</template> diff --git a/app/assets/javascripts/environments/components/environment_external_url.vue b/app/assets/javascripts/environments/components/environment_external_url.vue index 6b749814ea4..520c3ac8ace 100644 --- a/app/assets/javascripts/environments/components/environment_external_url.vue +++ b/app/assets/javascripts/environments/components/environment_external_url.vue @@ -1,5 +1,6 @@ <script> import tooltip from '../../vue_shared/directives/tooltip'; +import { s__ } from '../../locale'; /** * Renders the external url link in environments table. @@ -18,7 +19,7 @@ export default { computed: { title() { - return 'Open'; + return s__('Environments|Open'); }, }, }; diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue index fc0308b81ba..2f0e397aa45 100644 --- a/app/assets/javascripts/environments/components/environment_item.vue +++ b/app/assets/javascripts/environments/components/environment_item.vue @@ -2,7 +2,7 @@ import Timeago from 'timeago.js'; import _ from 'underscore'; import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; -import '../../lib/utils/text_utility'; +import { humanize } from '../../lib/utils/text_utility'; import ActionsComponent from './environment_actions.vue'; import ExternalUrlComponent from './environment_external_url.vue'; import StopComponent from './environment_stop.vue'; @@ -139,7 +139,7 @@ export default { if (this.hasManualActions) { return this.model.last_deployment.manual_actions.map((action) => { const parsedAction = { - name: gl.text.humanize(action.name), + name: humanize(action.name), play_path: action.play_path, playable: action.playable, }; @@ -432,7 +432,7 @@ export default { v-if="!model.isFolder" class="table-mobile-header" role="rowheader"> - Environment + {{s__("Environments|Environment")}} </div> <a v-if="!model.isFolder" @@ -505,7 +505,7 @@ export default { <div role="rowheader" class="table-mobile-header"> - Commit + {{s__("Environments|Commit")}} </div> <div v-if="hasLastDeploymentKey" @@ -521,7 +521,7 @@ export default { <div v-if="!hasLastDeploymentKey" class="commit-title table-mobile-content"> - No deployments yet + {{s__("Environments|No deployments yet")}} </div> </div> @@ -531,7 +531,7 @@ export default { <div role="rowheader" class="table-mobile-header"> - Updated + {{s__("Environments|Updated")}} </div> <span v-if="canShowDate" diff --git a/app/assets/javascripts/environments/components/environment_monitoring.vue b/app/assets/javascripts/environments/components/environment_monitoring.vue index 1655561cdd3..b45af1a5ebc 100644 --- a/app/assets/javascripts/environments/components/environment_monitoring.vue +++ b/app/assets/javascripts/environments/components/environment_monitoring.vue @@ -34,6 +34,7 @@ export default { :aria-label="title"> <i class="fa fa-area-chart" - aria-hidden="true" /> + aria-hidden="true" + /> </a> </template> diff --git a/app/assets/javascripts/environments/components/environment_rollback.vue b/app/assets/javascripts/environments/components/environment_rollback.vue index 49dba38edfb..92a596bfd33 100644 --- a/app/assets/javascripts/environments/components/environment_rollback.vue +++ b/app/assets/javascripts/environments/components/environment_rollback.vue @@ -48,10 +48,10 @@ export default { :disabled="isLoading"> <span v-if="isLastDeployment"> - Re-deploy + {{s__("Environments|Re-deploy")}} </span> <span v-else> - Rollback + {{s__("Environments|Rollback")}} </span> <loading-icon v-if="isLoading" /> diff --git a/app/assets/javascripts/environments/components/environments_app.vue b/app/assets/javascripts/environments/components/environments_app.vue new file mode 100644 index 00000000000..2592909734f --- /dev/null +++ b/app/assets/javascripts/environments/components/environments_app.vue @@ -0,0 +1,128 @@ +<script> + import Flash from '../../flash'; + import { s__ } from '../../locale'; + import emptyState from './empty_state.vue'; + import eventHub from '../event_hub'; + import environmentsMixin from '../mixins/environments_mixin'; + import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin'; + + export default { + props: { + endpoint: { + type: String, + required: true, + }, + canCreateEnvironment: { + type: Boolean, + required: true, + }, + canCreateDeployment: { + type: Boolean, + required: true, + }, + canReadEnvironment: { + type: Boolean, + required: true, + }, + cssContainerClass: { + type: String, + required: true, + }, + newEnvironmentPath: { + type: String, + required: true, + }, + helpPagePath: { + type: String, + required: true, + }, + }, + components: { + emptyState, + }, + + mixins: [ + CIPaginationMixin, + environmentsMixin, + ], + + created() { + eventHub.$on('toggleFolder', this.toggleFolder); + }, + + beforeDestroy() { + eventHub.$off('toggleFolder'); + }, + + methods: { + toggleFolder(folder) { + this.store.toggleFolder(folder); + + if (!folder.isOpen) { + this.fetchChildEnvironments(folder, true); + } + }, + + fetchChildEnvironments(folder, showLoader = false) { + this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', showLoader); + + this.service.getFolderContent(folder.folder_path) + .then(resp => resp.json()) + .then(response => this.store.setfolderContent(folder, response.environments)) + .then(() => this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', false)) + .catch(() => { + Flash(s__('Environments|An error occurred while fetching the environments.')); + this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', false); + }); + }, + + successCallback(resp) { + this.saveData(resp); + + // We need to verify if any folder is open to also update it + const openFolders = this.store.getOpenFolders(); + if (openFolders.length) { + openFolders.forEach(folder => this.fetchChildEnvironments(folder)); + } + }, + }, + }; +</script> +<template> + <div :class="cssContainerClass"> + <div class="top-area"> + <tabs + :tabs="tabs" + @onChangeTab="onChangeTab" + scope="environments" + /> + + <div + v-if="canCreateEnvironment && !isLoading" + class="nav-controls"> + <a + :href="newEnvironmentPath" + class="btn btn-create"> + {{s__("Environments|New environment")}} + </a> + </div> + </div> + + <container + :is-loading="isLoading" + :environments="state.environments" + :pagination="state.paginationInformation" + :can-create-deployment="canCreateDeployment" + :can-read-environment="canReadEnvironment" + @onChangePage="onChangePage" + > + <empty-state + slot="emptyState" + v-if="!isLoading && state.environments.length === 0" + :new-path="newEnvironmentPath" + :help-path="helpPagePath" + :can-create-environment="canCreateEnvironment" + /> + </container> + </div> +</template> diff --git a/app/assets/javascripts/environments/components/environments_table.vue b/app/assets/javascripts/environments/components/environments_table.vue index 175cc8f1f72..c04da4b81b7 100644 --- a/app/assets/javascripts/environments/components/environments_table.vue +++ b/app/assets/javascripts/environments/components/environments_table.vue @@ -2,12 +2,12 @@ /** * Render environments table. */ -import EnvironmentTableRowComponent from './environment_item.vue'; +import environmentItem from './environment_item.vue'; import loadingIcon from '../../vue_shared/components/loading_icon.vue'; export default { components: { - 'environment-item': EnvironmentTableRowComponent, + environmentItem, loadingIcon, }, @@ -42,19 +42,19 @@ export default { <div class="ci-table" role="grid"> <div class="gl-responsive-table-row table-row-header" role="row"> <div class="table-section section-10 environments-name" role="columnheader"> - Environment + {{s__("Environments|Environment")}} </div> <div class="table-section section-10 environments-deploy" role="columnheader"> - Deployment + {{s__("Environments|Deployment")}} </div> <div class="table-section section-15 environments-build" role="columnheader"> - Job + {{s__("Environments|Job")}} </div> <div class="table-section section-25 environments-commit" role="columnheader"> - Commit + {{s__("Environments|Commit")}} </div> <div class="table-section section-10 environments-date" role="columnheader"> - Updated + {{s__("Environments|Updated")}} </div> </div> <template @@ -86,7 +86,7 @@ export default { <a :href="folderUrl(model)" class="btn btn-default"> - Show all + {{s__("Environments|Show all")}} </a> </div> </div> diff --git a/app/assets/javascripts/environments/environments_bundle.js b/app/assets/javascripts/environments/environments_bundle.js index c0662125f28..2e0a4001b7c 100644 --- a/app/assets/javascripts/environments/environments_bundle.js +++ b/app/assets/javascripts/environments/environments_bundle.js @@ -1,10 +1,39 @@ import Vue from 'vue'; -import EnvironmentsComponent from './components/environment.vue'; +import environmentsComponent from './components/environments_app.vue'; +import { convertPermissionToBoolean } from '../lib/utils/common_utils'; +import Translate from '../vue_shared/translate'; + +Vue.use(Translate); document.addEventListener('DOMContentLoaded', () => new Vue({ el: '#environments-list-view', components: { - 'environments-table-app': EnvironmentsComponent, + environmentsComponent, + }, + data() { + const environmentsData = document.querySelector(this.$options.el).dataset; + + return { + endpoint: environmentsData.environmentsDataEndpoint, + newEnvironmentPath: environmentsData.newEnvironmentPath, + helpPagePath: environmentsData.helpPagePath, + cssContainerClass: environmentsData.cssClass, + canCreateEnvironment: convertPermissionToBoolean(environmentsData.canCreateEnvironment), + canCreateDeployment: convertPermissionToBoolean(environmentsData.canCreateDeployment), + canReadEnvironment: convertPermissionToBoolean(environmentsData.canReadEnvironment), + }; + }, + render(createElement) { + return createElement('environments-component', { + props: { + endpoint: this.endpoint, + newEnvironmentPath: this.newEnvironmentPath, + helpPagePath: this.helpPagePath, + cssContainerClass: this.cssContainerClass, + canCreateEnvironment: this.canCreateEnvironment, + canCreateDeployment: this.canCreateDeployment, + canReadEnvironment: this.canReadEnvironment, + }, + }); }, - render: createElement => createElement('environments-table-app'), })); diff --git a/app/assets/javascripts/environments/folder/environments_folder_bundle.js b/app/assets/javascripts/environments/folder/environments_folder_bundle.js index 9add8c3d721..5d2d14c7682 100644 --- a/app/assets/javascripts/environments/folder/environments_folder_bundle.js +++ b/app/assets/javascripts/environments/folder/environments_folder_bundle.js @@ -1,10 +1,35 @@ import Vue from 'vue'; -import EnvironmentsFolderComponent from './environments_folder_view.vue'; +import environmentsFolderApp from './environments_folder_view.vue'; +import { convertPermissionToBoolean } from '../../lib/utils/common_utils'; +import Translate from '../../vue_shared/translate'; + +Vue.use(Translate); document.addEventListener('DOMContentLoaded', () => new Vue({ el: '#environments-folder-list-view', components: { - 'environments-folder-app': EnvironmentsFolderComponent, + environmentsFolderApp, + }, + data() { + const environmentsData = document.querySelector(this.$options.el).dataset; + + return { + endpoint: environmentsData.endpoint, + folderName: environmentsData.folderName, + cssContainerClass: environmentsData.cssClass, + canCreateDeployment: convertPermissionToBoolean(environmentsData.canCreateDeployment), + canReadEnvironment: convertPermissionToBoolean(environmentsData.canReadEnvironment), + }; + }, + render(createElement) { + return createElement('environments-folder-app', { + props: { + endpoint: this.endpoint, + folderName: this.folderName, + cssContainerClass: this.cssContainerClass, + canCreateDeployment: this.canCreateDeployment, + canReadEnvironment: this.canReadEnvironment, + }, + }); }, - render: createElement => createElement('environments-folder-app'), })); diff --git a/app/assets/javascripts/environments/folder/environments_folder_view.vue b/app/assets/javascripts/environments/folder/environments_folder_view.vue index b155560df9d..27418bad01a 100644 --- a/app/assets/javascripts/environments/folder/environments_folder_view.vue +++ b/app/assets/javascripts/environments/folder/environments_folder_view.vue @@ -1,168 +1,40 @@ <script> -import Visibility from 'visibilityjs'; -import Flash from '../../flash'; -import EnvironmentsService from '../services/environments_service'; -import environmentTable from '../components/environments_table.vue'; -import EnvironmentsStore from '../stores/environments_store'; -import loadingIcon from '../../vue_shared/components/loading_icon.vue'; -import tablePagination from '../../vue_shared/components/table_pagination.vue'; -import Poll from '../../lib/utils/poll'; -import eventHub from '../event_hub'; -import environmentsMixin from '../mixins/environments_mixin'; -import { convertPermissionToBoolean, getParameterByName, setParamInURL } from '../../lib/utils/common_utils'; - -export default { - components: { - environmentTable, - tablePagination, - loadingIcon, - }, - - mixins: [ - environmentsMixin, - ], - - data() { - const environmentsData = document.querySelector('#environments-folder-list-view').dataset; - const store = new EnvironmentsStore(); - const pathname = window.location.pathname; - const endpoint = `${pathname}.json`; - const folderName = pathname.substr(pathname.lastIndexOf('/') + 1); - - return { - store, - folderName, - endpoint, - state: store.state, - visibility: 'available', - isLoading: false, - cssContainerClass: environmentsData.cssClass, - canCreateDeployment: environmentsData.canCreateDeployment, - canReadEnvironment: environmentsData.canReadEnvironment, - // Pagination Properties, - paginationInformation: {}, - pageNumber: 1, - }; - }, - - computed: { - scope() { - return getParameterByName('scope'); - }, - - canReadEnvironmentParsed() { - return convertPermissionToBoolean(this.canReadEnvironment); - }, - - canCreateDeploymentParsed() { - return convertPermissionToBoolean(this.canCreateDeployment); - }, - - /** - * URL to link in the stopped tab. - * - * @return {String} - */ - stoppedPath() { - return `${window.location.pathname}?scope=stopped`; - }, - - /** - * URL to link in the available tab. - * - * @return {String} - */ - availablePath() { - return window.location.pathname; - }, - }, - - /** - * Fetches all the environments and stores them. - * Toggles loading property. - */ - created() { - const scope = getParameterByName('scope') || this.visibility; - const page = getParameterByName('page') || this.pageNumber; - - this.service = new EnvironmentsService(this.endpoint); - - const poll = new Poll({ - resource: this.service, - method: 'get', - data: { scope, page }, - successCallback: this.successCallback, - errorCallback: this.errorCallback, - notificationCallback: (isMakingRequest) => { - this.isMakingRequest = isMakingRequest; + import environmentsMixin from '../mixins/environments_mixin'; + import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin'; + + export default { + props: { + endpoint: { + type: String, + required: true, + }, + folderName: { + type: String, + required: true, + }, + cssContainerClass: { + type: String, + required: true, + }, + canCreateDeployment: { + type: Boolean, + required: true, + }, + canReadEnvironment: { + type: Boolean, + required: true, }, - }); - - if (!Visibility.hidden()) { - this.isLoading = true; - poll.makeRequest(); - } - - Visibility.change(() => { - if (!Visibility.hidden()) { - poll.restart(); - } else { - poll.stop(); - } - }); - - eventHub.$on('postAction', this.postAction); - }, - - beforeDestroyed() { - eventHub.$off('postAction'); - }, - - methods: { - /** - * Will change the page number and update the URL. - * - * @param {Number} pageNumber desired page to go to. - */ - changePage(pageNumber) { - const param = setParamInURL('page', pageNumber); - - gl.utils.visitUrl(param); - return param; - }, - - fetchEnvironments() { - const scope = getParameterByName('scope') || this.visibility; - const page = getParameterByName('page') || this.pageNumber; - - this.isLoading = true; - - return this.service.get({ scope, page }) - .then(this.successCallback) - .catch(this.errorCallback); - }, - - successCallback(resp) { - this.saveData(resp); - }, - - errorCallback() { - this.isLoading = false; - // eslint-disable-next-line no-new - new Flash('An error occurred while fetching the environments.'); }, - - postAction(endpoint) { - if (!this.isMakingRequest) { - this.isLoading = true; - - this.service.postAction(endpoint) - .then(() => this.fetchEnvironments()) - .catch(() => new Flash('An error occurred while making the request.')); - } + mixins: [ + environmentsMixin, + CIPaginationMixin, + ], + methods: { + successCallback(resp) { + this.saveData(resp); + }, }, - }, -}; + }; </script> <template> <div :class="cssContainerClass"> @@ -171,56 +43,23 @@ export default { v-if="!isLoading"> <h4 class="js-folder-name environments-folder-name"> - Environments / <b>{{folderName}}</b> + {{s__("Environments|Environments")}} / <b>{{folderName}}</b> </h4> - <ul class="nav-links"> - <li :class="{ active: scope === null || scope === 'available' }"> - <a - :href="availablePath" - class="js-available-environments-folder-tab"> - Available - <span class="badge js-available-environments-count"> - {{state.availableCounter}} - </span> - </a> - </li> - <li :class="{ active : scope === 'stopped' }"> - <a - :href="stoppedPath" - class="js-stopped-environments-folder-tab"> - Stopped - <span class="badge js-stopped-environments-count"> - {{state.stoppedCounter}} - </span> - </a> - </li> - </ul> - </div> - - <div class="environments-container"> - - <loading-icon - label="Loading environments" - v-if="isLoading" - size="3" + <tabs + :tabs="tabs" + @onChangeTab="onChangeTab" + scope="environments" /> - - <div - class="table-holder" - v-if="!isLoading && state.environments.length > 0"> - - <environment-table - :environments="state.environments" - :can-create-deployment="canCreateDeploymentParsed" - :can-read-environment="canReadEnvironmentParsed" - /> - - <table-pagination - v-if="state.paginationInformation && state.paginationInformation.totalPages > 1" - :change="changePage" - :pageInfo="state.paginationInformation"/> - </div> </div> + + <container + :is-loading="isLoading" + :environments="state.environments" + :pagination="state.paginationInformation" + :can-create-deployment="canCreateDeployment" + :can-read-environment="canReadEnvironment" + @onChangePage="onChangePage" + /> </div> </template> diff --git a/app/assets/javascripts/environments/mixins/environments_mixin.js b/app/assets/javascripts/environments/mixins/environments_mixin.js index 8f4066e3a6e..7219b076721 100644 --- a/app/assets/javascripts/environments/mixins/environments_mixin.js +++ b/app/assets/javascripts/environments/mixins/environments_mixin.js @@ -1,15 +1,174 @@ +/** + * Common code between environmets app and folder view + */ + +import Visibility from 'visibilityjs'; +import Poll from '../../lib/utils/poll'; +import { + getParameterByName, + parseQueryStringIntoObject, +} from '../../lib/utils/common_utils'; +import { s__ } from '../../locale'; +import Flash from '../../flash'; +import eventHub from '../event_hub'; + +import EnvironmentsStore from '../stores/environments_store'; +import EnvironmentsService from '../services/environments_service'; +import loadingIcon from '../../vue_shared/components/loading_icon.vue'; +import tablePagination from '../../vue_shared/components/table_pagination.vue'; +import environmentTable from '../components/environments_table.vue'; +import tabs from '../../vue_shared/components/navigation_tabs.vue'; +import container from '../components/container.vue'; + export default { + + components: { + environmentTable, + container, + loadingIcon, + tabs, + tablePagination, + }, + + data() { + const store = new EnvironmentsStore(); + + return { + store, + state: store.state, + isLoading: false, + isMakingRequest: false, + scope: getParameterByName('scope') || 'available', + page: getParameterByName('page') || '1', + requestData: {}, + }; + }, + methods: { saveData(resp) { const headers = resp.headers; return resp.json().then((response) => { this.isLoading = false; - this.store.storeAvailableCount(response.available_count); - this.store.storeStoppedCount(response.stopped_count); - this.store.storeEnvironments(response.environments); - this.store.setPagination(headers); + if (_.isEqual(parseQueryStringIntoObject(resp.url.split('?')[1]), this.requestData)) { + this.store.storeAvailableCount(response.available_count); + this.store.storeStoppedCount(response.stopped_count); + this.store.storeEnvironments(response.environments); + this.store.setPagination(headers); + } }); }, + + /** + * Handles URL and query parameter changes. + * When the user uses the pagination or the tabs, + * - update URL + * - Make API request to the server with new parameters + * - Update the polling function + * - Update the internal state + */ + updateContent(parameters) { + this.updateInternalState(parameters); + // fetch new data + return this.service.get(this.requestData) + .then(response => this.successCallback(response)) + .then(() => { + // restart polling + this.poll.restart({ data: this.requestData }); + }) + .catch(() => { + this.errorCallback(); + + // restart polling + this.poll.restart(); + }); + }, + + errorCallback() { + this.isLoading = false; + Flash(s__('Environments|An error occurred while fetching the environments.')); + }, + + postAction(endpoint) { + if (!this.isMakingRequest) { + this.isLoading = true; + + this.service.postAction(endpoint) + .then(() => this.fetchEnvironments()) + .catch(() => { + this.isLoading = false; + Flash(s__('Environments|An error occurred while making the request.')); + }); + } + }, + + fetchEnvironments() { + this.isLoading = true; + + return this.service.get(this.requestData) + .then(this.successCallback) + .catch(this.errorCallback); + }, + + }, + + computed: { + tabs() { + return [ + { + name: s__('Available'), + scope: 'available', + count: this.state.availableCounter, + isActive: this.scope === 'available', + }, + { + name: s__('Stopped'), + scope: 'stopped', + count: this.state.stoppedCounter, + isActive: this.scope === 'stopped', + }, + ]; + }, + }, + + /** + * Fetches all the environments and stores them. + * Toggles loading property. + */ + created() { + this.service = new EnvironmentsService(this.endpoint); + this.requestData = { page: this.page, scope: this.scope }; + + this.poll = new Poll({ + resource: this.service, + method: 'get', + data: this.requestData, + successCallback: this.successCallback, + errorCallback: this.errorCallback, + notificationCallback: (isMakingRequest) => { + this.isMakingRequest = isMakingRequest; + }, + }); + + if (!Visibility.hidden()) { + this.isLoading = true; + this.poll.makeRequest(); + } else { + this.fetchEnvironments(); + } + + Visibility.change(() => { + if (!Visibility.hidden()) { + this.poll.restart(); + } else { + this.poll.stop(); + } + }); + + eventHub.$on('postAction', this.postAction); + }, + + beforeDestroyed() { + eventHub.$off('postAction'); }, }; diff --git a/app/assets/javascripts/environments/stores/environments_store.js b/app/assets/javascripts/environments/stores/environments_store.js index aff8227c38c..5f2989ab854 100644 --- a/app/assets/javascripts/environments/stores/environments_store.js +++ b/app/assets/javascripts/environments/stores/environments_store.js @@ -36,7 +36,12 @@ export default class EnvironmentsStore { storeEnvironments(environments = []) { const filteredEnvironments = environments.map((env) => { const oldEnvironmentState = this.state.environments - .find(element => element.id === env.latest.id) || {}; + .find((element) => { + if (env.latest) { + return element.id === env.latest.id; + } + return element.id === env.id; + }) || {}; let filtered = {}; diff --git a/app/assets/javascripts/flash.js b/app/assets/javascripts/flash.js index 67261c1c9b4..44deab9288e 100644 --- a/app/assets/javascripts/flash.js +++ b/app/assets/javascripts/flash.js @@ -41,7 +41,7 @@ const createFlashEl = (message, type, isInContentWrapper = false) => ` `; const removeFlashClickListener = (flashEl, fadeTransition) => { - flashEl.parentNode.addEventListener('click', () => hideFlash(flashEl, fadeTransition)); + flashEl.addEventListener('click', () => hideFlash(flashEl, fadeTransition)); }; /* diff --git a/app/assets/javascripts/gfm_auto_complete.js b/app/assets/javascripts/gfm_auto_complete.js index 5c624b79d45..d918d80df8d 100644 --- a/app/assets/javascripts/gfm_auto_complete.js +++ b/app/assets/javascripts/gfm_auto_complete.js @@ -287,6 +287,10 @@ class GfmAutoComplete { } setupLabels($input) { + const fetchData = this.fetchData.bind(this); + const LABEL_COMMAND = { LABEL: '/label', UNLABEL: '/unlabel', RELABEL: '/relabel' }; + let command = ''; + $input.atwho({ at: '~', alias: 'labels', @@ -309,8 +313,45 @@ class GfmAutoComplete { title: sanitize(m.title), color: m.color, search: m.title, + set: m.set, })); }, + matcher(flag, subtext) { + const match = GfmAutoComplete.defaultMatcher(flag, subtext, this.app.controllers); + const subtextNodes = subtext.split(/\n+/g).pop().split(GfmAutoComplete.regexSubtext); + + // Check if ~ is followed by '/label', '/relabel' or '/unlabel' commands. + command = subtextNodes.find((node) => { + if (node === LABEL_COMMAND.LABEL || + node === LABEL_COMMAND.RELABEL || + node === LABEL_COMMAND.UNLABEL) { return node; } + return null; + }); + + return match && match.length ? match[1] : null; + }, + filter(query, data, searchKey) { + if (GfmAutoComplete.isLoading(data)) { + fetchData(this.$inputor, this.at); + return data; + } + + if (data === GfmAutoComplete.defaultLoadingData) { + return $.fn.atwho.default.callbacks.filter(query, data, searchKey); + } + + // The `LABEL_COMMAND.RELABEL` is intentionally skipped + // because we want to return all the labels (unfiltered) for that command. + if (command === LABEL_COMMAND.LABEL) { + // Return labels with set: undefined. + return data.filter(label => !label.set); + } else if (command === LABEL_COMMAND.UNLABEL) { + // Return labels with set: true. + return data.filter(label => label.set); + } + + return data; + }, }, }); } @@ -338,27 +379,15 @@ class GfmAutoComplete { let resultantValue = value; if (value && !this.setting.skipSpecialCharacterTest) { const withoutAt = value.substring(1); - if (withoutAt && /[^\w\d]/.test(withoutAt)) { + const regex = value.charAt() === '~' ? /\W|^\d+$/ : /\W/; + if (withoutAt && regex.test(withoutAt)) { resultantValue = `${value.charAt()}"${withoutAt}"`; } } return resultantValue; }, matcher(flag, subtext) { - // The below is taken from At.js source - // Tweaked to commands to start without a space only if char before is a non-word character - // https://github.com/ichord/At.js - const atSymbolsWithBar = Object.keys(this.app.controllers).join('|'); - const atSymbolsWithoutBar = Object.keys(this.app.controllers).join(''); - const targetSubtext = subtext.split(/\s+/g).pop(); - const resultantFlag = flag.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&'); - - const accentAChar = decodeURI('%C3%80'); - const accentYChar = decodeURI('%C3%BF'); - - const regexp = new RegExp(`^(?:\\B|[^a-zA-Z0-9_${atSymbolsWithoutBar}]|\\s)${resultantFlag}(?!${atSymbolsWithBar})((?:[A-Za-z${accentAChar}-${accentYChar}0-9_'.+-]|[^\\x00-\\x7a])*)$`, 'gi'); - - const match = regexp.exec(targetSubtext); + const match = GfmAutoComplete.defaultMatcher(flag, subtext, this.app.controllers); if (match) { return match[1]; @@ -419,8 +448,27 @@ class GfmAutoComplete { return dataToInspect && (dataToInspect === loadingState || dataToInspect.name === loadingState); } + + static defaultMatcher(flag, subtext, controllers) { + // The below is taken from At.js source + // Tweaked to commands to start without a space only if char before is a non-word character + // https://github.com/ichord/At.js + const atSymbolsWithBar = Object.keys(controllers).join('|'); + const atSymbolsWithoutBar = Object.keys(controllers).join(''); + const targetSubtext = subtext.split(GfmAutoComplete.regexSubtext).pop(); + const resultantFlag = flag.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&'); + + const accentAChar = decodeURI('%C3%80'); + const accentYChar = decodeURI('%C3%BF'); + + const regexp = new RegExp(`^(?:\\B|[^a-zA-Z0-9_${atSymbolsWithoutBar}]|\\s)${resultantFlag}(?!${atSymbolsWithBar})((?:[A-Za-z${accentAChar}-${accentYChar}0-9_'.+-]|[^\\x00-\\x7a])*)$`, 'gi'); + + return regexp.exec(targetSubtext); + } } +GfmAutoComplete.regexSubtext = new RegExp(/\s+/g); + GfmAutoComplete.defaultLoadingData = ['loading']; GfmAutoComplete.atTypeMap = { diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js index c4202f92443..7ca783d3af6 100644 --- a/app/assets/javascripts/gl_dropdown.js +++ b/app/assets/javascripts/gl_dropdown.js @@ -331,7 +331,7 @@ GitLabDropdown = (function() { if (_this.dropdown.find('.dropdown-toggle-page').length) { selector = ".dropdown-page-one " + selector; } - return $(selector); + return $(selector, this.instance.dropdown); }; })(this), data: (function(_this) { @@ -514,10 +514,11 @@ GitLabDropdown = (function() { const dropdownToggle = this.dropdown.find('.dropdown-menu-toggle'); const hasFilterBulkUpdate = dropdownToggle.hasClass('js-filter-bulk-update'); + const shouldRefreshOnOpen = dropdownToggle.hasClass('js-gl-dropdown-refresh-on-open'); const hasMultiSelect = dropdownToggle.hasClass('js-multiselect'); // Makes indeterminate items effective - if (this.fullData && hasFilterBulkUpdate) { + if (this.fullData && (shouldRefreshOnOpen || hasFilterBulkUpdate)) { this.parseData(this.fullData); } diff --git a/app/assets/javascripts/gl_form.js b/app/assets/javascripts/gl_form.js index 48cd43d3348..d0f9e6af0f8 100644 --- a/app/assets/javascripts/gl_form.js +++ b/app/assets/javascripts/gl_form.js @@ -2,6 +2,7 @@ import GfmAutoComplete from './gfm_auto_complete'; import dropzoneInput from './dropzone_input'; +import textUtils from './lib/utils/text_markdown'; export default class GLForm { constructor(form, enableGFM = false) { @@ -46,7 +47,7 @@ export default class GLForm { } // form and textarea event listeners this.addEventListeners(); - gl.text.init(this.form); + textUtils.init(this.form); // hide discard button this.form.find('.js-note-discard').hide(); this.form.show(); @@ -85,7 +86,7 @@ export default class GLForm { clearEventListeners() { this.textarea.off('focus'); this.textarea.off('blur'); - gl.text.removeListeners(this.form); + textUtils.removeListeners(this.form); } addEventListeners() { diff --git a/app/assets/javascripts/groups/components/group_item.vue b/app/assets/javascripts/groups/components/group_item.vue index 356a95c05ca..c76ce762b54 100644 --- a/app/assets/javascripts/groups/components/group_item.vue +++ b/app/assets/javascripts/groups/components/group_item.vue @@ -1,4 +1,5 @@ <script> +import tooltip from '../../vue_shared/directives/tooltip'; import identicon from '../../vue_shared/components/identicon.vue'; import eventHub from '../event_hub'; @@ -8,6 +9,9 @@ import itemStats from './item_stats.vue'; import itemActions from './item_actions.vue'; export default { + directives: { + tooltip, + }, components: { identicon, itemCaret, @@ -112,19 +116,30 @@ export default { </a> </div> <div - class="title"> + class="title namespace-title"> <a + v-tooltip :href="group.relativePath" - class="no-expand">{{group.fullName}}</a> + :title="group.fullName" + class="no-expand" + data-placement="top" + >{{ + // ending bracket must be by closing tag to prevent + // link hover text-decoration from over-extending + group.name + }}</a> <span v-if="group.permission" - class="access-type" + class="user-access-role" > - {{s__('GroupsTreeRole|as')}} {{group.permission}} + {{group.permission}} </span> </div> <div - class="description">{{group.description}}</div> + v-if="group.description" + class="description"> + {{group.description}} + </div> </div> <group-folder v-if="group.isOpen && hasChildren" diff --git a/app/assets/javascripts/groups/components/item_actions.vue b/app/assets/javascripts/groups/components/item_actions.vue index 7eff19e2e5a..09cb79c1afd 100644 --- a/app/assets/javascripts/groups/components/item_actions.vue +++ b/app/assets/javascripts/groups/components/item_actions.vue @@ -4,9 +4,11 @@ import tooltip from '../../vue_shared/directives/tooltip'; import PopupDialog from '../../vue_shared/components/popup_dialog.vue'; import eventHub from '../event_hub'; import { COMMON_STR } from '../constants'; +import Icon from '../../vue_shared/components/icon.vue'; export default { components: { + Icon, PopupDialog, }, directives: { @@ -63,9 +65,9 @@ export default { :aria-label="editBtnTitle" data-container="body" class="edit-group btn no-expand"> - <i - class="fa fa-cogs" - aria-hidden="true"/> + <icon + name="settings"> + </icon> </a> <a v-tooltip diff --git a/app/assets/javascripts/image_diff/helpers/utils_helper.js b/app/assets/javascripts/image_diff/helpers/utils_helper.js index 96fc735e629..28d9a969143 100644 --- a/app/assets/javascripts/image_diff/helpers/utils_helper.js +++ b/app/assets/javascripts/image_diff/helpers/utils_helper.js @@ -1,7 +1,7 @@ import ImageBadge from '../image_badge'; import ImageDiff from '../image_diff'; import ReplacedImageDiff from '../replaced_image_diff'; -import '../../commit/image_file'; +import ImageFile from '../../commit/image_file'; export function resizeCoordinatesToImageElement(imageEl, meta) { const { x, y, width, height } = meta; @@ -81,7 +81,7 @@ export function initImageDiff(fileEl, canCreateNote, renderCommentBadge) { // ImageFile needs to be invoked before initImageDiff so that badges // can mount to the correct location - new gl.ImageFile(fileEl); // eslint-disable-line no-new + new ImageFile(fileEl); // eslint-disable-line no-new if (fileEl.querySelector('.diff-file .js-single-image')) { diff = new ImageDiff(fileEl, options); diff --git a/app/assets/javascripts/init_issuable_sidebar.js b/app/assets/javascripts/init_issuable_sidebar.js index 1191e0b895e..ada693afc46 100644 --- a/app/assets/javascripts/init_issuable_sidebar.js +++ b/app/assets/javascripts/init_issuable_sidebar.js @@ -14,7 +14,6 @@ export default () => { }); new LabelsSelect(); new IssuableContext(sidebarOptions.currentUser); - gl.Subscription.bindAll('.subscription'); new DueDateSelectors(); window.sidebar = new Sidebar(); }; diff --git a/app/assets/javascripts/init_legacy_filters.js b/app/assets/javascripts/init_legacy_filters.js index 1b265721581..2cbb70220d0 100644 --- a/app/assets/javascripts/init_legacy_filters.js +++ b/app/assets/javascripts/init_legacy_filters.js @@ -1,8 +1,7 @@ /* eslint-disable no-new */ import LabelsSelect from './labels_select'; /* global MilestoneSelect */ -/* global SubscriptionSelect */ - +import subscriptionSelect from './subscription_select'; import UsersSelect from './users_select'; import issueStatusSelect from './issue_status_select'; @@ -11,5 +10,5 @@ export default () => { new LabelsSelect(); new MilestoneSelect(); issueStatusSelect(); - new SubscriptionSelect(); + subscriptionSelect(); }; diff --git a/app/assets/javascripts/issuable_bulk_update_sidebar.js b/app/assets/javascripts/issuable_bulk_update_sidebar.js index af6358953cf..ba2b6737988 100644 --- a/app/assets/javascripts/issuable_bulk_update_sidebar.js +++ b/app/assets/javascripts/issuable_bulk_update_sidebar.js @@ -1,11 +1,10 @@ /* eslint-disable class-methods-use-this, no-new */ /* global MilestoneSelect */ -/* global SubscriptionSelect */ import IssuableBulkUpdateActions from './issuable_bulk_update_actions'; import './milestone_select'; import issueStatusSelect from './issue_status_select'; -import './subscription_select'; +import subscriptionSelect from './subscription_select'; import LabelsSelect from './labels_select'; const HIDDEN_CLASS = 'hidden'; @@ -48,7 +47,7 @@ export default class IssuableBulkUpdateSidebar { new LabelsSelect(); new MilestoneSelect(); issueStatusSelect(); - new SubscriptionSelect(); + subscriptionSelect(); } setupBulkUpdateActions() { diff --git a/app/assets/javascripts/issuable_index.js b/app/assets/javascripts/issuable_index.js index 0b123a11a3b..c3e0acdff66 100644 --- a/app/assets/javascripts/issuable_index.js +++ b/app/assets/javascripts/issuable_index.js @@ -28,7 +28,7 @@ export default class IssuableIndex { url: $('.incoming-email-token-reset').attr('href'), dataType: 'json', success(response) { - $('#issue_email').val(response.new_issue_address).focus(); + $('#issuable_email').val(response.new_address).focus(); }, beforeSend() { $('.incoming-email-token-reset').text('resetting...'); diff --git a/app/assets/javascripts/issue.js b/app/assets/javascripts/issue.js index acd5730cf3c..7de07e9403d 100644 --- a/app/assets/javascripts/issue.js +++ b/app/assets/javascripts/issue.js @@ -1,6 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, one-var, no-underscore-dangle, one-var-declaration-per-line, object-shorthand, no-unused-vars, no-new, comma-dangle, consistent-return, quotes, dot-notation, quote-props, prefer-arrow-callback, max-len */ import 'vendor/jquery.waitforimages'; -import '~/lib/utils/text_utility'; +import { addDelimiter } from './lib/utils/text_utility'; import Flash from './flash'; import TaskList from './task_list'; import CreateMergeRequestDropdown from './create_merge_request_dropdown'; @@ -73,7 +73,7 @@ export default class Issue { let numProjectIssues = Number(projectIssuesCounter.first().text().trim().replace(/[^\d]/, '')); numProjectIssues = isClosed ? numProjectIssues - 1 : numProjectIssues + 1; - projectIssuesCounter.text(gl.text.addDelimiter(numProjectIssues)); + projectIssuesCounter.text(addDelimiter(numProjectIssues)); if (this.createMergeRequestDropdown) { if (isClosed) { diff --git a/app/assets/javascripts/issue_show/components/app.vue b/app/assets/javascripts/issue_show/components/app.vue index d1aa83ea57f..5bdc7c99503 100644 --- a/app/assets/javascripts/issue_show/components/app.vue +++ b/app/assets/javascripts/issue_show/components/app.vue @@ -16,6 +16,10 @@ export default { required: true, type: String, }, + updateEndpoint: { + required: true, + type: String, + }, canUpdate: { required: true, type: Boolean, @@ -29,6 +33,16 @@ export default { required: false, default: false, }, + showDeleteButton: { + type: Boolean, + required: false, + default: true, + }, + enableAutocomplete: { + type: Boolean, + required: false, + default: true, + }, issuableRef: { type: String, required: true, @@ -92,6 +106,16 @@ export default { type: String, required: true, }, + issuableType: { + type: String, + required: false, + default: 'issue', + }, + canAttachFile: { + type: Boolean, + required: false, + default: true, + }, }, data() { const store = new Store({ @@ -157,21 +181,21 @@ export default { }) .catch(() => { eventHub.$emit('close.form'); - window.Flash('Error updating issue'); + window.Flash(`Error updating ${this.issuableType}`); }); }, deleteIssuable() { this.service.deleteIssuable() .then(res => res.json()) .then((data) => { - // Stop the poll so we don't get 404's with the issue not existing + // Stop the poll so we don't get 404's with the issuable not existing this.poll.stop(); gl.utils.visitUrl(data.web_url); }) .catch(() => { eventHub.$emit('close.form'); - window.Flash('Error deleting issue'); + window.Flash(`Error deleting ${this.issuableType}`); }); }, }, @@ -223,6 +247,9 @@ export default { :markdown-preview-path="markdownPreviewPath" :project-path="projectPath" :project-namespace="projectNamespace" + :show-delete-button="showDeleteButton" + :can-attach-file="canAttachFile" + :enable-autocomplete="enableAutocomplete" /> <div v-else> <title-component @@ -239,6 +266,8 @@ export default { :description-text="state.descriptionText" :updated-at="state.updatedAt" :task-status="state.taskStatus" + :issuable-type="issuableType" + :update-url="updateEndpoint" /> <edited-component v-if="hasUpdated" diff --git a/app/assets/javascripts/issue_show/components/description.vue b/app/assets/javascripts/issue_show/components/description.vue index 48bad8f1e68..b7559ced946 100644 --- a/app/assets/javascripts/issue_show/components/description.vue +++ b/app/assets/javascripts/issue_show/components/description.vue @@ -22,6 +22,16 @@ required: false, default: '', }, + issuableType: { + type: String, + required: false, + default: 'issue', + }, + updateUrl: { + type: String, + required: false, + default: null, + }, }, data() { return { @@ -48,7 +58,7 @@ if (this.canUpdate) { // eslint-disable-next-line no-new new TaskList({ - dataType: 'issue', + dataType: this.issuableType, fieldName: 'description', selector: '.detail-page-description', }); @@ -95,7 +105,9 @@ <textarea class="hidden js-task-list-field" v-if="descriptionText" - v-model="descriptionText"> + v-model="descriptionText" + :data-update-url="updateUrl" + > </textarea> </div> </template> diff --git a/app/assets/javascripts/issue_show/components/edit_actions.vue b/app/assets/javascripts/issue_show/components/edit_actions.vue index 8c81575fe6f..a539506bce2 100644 --- a/app/assets/javascripts/issue_show/components/edit_actions.vue +++ b/app/assets/javascripts/issue_show/components/edit_actions.vue @@ -13,6 +13,11 @@ type: Object, required: true, }, + showDeleteButton: { + type: Boolean, + required: false, + default: true, + }, }, data() { return { @@ -23,6 +28,9 @@ isSubmitEnabled() { return this.formState.title.trim() !== ''; }, + shouldShowDeleteButton() { + return this.canDestroy && this.showDeleteButton; + }, }, methods: { closeForm() { @@ -62,7 +70,7 @@ Cancel </button> <button - v-if="canDestroy" + v-if="shouldShowDeleteButton" class="btn btn-danger pull-right append-right-default" :class="{ disabled: deleteLoading }" type="button" diff --git a/app/assets/javascripts/issue_show/components/fields/description.vue b/app/assets/javascripts/issue_show/components/fields/description.vue index 0aa1b2c2e31..52fe4ecd08b 100644 --- a/app/assets/javascripts/issue_show/components/fields/description.vue +++ b/app/assets/javascripts/issue_show/components/fields/description.vue @@ -17,6 +17,16 @@ type: String, required: true, }, + canAttachFile: { + type: Boolean, + required: false, + default: true, + }, + enableAutocomplete: { + type: Boolean, + required: false, + default: true, + }, }, components: { markdownField, @@ -36,7 +46,10 @@ </label> <markdown-field :markdown-preview-path="markdownPreviewPath" - :markdown-docs-path="markdownDocsPath"> + :markdown-docs-path="markdownDocsPath" + :can-attach-file="canAttachFile" + :enable-autocomplete="enableAutocomplete" + > <textarea id="issue-description" class="note-textarea js-gfm-input js-autosize markdown-area" diff --git a/app/assets/javascripts/issue_show/components/fields/description_template.vue b/app/assets/javascripts/issue_show/components/fields/description_template.vue index 1c40b286513..1ad0e59287e 100644 --- a/app/assets/javascripts/issue_show/components/fields/description_template.vue +++ b/app/assets/javascripts/issue_show/components/fields/description_template.vue @@ -1,4 +1,6 @@ <script> + import IssuableTemplateSelectors from '../../../templates/issuable_template_selectors'; + export default { props: { formState: { @@ -32,7 +34,7 @@ }; editor.getValue = () => this.formState.description; - this.issuableTemplate = new gl.IssuableTemplateSelectors({ + this.issuableTemplate = new IssuableTemplateSelectors({ $dropdowns: $(this.$refs.toggle), editor, }); diff --git a/app/assets/javascripts/issue_show/components/form.vue b/app/assets/javascripts/issue_show/components/form.vue index 28bf6c67ea5..0fa19022336 100644 --- a/app/assets/javascripts/issue_show/components/form.vue +++ b/app/assets/javascripts/issue_show/components/form.vue @@ -36,6 +36,21 @@ type: String, required: true, }, + showDeleteButton: { + type: Boolean, + required: false, + default: true, + }, + canAttachFile: { + type: Boolean, + required: false, + default: true, + }, + enableAutocomplete: { + type: Boolean, + required: false, + default: true, + }, }, components: { lockedWarning, @@ -78,9 +93,13 @@ <description-field :form-state="formState" :markdown-preview-path="markdownPreviewPath" - :markdown-docs-path="markdownDocsPath" /> + :markdown-docs-path="markdownDocsPath" + :can-attach-file="canAttachFile" + :enable-autocomplete="enableAutocomplete" + /> <edit-actions :form-state="formState" - :can-destroy="canDestroy" /> + :can-destroy="canDestroy" + :show-delete-button="showDeleteButton" /> </form> </template> diff --git a/app/assets/javascripts/issue_show/components/title.vue b/app/assets/javascripts/issue_show/components/title.vue index 00002709ac6..a363d06d950 100644 --- a/app/assets/javascripts/issue_show/components/title.vue +++ b/app/assets/javascripts/issue_show/components/title.vue @@ -79,7 +79,7 @@ v-tooltip v-if="showInlineEditButton && canUpdate" type="button" - class="btn-blank btn-edit note-action-button" + class="btn btn-default btn-edit btn-svg" v-html="pencilIcon" title="Edit title and description" data-placement="bottom" diff --git a/app/assets/javascripts/issue_show/index.js b/app/assets/javascripts/issue_show/index.js index aca9dec2a96..a21ce41e65e 100644 --- a/app/assets/javascripts/issue_show/index.js +++ b/app/assets/javascripts/issue_show/index.js @@ -5,7 +5,7 @@ import '../vue_shared/vue_resource_interceptor'; document.addEventListener('DOMContentLoaded', () => { const initialDataEl = document.getElementById('js-issuable-app-initial-data'); - const initialData = JSON.parse(initialDataEl.innerHTML.replace(/"/g, '"')); + const props = JSON.parse(initialDataEl.innerHTML.replace(/"/g, '"')); $('.issuable-edit').on('click', (e) => { e.preventDefault(); @@ -18,32 +18,9 @@ document.addEventListener('DOMContentLoaded', () => { components: { issuableApp, }, - data() { - return { - ...initialData, - }; - }, render(createElement) { return createElement('issuable-app', { - props: { - canUpdate: this.canUpdate, - canDestroy: this.canDestroy, - endpoint: this.endpoint, - issuableRef: this.issuableRef, - initialTitleHtml: this.initialTitleHtml, - initialTitleText: this.initialTitleText, - initialDescriptionHtml: this.initialDescriptionHtml, - initialDescriptionText: this.initialDescriptionText, - issuableTemplates: this.issuableTemplates, - markdownPreviewPath: this.markdownPreviewPath, - markdownDocsPath: this.markdownDocsPath, - projectPath: this.projectPath, - projectNamespace: this.projectNamespace, - updatedAt: this.updatedAt, - updatedByName: this.updatedByName, - updatedByPath: this.updatedByPath, - initialTaskStatus: this.initialTaskStatus, - }, + props, }); }, }); diff --git a/app/assets/javascripts/job.js b/app/assets/javascripts/job.js index c6b5844dff6..85ea6330ee9 100644 --- a/app/assets/javascripts/job.js +++ b/app/assets/javascripts/job.js @@ -9,13 +9,13 @@ export default class Job { this.state = null; this.options = options || $('.js-build-options').data(); - this.pageUrl = this.options.pageUrl; + this.pagePath = this.options.pagePath; this.buildStatus = this.options.buildStatus; this.state = this.options.logState; this.buildStage = this.options.buildStage; this.$document = $(document); + this.$window = $(window); this.logBytes = 0; - this.hasBeenScrolled = false; this.updateDropdown = this.updateDropdown.bind(this); this.$buildTrace = $('#build-trace'); @@ -54,23 +54,18 @@ export default class Job { this.scrollThrottled = _.throttle(this.toggleScroll.bind(this), 100); - $(window) + this.$window .off('scroll') .on('scroll', () => { - const contentHeight = this.$buildTraceOutput.height(); - if (contentHeight > this.windowSize) { - // means the user did not scroll, the content was updated. - this.windowSize = contentHeight; - } else { - // User scrolled - this.hasBeenScrolled = true; + if (!this.isScrolledToBottom()) { this.toggleScrollAnimation(false); + } else if (this.isScrolledToBottom() && !this.isLogComplete) { + this.toggleScrollAnimation(true); } - this.scrollThrottled(); }); - $(window) + this.$window .off('resize.build') .on('resize.build', _.throttle(this.sidebarOnResize.bind(this), 100)); @@ -99,14 +94,14 @@ export default class Job { // eslint-disable-next-line class-methods-use-this canScroll() { - return $(document).height() > $(window).height(); + return this.$document.height() > this.$window.height(); } toggleScroll() { - const currentPosition = $(document).scrollTop(); - const scrollHeight = $(document).height(); + const currentPosition = this.$document.scrollTop(); + const scrollHeight = this.$document.height(); - const windowHeight = $(window).height(); + const windowHeight = this.$window.height(); if (this.canScroll()) { if (currentPosition > 0 && (scrollHeight - currentPosition !== windowHeight)) { @@ -119,7 +114,7 @@ export default class Job { this.toggleDisableButton(this.$scrollTopBtn, true); this.toggleDisableButton(this.$scrollBottomBtn, false); - } else if (scrollHeight - currentPosition === windowHeight) { + } else if (this.isScrolledToBottom()) { // User is at the bottom of the build log. this.toggleDisableButton(this.$scrollTopBtn, false); @@ -131,9 +126,17 @@ export default class Job { } } + isScrolledToBottom() { + const currentPosition = this.$document.scrollTop(); + const scrollHeight = this.$document.height(); + + const windowHeight = this.$window.height(); + return scrollHeight - currentPosition === windowHeight; + } + // eslint-disable-next-line class-methods-use-this scrollDown() { - $(document).scrollTop($(document).height()); + this.$document.scrollTop(this.$document.height()); } scrollToBottom() { @@ -143,7 +146,7 @@ export default class Job { } scrollToTop() { - $(document).scrollTop(0); + this.$document.scrollTop(0); this.hasBeenScrolled = true; this.toggleScroll(); } @@ -164,17 +167,17 @@ export default class Job { getBuildTrace() { return $.ajax({ - url: `${this.pageUrl}/trace.json`, + url: `${this.pagePath}/trace.json`, data: { state: this.state }, }) .done((log) => { - setCiStatusFavicon(`${this.pageUrl}/status.json`); + setCiStatusFavicon(`${this.pagePath}/status.json`); if (log.state) { this.state = log.state; } - this.windowSize = this.$buildTraceOutput.height(); + this.isScrollInBottom = this.isScrolledToBottom(); if (log.append) { this.$buildTraceOutput.append(log.html); @@ -194,14 +197,9 @@ export default class Job { } else { this.$truncatedInfo.addClass('hidden'); } + this.isLogComplete = log.complete; if (!log.complete) { - if (!this.hasBeenScrolled) { - this.toggleScrollAnimation(true); - } else { - this.toggleScrollAnimation(false); - } - this.timeout = setTimeout(() => { this.getBuildTrace(); }, 4000); @@ -211,14 +209,14 @@ export default class Job { } if (log.status !== this.buildStatus) { - gl.utils.visitUrl(this.pageUrl); + gl.utils.visitUrl(this.pagePath); } }) .fail(() => { this.$buildRefreshAnimation.remove(); }) .then(() => { - if (!this.hasBeenScrolled) { + if (this.isScrollInBottom) { this.scrollDown(); } }) diff --git a/app/assets/javascripts/jobs/job_details_mediator.js b/app/assets/javascripts/jobs/job_details_mediator.js index 3e2658f9fc1..5a216f8fae2 100644 --- a/app/assets/javascripts/jobs/job_details_mediator.js +++ b/app/assets/javascripts/jobs/job_details_mediator.js @@ -29,8 +29,8 @@ export default class JobMediator { this.poll = new Poll({ resource: this.service, method: 'getJob', - successCallback: this.successCallback.bind(this), - errorCallback: this.errorCallback.bind(this), + successCallback: response => this.successCallback(response), + errorCallback: () => this.errorCallback(), }); if (!Visibility.hidden()) { @@ -57,7 +57,7 @@ export default class JobMediator { successCallback(response) { this.state.isLoading = false; - return response.json().then(data => this.store.storeJob(data)); + return this.store.storeJob(response.data); } errorCallback() { diff --git a/app/assets/javascripts/jobs/services/job_service.js b/app/assets/javascripts/jobs/services/job_service.js index eaf1c6e500a..b746489c45c 100644 --- a/app/assets/javascripts/jobs/services/job_service.js +++ b/app/assets/javascripts/jobs/services/job_service.js @@ -1,14 +1,11 @@ -import Vue from 'vue'; -import VueResource from 'vue-resource'; - -Vue.use(VueResource); +import axios from '../../lib/utils/axios_utils'; export default class JobService { constructor(endpoint) { - this.job = Vue.resource(endpoint); + this.job = endpoint; } getJob() { - return this.job.get(); + return axios.get(this.job); } } diff --git a/app/assets/javascripts/lib/utils/axios_utils.js b/app/assets/javascripts/lib/utils/axios_utils.js index 45bff245827..7aeeca3b283 100644 --- a/app/assets/javascripts/lib/utils/axios_utils.js +++ b/app/assets/javascripts/lib/utils/axios_utils.js @@ -1,6 +1,22 @@ import axios from 'axios'; import csrf from './csrf'; -export default function setAxiosCsrfToken() { - axios.defaults.headers.common[csrf.headerKey] = csrf.token; -} +axios.defaults.headers.common[csrf.headerKey] = csrf.token; + +// Maintain a global counter for active requests +// see: spec/support/wait_for_requests.rb +axios.interceptors.request.use((config) => { + window.activeVueResources = window.activeVueResources || 0; + window.activeVueResources += 1; + + return config; +}); + +// Remove the global counter +axios.interceptors.response.use((config) => { + window.activeVueResources -= 1; + + return config; +}); + +export default axios; diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js index 07899777a1e..33cc807912c 100644 --- a/app/assets/javascripts/lib/utils/common_utils.js +++ b/app/assets/javascripts/lib/utils/common_utils.js @@ -172,7 +172,6 @@ export const getSelectedFragment = () => { return documentFragment; }; -// TODO: Update this name, there is a gl.text.insertText function. export const insertText = (target, text) => { // Firefox doesn't support `document.execCommand('insertText', false, text)` on textareas const selectionStart = target.selectionStart; @@ -191,7 +190,7 @@ export const insertText = (target, text) => { target.selectionStart = target.selectionEnd = selectionStart + insertedText.length; // Trigger autosave - $(target).trigger('input'); + target.dispatchEvent(new Event('input')); // Trigger autosize const event = document.createEvent('Event'); @@ -271,43 +270,39 @@ export const parseIntPagination = paginationInformation => ({ }); /** - * Updates the search parameter of a URL given the parameter and value provided. + * Given a string of query parameters creates an object. * - * If no search params are present we'll add it. - * If param for page is already present, we'll update it - * If there are params but not for the given one, we'll add it at the end. - * Returns the new search parameters. + * @example + * `scope=all&page=2` -> { scope: 'all', page: '2'} + * `scope=all` -> { scope: 'all' } + * ``-> {} + * @param {String} query + * @returns {Object} + */ +export const parseQueryStringIntoObject = (query = '') => { + if (query === '') return {}; + + return query + .split('&') + .reduce((acc, element) => { + const val = element.split('='); + Object.assign(acc, { + [val[0]]: decodeURIComponent(val[1]), + }); + return acc; + }, {}); +}; + +export const buildUrlWithCurrentLocation = param => (param ? `${window.location.pathname}${param}` : window.location.pathname); + +/** + * Based on the current location and the string parameters provided + * creates a new entry in the history without reloading the page. * * @param {String} param - * @param {Number|String|Undefined|Null} value - * @return {String} */ -export const setParamInURL = (param, value) => { - let search; - const locationSearch = window.location.search; - - if (locationSearch.length) { - const parameters = locationSearch.substring(1, locationSearch.length) - .split('&') - .reduce((acc, element) => { - const val = element.split('='); - // eslint-disable-next-line no-param-reassign - acc[val[0]] = decodeURIComponent(val[1]); - return acc; - }, {}); - - parameters[param] = value; - - const toString = Object.keys(parameters) - .map(val => `${val}=${encodeURIComponent(parameters[val])}`) - .join('&'); - - search = `?${toString}`; - } else { - search = `?${param}=${value}`; - } - - return search; +export const historyPushState = (newUrl) => { + window.history.pushState({}, document.title, newUrl); }; /** diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js index 29fc91733b3..d0578b230b1 100644 --- a/app/assets/javascripts/lib/utils/datetime_utility.js +++ b/app/assets/javascripts/lib/utils/datetime_utility.js @@ -2,6 +2,7 @@ import timeago from 'timeago.js'; import dateFormat from 'vendor/date.format'; +import { pluralize } from './text_utility'; import { lang, @@ -34,8 +35,6 @@ window.dateFormat = dateFormat; w.gl.utils.localTimeAgo = function($timeagoEls, setTimeago = true) { $timeagoEls.each((i, el) => { - el.setAttribute('title', el.getAttribute('title')); - if (setTimeago) { // Recreate with custom template $(el).tooltip({ @@ -143,9 +142,23 @@ export function timeIntervalInWords(intervalInSeconds) { let text = ''; if (minutes >= 1) { - text = `${minutes} ${gl.text.pluralize('minute', minutes)} ${seconds} ${gl.text.pluralize('second', seconds)}`; + text = `${minutes} ${pluralize('minute', minutes)} ${seconds} ${pluralize('second', seconds)}`; } else { - text = `${seconds} ${gl.text.pluralize('second', seconds)}`; + text = `${seconds} ${pluralize('second', seconds)}`; } return text; } + +export function dateInWords(date, abbreviated = false) { + if (!date) return date; + + const month = date.getMonth(); + const year = date.getFullYear(); + + const monthNames = [s__('January'), s__('February'), s__('March'), s__('April'), s__('May'), s__('June'), s__('July'), s__('August'), s__('September'), s__('October'), s__('November'), s__('December')]; + const monthNamesAbbr = [s__('Jan'), s__('Feb'), s__('Mar'), s__('Apr'), s__('May'), s__('Jun'), s__('Jul'), s__('Aug'), s__('Sep'), s__('Oct'), s__('Nov'), s__('Dec')]; + + const monthName = abbreviated ? monthNamesAbbr[month] : monthNames[month]; + + return `${monthName} ${date.getDate()}, ${year}`; +} diff --git a/app/assets/javascripts/lib/utils/number_utils.js b/app/assets/javascripts/lib/utils/number_utils.js index 917a45eb06b..a02c79b787e 100644 --- a/app/assets/javascripts/lib/utils/number_utils.js +++ b/app/assets/javascripts/lib/utils/number_utils.js @@ -52,3 +52,31 @@ export function bytesToKiB(number) { export function bytesToMiB(number) { return number / (BYTES_IN_KIB * BYTES_IN_KIB); } + +/** + * Utility function that calculates GiB of the given bytes. + * @param {Number} number + * @returns {Number} + */ +export function bytesToGiB(number) { + return number / (BYTES_IN_KIB * BYTES_IN_KIB * BYTES_IN_KIB); +} + +/** + * Port of rails number_to_human_size + * Formats the bytes in number into a more understandable + * representation (e.g., giving it 1500 yields 1.5 KB). + * + * @param {Number} size + * @returns {String} + */ +export function numberToHumanSize(size) { + if (size < BYTES_IN_KIB) { + return `${size} bytes`; + } else if (size < BYTES_IN_KIB * BYTES_IN_KIB) { + return `${bytesToKiB(size).toFixed(2)} KiB`; + } else if (size < BYTES_IN_KIB * BYTES_IN_KIB * BYTES_IN_KIB) { + return `${bytesToMiB(size).toFixed(2)} MiB`; + } + return `${bytesToGiB(size).toFixed(2)} GiB`; +} diff --git a/app/assets/javascripts/lib/utils/poll.js b/app/assets/javascripts/lib/utils/poll.js index 1485e900945..7fca80c2fdb 100644 --- a/app/assets/javascripts/lib/utils/poll.js +++ b/app/assets/javascripts/lib/utils/poll.js @@ -3,7 +3,9 @@ import { normalizeHeaders } from './common_utils'; /** * Polling utility for handling realtime updates. - * Service for vue resouce and method need to be provided as props + * Requirements: Promise based HTTP client + * + * Service for promise based http client and method need to be provided as props * * @example * new Poll({ @@ -60,7 +62,6 @@ export default class Poll { checkConditions(response) { const headers = normalizeHeaders(response.headers); const pollInterval = parseInt(headers[this.intervalHeader], 10); - if (pollInterval > 0 && response.status === httpStatusCodes.OK && this.canPoll) { this.timeoutID = setTimeout(() => { this.makeRequest(); @@ -102,7 +103,12 @@ export default class Poll { /** * Restarts polling after it has been stoped */ - restart() { + restart(options) { + // update data + if (options && options.data) { + this.options.data = options.data; + } + this.canPoll = true; this.makeRequest(); } diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js new file mode 100644 index 00000000000..2dc9cf0cc29 --- /dev/null +++ b/app/assets/javascripts/lib/utils/text_markdown.js @@ -0,0 +1,153 @@ +/* eslint-disable import/prefer-default-export, func-names, space-before-function-paren, wrap-iife, no-var, no-param-reassign, no-cond-assign, quotes, one-var, one-var-declaration-per-line, operator-assignment, no-else-return, prefer-template, prefer-arrow-callback, no-empty, max-len, consistent-return, no-unused-vars, no-return-assign, max-len, vars-on-top */ + +const textUtils = {}; + +textUtils.selectedText = function(text, textarea) { + return text.substring(textarea.selectionStart, textarea.selectionEnd); +}; + +textUtils.lineBefore = function(text, textarea) { + var split; + split = text.substring(0, textarea.selectionStart).trim().split('\n'); + return split[split.length - 1]; +}; + +textUtils.lineAfter = function(text, textarea) { + return text.substring(textarea.selectionEnd).trim().split('\n')[0]; +}; + +textUtils.blockTagText = function(text, textArea, blockTag, selected) { + var lineAfter, lineBefore; + lineBefore = this.lineBefore(text, textArea); + lineAfter = this.lineAfter(text, textArea); + if (lineBefore === blockTag && lineAfter === blockTag) { + // To remove the block tag we have to select the line before & after + if (blockTag != null) { + textArea.selectionStart = textArea.selectionStart - (blockTag.length + 1); + textArea.selectionEnd = textArea.selectionEnd + (blockTag.length + 1); + } + return selected; + } else { + return blockTag + "\n" + selected + "\n" + blockTag; + } +}; + +textUtils.insertText = function(textArea, text, tag, blockTag, selected, wrap) { + var insertText, inserted, selectedSplit, startChar, removedLastNewLine, removedFirstNewLine, currentLineEmpty, lastNewLine; + removedLastNewLine = false; + removedFirstNewLine = false; + currentLineEmpty = false; + + // Remove the first newline + if (selected.indexOf('\n') === 0) { + removedFirstNewLine = true; + selected = selected.replace(/\n+/, ''); + } + + // Remove the last newline + if (textArea.selectionEnd - textArea.selectionStart > selected.replace(/\n$/, '').length) { + removedLastNewLine = true; + selected = selected.replace(/\n$/, ''); + } + + selectedSplit = selected.split('\n'); + + if (!wrap) { + lastNewLine = textArea.value.substr(0, textArea.selectionStart).lastIndexOf('\n'); + + // Check whether the current line is empty or consists only of spaces(=handle as empty) + if (/^\s*$/.test(textArea.value.substring(lastNewLine, textArea.selectionStart))) { + currentLineEmpty = true; + } + } + + startChar = !wrap && !currentLineEmpty && textArea.selectionStart > 0 ? '\n' : ''; + + if (selectedSplit.length > 1 && (!wrap || (blockTag != null && blockTag !== ''))) { + if (blockTag != null && blockTag !== '') { + insertText = this.blockTagText(text, textArea, blockTag, selected); + } else { + insertText = selectedSplit.map(function(val) { + if (val.indexOf(tag) === 0) { + return "" + (val.replace(tag, '')); + } else { + return "" + tag + val; + } + }).join('\n'); + } + } else { + insertText = "" + startChar + tag + selected + (wrap ? tag : ' '); + } + + if (removedFirstNewLine) { + insertText = '\n' + insertText; + } + + if (removedLastNewLine) { + insertText += '\n'; + } + + if (document.queryCommandSupported('insertText')) { + inserted = document.execCommand('insertText', false, insertText); + } + if (!inserted) { + try { + document.execCommand("ms-beginUndoUnit"); + } catch (error) {} + textArea.value = this.replaceRange(text, textArea.selectionStart, textArea.selectionEnd, insertText); + try { + document.execCommand("ms-endUndoUnit"); + } catch (error) {} + } + return this.moveCursor(textArea, tag, wrap, removedLastNewLine); +}; + +textUtils.moveCursor = function(textArea, tag, wrapped, removedLastNewLine) { + var pos; + if (!textArea.setSelectionRange) { + return; + } + if (textArea.selectionStart === textArea.selectionEnd) { + if (wrapped) { + pos = textArea.selectionStart - tag.length; + } else { + pos = textArea.selectionStart; + } + + if (removedLastNewLine) { + pos -= 1; + } + + return textArea.setSelectionRange(pos, pos); + } +}; + +textUtils.updateText = function(textArea, tag, blockTag, wrap) { + var $textArea, selected, text; + $textArea = $(textArea); + textArea = $textArea.get(0); + text = $textArea.val(); + selected = this.selectedText(text, textArea); + $textArea.focus(); + return this.insertText(textArea, text, tag, blockTag, selected, wrap); +}; + +textUtils.init = function(form) { + var self; + self = this; + return $('.js-md', form).off('click').on('click', function() { + var $this; + $this = $(this); + return self.updateText($this.closest('.md-area').find('textarea'), $this.data('md-tag'), $this.data('md-block'), !$this.data('md-prepend')); + }); +}; + +textUtils.removeListeners = function(form) { + return $('.js-md', form).off('click'); +}; + +textUtils.replaceRange = function(s, start, end, substitute) { + return s.substring(0, start) + substitute + s.substring(end); +}; + +export default textUtils; diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js index f776829f69c..9280b7f150c 100644 --- a/app/assets/javascripts/lib/utils/text_utility.js +++ b/app/assets/javascripts/lib/utils/text_utility.js @@ -1,18 +1,13 @@ -/* eslint-disable import/prefer-default-export, func-names, space-before-function-paren, wrap-iife, no-var, no-param-reassign, no-cond-assign, quotes, one-var, one-var-declaration-per-line, operator-assignment, no-else-return, prefer-template, prefer-arrow-callback, no-empty, max-len, consistent-return, no-unused-vars, no-return-assign, max-len, vars-on-top */ - -import 'vendor/latinise'; - -var base; -var w = window; -if (w.gl == null) { - w.gl = {}; -} -if ((base = w.gl).text == null) { - base.text = {}; -} -gl.text.addDelimiter = function(text) { - return text ? text.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") : text; -}; +/** + * Adds a , to a string composed by numbers, at every 3 chars. + * + * 2333 -> 2,333 + * 232324 -> 232,324 + * + * @param {String} text + * @returns {String} + */ +export const addDelimiter = text => (text ? text.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') : text); /** * Returns '99+' for numbers bigger than 99. @@ -20,178 +15,52 @@ gl.text.addDelimiter = function(text) { * @param {Number} count * @return {Number|String} */ -export function highCountTrim(count) { - return count > 99 ? '99+' : count; -} - -gl.text.randomString = function() { - return Math.random().toString(36).substring(7); -}; -gl.text.replaceRange = function(s, start, end, substitute) { - return s.substring(0, start) + substitute + s.substring(end); -}; -gl.text.getTextWidth = function(text, font) { - /** - * Uses canvas.measureText to compute and return the width of the given text of given font in pixels. - * - * @param {String} text The text to be rendered. - * @param {String} font The css font descriptor that text is to be rendered with (e.g. "bold 14px verdana"). - * - * @see http://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393 - */ - // re-use canvas object for better performance - var canvas = gl.text.getTextWidth.canvas || (gl.text.getTextWidth.canvas = document.createElement('canvas')); - var context = canvas.getContext('2d'); - context.font = font; - return context.measureText(text).width; -}; -gl.text.selectedText = function(text, textarea) { - return text.substring(textarea.selectionStart, textarea.selectionEnd); -}; -gl.text.lineBefore = function(text, textarea) { - var split; - split = text.substring(0, textarea.selectionStart).trim().split('\n'); - return split[split.length - 1]; -}; -gl.text.lineAfter = function(text, textarea) { - return text.substring(textarea.selectionEnd).trim().split('\n')[0]; -}; -gl.text.blockTagText = function(text, textArea, blockTag, selected) { - var lineAfter, lineBefore; - lineBefore = this.lineBefore(text, textArea); - lineAfter = this.lineAfter(text, textArea); - if (lineBefore === blockTag && lineAfter === blockTag) { - // To remove the block tag we have to select the line before & after - if (blockTag != null) { - textArea.selectionStart = textArea.selectionStart - (blockTag.length + 1); - textArea.selectionEnd = textArea.selectionEnd + (blockTag.length + 1); - } - return selected; - } else { - return blockTag + "\n" + selected + "\n" + blockTag; - } -}; -gl.text.insertText = function(textArea, text, tag, blockTag, selected, wrap) { - var insertText, inserted, selectedSplit, startChar, removedLastNewLine, removedFirstNewLine, currentLineEmpty, lastNewLine; - removedLastNewLine = false; - removedFirstNewLine = false; - currentLineEmpty = false; - - // Remove the first newline - if (selected.indexOf('\n') === 0) { - removedFirstNewLine = true; - selected = selected.replace(/\n+/, ''); - } - - // Remove the last newline - if (textArea.selectionEnd - textArea.selectionStart > selected.replace(/\n$/, '').length) { - removedLastNewLine = true; - selected = selected.replace(/\n$/, ''); - } - - selectedSplit = selected.split('\n'); - - if (!wrap) { - lastNewLine = textArea.value.substr(0, textArea.selectionStart).lastIndexOf('\n'); - - // Check whether the current line is empty or consists only of spaces(=handle as empty) - if (/^\s*$/.test(textArea.value.substring(lastNewLine, textArea.selectionStart))) { - currentLineEmpty = true; - } - } - - startChar = !wrap && !currentLineEmpty && textArea.selectionStart > 0 ? '\n' : ''; +export const highCountTrim = count => (count > 99 ? '99+' : count); - if (selectedSplit.length > 1 && (!wrap || (blockTag != null && blockTag !== ''))) { - if (blockTag != null && blockTag !== '') { - insertText = this.blockTagText(text, textArea, blockTag, selected); - } else { - insertText = selectedSplit.map(function(val) { - if (val.indexOf(tag) === 0) { - return "" + (val.replace(tag, '')); - } else { - return "" + tag + val; - } - }).join('\n'); - } - } else { - insertText = "" + startChar + tag + selected + (wrap ? tag : ' '); - } +/** + * Converts first char to uppercase and replaces undercores with spaces + * @param {String} string + * @requires {String} + */ +export const humanize = string => string.charAt(0).toUpperCase() + string.replace(/_/g, ' ').slice(1); - if (removedFirstNewLine) { - insertText = '\n' + insertText; - } +/** + * Adds an 's' to the end of the string when count is bigger than 0 + * @param {String} str + * @param {Number} count + * @returns {String} + */ +export const pluralize = (str, count) => str + (count > 1 || count === 0 ? 's' : ''); - if (removedLastNewLine) { - insertText += '\n'; - } +/** + * Replaces underscores with dashes + * @param {*} str + * @returns {String} + */ +export const dasherize = str => str.replace(/[_\s]+/g, '-'); - if (document.queryCommandSupported('insertText')) { - inserted = document.execCommand('insertText', false, insertText); - } - if (!inserted) { - try { - document.execCommand("ms-beginUndoUnit"); - } catch (error) {} - textArea.value = this.replaceRange(text, textArea.selectionStart, textArea.selectionEnd, insertText); - try { - document.execCommand("ms-endUndoUnit"); - } catch (error) {} - } - return this.moveCursor(textArea, tag, wrap, removedLastNewLine); -}; -gl.text.moveCursor = function(textArea, tag, wrapped, removedLastNewLine) { - var pos; - if (!textArea.setSelectionRange) { - return; - } - if (textArea.selectionStart === textArea.selectionEnd) { - if (wrapped) { - pos = textArea.selectionStart - tag.length; - } else { - pos = textArea.selectionStart; - } +/** + * Removes accents and converts to lower case + * @param {String} str + * @returns {String} + */ +export const slugify = str => str.trim().toLowerCase(); - if (removedLastNewLine) { - pos -= 1; - } +/** + * Truncates given text + * + * @param {String} string + * @param {Number} maxLength + * @returns {String} + */ +export const truncate = (string, maxLength) => `${string.substr(0, (maxLength - 3))}...`; - return textArea.setSelectionRange(pos, pos); - } -}; -gl.text.updateText = function(textArea, tag, blockTag, wrap) { - var $textArea, selected, text; - $textArea = $(textArea); - textArea = $textArea.get(0); - text = $textArea.val(); - selected = this.selectedText(text, textArea); - $textArea.focus(); - return this.insertText(textArea, text, tag, blockTag, selected, wrap); -}; -gl.text.init = function(form) { - var self; - self = this; - return $('.js-md', form).off('click').on('click', function() { - var $this; - $this = $(this); - return self.updateText($this.closest('.md-area').find('textarea'), $this.data('md-tag'), $this.data('md-block'), !$this.data('md-prepend')); - }); -}; -gl.text.removeListeners = function(form) { - return $('.js-md', form).off('click'); -}; -gl.text.humanize = function(string) { - return string.charAt(0).toUpperCase() + string.replace(/_/g, ' ').slice(1); -}; -gl.text.pluralize = function(str, count) { - return str + (count > 1 || count === 0 ? 's' : ''); -}; -gl.text.truncate = function(string, maxLength) { - return string.substr(0, (maxLength - 3)) + '...'; -}; -gl.text.dasherize = function(str) { - return str.replace(/[_\s]+/g, '-'); -}; -gl.text.slugify = function(str) { - return str.trim().toLowerCase().latinise(); -}; +/** + * Capitalizes first character + * + * @param {String} text + * @return {String} + */ +export function capitalizeFirstCharacter(text) { + return `${text[0].toUpperCase()}${text.slice(1)}`; +} diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js index 1aa63216baf..17236c91490 100644 --- a/app/assets/javascripts/lib/utils/url_utility.js +++ b/app/assets/javascripts/lib/utils/url_utility.js @@ -100,6 +100,10 @@ export function visitUrl(url, external = false) { } } +export function redirectTo(url) { + return window.location.assign(url); +} + window.gl = window.gl || {}; window.gl.utils = { ...(window.gl.utils || {}), diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 31c5cfc5e55..dcc0fa63b63 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -29,8 +29,6 @@ import './commit/image_file'; // lib/utils import { handleLocationHash } from './lib/utils/common_utils'; import './lib/utils/datetime_utility'; -import './lib/utils/pretty_time'; -import './lib/utils/text_utility'; import './lib/utils/url_utility'; // behaviors @@ -46,7 +44,6 @@ import './commits'; import './compare'; import './compare_autocomplete'; import './confirm_danger_modal'; -import './copy_to_clipboard'; import Flash, { removeFlashClickListener } from './flash'; import './gl_dropdown'; import './gl_field_error'; @@ -60,36 +57,21 @@ import './line_highlighter'; import initLogoAnimation from './logo'; import './merge_request'; import './merge_request_tabs'; -import './milestone'; import './milestone_select'; -import './namespace_select'; -import './new_branch_form'; -import './new_commit_form'; import './notes'; import './notifications_dropdown'; import './notifications_form'; import './pager'; import './preview_markdown'; -import './project'; -import './project_avatar'; import './project_find_file'; import './project_import'; -import './project_label_subscription'; -import './project_new'; -import './project_select'; -import './project_show'; -import './project_variables'; import './projects_dropdown'; import './projects_list'; import './syntax_highlight'; -import './render_math'; import './render_gfm'; import './right_sidebar'; import './search'; import './search_autocomplete'; -import './smart_interval'; -import './subscription'; -import './subscription_select'; import initBreadcrumbs from './breadcrumb'; import './dispatcher'; @@ -318,6 +300,8 @@ $(function () { const flashContainer = document.querySelector('.flash-container'); if (flashContainer && flashContainer.children.length) { - removeFlashClickListener(flashContainer.children[0]); + flashContainer.querySelectorAll('.flash-alert, .flash-notice, .flash-success').forEach((flashEl) => { + removeFlashClickListener(flashEl); + }); } }); diff --git a/app/assets/javascripts/members.js b/app/assets/javascripts/members.js index 6264750a4fb..52315e969d1 100644 --- a/app/assets/javascripts/members.js +++ b/app/assets/javascripts/members.js @@ -5,7 +5,6 @@ export default class Members { } addListeners() { - $('.project_member, .group_member').off('ajax:success').on('ajax:success', this.removeRow); $('.js-member-update-control').off('change').on('change', this.formSubmit.bind(this)); $('.js-edit-member-form').off('ajax:success').on('ajax:success', this.formSuccess.bind(this)); gl.utils.disableButtonIfEmptyField('#user_ids', 'input[name=commit]', 'change'); @@ -33,17 +32,6 @@ export default class Members { }); }); } - // eslint-disable-next-line class-methods-use-this - removeRow(e) { - const $target = $(e.target); - - if ($target.hasClass('btn-remove')) { - $target.closest('.member') - .fadeOut(function fadeOutMemberRow() { - $(this).remove(); - }); - } - } formSubmit(e, $el = null) { const $this = e ? $(e.currentTarget) : $el; diff --git a/app/assets/javascripts/merge_request.js b/app/assets/javascripts/merge_request.js index af0658eb668..a9c08df4f93 100644 --- a/app/assets/javascripts/merge_request.js +++ b/app/assets/javascripts/merge_request.js @@ -5,6 +5,7 @@ import 'vendor/jquery.waitforimages'; import TaskList from './task_list'; import './merge_request_tabs'; import IssuablesHelper from './helpers/issuables_helper'; +import { addDelimiter } from './lib/utils/text_utility'; (function() { this.MergeRequest = (function() { @@ -124,11 +125,11 @@ import IssuablesHelper from './helpers/issuables_helper'; const $el = $('.nav-links .js-merge-counter'); const count = Math.max((parseInt($el.text().replace(/[^\d]/, ''), 10) - by), 0); - $el.text(gl.text.addDelimiter(count)); + $el.text(addDelimiter(count)); }; MergeRequest.prototype.hideCloseButton = function() { - const el = document.querySelector('.merge-request .issuable-actions'); + const el = document.querySelector('.merge-request .js-issuable-actions'); const closeDropdownItem = el.querySelector('li.close-item'); if (closeDropdownItem) { closeDropdownItem.classList.add('hidden'); diff --git a/app/assets/javascripts/milestone.js b/app/assets/javascripts/milestone.js index 8f3f1986763..f76a998bf8c 100644 --- a/app/assets/javascripts/milestone.js +++ b/app/assets/javascripts/milestone.js @@ -1,54 +1,49 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-use-before-define, camelcase, quotes, object-shorthand, no-shadow, no-unused-vars, comma-dangle, no-var, prefer-template, no-underscore-dangle, consistent-return, one-var, one-var-declaration-per-line, default-case, prefer-arrow-callback, max-len */ /* global Sortable */ import Flash from './flash'; -(function() { - this.Milestone = (function() { - function Milestone() { - this.bindTabsSwitching(); +export default class Milestone { + constructor() { + this.bindTabsSwitching(); - // Load merge request tab if it is active - // merge request tab is active based on different conditions in the backend - this.loadTab($('.js-milestone-tabs .active a')); + // Load merge request tab if it is active + // merge request tab is active based on different conditions in the backend + this.loadTab($('.js-milestone-tabs .active a')); - this.loadInitialTab(); - } + this.loadInitialTab(); + } + + bindTabsSwitching() { + return $('a[data-toggle="tab"]').on('show.bs.tab', (e) => { + const $target = $(e.target); - Milestone.prototype.bindTabsSwitching = function() { - return $('a[data-toggle="tab"]').on('show.bs.tab', (e) => { - const $target = $(e.target); + location.hash = $target.attr('href'); + this.loadTab($target); + }); + } + // eslint-disable-next-line class-methods-use-this + loadInitialTab() { + const $target = $(`.js-milestone-tabs a[href="${location.hash}"]`); - location.hash = $target.attr('href'); - this.loadTab($target); + if ($target.length) { + $target.tab('show'); + } + } + // eslint-disable-next-line class-methods-use-this + loadTab($target) { + const endpoint = $target.data('endpoint'); + const tabElId = $target.attr('href'); + + if (endpoint && !$target.hasClass('is-loaded')) { + $.ajax({ + url: endpoint, + dataType: 'JSON', + }) + .fail(() => new Flash('Error loading milestone tab')) + .done((data) => { + $(tabElId).html(data.html); + $target.addClass('is-loaded'); }); - }; - - Milestone.prototype.loadInitialTab = function() { - const $target = $(`.js-milestone-tabs a[href="${location.hash}"]`); - - if ($target.length) { - $target.tab('show'); - } - }; - - Milestone.prototype.loadTab = function($target) { - const endpoint = $target.data('endpoint'); - const tabElId = $target.attr('href'); - - if (endpoint && !$target.hasClass('is-loaded')) { - $.ajax({ - url: endpoint, - dataType: 'JSON', - }) - .fail(() => new Flash('Error loading milestone tab')) - .done((data) => { - $(tabElId).html(data.html); - $target.addClass('is-loaded'); - }); - } - }; - - return Milestone; - })(); -}).call(window); + } + } +} diff --git a/app/assets/javascripts/monitoring/services/monitoring_service.js b/app/assets/javascripts/monitoring/services/monitoring_service.js index fed884d5c94..e230a06cd8c 100644 --- a/app/assets/javascripts/monitoring/services/monitoring_service.js +++ b/app/assets/javascripts/monitoring/services/monitoring_service.js @@ -1,10 +1,7 @@ -import Vue from 'vue'; -import VueResource from 'vue-resource'; +import axios from '../../lib/utils/axios_utils'; import statusCodes from '../../lib/utils/http_status'; import { backOff } from '../../lib/utils/common_utils'; -Vue.use(VueResource); - const MAX_REQUESTS = 3; function backOffRequest(makeRequestCallback) { @@ -32,8 +29,8 @@ export default class MonitoringService { } getGraphsData() { - return backOffRequest(() => Vue.http.get(this.metricsEndpoint)) - .then(resp => resp.json()) + return backOffRequest(() => axios.get(this.metricsEndpoint)) + .then(resp => resp.data) .then((response) => { if (!response || !response.data) { throw new Error('Unexpected metrics data response from prometheus endpoint'); @@ -43,8 +40,8 @@ export default class MonitoringService { } getDeploymentData() { - return backOffRequest(() => Vue.http.get(this.deploymentEndpoint)) - .then(resp => resp.json()) + return backOffRequest(() => axios.get(this.deploymentEndpoint)) + .then(resp => resp.data) .then((response) => { if (!response || !response.deployments) { throw new Error('Unexpected deployment data response from prometheus endpoint'); diff --git a/app/assets/javascripts/new_branch_form.js b/app/assets/javascripts/new_branch_form.js index 39fb302b644..77733b67c4d 100644 --- a/app/assets/javascripts/new_branch_form.js +++ b/app/assets/javascripts/new_branch_form.js @@ -1,97 +1,93 @@ /* eslint-disable func-names, space-before-function-paren, no-var, one-var, prefer-rest-params, max-len, vars-on-top, wrap-iife, consistent-return, comma-dangle, one-var-declaration-per-line, quotes, no-return-assign, prefer-arrow-callback, prefer-template, no-shadow, no-else-return, max-len, object-shorthand */ -import RefSelectDropdown from '~/ref_select_dropdown'; +import RefSelectDropdown from './ref_select_dropdown'; -(function() { - this.NewBranchForm = (function() { - function NewBranchForm(form, availableRefs) { - this.validate = this.validate.bind(this); - this.branchNameError = form.find('.js-branch-name-error'); - this.name = form.find('.js-branch-name'); - this.ref = form.find('#ref'); - new RefSelectDropdown($('.js-branch-select'), availableRefs); // eslint-disable-line no-new - this.setupRestrictions(); - this.addBinding(); - this.init(); +export default class NewBranchForm { + constructor(form, availableRefs) { + this.validate = this.validate.bind(this); + this.branchNameError = form.find('.js-branch-name-error'); + this.name = form.find('.js-branch-name'); + this.ref = form.find('#ref'); + new RefSelectDropdown($('.js-branch-select'), availableRefs); // eslint-disable-line no-new + this.setupRestrictions(); + this.addBinding(); + this.init(); + } + + addBinding() { + return this.name.on('blur', this.validate); + } + + init() { + if (this.name.length && this.name.val().length > 0) { + return this.name.trigger('blur'); } + } - NewBranchForm.prototype.addBinding = function() { - return this.name.on('blur', this.validate); + setupRestrictions() { + var endsWith, invalid, single, startsWith; + startsWith = { + pattern: /^(\/|\.)/g, + prefix: "can't start with", + conjunction: "or" }; - - NewBranchForm.prototype.init = function() { - if (this.name.length && this.name.val().length > 0) { - return this.name.trigger('blur'); - } + endsWith = { + pattern: /(\/|\.|\.lock)$/g, + prefix: "can't end in", + conjunction: "or" }; - - NewBranchForm.prototype.setupRestrictions = function() { - var endsWith, invalid, single, startsWith; - startsWith = { - pattern: /^(\/|\.)/g, - prefix: "can't start with", - conjunction: "or" - }; - endsWith = { - pattern: /(\/|\.|\.lock)$/g, - prefix: "can't end in", - conjunction: "or" - }; - invalid = { - pattern: /(\s|~|\^|:|\?|\*|\[|\\|\.\.|@\{|\/{2,}){1}/g, - prefix: "can't contain", - conjunction: ", " - }; - single = { - pattern: /^@+$/g, - prefix: "can't be", - conjunction: "or" - }; - return this.restrictions = [startsWith, invalid, endsWith, single]; + invalid = { + pattern: /(\s|~|\^|:|\?|\*|\[|\\|\.\.|@\{|\/{2,}){1}/g, + prefix: "can't contain", + conjunction: ", " + }; + single = { + pattern: /^@+$/g, + prefix: "can't be", + conjunction: "or" }; + return this.restrictions = [startsWith, invalid, endsWith, single]; + } - NewBranchForm.prototype.validate = function() { - var errorMessage, errors, formatter, unique, validator; - const indexOf = [].indexOf; + validate() { + var errorMessage, errors, formatter, unique, validator; + const indexOf = [].indexOf; - this.branchNameError.empty(); - unique = function(values, value) { - if (indexOf.call(values, value) === -1) { - values.push(value); - } - return values; - }; - formatter = function(values, restriction) { - var formatted; - formatted = values.map(function(value) { - switch (false) { - case !/\s/.test(value): - return 'spaces'; - case !/\/{2,}/g.test(value): - return 'consecutive slashes'; - default: - return "'" + value + "'"; - } - }); - return restriction.prefix + " " + (formatted.join(restriction.conjunction)); - }; - validator = (function(_this) { - return function(errors, restriction) { - var matched; - matched = _this.name.val().match(restriction.pattern); - if (matched) { - return errors.concat(formatter(matched.reduce(unique, []), restriction)); - } else { - return errors; - } - }; - })(this); - errors = this.restrictions.reduce(validator, []); - if (errors.length > 0) { - errorMessage = $("<span/>").text(errors.join(', ')); - return this.branchNameError.append(errorMessage); + this.branchNameError.empty(); + unique = function(values, value) { + if (indexOf.call(values, value) === -1) { + values.push(value); } + return values; }; - - return NewBranchForm; - })(); -}).call(window); + formatter = function(values, restriction) { + var formatted; + formatted = values.map(function(value) { + switch (false) { + case !/\s/.test(value): + return 'spaces'; + case !/\/{2,}/g.test(value): + return 'consecutive slashes'; + default: + return "'" + value + "'"; + } + }); + return restriction.prefix + " " + (formatted.join(restriction.conjunction)); + }; + validator = (function(_this) { + return function(errors, restriction) { + var matched; + matched = _this.name.val().match(restriction.pattern); + if (matched) { + return errors.concat(formatter(matched.reduce(unique, []), restriction)); + } else { + return errors; + } + }; + })(this); + errors = this.restrictions.reduce(validator, []); + if (errors.length > 0) { + errorMessage = $("<span/>").text(errors.join(', ')); + return this.branchNameError.append(errorMessage); + } + } +} diff --git a/app/assets/javascripts/new_commit_form.js b/app/assets/javascripts/new_commit_form.js index 04073ef7270..6e152497d20 100644 --- a/app/assets/javascripts/new_commit_form.js +++ b/app/assets/javascripts/new_commit_form.js @@ -1,32 +1,28 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-return-assign, max-len */ -(function() { - this.NewCommitForm = (function() { - function NewCommitForm(form) { - this.form = form; - this.renderDestination = this.renderDestination.bind(this); - this.branchName = form.find('.js-branch-name'); - this.originalBranch = form.find('.js-original-branch'); - this.createMergeRequest = form.find('.js-create-merge-request'); - this.createMergeRequestContainer = form.find('.js-create-merge-request-container'); - this.branchName.keyup(this.renderDestination); - this.renderDestination(); - } +export default class NewCommitForm { + constructor(form) { + this.form = form; + this.renderDestination = this.renderDestination.bind(this); + this.branchName = form.find('.js-branch-name'); + this.originalBranch = form.find('.js-original-branch'); + this.createMergeRequest = form.find('.js-create-merge-request'); + this.createMergeRequestContainer = form.find('.js-create-merge-request-container'); + this.branchName.keyup(this.renderDestination); + this.renderDestination(); + } - NewCommitForm.prototype.renderDestination = function() { - var different; - different = this.branchName.val() !== this.originalBranch.val(); - if (different) { - this.createMergeRequestContainer.show(); - if (!this.wasDifferent) { - this.createMergeRequest.prop('checked', true); - } - } else { - this.createMergeRequestContainer.hide(); - this.createMergeRequest.prop('checked', false); + renderDestination() { + var different; + different = this.branchName.val() !== this.originalBranch.val(); + if (different) { + this.createMergeRequestContainer.show(); + if (!this.wasDifferent) { + this.createMergeRequest.prop('checked', true); } - return this.wasDifferent = different; - }; - - return NewCommitForm; - })(); -}).call(window); + } else { + this.createMergeRequestContainer.hide(); + this.createMergeRequest.prop('checked', false); + } + return this.wasDifferent = different; + } +} diff --git a/app/assets/javascripts/notes/components/discussion_locked_widget.vue b/app/assets/javascripts/notes/components/discussion_locked_widget.vue new file mode 100644 index 00000000000..e6f7ee56ff3 --- /dev/null +++ b/app/assets/javascripts/notes/components/discussion_locked_widget.vue @@ -0,0 +1,26 @@ +<script> + import Icon from '~/vue_shared/components/icon.vue'; + import Issuable from '~/vue_shared/mixins/issuable'; + + export default { + mixins: [ + Issuable, + ], + components: { + Icon, + }, + }; +</script> + +<template> + <div class="disabled-comment text-center"> + <span class="issuable-note-warning inline"> + <icon + name="lock" + :size="16" + class="icon"> + </icon> + <span>This {{ issuableDisplayName }} is locked. Only <b>project members</b> can comment.</span> + </span> + </div> +</template> diff --git a/app/assets/javascripts/notes/components/issue_comment_form.vue b/app/assets/javascripts/notes/components/issue_comment_form.vue index db8f85759b2..78986a450c2 100644 --- a/app/assets/javascripts/notes/components/issue_comment_form.vue +++ b/app/assets/javascripts/notes/components/issue_comment_form.vue @@ -8,8 +8,8 @@ import * as constants from '../constants'; import eventHub from '../event_hub'; import issueWarning from '../../vue_shared/components/issue/issue_warning.vue'; - import issueNoteSignedOutWidget from './issue_note_signed_out_widget.vue'; - import issueDiscussionLockedWidget from './issue_discussion_locked_widget.vue'; + import noteSignedOutWidget from './note_signed_out_widget.vue'; + import discussionLockedWidget from './discussion_locked_widget.vue'; import markdownField from '../../vue_shared/components/markdown/field.vue'; import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; import issuableStateMixin from '../mixins/issuable_state'; @@ -22,15 +22,15 @@ noteType: constants.COMMENT, // Can't use mapGetters, // this needs to be in the data object because it belongs to the state - issueState: this.$store.getters.getIssueData.state, + issueState: this.$store.getters.getNoteableData.state, isSubmitting: false, isSubmitButtonDisabled: true, }; }, components: { issueWarning, - issueNoteSignedOutWidget, - issueDiscussionLockedWidget, + noteSignedOutWidget, + discussionLockedWidget, markdownField, userAvatarLink, }, @@ -46,7 +46,7 @@ ...mapGetters([ 'getCurrentUserLastNote', 'getUserData', - 'getIssueData', + 'getNoteableData', 'getNotesData', ]), isLoggedIn() { @@ -59,7 +59,7 @@ return this.issueState === constants.OPENED || this.issueState === constants.REOPENED; }, canCreateNote() { - return this.getIssueData.current_user.can_create_note; + return this.getNoteableData.current_user.can_create_note; }, issueActionButtonTitle() { if (this.note.length) { @@ -85,16 +85,16 @@ return this.getNotesData.quickActionsDocsPath; }, markdownPreviewPath() { - return this.getIssueData.preview_note_path; + return this.getNoteableData.preview_note_path; }, author() { return this.getUserData; }, canUpdateIssue() { - return this.getIssueData.current_user.can_update; + return this.getNoteableData.current_user.can_update; }, endpoint() { - return this.getIssueData.create_note_path; + return this.getNoteableData.create_note_path; }, }, methods: { @@ -119,7 +119,7 @@ data: { note: { noteable_type: constants.NOTEABLE_TYPE, - noteable_id: this.getIssueData.id, + noteable_id: this.getNoteableData.id, note: this.note, }, }, @@ -207,7 +207,7 @@ }, initAutoSave() { if (this.isLoggedIn) { - this.autosave = new Autosave($(this.$refs.textarea), ['Note', 'Issue', this.getIssueData.id], 'issue'); + this.autosave = new Autosave($(this.$refs.textarea), ['Note', 'Issue', this.getNoteableData.id], 'issue'); } }, initTaskList() { @@ -240,8 +240,11 @@ <template> <div> - <issue-note-signed-out-widget v-if="!isLoggedIn" /> - <issue-discussion-locked-widget v-else-if="!canCreateNote" /> + <note-signed-out-widget v-if="!isLoggedIn" /> + <discussion-locked-widget + issuable-type="issue" + v-else-if="!canCreateNote" + /> <ul v-else class="notes notes-form timeline"> @@ -266,9 +269,9 @@ <div class="error-alert"></div> <issue-warning - v-if="hasWarning(getIssueData)" - :is-locked="isLocked(getIssueData)" - :is-confidential="isConfidential(getIssueData)" + v-if="hasWarning(getNoteableData)" + :is-locked="isLocked(getNoteableData)" + :is-confidential="isConfidential(getNoteableData)" /> <markdown-field @@ -357,7 +360,8 @@ @click="handleSave(true)" v-if="canUpdateIssue" :class="actionButtonClassNames" - class="btn btn-comment btn-comment-and-close"> + :disabled="isSubmitting" + class="btn btn-comment btn-comment-and-close js-action-button"> {{issueActionButtonTitle}} </button> <button diff --git a/app/assets/javascripts/notes/components/issue_discussion.vue b/app/assets/javascripts/notes/components/issue_discussion.vue index 0f13221b81e..460fde9b62a 100644 --- a/app/assets/javascripts/notes/components/issue_discussion.vue +++ b/app/assets/javascripts/notes/components/issue_discussion.vue @@ -4,10 +4,9 @@ import { SYSTEM_NOTE } from '../constants'; import issueNote from './issue_note.vue'; import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; - import issueNoteHeader from './issue_note_header.vue'; - import issueNoteActions from './issue_note_actions.vue'; - import issueNoteSignedOutWidget from './issue_note_signed_out_widget.vue'; - import issueNoteEditedText from './issue_note_edited_text.vue'; + import noteHeader from './note_header.vue'; + import noteSignedOutWidget from './note_signed_out_widget.vue'; + import noteEditedText from './note_edited_text.vue'; import issueNoteForm from './issue_note_form.vue'; import placeholderNote from '../../vue_shared/components/notes/placeholder_note.vue'; import placeholderSystemNote from '../../vue_shared/components/notes/placeholder_system_note.vue'; @@ -28,10 +27,9 @@ components: { issueNote, userAvatarLink, - issueNoteHeader, - issueNoteActions, - issueNoteSignedOutWidget, - issueNoteEditedText, + noteHeader, + noteSignedOutWidget, + noteEditedText, issueNoteForm, placeholderNote, placeholderSystemNote, @@ -41,7 +39,7 @@ ], computed: { ...mapGetters([ - 'getIssueData', + 'getNoteableData', ]), discussion() { return this.note.notes[0]; @@ -50,10 +48,10 @@ return this.discussion.author; }, canReply() { - return this.getIssueData.current_user.can_create_note; + return this.getNoteableData.current_user.can_create_note; }, newNotePath() { - return this.getIssueData.create_note_path; + return this.getNoteableData.create_note_path; }, lastUpdatedBy() { const { notes } = this.note; @@ -171,7 +169,7 @@ <div class="timeline-content"> <div class="discussion"> <div class="discussion-header"> - <issue-note-header + <note-header :author="author" :created-at="discussion.created_at" :note-id="discussion.id" @@ -179,8 +177,8 @@ @toggleHandler="toggleDiscussionHandler" action-text="started a discussion" class="discussion" - /> - <issue-note-edited-text + /> + <note-edited-text v-if="lastUpdatedAt" :edited-at="lastUpdatedAt" :edited-by="lastUpdatedBy" @@ -220,7 +218,7 @@ @cancelFormEdition="cancelReplyForm" ref="noteForm" /> - <issue-note-signed-out-widget v-if="!canReply" /> + <note-signed-out-widget v-if="!canReply" /> </div> </div> </div> diff --git a/app/assets/javascripts/notes/components/issue_discussion_locked_widget.vue b/app/assets/javascripts/notes/components/issue_discussion_locked_widget.vue deleted file mode 100644 index e73ec2aaf71..00000000000 --- a/app/assets/javascripts/notes/components/issue_discussion_locked_widget.vue +++ /dev/null @@ -1,19 +0,0 @@ -<script> - export default { - computed: { - lockIcon() { - return gl.utils.spriteIcon('lock'); - }, - }, - }; - -</script> - -<template> - <div class="disabled-comment text-center"> - <span class="issuable-note-warning"> - <span class="icon" v-html="lockIcon"></span> - <span>This issue is locked. Only <b>project members</b> can comment.</span> - </span> - </div> -</template> diff --git a/app/assets/javascripts/notes/components/issue_note.vue b/app/assets/javascripts/notes/components/issue_note.vue index 40318f9a600..8c81c5d6df3 100644 --- a/app/assets/javascripts/notes/components/issue_note.vue +++ b/app/assets/javascripts/notes/components/issue_note.vue @@ -2,8 +2,8 @@ import { mapGetters, mapActions } from 'vuex'; import Flash from '../../flash'; import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; - import issueNoteHeader from './issue_note_header.vue'; - import issueNoteActions from './issue_note_actions.vue'; + import noteHeader from './note_header.vue'; + import noteActions from './note_actions.vue'; import issueNoteBody from './issue_note_body.vue'; import eventHub from '../event_hub'; @@ -23,8 +23,8 @@ }, components: { userAvatarLink, - issueNoteHeader, - issueNoteActions, + noteHeader, + noteActions, issueNoteBody, }, computed: { @@ -155,13 +155,13 @@ </div> <div class="timeline-content"> <div class="note-header"> - <issue-note-header + <note-header :author="author" :created-at="note.created_at" :note-id="note.id" action-text="commented" /> - <issue-note-actions + <note-actions :author-id="author.id" :note-id="note.id" :access-level="note.human_access" diff --git a/app/assets/javascripts/notes/components/issue_note_body.vue b/app/assets/javascripts/notes/components/issue_note_body.vue index 5f9003bfd87..a16c5f6a785 100644 --- a/app/assets/javascripts/notes/components/issue_note_body.vue +++ b/app/assets/javascripts/notes/components/issue_note_body.vue @@ -1,7 +1,7 @@ <script> - import issueNoteEditedText from './issue_note_edited_text.vue'; - import issueNoteAwardsList from './issue_note_awards_list.vue'; - import issueNoteAttachment from './issue_note_attachment.vue'; + import noteEditedText from './note_edited_text.vue'; + import noteAwardsList from './note_awards_list.vue'; + import noteAttachment from './note_attachment.vue'; import issueNoteForm from './issue_note_form.vue'; import TaskList from '../../task_list'; import autosave from '../mixins/autosave'; @@ -26,9 +26,9 @@ autosave, ], components: { - issueNoteEditedText, - issueNoteAwardsList, - issueNoteAttachment, + noteEditedText, + noteAwardsList, + noteAttachment, issueNoteForm, }, computed: { @@ -101,20 +101,20 @@ v-model="note.note" :data-update-url="note.path" class="hidden js-task-list-field"></textarea> - <issue-note-edited-text + <note-edited-text v-if="note.last_edited_at" :edited-at="note.last_edited_at" :edited-by="note.last_edited_by" action-text="Edited" /> - <issue-note-awards-list + <note-awards-list v-if="note.award_emoji.length" :note-id="note.id" :note-author-id="note.author.id" :awards="note.award_emoji" :toggle-award-path="note.toggle_award_path" /> - <issue-note-attachment + <note-attachment v-if="note.attachment" :attachment="note.attachment" /> diff --git a/app/assets/javascripts/notes/components/issue_note_form.vue b/app/assets/javascripts/notes/components/issue_note_form.vue index e2539d6b89d..4d527cb6643 100644 --- a/app/assets/javascripts/notes/components/issue_note_form.vue +++ b/app/assets/javascripts/notes/components/issue_note_form.vue @@ -46,8 +46,8 @@ computed: { ...mapGetters([ 'getDiscussionLastNote', - 'getIssueData', - 'getIssueDataByProp', + 'getNoteableData', + 'getNoteableDataByProp', 'getNotesDataByProp', 'getUserDataByProp', ]), @@ -55,7 +55,7 @@ return `#note_${this.noteId}`; }, markdownPreviewPath() { - return this.getIssueDataByProp('preview_note_path'); + return this.getNoteableDataByProp('preview_note_path'); }, markdownDocsPath() { return this.getNotesDataByProp('markdownDocsPath'); @@ -129,9 +129,9 @@ class="edit-note common-note-form js-quick-submit gfm-form"> <issue-warning - v-if="hasWarning(getIssueData)" - :is-locked="isLocked(getIssueData)" - :is-confidential="isConfidential(getIssueData)" + v-if="hasWarning(getNoteableData)" + :is-locked="isLocked(getNoteableData)" + :is-confidential="isConfidential(getNoteableData)" /> <markdown-field diff --git a/app/assets/javascripts/notes/components/issue_notes_app.vue b/app/assets/javascripts/notes/components/issue_notes_app.vue index 5c9119644e3..4cfcffa2391 100644 --- a/app/assets/javascripts/notes/components/issue_notes_app.vue +++ b/app/assets/javascripts/notes/components/issue_notes_app.vue @@ -14,7 +14,7 @@ export default { name: 'issueNotesApp', props: { - issueData: { + noteableData: { type: Object, required: true, }, @@ -56,7 +56,7 @@ actionToggleAward: 'toggleAward', scrollToNoteIfNeeded: 'scrollToNoteIfNeeded', setNotesData: 'setNotesData', - setIssueData: 'setIssueData', + setNoteableData: 'setNoteableData', setUserData: 'setUserData', setLastFetchedAt: 'setLastFetchedAt', setTargetNoteHash: 'setTargetNoteHash', @@ -106,7 +106,7 @@ }, created() { this.setNotesData(this.notesData); - this.setIssueData(this.issueData); + this.setNoteableData(this.noteableData); this.setUserData(this.userData); }, mounted() { diff --git a/app/assets/javascripts/notes/components/issue_note_actions.vue b/app/assets/javascripts/notes/components/note_actions.vue index feb3e73194b..7fb45ed4d4b 100644 --- a/app/assets/javascripts/notes/components/issue_note_actions.vue +++ b/app/assets/javascripts/notes/components/note_actions.vue @@ -5,11 +5,11 @@ import emojiSmiley from 'icons/_emoji_smiley.svg'; import editSvg from 'icons/_icon_pencil.svg'; import ellipsisSvg from 'icons/_ellipsis_v.svg'; - import loadingIcon from '../../vue_shared/components/loading_icon.vue'; - import tooltip from '../../vue_shared/directives/tooltip'; + import loadingIcon from '~/vue_shared/components/loading_icon.vue'; + import tooltip from '~/vue_shared/directives/tooltip'; export default { - name: 'issueNoteActions', + name: 'noteActions', props: { authorId: { type: Number, @@ -86,7 +86,7 @@ <div class="note-actions"> <span v-if="accessLevel" - class="note-role note-role-access">{{accessLevel}}</span> + class="note-role user-access-role">{{accessLevel}}</span> <div v-if="canAddAwardEmoji" class="note-actions-item"> diff --git a/app/assets/javascripts/notes/components/issue_note_attachment.vue b/app/assets/javascripts/notes/components/note_attachment.vue index 7134a3eb47e..cd9571a4002 100644 --- a/app/assets/javascripts/notes/components/issue_note_attachment.vue +++ b/app/assets/javascripts/notes/components/note_attachment.vue @@ -1,6 +1,6 @@ <script> export default { - name: 'issueNoteAttachment', + name: 'noteAttachment', props: { attachment: { type: Object, diff --git a/app/assets/javascripts/notes/components/issue_note_awards_list.vue b/app/assets/javascripts/notes/components/note_awards_list.vue index c3a340139e7..c3a340139e7 100644 --- a/app/assets/javascripts/notes/components/issue_note_awards_list.vue +++ b/app/assets/javascripts/notes/components/note_awards_list.vue diff --git a/app/assets/javascripts/notes/components/issue_note_edited_text.vue b/app/assets/javascripts/notes/components/note_edited_text.vue index 49e09f0ecc5..49e09f0ecc5 100644 --- a/app/assets/javascripts/notes/components/issue_note_edited_text.vue +++ b/app/assets/javascripts/notes/components/note_edited_text.vue diff --git a/app/assets/javascripts/notes/components/issue_note_header.vue b/app/assets/javascripts/notes/components/note_header.vue index 63aa3d777d0..63aa3d777d0 100644 --- a/app/assets/javascripts/notes/components/issue_note_header.vue +++ b/app/assets/javascripts/notes/components/note_header.vue diff --git a/app/assets/javascripts/notes/components/issue_note_signed_out_widget.vue b/app/assets/javascripts/notes/components/note_signed_out_widget.vue index 77af3594c1c..45d3c2de355 100644 --- a/app/assets/javascripts/notes/components/issue_note_signed_out_widget.vue +++ b/app/assets/javascripts/notes/components/note_signed_out_widget.vue @@ -2,7 +2,6 @@ import { mapGetters } from 'vuex'; export default { - name: 'singInLinksNotes', computed: { ...mapGetters([ 'getNotesDataByProp', diff --git a/app/assets/javascripts/notes/index.js b/app/assets/javascripts/notes/index.js index e2ea37408cf..a94163a5f87 100644 --- a/app/assets/javascripts/notes/index.js +++ b/app/assets/javascripts/notes/index.js @@ -8,10 +8,18 @@ document.addEventListener('DOMContentLoaded', () => new Vue({ }, data() { const notesDataset = document.getElementById('js-vue-notes').dataset; + const parsedUserData = JSON.parse(notesDataset.currentUserData); + const currentUserData = parsedUserData ? { + id: parsedUserData.id, + name: parsedUserData.name, + username: parsedUserData.username, + avatar_url: parsedUserData.avatar_path || parsedUserData.avatar_url, + path: parsedUserData.path, + } : {}; return { - issueData: JSON.parse(notesDataset.issueData), - currentUserData: JSON.parse(notesDataset.currentUserData), + noteableData: JSON.parse(notesDataset.noteableData), + currentUserData, notesData: { lastFetchedAt: notesDataset.lastFetchedAt, discussionsPath: notesDataset.discussionsPath, @@ -26,7 +34,7 @@ document.addEventListener('DOMContentLoaded', () => new Vue({ render(createElement) { return createElement('issue-notes-app', { props: { - issueData: this.issueData, + noteableData: this.noteableData, notesData: this.notesData, userData: this.currentUserData, }, diff --git a/app/assets/javascripts/notes/services/issue_notes_service.js b/app/assets/javascripts/notes/services/notes_service.js index b51b0cb2013..b51b0cb2013 100644 --- a/app/assets/javascripts/notes/services/issue_notes_service.js +++ b/app/assets/javascripts/notes/services/notes_service.js diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js index 6f04aecc9b7..085b18642ba 100644 --- a/app/assets/javascripts/notes/stores/actions.js +++ b/app/assets/javascripts/notes/stores/actions.js @@ -4,7 +4,7 @@ import Poll from '../../lib/utils/poll'; import * as types from './mutation_types'; import * as utils from './utils'; import * as constants from '../constants'; -import service from '../services/issue_notes_service'; +import service from '../services/notes_service'; import loadAwardsHandler from '../../awards_handler'; import sidebarTimeTrackingEventHub from '../../sidebar/event_hub'; import { isInViewport, scrollToElement } from '../../lib/utils/common_utils'; @@ -12,7 +12,7 @@ import { isInViewport, scrollToElement } from '../../lib/utils/common_utils'; let eTagPoll; export const setNotesData = ({ commit }, data) => commit(types.SET_NOTES_DATA, data); -export const setIssueData = ({ commit }, data) => commit(types.SET_ISSUE_DATA, data); +export const setNoteableData = ({ commit }, data) => commit(types.SET_NOTEABLE_DATA, data); export const setUserData = ({ commit }, data) => commit(types.SET_USER_DATA, data); export const setLastFetchedAt = ({ commit }, data) => commit(types.SET_LAST_FETCHED_AT, data); export const setInitialNotes = ({ commit }, data) => commit(types.SET_INITIAL_NOTES, data); diff --git a/app/assets/javascripts/notes/stores/getters.js b/app/assets/javascripts/notes/stores/getters.js index 1f0c6af6156..e18b277119e 100644 --- a/app/assets/javascripts/notes/stores/getters.js +++ b/app/assets/javascripts/notes/stores/getters.js @@ -6,8 +6,8 @@ export const targetNoteHash = state => state.targetNoteHash; export const getNotesData = state => state.notesData; export const getNotesDataByProp = state => prop => state.notesData[prop]; -export const getIssueData = state => state.issueData; -export const getIssueDataByProp = state => prop => state.issueData[prop]; +export const getNoteableData = state => state.noteableData; +export const getNoteableDataByProp = state => prop => state.noteableData[prop]; export const getUserData = state => state.userData || {}; export const getUserDataByProp = state => prop => state.userData && state.userData[prop]; diff --git a/app/assets/javascripts/notes/stores/index.js b/app/assets/javascripts/notes/stores/index.js index 8e0c8531bbc..488a9ca38d3 100644 --- a/app/assets/javascripts/notes/stores/index.js +++ b/app/assets/javascripts/notes/stores/index.js @@ -15,7 +15,7 @@ export default new Vuex.Store({ // holds endpoints and permissions provided through haml notesData: {}, userData: {}, - issueData: {}, + noteableData: {}, }, actions, getters, diff --git a/app/assets/javascripts/notes/stores/mutation_types.js b/app/assets/javascripts/notes/stores/mutation_types.js index cd71533ba9d..d520c197407 100644 --- a/app/assets/javascripts/notes/stores/mutation_types.js +++ b/app/assets/javascripts/notes/stores/mutation_types.js @@ -3,7 +3,7 @@ export const ADD_NEW_REPLY_TO_DISCUSSION = 'ADD_NEW_REPLY_TO_DISCUSSION'; export const DELETE_NOTE = 'DELETE_NOTE'; export const REMOVE_PLACEHOLDER_NOTES = 'REMOVE_PLACEHOLDER_NOTES'; export const SET_NOTES_DATA = 'SET_NOTES_DATA'; -export const SET_ISSUE_DATA = 'SET_ISSUE_DATA'; +export const SET_NOTEABLE_DATA = 'SET_NOTEABLE_DATA'; export const SET_USER_DATA = 'SET_USER_DATA'; export const SET_INITIAL_NOTES = 'SET_INITIAL_NOTES'; export const SET_LAST_FETCHED_AT = 'SET_LAST_FETCHED_AT'; diff --git a/app/assets/javascripts/notes/stores/mutations.js b/app/assets/javascripts/notes/stores/mutations.js index c2a08f3d6fe..20f81a430c2 100644 --- a/app/assets/javascripts/notes/stores/mutations.js +++ b/app/assets/javascripts/notes/stores/mutations.js @@ -66,8 +66,8 @@ export default { Object.assign(state, { notesData: data }); }, - [types.SET_ISSUE_DATA](state, data) { - Object.assign(state, { issueData: data }); + [types.SET_NOTEABLE_DATA](state, data) { + Object.assign(state, { noteableData: data }); }, [types.SET_USER_DATA](state, data) { diff --git a/app/assets/javascripts/pipelines/components/graph/action_component.vue b/app/assets/javascripts/pipelines/components/graph/action_component.vue index 547140b1a43..19d8e1f49cf 100644 --- a/app/assets/javascripts/pipelines/components/graph/action_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/action_component.vue @@ -1,7 +1,7 @@ <script> import tooltip from '../../../vue_shared/directives/tooltip'; import icon from '../../../vue_shared/components/icon.vue'; - + import { dasherize } from '../../../lib/utils/text_utility'; /** * Renders either a cancel, retry or play icon pointing to the given path. * TODO: Remove UJS from here and use an async request instead. @@ -39,7 +39,7 @@ computed: { cssClass() { - const actionIconDash = gl.text.dasherize(this.actionIcon); + const actionIconDash = dasherize(this.actionIcon); return `${actionIconDash} js-icon-${actionIconDash}`; }, }, diff --git a/app/assets/javascripts/pipelines/components/graph/job_component.vue b/app/assets/javascripts/pipelines/components/graph/job_component.vue index 5dea4555515..08199b4234a 100644 --- a/app/assets/javascripts/pipelines/components/graph/job_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/job_component.vue @@ -78,11 +78,13 @@ <div class="ci-job-component"> <a v-tooltip - v-if="job.status.details_path" + v-if="job.status.has_details" :href="job.status.details_path" :title="tooltipText" :class="cssClassJobName" - data-container="body"> + data-container="body" + class="js-pipeline-graph-job-link" + > <job-name-component :name="job.name" @@ -95,7 +97,8 @@ v-tooltip :title="tooltipText" :class="cssClassJobName" - data-container="body"> + data-container="body" + > <job-name-component :name="job.name" diff --git a/app/assets/javascripts/pipelines/components/navigation_tabs.vue b/app/assets/javascripts/pipelines/components/navigation_tabs.vue deleted file mode 100644 index 73f7e3a0cad..00000000000 --- a/app/assets/javascripts/pipelines/components/navigation_tabs.vue +++ /dev/null @@ -1,90 +0,0 @@ -<script> - export default { - name: 'PipelineNavigationTabs', - props: { - scope: { - type: String, - required: true, - }, - count: { - type: Object, - required: true, - }, - paths: { - type: Object, - required: true, - }, - }, - mounted() { - $(document).trigger('init.scrolling-tabs'); - }, - methods: { - shouldRenderBadge(count) { - // 0 is valid in a badge, but evaluates to false, we need to check for undefined - return count !== undefined; - }, - }, -}; -</script> -<template> - <ul class="nav-links scrolling-tabs"> - <li - class="js-pipelines-tab-all" - :class="{ active: scope === 'all'}"> - <a :href="paths.allPath"> - All - <span - v-if="shouldRenderBadge(count.all)" - class="badge js-totalbuilds-count"> - {{count.all}} - </span> - </a> - </li> - <li - class="js-pipelines-tab-pending" - :class="{ active: scope === 'pending'}"> - <a :href="paths.pendingPath"> - Pending - <span - v-if="shouldRenderBadge(count.pending)" - class="badge"> - {{count.pending}} - </span> - </a> - </li> - <li - class="js-pipelines-tab-running" - :class="{ active: scope === 'running'}"> - <a :href="paths.runningPath"> - Running - <span - v-if="shouldRenderBadge(count.running)" - class="badge"> - {{count.running}} - </span> - </a> - </li> - <li - class="js-pipelines-tab-finished" - :class="{ active: scope === 'finished'}"> - <a :href="paths.finishedPath"> - Finished - <span - v-if="shouldRenderBadge(count.finished)" - class="badge"> - {{count.finished}} - </span> - </a> - </li> - <li - class="js-pipelines-tab-branches" - :class="{ active: scope === 'branches'}"> - <a :href="paths.branchesPath">Branches</a> - </li> - <li - class="js-pipelines-tab-tags" - :class="{ active: scope === 'tags'}"> - <a :href="paths.tagsPath">Tags</a> - </li> - </ul> -</template> diff --git a/app/assets/javascripts/pipelines/components/pipelines.vue b/app/assets/javascripts/pipelines/components/pipelines.vue index 3da60e88474..fe1f3b4246a 100644 --- a/app/assets/javascripts/pipelines/components/pipelines.vue +++ b/app/assets/javascripts/pipelines/components/pipelines.vue @@ -1,10 +1,16 @@ <script> + import _ from 'underscore'; import PipelinesService from '../services/pipelines_service'; import pipelinesMixin from '../mixins/pipelines'; import tablePagination from '../../vue_shared/components/table_pagination.vue'; - import navigationTabs from './navigation_tabs.vue'; + import navigationTabs from '../../vue_shared/components/navigation_tabs.vue'; import navigationControls from './nav_controls.vue'; - import { convertPermissionToBoolean, getParameterByName, setParamInURL } from '../../lib/utils/common_utils'; + import { + convertPermissionToBoolean, + getParameterByName, + parseQueryStringIntoObject, + } from '../../lib/utils/common_utils'; + import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin'; export default { props: { @@ -29,6 +35,7 @@ }, mixins: [ pipelinesMixin, + CIPaginationMixin, ], data() { const pipelinesData = document.querySelector('#pipelines-list-vue').dataset; @@ -41,27 +48,18 @@ autoDevopsPath: pipelinesData.helpAutoDevopsPath, newPipelinePath: pipelinesData.newPipelinePath, canCreatePipeline: pipelinesData.canCreatePipeline, - allPath: pipelinesData.allPath, - pendingPath: pipelinesData.pendingPath, - runningPath: pipelinesData.runningPath, - finishedPath: pipelinesData.finishedPath, - branchesPath: pipelinesData.branchesPath, - tagsPath: pipelinesData.tagsPath, hasCi: pipelinesData.hasCi, ciLintPath: pipelinesData.ciLintPath, state: this.store.state, - apiScope: 'all', - pagenum: 1, + scope: getParameterByName('scope') || 'all', + page: getParameterByName('page') || '1', + requestData: {}, }; }, computed: { canCreatePipelineParsed() { return convertPermissionToBoolean(this.canCreatePipeline); }, - scope() { - const scope = getParameterByName('scope'); - return scope === null ? 'all' : scope; - }, /** * The empty state should only be rendered when the request is made to fetch all pipelines @@ -106,46 +104,90 @@ hasCiEnabled() { return this.hasCi !== undefined; }, - paths() { - return { - allPath: this.allPath, - pendingPath: this.pendingPath, - finishedPath: this.finishedPath, - runningPath: this.runningPath, - branchesPath: this.branchesPath, - tagsPath: this.tagsPath, - }; - }, - pageParameter() { - return getParameterByName('page') || this.pagenum; - }, - scopeParameter() { - return getParameterByName('scope') || this.apiScope; + + tabs() { + const { count } = this.state; + return [ + { + name: 'All', + scope: 'all', + count: count.all, + isActive: this.scope === 'all', + }, + { + name: 'Pending', + scope: 'pending', + count: count.pending, + isActive: this.scope === 'pending', + }, + { + name: 'Running', + scope: 'running', + count: count.running, + isActive: this.scope === 'running', + }, + { + name: 'Finished', + scope: 'finished', + count: count.finished, + isActive: this.scope === 'finished', + }, + { + name: 'Branches', + scope: 'branches', + isActive: this.scope === 'branches', + }, + { + name: 'Tags', + scope: 'tags', + isActive: this.scope === 'tags', + }, + ]; }, }, created() { this.service = new PipelinesService(this.endpoint); - this.requestData = { page: this.pageParameter, scope: this.scopeParameter }; + this.requestData = { page: this.page, scope: this.scope }; }, methods: { + successCallback(resp) { + return resp.json().then((response) => { + // Because we are polling & the user is interacting verify if the response received + // matches the last request made + if (_.isEqual(parseQueryStringIntoObject(resp.url.split('?')[1]), this.requestData)) { + this.store.storeCount(response.count); + this.store.storePagination(resp.headers); + this.setCommonData(response.pipelines); + } + }); + }, /** - * Will change the page number and update the URL. - * - * @param {Number} pageNumber desired page to go to. + * Handles URL and query parameter changes. + * When the user uses the pagination or the tabs, + * - update URL + * - Make API request to the server with new parameters + * - Update the polling function + * - Update the internal state */ - change(pageNumber) { - const param = setParamInURL('page', pageNumber); + updateContent(parameters) { + this.updateInternalState(parameters); - gl.utils.visitUrl(param); - return param; - }, + // fetch new data + return this.service.getPipelines(this.requestData) + .then((response) => { + this.isLoading = false; + this.successCallback(response); - successCallback(resp) { - return resp.json().then((response) => { - this.store.storeCount(response.count); - this.store.storePagination(resp.headers); - this.setCommonData(response.pipelines); - }); + // restart polling + this.poll.restart({ data: this.requestData }); + }) + .catch(() => { + this.isLoading = false; + this.errorCallback(); + + // restart polling + this.poll.restart(); + }); }, }, }; @@ -154,7 +196,7 @@ <div class="pipelines-container"> <div class="top-area scrolling-tabs-container inner-page-scroll-tabs" - v-if="!isLoading && !shouldRenderEmptyState"> + v-if="!shouldRenderEmptyState"> <div class="fade-left"> <i class="fa fa-angle-left" @@ -167,17 +209,18 @@ aria-hidden="true"> </i> </div> + <navigation-tabs - :scope="scope" - :count="state.count" - :paths="paths" + :tabs="tabs" + @onChangeTab="onChangeTab" + scope="pipelines" /> <navigation-controls :new-pipeline-path="newPipelinePath" :has-ci-enabled="hasCiEnabled" :help-page-path="helpPagePath" - :ciLintPath="ciLintPath" + :ci-lint-path="ciLintPath" :can-create-pipeline="canCreatePipelineParsed " /> </div> @@ -188,6 +231,7 @@ label="Loading Pipelines" size="3" v-if="isLoading" + class="prepend-top-20" /> <empty-state @@ -202,9 +246,11 @@ /> <div - class="blank-state blank-state-no-icon" + class="blank-state-row" v-if="shouldRenderNoPipelinesMessage"> - <h2 class="blank-state-title js-blank-state-title">No pipelines to show.</h2> + <div class="blank-state-center"> + <h2 class="blank-state-title js-blank-state-title">No pipelines to show.</h2> + </div> </div> <div @@ -221,8 +267,8 @@ <table-pagination v-if="shouldRenderPagination" - :change="change" - :pageInfo="state.pageInfo" + :change="onChangePage" + :page-info="state.pageInfo" /> </div> </div> diff --git a/app/assets/javascripts/project.js b/app/assets/javascripts/project.js index fe6602259e2..3131e71d9d6 100644 --- a/app/assets/javascripts/project.js +++ b/app/assets/javascripts/project.js @@ -1,139 +1,132 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, quotes, consistent-return, no-new, prefer-arrow-callback, no-return-assign, one-var, one-var-declaration-per-line, object-shorthand, comma-dangle, no-else-return, newline-per-chained-call, no-shadow, vars-on-top, prefer-template, max-len */ -/* global ProjectSelect */ +/* eslint-disable func-names, space-before-function-paren, no-var, consistent-return, no-new, prefer-arrow-callback, no-return-assign, one-var, one-var-declaration-per-line, object-shorthand, no-else-return, newline-per-chained-call, no-shadow, vars-on-top, prefer-template, max-len */ import Cookies from 'js-cookie'; +import projectSelect from './project_select'; -(function() { - this.Project = (function() { - function Project() { - const $cloneOptions = $('ul.clone-options-dropdown'); - const $projectCloneField = $('#project_clone'); - const $cloneBtnText = $('a.clone-dropdown-btn span'); +export default class Project { + constructor() { + const $cloneOptions = $('ul.clone-options-dropdown'); + const $projectCloneField = $('#project_clone'); + const $cloneBtnText = $('a.clone-dropdown-btn span'); - const selectedCloneOption = $cloneBtnText.text().trim(); - if (selectedCloneOption.length > 0) { - $(`a:contains('${selectedCloneOption}')`, $cloneOptions).addClass('is-active'); - } - - $('a', $cloneOptions).on('click', (e) => { - const $this = $(e.currentTarget); - const url = $this.attr('href'); - - e.preventDefault(); - - $('.is-active', $cloneOptions).not($this).removeClass('is-active'); - $this.toggleClass('is-active'); - $projectCloneField.val(url); - $cloneBtnText.text($this.text()); - - return $('.clone').text(url); - }); - // Ref switcher - this.initRefSwitcher(); - $('.project-refs-select').on('change', function() { - return $(this).parents('form').submit(); - }); - $('.hide-no-ssh-message').on('click', function(e) { - Cookies.set('hide_no_ssh_message', 'false'); - $(this).parents('.no-ssh-key-message').remove(); - return e.preventDefault(); - }); - $('.hide-no-password-message').on('click', function(e) { - Cookies.set('hide_no_password_message', 'false'); - $(this).parents('.no-password-message').remove(); - return e.preventDefault(); - }); - this.projectSelectDropdown(); + const selectedCloneOption = $cloneBtnText.text().trim(); + if (selectedCloneOption.length > 0) { + $(`a:contains('${selectedCloneOption}')`, $cloneOptions).addClass('is-active'); } - Project.prototype.projectSelectDropdown = function() { - new ProjectSelect(); - $('.project-item-select').on('click', (function(_this) { - return function(e) { - return _this.changeProject($(e.currentTarget).val()); - }; - })(this)); - }; - - Project.prototype.changeProject = function(url) { - return window.location = url; - }; - - Project.prototype.initRefSwitcher = function() { - var refListItem = document.createElement('li'); - var refLink = document.createElement('a'); - - refLink.href = '#'; - - return $('.js-project-refs-dropdown').each(function() { - var $dropdown, selected; - $dropdown = $(this); - selected = $dropdown.data('selected'); - return $dropdown.glDropdown({ - data: function(term, callback) { - return $.ajax({ - url: $dropdown.data('refs-url'), - data: { - ref: $dropdown.data('ref'), - search: term - }, - dataType: "json" - }).done(function(refs) { - return callback(refs); - }); - }, - selectable: true, - filterable: true, - filterRemote: true, - filterByText: true, - inputFieldName: $dropdown.data('input-field-name'), - fieldName: $dropdown.data('field-name'), - renderRow: function(ref) { - var li = refListItem.cloneNode(false); - - if (ref.header != null) { - li.className = 'dropdown-header'; - li.textContent = ref.header; - } else { - var link = refLink.cloneNode(false); - - if (ref === selected) { - link.className = 'is-active'; - } - - link.textContent = ref; - link.dataset.ref = ref; - - li.appendChild(link); + $('a', $cloneOptions).on('click', (e) => { + const $this = $(e.currentTarget); + const url = $this.attr('href'); + const activeText = $this.find('.dropdown-menu-inner-title').text(); + + e.preventDefault(); + + $('.is-active', $cloneOptions).not($this).removeClass('is-active'); + $this.toggleClass('is-active'); + $projectCloneField.val(url); + $cloneBtnText.text(activeText); + + return $('.clone').text(url); + }); + // Ref switcher + Project.initRefSwitcher(); + $('.project-refs-select').on('change', function() { + return $(this).parents('form').submit(); + }); + $('.hide-no-ssh-message').on('click', function(e) { + Cookies.set('hide_no_ssh_message', 'false'); + $(this).parents('.no-ssh-key-message').remove(); + return e.preventDefault(); + }); + $('.hide-no-password-message').on('click', function(e) { + Cookies.set('hide_no_password_message', 'false'); + $(this).parents('.no-password-message').remove(); + return e.preventDefault(); + }); + Project.projectSelectDropdown(); + } + + static projectSelectDropdown () { + projectSelect(); + $('.project-item-select').on('click', e => Project.changeProject($(e.currentTarget).val())); + } + + static changeProject(url) { + return window.location = url; + } + + static initRefSwitcher() { + var refListItem = document.createElement('li'); + var refLink = document.createElement('a'); + + refLink.href = '#'; + + return $('.js-project-refs-dropdown').each(function() { + var $dropdown, selected; + $dropdown = $(this); + selected = $dropdown.data('selected'); + return $dropdown.glDropdown({ + data: function(term, callback) { + return $.ajax({ + url: $dropdown.data('refs-url'), + data: { + ref: $dropdown.data('ref'), + search: term, + }, + dataType: 'json', + }).done(function(refs) { + return callback(refs); + }); + }, + selectable: true, + filterable: true, + filterRemote: true, + filterByText: true, + inputFieldName: $dropdown.data('input-field-name'), + fieldName: $dropdown.data('field-name'), + renderRow: function(ref) { + var li = refListItem.cloneNode(false); + + if (ref.header != null) { + li.className = 'dropdown-header'; + li.textContent = ref.header; + } else { + var link = refLink.cloneNode(false); + + if (ref === selected) { + link.className = 'is-active'; } - return li; - }, - id: function(obj, $el) { - return $el.attr('data-ref'); - }, - toggleLabel: function(obj, $el) { - return $el.text().trim(); - }, - clicked: function(options) { - const { e } = options; - e.preventDefault(); - if ($('input[name="ref"]').length) { - var $form = $dropdown.closest('form'); - - var $visit = $dropdown.data('visit'); - var shouldVisit = $visit ? true : $visit; - var action = $form.attr('action'); - var divider = action.indexOf('?') === -1 ? '?' : '&'; - if (shouldVisit) { - gl.utils.visitUrl(`${action}${divider}${$form.serialize()}`); - } + link.textContent = ref; + link.dataset.ref = ref; + + li.appendChild(link); + } + + return li; + }, + id: function(obj, $el) { + return $el.attr('data-ref'); + }, + toggleLabel: function(obj, $el) { + return $el.text().trim(); + }, + clicked: function(options) { + const { e } = options; + e.preventDefault(); + if ($('input[name="ref"]').length) { + var $form = $dropdown.closest('form'); + + var $visit = $dropdown.data('visit'); + var shouldVisit = $visit ? true : $visit; + var action = $form.attr('action'); + var divider = action.indexOf('?') === -1 ? '?' : '&'; + if (shouldVisit) { + gl.utils.visitUrl(`${action}${divider}${$form.serialize()}`); } } - }); + }, }); - }; - - return Project; - })(); -}).call(window); + }); + } +} diff --git a/app/assets/javascripts/project_avatar.js b/app/assets/javascripts/project_avatar.js index aabdfbf65e2..56627aa155c 100644 --- a/app/assets/javascripts/project_avatar.js +++ b/app/assets/javascripts/project_avatar.js @@ -1,20 +1,13 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, one-var-declaration-per-line, no-useless-escape, max-len */ -(function() { - this.ProjectAvatar = (function() { - function ProjectAvatar() { - $('.js-choose-project-avatar-button').bind('click', function() { - var form; - form = $(this).closest('form'); - return form.find('.js-project-avatar-input').click(); - }); - $('.js-project-avatar-input').bind('change', function() { - var filename, form; - form = $(this).closest('form'); - filename = $(this).val().replace(/^.*[\\\/]/, ''); - return form.find('.js-avatar-filename').text(filename); - }); - } +export default function projectAvatar() { + $('.js-choose-project-avatar-button').bind('click', function onClickAvatar() { + const form = $(this).closest('form'); + return form.find('.js-project-avatar-input').click(); + }); - return ProjectAvatar; - })(); -}).call(window); + $('.js-project-avatar-input').bind('change', function onClickAvatarInput() { + const form = $(this).closest('form'); + // eslint-disable-next-line no-useless-escape + const filename = $(this).val().replace(/^.*[\\\/]/, ''); + return form.find('.js-avatar-filename').text(filename); + }); +} diff --git a/app/assets/javascripts/project_import.js b/app/assets/javascripts/project_import.js index 08334bf1ec5..d2d26d6f67e 100644 --- a/app/assets/javascripts/project_import.js +++ b/app/assets/javascripts/project_import.js @@ -1,13 +1,8 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, max-len */ +import { visitUrl } from './lib/utils/url_utility'; -(function() { - this.ProjectImport = (function() { - function ProjectImport() { - setTimeout(function() { - return gl.utils.visitUrl(location.href); - }, 5000); - } +export default function projectImport() { + setTimeout(() => { + visitUrl(location.href); + }, 5000); +} - return ProjectImport; - })(); -}).call(window); diff --git a/app/assets/javascripts/project_label_subscription.js b/app/assets/javascripts/project_label_subscription.js index 0a811627600..b65521b278f 100644 --- a/app/assets/javascripts/project_label_subscription.js +++ b/app/assets/javascripts/project_label_subscription.js @@ -1,55 +1,50 @@ -/* eslint-disable wrap-iife, func-names, space-before-function-paren, object-shorthand, comma-dangle, one-var, one-var-declaration-per-line, no-restricted-syntax, max-len, no-param-reassign */ +export default class ProjectLabelSubscription { + constructor(container) { + this.$container = $(container); + this.$buttons = this.$container.find('.js-subscribe-button'); -(function(global) { - class ProjectLabelSubscription { - constructor(container) { - this.$container = $(container); - this.$buttons = this.$container.find('.js-subscribe-button'); - - this.$buttons.on('click', this.toggleSubscription.bind(this)); - } + this.$buttons.on('click', this.toggleSubscription.bind(this)); + } - toggleSubscription(event) { - event.preventDefault(); + toggleSubscription(event) { + event.preventDefault(); - const $btn = $(event.currentTarget); - const $span = $btn.find('span'); - const url = $btn.attr('data-url'); - const oldStatus = $btn.attr('data-status'); + const $btn = $(event.currentTarget); + const $span = $btn.find('span'); + const url = $btn.attr('data-url'); + const oldStatus = $btn.attr('data-status'); - $btn.addClass('disabled'); - $span.toggleClass('hidden'); + $btn.addClass('disabled'); + $span.toggleClass('hidden'); - $.ajax({ - type: 'POST', - url: url - }).done(() => { - let newStatus, newAction; + $.ajax({ + type: 'POST', + url, + }).done(() => { + let newStatus; + let newAction; - if (oldStatus === 'unsubscribed') { - [newStatus, newAction] = ['subscribed', 'Unsubscribe']; - } else { - [newStatus, newAction] = ['unsubscribed', 'Subscribe']; - } + if (oldStatus === 'unsubscribed') { + [newStatus, newAction] = ['subscribed', 'Unsubscribe']; + } else { + [newStatus, newAction] = ['unsubscribed', 'Subscribe']; + } - $span.toggleClass('hidden'); - $btn.removeClass('disabled'); + $span.toggleClass('hidden'); + $btn.removeClass('disabled'); - this.$buttons.attr('data-status', newStatus); - this.$buttons.find('> span').text(newAction); + this.$buttons.attr('data-status', newStatus); + this.$buttons.find('> span').text(newAction); - this.$buttons.map((button) => { - const $button = $(button); + this.$buttons.map((button) => { + const $button = $(button); - if ($button.attr('data-original-title')) { - $button.tooltip('hide').attr('data-original-title', newAction).tooltip('fixTitle'); - } + if ($button.attr('data-original-title')) { + $button.tooltip('hide').attr('data-original-title', newAction).tooltip('fixTitle'); + } - return button; - }); + return button; }); - } + }); } - - global.ProjectLabelSubscription = ProjectLabelSubscription; -})(window.gl || (window.gl = {})); +} diff --git a/app/assets/javascripts/project_new.js b/app/assets/javascripts/project_new.js index fd89a1a85c3..ca548d011b6 100644 --- a/app/assets/javascripts/project_new.js +++ b/app/assets/javascripts/project_new.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-unused-vars, one-var, no-underscore-dangle, prefer-template, no-else-return, prefer-arrow-callback, max-len */ +/* eslint-disable func-names, no-var, no-underscore-dangle, prefer-template, prefer-arrow-callback*/ import VisibilitySelect from './visibility_select'; @@ -7,153 +7,145 @@ function highlightChanges($elm) { setTimeout(() => $elm.removeClass('highlight-changes'), 10); } -(function() { - this.ProjectNew = (function() { - function ProjectNew() { - this.toggleSettings = this.toggleSettings.bind(this); - this.$selects = $('.features select'); - this.$repoSelects = this.$selects.filter('.js-repo-select'); - this.$projectSelects = this.$selects.not('.js-repo-select'); - - $('.project-edit-container').on('ajax:before', (function(_this) { - return function() { - $('.project-edit-container').hide(); - return $('.save-project-loader').show(); - }; - })(this)); - - this.initVisibilitySelect(); - - this.toggleSettings(); - this.toggleSettingsOnclick(); - this.toggleRepoVisibility(); - } - - ProjectNew.prototype.initVisibilitySelect = function() { - const visibilityContainer = document.querySelector('.js-visibility-select'); - if (!visibilityContainer) return; - const visibilitySelect = new VisibilitySelect(visibilityContainer); - visibilitySelect.init(); - - const $visibilitySelect = $(visibilityContainer).find('select'); - let projectVisibility = $visibilitySelect.val(); - const PROJECT_VISIBILITY_PRIVATE = '0'; - - $visibilitySelect.on('change', () => { - const newProjectVisibility = $visibilitySelect.val(); - - if (projectVisibility !== newProjectVisibility) { - this.$projectSelects.each((idx, select) => { - const $select = $(select); - const $options = $select.find('option'); - const values = $.map($options, e => e.value); - - // if switched to "private", limit visibility options - if (newProjectVisibility === PROJECT_VISIBILITY_PRIVATE) { - if ($select.val() !== values[0] && $select.val() !== values[1]) { - $select.val(values[1]).trigger('change'); - highlightChanges($select); - } - $options.slice(2).disable(); +export default class ProjectNew { + constructor() { + this.toggleSettings = this.toggleSettings.bind(this); + this.$selects = $('.features select'); + this.$repoSelects = this.$selects.filter('.js-repo-select'); + this.$projectSelects = this.$selects.not('.js-repo-select'); + + $('.project-edit-container').on('ajax:before', () => { + $('.project-edit-container').hide(); + return $('.save-project-loader').show(); + }); + + this.initVisibilitySelect(); + + this.toggleSettings(); + this.toggleSettingsOnclick(); + this.toggleRepoVisibility(); + } + + initVisibilitySelect() { + const visibilityContainer = document.querySelector('.js-visibility-select'); + if (!visibilityContainer) return; + const visibilitySelect = new VisibilitySelect(visibilityContainer); + visibilitySelect.init(); + + const $visibilitySelect = $(visibilityContainer).find('select'); + let projectVisibility = $visibilitySelect.val(); + const PROJECT_VISIBILITY_PRIVATE = '0'; + + $visibilitySelect.on('change', () => { + const newProjectVisibility = $visibilitySelect.val(); + + if (projectVisibility !== newProjectVisibility) { + this.$projectSelects.each((idx, select) => { + const $select = $(select); + const $options = $select.find('option'); + const values = $.map($options, e => e.value); + + // if switched to "private", limit visibility options + if (newProjectVisibility === PROJECT_VISIBILITY_PRIVATE) { + if ($select.val() !== values[0] && $select.val() !== values[1]) { + $select.val(values[1]).trigger('change'); + highlightChanges($select); } + $options.slice(2).disable(); + } - // if switched from "private", increase visibility for non-disabled options - if (projectVisibility === PROJECT_VISIBILITY_PRIVATE) { - $options.enable(); - if ($select.val() !== values[0] && $select.val() !== values[values.length - 1]) { - $select.val(values[values.length - 1]).trigger('change'); - highlightChanges($select); - } + // if switched from "private", increase visibility for non-disabled options + if (projectVisibility === PROJECT_VISIBILITY_PRIVATE) { + $options.enable(); + if ($select.val() !== values[0] && $select.val() !== values[values.length - 1]) { + $select.val(values[values.length - 1]).trigger('change'); + highlightChanges($select); } - }); + } + }); - projectVisibility = newProjectVisibility; - } - }); - }; - - ProjectNew.prototype.toggleSettings = function() { - var self = this; - - this.$selects.each(function () { - var $select = $(this); - var className = $select.data('field') - .replace(/_/g, '-') - .replace('access-level', 'feature'); - self._showOrHide($select, '.' + className); - }); - }; - - ProjectNew.prototype.toggleSettingsOnclick = function() { - this.$selects.on('change', this.toggleSettings); - }; - - ProjectNew.prototype._showOrHide = function(checkElement, container) { - var $container = $(container); - - if ($(checkElement).val() !== '0') { - return $container.show(); - } else { - return $container.hide(); + projectVisibility = newProjectVisibility; } - }; - - ProjectNew.prototype.toggleRepoVisibility = function () { - var $repoAccessLevel = $('.js-repo-access-level select'); - var $lfsEnabledOption = $('.js-lfs-enabled select'); - var containerRegistry = document.querySelectorAll('.js-container-registry')[0]; - var containerRegistryCheckbox = document.getElementById('project_container_registry_enabled'); - var prevSelectedVal = parseInt($repoAccessLevel.val(), 10); - - this.$repoSelects.find("option[value='" + $repoAccessLevel.val() + "']") - .nextAll() - .hide(); - - $repoAccessLevel.off('change') - .on('change', function () { - var selectedVal = parseInt($repoAccessLevel.val(), 10); - - this.$repoSelects.each(function () { - var $this = $(this); - var repoSelectVal = parseInt($this.val(), 10); - - $this.find('option').enable(); - - if (selectedVal < repoSelectVal || repoSelectVal === prevSelectedVal) { - $this.val(selectedVal).trigger('change'); - highlightChanges($this); - } - - $this.find("option[value='" + selectedVal + "']").nextAll().disable(); - }); + }); + } + + toggleSettings() { + this.$selects.each(function () { + var $select = $(this); + var className = $select.data('field') + .replace(/_/g, '-') + .replace('access-level', 'feature'); + ProjectNew._showOrHide($select, '.' + className); + }); + } + + toggleSettingsOnclick() { + this.$selects.on('change', this.toggleSettings); + } + + static _showOrHide(checkElement, container) { + const $container = $(container); + + if ($(checkElement).val() !== '0') { + return $container.show(); + } + return $container.hide(); + } + + toggleRepoVisibility() { + var $repoAccessLevel = $('.js-repo-access-level select'); + var $lfsEnabledOption = $('.js-lfs-enabled select'); + var containerRegistry = document.querySelectorAll('.js-container-registry')[0]; + var containerRegistryCheckbox = document.getElementById('project_container_registry_enabled'); + var prevSelectedVal = parseInt($repoAccessLevel.val(), 10); + + this.$repoSelects.find("option[value='" + $repoAccessLevel.val() + "']") + .nextAll() + .hide(); + + $repoAccessLevel + .off('change') + .on('change', function () { + var selectedVal = parseInt($repoAccessLevel.val(), 10); + + this.$repoSelects.each(function () { + var $this = $(this); + var repoSelectVal = parseInt($this.val(), 10); + + $this.find('option').enable(); + + if (selectedVal < repoSelectVal || repoSelectVal === prevSelectedVal) { + $this.val(selectedVal).trigger('change'); + highlightChanges($this); + } - if (selectedVal) { - this.$repoSelects.removeClass('disabled'); + $this.find("option[value='" + selectedVal + "']").nextAll().disable(); + }); - if ($lfsEnabledOption.length) { - $lfsEnabledOption.removeClass('disabled'); - highlightChanges($lfsEnabledOption); - } - if (containerRegistry) { - containerRegistry.style.display = ''; - } - } else { - this.$repoSelects.addClass('disabled'); + if (selectedVal) { + this.$repoSelects.removeClass('disabled'); - if ($lfsEnabledOption.length) { - $lfsEnabledOption.val('false').addClass('disabled'); - highlightChanges($lfsEnabledOption); - } - if (containerRegistry) { - containerRegistry.style.display = 'none'; - containerRegistryCheckbox.checked = false; - } + if ($lfsEnabledOption.length) { + $lfsEnabledOption.removeClass('disabled'); + highlightChanges($lfsEnabledOption); + } + if (containerRegistry) { + containerRegistry.style.display = ''; } + } else { + this.$repoSelects.addClass('disabled'); - prevSelectedVal = selectedVal; - }.bind(this)); - }; + if ($lfsEnabledOption.length) { + $lfsEnabledOption.val('false').addClass('disabled'); + highlightChanges($lfsEnabledOption); + } + if (containerRegistry) { + containerRegistry.style.display = 'none'; + containerRegistryCheckbox.checked = false; + } + } - return ProjectNew; - })(); -}).call(window); + prevSelectedVal = selectedVal; + }.bind(this)); + } +} diff --git a/app/assets/javascripts/project_select.js b/app/assets/javascripts/project_select.js index bffc85e6315..07a49d1506c 100644 --- a/app/assets/javascripts/project_select.js +++ b/app/assets/javascripts/project_select.js @@ -2,79 +2,73 @@ import Api from './api'; import ProjectSelectComboButton from './project_select_combo_button'; -(function () { - this.ProjectSelect = (function () { - function ProjectSelect() { - $('.ajax-project-select').each(function(i, select) { - var placeholder; - const simpleFilter = $(select).data('simple-filter') || false; - this.groupId = $(select).data('group-id'); - this.includeGroups = $(select).data('include-groups'); - this.allProjects = $(select).data('all-projects') || false; - this.orderBy = $(select).data('order-by') || 'id'; - this.withIssuesEnabled = $(select).data('with-issues-enabled'); - this.withMergeRequestsEnabled = $(select).data('with-merge-requests-enabled'); +export default function projectSelect() { + $('.ajax-project-select').each(function(i, select) { + var placeholder; + const simpleFilter = $(select).data('simple-filter') || false; + this.groupId = $(select).data('group-id'); + this.includeGroups = $(select).data('include-groups'); + this.allProjects = $(select).data('all-projects') || false; + this.orderBy = $(select).data('order-by') || 'id'; + this.withIssuesEnabled = $(select).data('with-issues-enabled'); + this.withMergeRequestsEnabled = $(select).data('with-merge-requests-enabled'); - placeholder = "Search for project"; - if (this.includeGroups) { - placeholder += " or group"; - } + placeholder = "Search for project"; + if (this.includeGroups) { + placeholder += " or group"; + } - $(select).select2({ - placeholder: placeholder, - minimumInputLength: 0, - query: (function (_this) { - return function (query) { - var finalCallback, projectsCallback; - finalCallback = function (projects) { + $(select).select2({ + placeholder: placeholder, + minimumInputLength: 0, + query: (function (_this) { + return function (query) { + var finalCallback, projectsCallback; + finalCallback = function (projects) { + var data; + data = { + results: projects + }; + return query.callback(data); + }; + if (_this.includeGroups) { + projectsCallback = function (projects) { + var groupsCallback; + groupsCallback = function (groups) { var data; - data = { - results: projects - }; - return query.callback(data); + data = groups.concat(projects); + return finalCallback(data); }; - if (_this.includeGroups) { - projectsCallback = function (projects) { - var groupsCallback; - groupsCallback = function (groups) { - var data; - data = groups.concat(projects); - return finalCallback(data); - }; - return Api.groups(query.term, {}, groupsCallback); - }; - } else { - projectsCallback = finalCallback; - } - if (_this.groupId) { - return Api.groupProjects(_this.groupId, query.term, projectsCallback); - } else { - return Api.projects(query.term, { - order_by: _this.orderBy, - with_issues_enabled: _this.withIssuesEnabled, - with_merge_requests_enabled: _this.withMergeRequestsEnabled, - membership: !_this.allProjects, - }, projectsCallback); - } + return Api.groups(query.term, {}, groupsCallback); }; - })(this), - id: function(project) { - if (simpleFilter) return project.id; - return JSON.stringify({ - name: project.name, - url: project.web_url, - }); - }, - text: function (project) { - return project.name_with_namespace || project.name; - }, - dropdownCssClass: "ajax-project-dropdown" + } else { + projectsCallback = finalCallback; + } + if (_this.groupId) { + return Api.groupProjects(_this.groupId, query.term, projectsCallback); + } else { + return Api.projects(query.term, { + order_by: _this.orderBy, + with_issues_enabled: _this.withIssuesEnabled, + with_merge_requests_enabled: _this.withMergeRequestsEnabled, + membership: !_this.allProjects, + }, projectsCallback); + } + }; + })(this), + id: function(project) { + if (simpleFilter) return project.id; + return JSON.stringify({ + name: project.name, + url: project.web_url, }); - if (simpleFilter) return select; - return new ProjectSelectComboButton(select); - }); - } - - return ProjectSelect; - })(); -}).call(window); + }, + text: function (project) { + return project.name_with_namespace || project.name; + }, + dropdownCssClass: "ajax-project-dropdown" + }); + if (simpleFilter) return select; + return new ProjectSelectComboButton(select); + }); +} diff --git a/app/assets/javascripts/project_show.js b/app/assets/javascripts/project_show.js deleted file mode 100644 index 3a51c1f26ac..00000000000 --- a/app/assets/javascripts/project_show.js +++ /dev/null @@ -1,11 +0,0 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife */ - -(function() { - this.ProjectShow = (function() { - function ProjectShow() {} - - return ProjectShow; - })(); -}).call(window); - -// I kept class for future diff --git a/app/assets/javascripts/project_variables.js b/app/assets/javascripts/project_variables.js index 4ee2e49306d..567c311f119 100644 --- a/app/assets/javascripts/project_variables.js +++ b/app/assets/javascripts/project_variables.js @@ -1,43 +1,39 @@ -(() => { - const HIDDEN_VALUE_TEXT = '******'; - class ProjectVariables { - constructor() { - this.$revealBtn = $('.js-btn-toggle-reveal-values'); - this.$revealBtn.on('click', this.toggleRevealState.bind(this)); - } +const HIDDEN_VALUE_TEXT = '******'; + +export default class ProjectVariables { + constructor() { + this.$revealBtn = $('.js-btn-toggle-reveal-values'); + this.$revealBtn.on('click', this.toggleRevealState.bind(this)); + } - toggleRevealState(e) { - e.preventDefault(); + toggleRevealState(e) { + e.preventDefault(); - const oldStatus = this.$revealBtn.attr('data-status'); - let newStatus = 'hidden'; - let newAction = 'Reveal Values'; + const oldStatus = this.$revealBtn.attr('data-status'); + let newStatus = 'hidden'; + let newAction = 'Reveal Values'; - if (oldStatus === 'hidden') { - newStatus = 'revealed'; - newAction = 'Hide Values'; - } + if (oldStatus === 'hidden') { + newStatus = 'revealed'; + newAction = 'Hide Values'; + } - this.$revealBtn.attr('data-status', newStatus); + this.$revealBtn.attr('data-status', newStatus); - const $variables = $('.variable-value'); + const $variables = $('.variable-value'); - $variables.each((_, variable) => { - const $variable = $(variable); - let newText = HIDDEN_VALUE_TEXT; + $variables.each((_, variable) => { + const $variable = $(variable); + let newText = HIDDEN_VALUE_TEXT; - if (newStatus === 'revealed') { - newText = $variable.attr('data-value'); - } + if (newStatus === 'revealed') { + newText = $variable.attr('data-value'); + } - $variable.text(newText); - }); + $variable.text(newText); + }); - this.$revealBtn.text(newAction); - } + this.$revealBtn.text(newAction); } - - window.gl = window.gl || {}; - window.gl.ProjectVariables = ProjectVariables; -})(); +} diff --git a/app/assets/javascripts/projects/permissions/components/project_feature_setting.vue b/app/assets/javascripts/projects/permissions/components/project_feature_setting.vue index 80c5d39f736..8fce4c63872 100644 --- a/app/assets/javascripts/projects/permissions/components/project_feature_setting.vue +++ b/app/assets/javascripts/projects/permissions/components/project_feature_setting.vue @@ -1,5 +1,5 @@ <script> -import projectFeatureToggle from './project_feature_toggle.vue'; +import projectFeatureToggle from '../../../vue_shared/components/toggle_button.vue'; export default { props: { diff --git a/app/assets/javascripts/projects/permissions/components/project_feature_toggle.vue b/app/assets/javascripts/projects/permissions/components/project_feature_toggle.vue deleted file mode 100644 index 2403c60186a..00000000000 --- a/app/assets/javascripts/projects/permissions/components/project_feature_toggle.vue +++ /dev/null @@ -1,51 +0,0 @@ -<script> -export default { - props: { - name: { - type: String, - required: false, - default: '', - }, - value: { - type: Boolean, - required: true, - }, - disabledInput: { - type: Boolean, - required: false, - default: false, - }, - }, - - model: { - prop: 'value', - event: 'change', - }, - - methods: { - toggleFeature() { - if (!this.disabledInput) this.$emit('change', !this.value); - }, - }, -}; -</script> - -<template> - <label class="toggle-wrapper"> - <input - v-if="name" - type="hidden" - :name="name" - :value="value" - /> - <button - type="button" - aria-label="Toggle" - class="project-feature-toggle" - data-enabled-text="Enabled" - data-disabled-text="Disabled" - :class="{ checked: value, disabled: disabledInput }" - @click="toggleFeature" - /> - </label> -</template> diff --git a/app/assets/javascripts/projects/permissions/components/settings_panel.vue b/app/assets/javascripts/projects/permissions/components/settings_panel.vue index 326d9105666..639429baf26 100644 --- a/app/assets/javascripts/projects/permissions/components/settings_panel.vue +++ b/app/assets/javascripts/projects/permissions/components/settings_panel.vue @@ -1,6 +1,6 @@ <script> import projectFeatureSetting from './project_feature_setting.vue'; -import projectFeatureToggle from './project_feature_toggle.vue'; +import projectFeatureToggle from '../../../vue_shared/components/toggle_button.vue'; import projectSettingRow from './project_setting_row.vue'; import { visibilityOptions, visibilityLevelDescriptions } from '../constants'; import { toggleHiddenClassBySelector } from '../external'; diff --git a/app/assets/javascripts/projects_dropdown/components/projects_list_item.vue b/app/assets/javascripts/projects_dropdown/components/projects_list_item.vue index fe5179de206..d482a7025de 100644 --- a/app/assets/javascripts/projects_dropdown/components/projects_list_item.vue +++ b/app/assets/javascripts/projects_dropdown/components/projects_list_item.vue @@ -48,6 +48,27 @@ export default { } return this.projectName; }, + /** + * Smartly truncates project namespace by doing two things; + * 1. Only include Group names in path by removing project name + * 2. Only include first and last group names in the path + * when namespace has more than 2 groups present + * + * First part (removal of project name from namespace) can be + * done from backend but doing so involves migration of + * existing project namespaces which is not wise thing to do. + */ + truncatedNamespace() { + const namespaceArr = this.namespace.split(' / '); + namespaceArr.splice(-1, 1); + let namespace = namespaceArr.join(' / '); + + if (namespaceArr.length > 2) { + namespace = `${namespaceArr[0]} / ... / ${namespaceArr.pop()}`; + } + + return namespace; + }, }, }; </script> @@ -87,9 +108,7 @@ export default { <div class="project-namespace" :title="namespace" - > - {{namespace}} - </div> + >{{truncatedNamespace}}</div> </div> </a> </li> diff --git a/app/assets/javascripts/registry/components/table_registry.vue b/app/assets/javascripts/registry/components/table_registry.vue index e917279947e..14d43e135fe 100644 --- a/app/assets/javascripts/registry/components/table_registry.vue +++ b/app/assets/javascripts/registry/components/table_registry.vue @@ -8,6 +8,7 @@ import tooltip from '../../vue_shared/directives/tooltip'; import timeagoMixin from '../../vue_shared/mixins/timeago'; import { errorMessages, errorMessagesTypes } from '../constants'; + import { numberToHumanSize } from '../../lib/utils/number_utils'; export default { props: { @@ -41,6 +42,10 @@ return item.layers ? n__('%d layer', '%d layers', item.layers) : ''; }, + formatSize(size) { + return numberToHumanSize(size); + }, + handleDeleteRegistry(registry) { this.deleteRegistry(registry) .then(() => this.fetchList({ repo: this.repo })) @@ -97,7 +102,7 @@ </span> </td> <td> - {{item.size}} + {{formatSize(item.size)}} <template v-if="item.size && item.layers"> · </template> diff --git a/app/assets/javascripts/render_gfm.js b/app/assets/javascripts/render_gfm.js index bcdc0fd67b8..c91a0d9ba41 100644 --- a/app/assets/javascripts/render_gfm.js +++ b/app/assets/javascripts/render_gfm.js @@ -1,15 +1,15 @@ -/* eslint-disable func-names, space-before-function-paren, consistent-return, no-var, no-else-return, prefer-arrow-callback, max-len */ +import renderMath from './render_math'; +import renderMermaid from './render_mermaid'; // Render Gitlab flavoured Markdown // -// Delegates to syntax highlight and render math +// Delegates to syntax highlight and render math & mermaid diagrams. // -(function() { - $.fn.renderGFM = function() { - this.find('.js-syntax-highlight').syntaxHighlight(); - this.find('.js-render-math').renderMath(); - return this; - }; +$.fn.renderGFM = function renderGFM() { + this.find('.js-syntax-highlight').syntaxHighlight(); + renderMath(this.find('.js-render-math')); + renderMermaid(this.find('.js-render-mermaid')); + return this; +}; - $(() => $('body').renderGFM()); -}).call(window); +$(() => $('body').renderGFM()); diff --git a/app/assets/javascripts/render_math.js b/app/assets/javascripts/render_math.js index 8b3fee49cb9..a759992cd54 100644 --- a/app/assets/javascripts/render_math.js +++ b/app/assets/javascripts/render_math.js @@ -1,4 +1,3 @@ -/* eslint-disable func-names, space-before-function-paren, consistent-return, no-var, no-else-return, prefer-arrow-callback, max-len, no-console */ /* global katex */ // Renders math using KaTeX in any element with the @@ -8,49 +7,45 @@ // // <code class="js-render-math"></div> // -(function() { // Only load once - var katexLoaded = false; +let katexLoaded = false; - // Loop over all math elements and render math - var renderWithKaTeX = function (elements) { - elements.each(function () { - var mathNode = $('<span></span>'); - var $this = $(this); +// Loop over all math elements and render math +function renderWithKaTeX(elements) { + elements.each(function katexElementsLoop() { + const mathNode = $('<span></span>'); + const $this = $(this); - var display = $this.attr('data-math-style') === 'display'; - try { - katex.render($this.text(), mathNode.get(0), { displayMode: display }); - mathNode.insertAfter($this); - $this.remove(); - } catch (err) { - // What can we do?? - console.log(err.message); - } - }); - }; + const display = $this.attr('data-math-style') === 'display'; + try { + katex.render($this.text(), mathNode.get(0), { displayMode: display }); + mathNode.insertAfter($this); + $this.remove(); + } catch (err) { + throw err; + } + }); +} - $.fn.renderMath = function() { - var $this = this; - if ($this.length === 0) return; +export default function renderMath($els) { + if (!$els.length) return; - if (katexLoaded) renderWithKaTeX($this); - else { - // Request CSS file so it is in the cache - $.get(gon.katex_css_url, function() { - var css = $('<link>', - { rel: 'stylesheet', - type: 'text/css', - href: gon.katex_css_url, - }); - css.appendTo('head'); + if (katexLoaded) { + renderWithKaTeX($els); + } else { + $.get(gon.katex_css_url, () => { + const css = $('<link>', { + rel: 'stylesheet', + type: 'text/css', + href: gon.katex_css_url, + }); + css.appendTo('head'); - // Load KaTeX js - $.getScript(gon.katex_js_url, function() { - katexLoaded = true; - renderWithKaTeX($this); // Run KaTeX - }); + // Load KaTeX js + $.getScript(gon.katex_js_url, () => { + katexLoaded = true; + renderWithKaTeX($els); // Run KaTeX }); - } - }; -}).call(window); + }); + } +} diff --git a/app/assets/javascripts/render_mermaid.js b/app/assets/javascripts/render_mermaid.js new file mode 100644 index 00000000000..41942c04a4e --- /dev/null +++ b/app/assets/javascripts/render_mermaid.js @@ -0,0 +1,32 @@ +// Renders diagrams and flowcharts from text using Mermaid in any element with the +// `js-render-mermaid` class. +// +// Example markup: +// +// <pre class="js-render-mermaid"> +// graph TD; +// A-- > B; +// A-- > C; +// B-- > D; +// C-- > D; +// </pre> +// + +import Flash from './flash'; + +export default function renderMermaid($els) { + if (!$els.length) return; + + import(/* webpackChunkName: 'mermaid' */ 'blackst0ne-mermaid').then((mermaid) => { + mermaid.initialize({ + loadOnStart: false, + theme: 'neutral', + }); + + $els.each((i, el) => { + mermaid.init(undefined, el); + }); + }).catch((err) => { + Flash(`Can't load mermaid module: ${err}`); + }); +} diff --git a/app/assets/javascripts/repo/components/commit_sidebar/list.vue b/app/assets/javascripts/repo/components/commit_sidebar/list.vue new file mode 100644 index 00000000000..fb862e7bf01 --- /dev/null +++ b/app/assets/javascripts/repo/components/commit_sidebar/list.vue @@ -0,0 +1,89 @@ +<script> + import icon from '../../../vue_shared/components/icon.vue'; + import listItem from './list_item.vue'; + import listCollapsed from './list_collapsed.vue'; + + export default { + components: { + icon, + listItem, + listCollapsed, + }, + props: { + title: { + type: String, + required: true, + }, + fileList: { + type: Array, + required: true, + }, + collapsed: { + type: Boolean, + required: true, + }, + }, + methods: { + toggleCollapsed() { + this.$emit('toggleCollapsed'); + }, + }, + }; +</script> + +<template> + <div class="multi-file-commit-panel-section"> + <header + class="multi-file-commit-panel-header" + :class="{ + 'is-collapsed': collapsed, + }" + > + <icon + name="list-bulleted" + :size="18" + css-classes="append-right-default" + /> + <template v-if="!collapsed"> + {{ title }} + <button + type="button" + class="btn btn-transparent multi-file-commit-panel-collapse-btn" + @click="toggleCollapsed" + > + <i + aria-hidden="true" + class="fa fa-angle-double-right" + > + </i> + </button> + </template> + </header> + <div class="multi-file-commit-list"> + <list-collapsed + v-if="collapsed" + /> + <template v-else> + <ul + v-if="fileList.length" + class="list-unstyled append-bottom-0" + > + <li + v-for="file in fileList" + :key="file.key" + > + <list-item + :file="file" + /> + </li> + </ul> + <div + v-else + class="help-block prepend-top-0" + > + No changes + </div> + </template> + </div> + </div> +</template> diff --git a/app/assets/javascripts/repo/components/commit_sidebar/list_collapsed.vue b/app/assets/javascripts/repo/components/commit_sidebar/list_collapsed.vue new file mode 100644 index 00000000000..6a0262f271b --- /dev/null +++ b/app/assets/javascripts/repo/components/commit_sidebar/list_collapsed.vue @@ -0,0 +1,35 @@ +<script> + import { mapGetters } from 'vuex'; + import icon from '../../../vue_shared/components/icon.vue'; + + export default { + components: { + icon, + }, + computed: { + ...mapGetters([ + 'addedFiles', + 'modifiedFiles', + ]), + }, + }; +</script> + +<template> + <div + class="multi-file-commit-list-collapsed text-center" + > + <icon + name="file-addition" + :size="18" + css-classes="multi-file-addition append-bottom-10" + /> + {{ addedFiles.length }} + <icon + name="file-modified" + :size="18" + css-classes="multi-file-modified prepend-top-10 append-bottom-10" + /> + {{ modifiedFiles.length }} + </div> +</template> diff --git a/app/assets/javascripts/repo/components/commit_sidebar/list_item.vue b/app/assets/javascripts/repo/components/commit_sidebar/list_item.vue new file mode 100644 index 00000000000..742f746e02f --- /dev/null +++ b/app/assets/javascripts/repo/components/commit_sidebar/list_item.vue @@ -0,0 +1,36 @@ +<script> + import icon from '../../../vue_shared/components/icon.vue'; + + export default { + components: { + icon, + }, + props: { + file: { + type: Object, + required: true, + }, + }, + computed: { + iconName() { + return this.file.tempFile ? 'file-addition' : 'file-modified'; + }, + iconClass() { + return `multi-file-${this.file.tempFile ? 'addition' : 'modified'} append-right-8`; + }, + }, + }; +</script> + +<template> + <div class="multi-file-commit-list-item"> + <icon + :name="iconName" + :size="16" + :css-classes="iconClass" + /> + <span class="multi-file-commit-list-path"> + {{ file.path }} + </span> + </div> +</template> diff --git a/app/assets/javascripts/repo/components/new_dropdown/index.vue b/app/assets/javascripts/repo/components/new_dropdown/index.vue index a5ee4f71281..781404cf8ca 100644 --- a/app/assets/javascripts/repo/components/new_dropdown/index.vue +++ b/app/assets/javascripts/repo/components/new_dropdown/index.vue @@ -2,9 +2,11 @@ import { mapState } from 'vuex'; import newModal from './modal.vue'; import upload from './upload.vue'; + import icon from '../../../vue_shared/components/icon.vue'; export default { components: { + icon, newModal, upload, }, @@ -41,11 +43,14 @@ data-toggle="dropdown" aria-label="Create new file or directory" > - <i - class="fa fa-plus" - aria-hidden="true" - > - </i> + <icon + name="plus" + css-classes="pull-left" + /> + <icon + name="arrow-down" + css-classes="pull-left" + /> </button> <ul class="dropdown-menu"> <li> diff --git a/app/assets/javascripts/repo/components/repo.vue b/app/assets/javascripts/repo/components/repo.vue index 98117802016..a00e1e9d809 100644 --- a/app/assets/javascripts/repo/components/repo.vue +++ b/app/assets/javascripts/repo/components/repo.vue @@ -40,20 +40,24 @@ export default { </script> <template> - <div class="repository-view"> - <div class="tree-content-holder" :class="{'tree-content-holder-mini' : isCollapsed}"> - <repo-sidebar/> - <div - v-if="isCollapsed" - class="panel-right" - > - <repo-tabs/> - <component - :is="currentBlobView" - /> - <repo-file-buttons/> - </div> + <div + class="multi-file" + :class="{ + 'is-collapsed': isCollapsed + }" + > + <repo-sidebar/> + <div + v-if="isCollapsed" + class="multi-file-edit-pane" + > + <repo-tabs /> + <component + class="multi-file-edit-pane-content" + :is="currentBlobView" + /> + <repo-file-buttons /> </div> - <repo-commit-section v-if="changedFiles.length" /> + <repo-commit-section /> </div> </template> diff --git a/app/assets/javascripts/repo/components/repo_commit_section.vue b/app/assets/javascripts/repo/components/repo_commit_section.vue index 377e3d65348..d3344d0c8dc 100644 --- a/app/assets/javascripts/repo/components/repo_commit_section.vue +++ b/app/assets/javascripts/repo/components/repo_commit_section.vue @@ -1,11 +1,18 @@ <script> import { mapGetters, mapState, mapActions } from 'vuex'; +import tooltip from '../../vue_shared/directives/tooltip'; +import icon from '../../vue_shared/components/icon.vue'; import PopupDialog from '../../vue_shared/components/popup_dialog.vue'; -import { n__ } from '../../locale'; +import commitFilesList from './commit_sidebar/list.vue'; export default { components: { PopupDialog, + icon, + commitFilesList, + }, + directives: { + tooltip, }, data() { return { @@ -13,6 +20,7 @@ export default { submitCommitsLoading: false, startNewMR: false, commitMessage: '', + collapsed: true, }; }, computed: { @@ -23,10 +31,10 @@ export default { 'changedFiles', ]), commitButtonDisabled() { - return !this.commitMessage || this.submitCommitsLoading; + return this.commitMessage === '' || this.submitCommitsLoading || !this.changedFiles.length; }, - commitButtonText() { - return n__('Commit %d file', 'Commit %d files', this.changedFiles.length); + commitMessageCount() { + return this.commitMessage.length; }, }, methods: { @@ -77,12 +85,20 @@ export default { this.submitCommitsLoading = false; }); }, + toggleCollapsed() { + this.collapsed = !this.collapsed; + }, }, }; </script> <template> -<div id="commit-area"> +<div + class="multi-file-commit-panel" + :class="{ + 'is-collapsed': collapsed, + }" +> <popup-dialog v-if="showNewBranchDialog" :primary-button-label="__('Create new branch')" @@ -92,78 +108,71 @@ export default { @toggle="showNewBranchDialog = false" @submit="makeCommit(true)" /> + <button + v-if="collapsed" + type="button" + class="btn btn-transparent multi-file-commit-panel-collapse-btn is-collapsed prepend-top-10 append-bottom-10" + @click="toggleCollapsed" + > + <i + aria-hidden="true" + class="fa fa-angle-double-left" + > + </i> + </button> + <commit-files-list + title="Staged" + :file-list="changedFiles" + :collapsed="collapsed" + @toggleCollapsed="toggleCollapsed" + /> <form - class="form-horizontal" - @submit.prevent="tryCommit()"> - <fieldset> - <div class="form-group"> - <label class="col-md-4 control-label staged-files"> - Staged files ({{changedFiles.length}}) - </label> - <div class="col-md-6"> - <ul class="list-unstyled changed-files"> - <li - v-for="(file, index) in changedFiles" - :key="index"> - <span class="help-block"> - {{ file.path }} - </span> - </li> - </ul> - </div> - </div> - <div class="form-group"> - <label - class="col-md-4 control-label" - for="commit-message"> - Commit message - </label> - <div class="col-md-6"> - <textarea - id="commit-message" - class="form-control" - name="commit-message" - v-model="commitMessage"> - </textarea> - </div> - </div> - <div class="form-group target-branch"> - <label - class="col-md-4 control-label" - for="target-branch"> - Target branch - </label> - <div class="col-md-6"> - <span class="help-block"> - {{currentBranch}} - </span> - </div> - </div> - <div class="col-md-offset-4 col-md-6"> - <button - type="submit" - :disabled="commitButtonDisabled" - class="btn btn-success"> - <i - v-if="submitCommitsLoading" - class="js-commit-loading-icon fa fa-spinner fa-spin" - aria-hidden="true" - aria-label="loading"> - </i> - <span class="commit-summary"> - {{ commitButtonText }} - </span> - </button> - </div> - <div class="col-md-offset-4 col-md-6"> - <div class="checkbox"> - <label> - <input type="checkbox" v-model="startNewMR"> - <span>Start a <strong>new merge request</strong> with these changes</span> - </label> - </div> + class="form-horizontal multi-file-commit-form" + @submit.prevent="tryCommit" + v-if="!collapsed" + > + <div class="multi-file-commit-fieldset"> + <textarea + class="form-control multi-file-commit-message" + name="commit-message" + v-model="commitMessage" + placeholder="Commit message" + > + </textarea> + </div> + <div class="multi-file-commit-fieldset"> + <label + v-tooltip + title="Create a new merge request with these changes" + data-container="body" + data-placement="top" + > + <input + type="checkbox" + v-model="startNewMR" + /> + Merge Request + </label> + <button + type="submit" + :disabled="commitButtonDisabled" + class="btn btn-default btn-sm append-right-10 prepend-left-10" + > + <i + v-if="submitCommitsLoading" + class="js-commit-loading-icon fa fa-spinner fa-spin" + aria-hidden="true" + aria-label="loading" + > + </i> + Commit + </button> + <div + class="multi-file-commit-message-count" + > + {{ commitMessageCount }} </div> - </fieldset> + </div> </form> </div> </template> diff --git a/app/assets/javascripts/repo/components/repo_editor.vue b/app/assets/javascripts/repo/components/repo_editor.vue index 1c864b176b1..f37cbd1e961 100644 --- a/app/assets/javascripts/repo/components/repo_editor.vue +++ b/app/assets/javascripts/repo/components/repo_editor.vue @@ -3,19 +3,18 @@ import { mapGetters, mapActions } from 'vuex'; import flash from '../../flash'; import monacoLoader from '../monaco_loader'; +import Editor from '../lib/editor'; export default { - destroyed() { - if (this.monacoInstance) { - this.monacoInstance.destroy(); - } + beforeDestroy() { + this.editor.dispose(); }, mounted() { - if (this.monaco) { + if (this.editor && monaco) { this.initMonaco(); } else { monacoLoader(['vs/editor/editor.main'], () => { - this.monaco = monaco; + this.editor = Editor.create(monaco); this.initMonaco(); }); @@ -29,47 +28,25 @@ export default { initMonaco() { if (this.shouldHideEditor) return; - if (this.monacoInstance) { - this.monacoInstance.setModel(null); - } + this.editor.clearEditor(); this.getRawFileData(this.activeFile) .then(() => { - if (!this.monacoInstance) { - this.monacoInstance = this.monaco.editor.create(this.$el, { - model: null, - readOnly: false, - contextmenu: true, - scrollBeyondLastLine: false, - }); - - this.languages = this.monaco.languages.getLanguages(); - - this.addMonacoEvents(); - } - - this.setupEditor(); + this.editor.createInstance(this.$refs.editor); }) + .then(() => this.setupEditor()) .catch(() => flash('Error setting up monaco. Please try again.')); }, setupEditor() { if (!this.activeFile) return; - const content = this.activeFile.content !== '' ? this.activeFile.content : this.activeFile.raw; - const foundLang = this.languages.find(lang => - lang.extensions && lang.extensions.indexOf(this.activeFileExtension) === 0, - ); - const newModel = this.monaco.editor.createModel( - content, foundLang ? foundLang.id : 'plaintext', - ); + const model = this.editor.createModel(this.activeFile); - this.monacoInstance.setModel(newModel); - }, - addMonacoEvents() { - this.monacoInstance.onKeyUp(() => { + this.editor.attachModel(model); + model.onChange((m) => { this.changeFileContent({ file: this.activeFile, - content: this.monacoInstance.getValue(), + content: m.getValue(), }); }); }, @@ -99,9 +76,14 @@ export default { class="blob-viewer-container blob-editor-container" > <div - v-if="shouldHideEditor" + v-show="shouldHideEditor" v-html="activeFile.html" > </div> + <div + v-show="!shouldHideEditor" + ref="editor" + > + </div> </div> </template> diff --git a/app/assets/javascripts/repo/components/repo_file.vue b/app/assets/javascripts/repo/components/repo_file.vue index 5be47d568e7..75787ad6103 100644 --- a/app/assets/javascripts/repo/components/repo_file.vue +++ b/app/assets/javascripts/repo/components/repo_file.vue @@ -55,7 +55,7 @@ class="file" @click.prevent="clickedTreeRow(file)"> <td - class="multi-file-table-col-name" + class="multi-file-table-name" :colspan="submoduleColSpan" > <i @@ -85,12 +85,11 @@ </td> <template v-if="!isCollapsed && !isSubmodule"> - <td class="hidden-sm hidden-xs"> + <td class="multi-file-table-col-commit-message hidden-sm hidden-xs"> <a v-if="file.lastCommit.message" @click.stop :href="file.lastCommit.url" - class="commit-message" > {{ file.lastCommit.message }} </a> diff --git a/app/assets/javascripts/repo/components/repo_file_buttons.vue b/app/assets/javascripts/repo/components/repo_file_buttons.vue index dd948ee84fb..34f0d51819a 100644 --- a/app/assets/javascripts/repo/components/repo_file_buttons.vue +++ b/app/assets/javascripts/repo/components/repo_file_buttons.vue @@ -22,12 +22,12 @@ export default { <template> <div v-if="showButtons" - class="repo-file-buttons" + class="multi-file-editor-btn-group" > <a :href="activeFile.rawPath" target="_blank" - class="btn btn-default raw" + class="btn btn-default btn-sm raw" rel="noopener noreferrer"> {{ rawDownloadButtonLabel }} </a> @@ -38,17 +38,17 @@ export default { aria-label="File actions"> <a :href="activeFile.blamePath" - class="btn btn-default blame"> + class="btn btn-default btn-sm blame"> Blame </a> <a :href="activeFile.commitsPath" - class="btn btn-default history"> + class="btn btn-default btn-sm history"> History </a> <a :href="activeFile.permalink" - class="btn btn-default permalink"> + class="btn btn-default btn-sm permalink"> Permalink </a> </div> diff --git a/app/assets/javascripts/repo/components/repo_preview.vue b/app/assets/javascripts/repo/components/repo_preview.vue index d1883299bd9..6ce9267f598 100644 --- a/app/assets/javascripts/repo/components/repo_preview.vue +++ b/app/assets/javascripts/repo/components/repo_preview.vue @@ -32,10 +32,12 @@ export default { </script> <template> -<div class="blob-viewer-container"> +<div> <div v-if="!activeFile.renderError" - v-html="activeFile.html"> + v-html="activeFile.html" + class="multi-file-preview-holder" + > </div> <div v-else-if="activeFile.tempFile" diff --git a/app/assets/javascripts/repo/components/repo_sidebar.vue b/app/assets/javascripts/repo/components/repo_sidebar.vue index 9365b09326f..4ea21913129 100644 --- a/app/assets/javascripts/repo/components/repo_sidebar.vue +++ b/app/assets/javascripts/repo/components/repo_sidebar.vue @@ -44,20 +44,16 @@ export default { </script> <template> -<div id="sidebar" :class="{'sidebar-mini' : isCollapsed}"> +<div class="ide-file-list"> <table class="table"> <thead> <tr> <th v-if="isCollapsed" - class="repo-file-options title" > - <strong class="clgray"> - {{ projectName }} - </strong> </th> <template v-else> - <th class="name multi-file-table-col-name"> + <th class="name multi-file-table-name"> Name </th> <th class="hidden-sm hidden-xs last-commit"> @@ -79,7 +75,7 @@ export default { :key="n" /> <repo-file - v-for="(file, index) in treeList" + v-for="file in treeList" :key="file.key" :file="file" /> diff --git a/app/assets/javascripts/repo/components/repo_tab.vue b/app/assets/javascripts/repo/components/repo_tab.vue index da0714c368c..fb29a60df66 100644 --- a/app/assets/javascripts/repo/components/repo_tab.vue +++ b/app/assets/javascripts/repo/components/repo_tab.vue @@ -36,27 +36,32 @@ export default { <template> <li - :class="{ active : tab.active }" @click="setFileActive(tab)" > <button type="button" - class="close-btn" + class="multi-file-tab-close" @click.stop.prevent="closeFile({ file: tab })" - :aria-label="closeLabel"> + :aria-label="closeLabel" + :class="{ + 'modified': tab.changed, + }" + :disabled="tab.changed" + > <i class="fa" :class="changedClass" - aria-hidden="true"> + aria-hidden="true" + > </i> </button> - <a - href="#" - class="repo-tab" + <div + class="multi-file-tab" + :class="{active : tab.active }" :title="tab.url" - @click.prevent.stop="setFileActive(tab)"> - {{tab.name}} - </a> + > + {{ tab.name }} + </div> </li> </template> diff --git a/app/assets/javascripts/repo/components/repo_tabs.vue b/app/assets/javascripts/repo/components/repo_tabs.vue index 59beae53e8d..ab0bef4f0ac 100644 --- a/app/assets/javascripts/repo/components/repo_tabs.vue +++ b/app/assets/javascripts/repo/components/repo_tabs.vue @@ -16,14 +16,12 @@ <template> <ul - id="tabs" - class="list-unstyled" + class="multi-file-tabs list-unstyled append-bottom-0" > <repo-tab v-for="tab in openFiles" :key="tab.id" :tab="tab" /> - <li class="tabs-divider" /> </ul> </template> diff --git a/app/assets/javascripts/repo/lib/common/disposable.js b/app/assets/javascripts/repo/lib/common/disposable.js new file mode 100644 index 00000000000..84b29bdb600 --- /dev/null +++ b/app/assets/javascripts/repo/lib/common/disposable.js @@ -0,0 +1,14 @@ +export default class Disposable { + constructor() { + this.disposers = new Set(); + } + + add(...disposers) { + disposers.forEach(disposer => this.disposers.add(disposer)); + } + + dispose() { + this.disposers.forEach(disposer => disposer.dispose()); + this.disposers.clear(); + } +} diff --git a/app/assets/javascripts/repo/lib/common/model.js b/app/assets/javascripts/repo/lib/common/model.js new file mode 100644 index 00000000000..23c4811e6c0 --- /dev/null +++ b/app/assets/javascripts/repo/lib/common/model.js @@ -0,0 +1,56 @@ +/* global monaco */ +import Disposable from './disposable'; + +export default class Model { + constructor(monaco, file) { + this.monaco = monaco; + this.disposable = new Disposable(); + this.file = file; + this.content = file.content !== '' ? file.content : file.raw; + + this.disposable.add( + this.originalModel = this.monaco.editor.createModel( + this.file.raw, + undefined, + new this.monaco.Uri(null, null, `original/${this.file.path}`), + ), + this.model = this.monaco.editor.createModel( + this.content, + undefined, + new this.monaco.Uri(null, null, this.file.path), + ), + ); + + this.events = new Map(); + } + + get url() { + return this.model.uri.toString(); + } + + get path() { + return this.file.path; + } + + getModel() { + return this.model; + } + + getOriginalModel() { + return this.originalModel; + } + + onChange(cb) { + this.events.set( + this.path, + this.disposable.add( + this.model.onDidChangeContent(e => cb(this.model, e)), + ), + ); + } + + dispose() { + this.disposable.dispose(); + this.events.clear(); + } +} diff --git a/app/assets/javascripts/repo/lib/common/model_manager.js b/app/assets/javascripts/repo/lib/common/model_manager.js new file mode 100644 index 00000000000..fd462252795 --- /dev/null +++ b/app/assets/javascripts/repo/lib/common/model_manager.js @@ -0,0 +1,32 @@ +import Disposable from './disposable'; +import Model from './model'; + +export default class ModelManager { + constructor(monaco) { + this.monaco = monaco; + this.disposable = new Disposable(); + this.models = new Map(); + } + + hasCachedModel(path) { + return this.models.has(path); + } + + addModel(file) { + if (this.hasCachedModel(file.path)) { + return this.models.get(file.path); + } + + const model = new Model(this.monaco, file); + this.models.set(model.path, model); + this.disposable.add(model); + + return model; + } + + dispose() { + // dispose of all the models + this.disposable.dispose(); + this.models.clear(); + } +} diff --git a/app/assets/javascripts/repo/lib/decorations/controller.js b/app/assets/javascripts/repo/lib/decorations/controller.js new file mode 100644 index 00000000000..0954b7973c4 --- /dev/null +++ b/app/assets/javascripts/repo/lib/decorations/controller.js @@ -0,0 +1,43 @@ +export default class DecorationsController { + constructor(editor) { + this.editor = editor; + this.decorations = new Map(); + this.editorDecorations = new Map(); + } + + getAllDecorationsForModel(model) { + if (!this.decorations.has(model.url)) return []; + + const modelDecorations = this.decorations.get(model.url); + const decorations = []; + + modelDecorations.forEach(val => decorations.push(...val)); + + return decorations; + } + + addDecorations(model, decorationsKey, decorations) { + const decorationMap = this.decorations.get(model.url) || new Map(); + + decorationMap.set(decorationsKey, decorations); + + this.decorations.set(model.url, decorationMap); + + this.decorate(model); + } + + decorate(model) { + const decorations = this.getAllDecorationsForModel(model); + const oldDecorations = this.editorDecorations.get(model.url) || []; + + this.editorDecorations.set( + model.url, + this.editor.instance.deltaDecorations(oldDecorations, decorations), + ); + } + + dispose() { + this.decorations.clear(); + this.editorDecorations.clear(); + } +} diff --git a/app/assets/javascripts/repo/lib/diff/controller.js b/app/assets/javascripts/repo/lib/diff/controller.js new file mode 100644 index 00000000000..dc0b1c95e59 --- /dev/null +++ b/app/assets/javascripts/repo/lib/diff/controller.js @@ -0,0 +1,71 @@ +/* global monaco */ +import { throttle } from 'underscore'; +import DirtyDiffWorker from './diff_worker'; +import Disposable from '../common/disposable'; + +export const getDiffChangeType = (change) => { + if (change.modified) { + return 'modified'; + } else if (change.added) { + return 'added'; + } else if (change.removed) { + return 'removed'; + } + + return ''; +}; + +export const getDecorator = change => ({ + range: new monaco.Range( + change.lineNumber, + 1, + change.endLineNumber, + 1, + ), + options: { + isWholeLine: true, + linesDecorationsClassName: `dirty-diff dirty-diff-${getDiffChangeType(change)}`, + }, +}); + +export default class DirtyDiffController { + constructor(modelManager, decorationsController) { + this.disposable = new Disposable(); + this.editorSimpleWorker = null; + this.modelManager = modelManager; + this.decorationsController = decorationsController; + this.dirtyDiffWorker = new DirtyDiffWorker(); + this.throttledComputeDiff = throttle(this.computeDiff, 250); + this.decorate = this.decorate.bind(this); + + this.dirtyDiffWorker.addEventListener('message', this.decorate); + } + + attachModel(model) { + model.onChange(() => this.throttledComputeDiff(model)); + } + + computeDiff(model) { + this.dirtyDiffWorker.postMessage({ + path: model.path, + originalContent: model.getOriginalModel().getValue(), + newContent: model.getModel().getValue(), + }); + } + + reDecorate(model) { + this.decorationsController.decorate(model); + } + + decorate({ data }) { + const decorations = data.changes.map(change => getDecorator(change)); + this.decorationsController.addDecorations(data.path, 'dirtyDiff', decorations); + } + + dispose() { + this.disposable.dispose(); + + this.dirtyDiffWorker.removeEventListener('message', this.decorate); + this.dirtyDiffWorker.terminate(); + } +} diff --git a/app/assets/javascripts/repo/lib/diff/diff.js b/app/assets/javascripts/repo/lib/diff/diff.js new file mode 100644 index 00000000000..0e37f5c4704 --- /dev/null +++ b/app/assets/javascripts/repo/lib/diff/diff.js @@ -0,0 +1,30 @@ +import { diffLines } from 'diff'; + +// eslint-disable-next-line import/prefer-default-export +export const computeDiff = (originalContent, newContent) => { + const changes = diffLines(originalContent, newContent); + + let lineNumber = 1; + return changes.reduce((acc, change) => { + const findOnLine = acc.find(c => c.lineNumber === lineNumber); + + if (findOnLine) { + Object.assign(findOnLine, change, { + modified: true, + endLineNumber: (lineNumber + change.count) - 1, + }); + } else if ('added' in change || 'removed' in change) { + acc.push(Object.assign({}, change, { + lineNumber, + modified: undefined, + endLineNumber: (lineNumber + change.count) - 1, + })); + } + + if (!change.removed) { + lineNumber += change.count; + } + + return acc; + }, []); +}; diff --git a/app/assets/javascripts/repo/lib/diff/diff_worker.js b/app/assets/javascripts/repo/lib/diff/diff_worker.js new file mode 100644 index 00000000000..e74c4046330 --- /dev/null +++ b/app/assets/javascripts/repo/lib/diff/diff_worker.js @@ -0,0 +1,10 @@ +import { computeDiff } from './diff'; + +self.addEventListener('message', (e) => { + const data = e.data; + + self.postMessage({ + path: data.path, + changes: computeDiff(data.originalContent, data.newContent), + }); +}); diff --git a/app/assets/javascripts/repo/lib/editor.js b/app/assets/javascripts/repo/lib/editor.js new file mode 100644 index 00000000000..db499444402 --- /dev/null +++ b/app/assets/javascripts/repo/lib/editor.js @@ -0,0 +1,79 @@ +import DecorationsController from './decorations/controller'; +import DirtyDiffController from './diff/controller'; +import Disposable from './common/disposable'; +import ModelManager from './common/model_manager'; +import editorOptions from './editor_options'; + +export default class Editor { + static create(monaco) { + this.editorInstance = new Editor(monaco); + + return this.editorInstance; + } + + constructor(monaco) { + this.monaco = monaco; + this.currentModel = null; + this.instance = null; + this.dirtyDiffController = null; + this.disposable = new Disposable(); + + this.disposable.add( + this.modelManager = new ModelManager(this.monaco), + this.decorationsController = new DecorationsController(this), + ); + } + + createInstance(domElement) { + if (!this.instance) { + this.disposable.add( + this.instance = this.monaco.editor.create(domElement, { + model: null, + readOnly: false, + contextmenu: true, + scrollBeyondLastLine: false, + }), + this.dirtyDiffController = new DirtyDiffController( + this.modelManager, this.decorationsController, + ), + ); + } + } + + createModel(file) { + return this.modelManager.addModel(file); + } + + attachModel(model) { + this.instance.setModel(model.getModel()); + this.dirtyDiffController.attachModel(model); + + this.currentModel = model; + + this.instance.updateOptions(editorOptions.reduce((acc, obj) => { + Object.keys(obj).forEach((key) => { + Object.assign(acc, { + [key]: obj[key](model), + }); + }); + return acc; + }, {})); + + this.dirtyDiffController.reDecorate(model); + } + + clearEditor() { + if (this.instance) { + this.instance.setModel(null); + } + } + + dispose() { + this.disposable.dispose(); + + // dispose main monaco instance + if (this.instance) { + this.instance = null; + } + } +} diff --git a/app/assets/javascripts/repo/lib/editor_options.js b/app/assets/javascripts/repo/lib/editor_options.js new file mode 100644 index 00000000000..701affc466e --- /dev/null +++ b/app/assets/javascripts/repo/lib/editor_options.js @@ -0,0 +1,2 @@ +export default [{ +}]; diff --git a/app/assets/javascripts/repo/services/index.js b/app/assets/javascripts/repo/services/index.js index 2fb45dcb03c..994d325e991 100644 --- a/app/assets/javascripts/repo/services/index.js +++ b/app/assets/javascripts/repo/services/index.js @@ -16,6 +16,10 @@ export default { return Promise.resolve(file.content); } + if (file.raw) { + return Promise.resolve(file.raw); + } + return Vue.http.get(file.rawPath, { params: { format: 'json' } }) .then(res => res.text()); }, diff --git a/app/assets/javascripts/repo/stores/actions.js b/app/assets/javascripts/repo/stores/actions.js index be290c268b1..120ce96f44d 100644 --- a/app/assets/javascripts/repo/stores/actions.js +++ b/app/assets/javascripts/repo/stores/actions.js @@ -3,7 +3,7 @@ import flash from '../../flash'; import service from '../services'; import * as types from './mutation_types'; -export const redirectToUrl = url => gl.utils.visitUrl(url); +export const redirectToUrl = (_, url) => gl.utils.visitUrl(url); export const setInitialData = ({ commit }, data) => commit(types.SET_INITIAL_DATA, data); @@ -84,7 +84,7 @@ export const commitChanges = ({ commit, state, dispatch, getters }, { payload, n flash(`Your changes have been committed. Commit ${data.short_id} with ${data.stats.additions} additions, ${data.stats.deletions} deletions.`, 'notice'); if (newMr) { - redirectToUrl(`${state.endpoints.newMergeRequestUrl}${branch}`); + dispatch('redirectToUrl', `${state.endpoints.newMergeRequestUrl}${branch}`); } else { commit(types.SET_COMMIT_REF, data.id); diff --git a/app/assets/javascripts/repo/stores/actions/branch.js b/app/assets/javascripts/repo/stores/actions/branch.js index b81a70dfd1e..61d9a5af3e3 100644 --- a/app/assets/javascripts/repo/stores/actions/branch.js +++ b/app/assets/javascripts/repo/stores/actions/branch.js @@ -3,16 +3,16 @@ import * as types from '../mutation_types'; import { pushState } from '../utils'; // eslint-disable-next-line import/prefer-default-export -export const createNewBranch = ({ rootState, commit }, branch) => service.createBranch( - rootState.project.id, +export const createNewBranch = ({ state, commit }, branch) => service.createBranch( + state.project.id, { branch, - ref: rootState.currentBranch, + ref: state.currentBranch, }, ).then(res => res.json()) .then((data) => { const branchName = data.name; - const url = location.href.replace(rootState.currentBranch, branchName); + const url = location.href.replace(state.currentBranch, branchName); pushState(url); diff --git a/app/assets/javascripts/repo/stores/getters.js b/app/assets/javascripts/repo/stores/getters.js index 1ed05ac6e35..5ce9f449905 100644 --- a/app/assets/javascripts/repo/stores/getters.js +++ b/app/assets/javascripts/repo/stores/getters.js @@ -34,3 +34,7 @@ export const canEditFile = (state) => { openedFiles.length && (currentActiveFile && !currentActiveFile.renderError && !currentActiveFile.binary); }; + +export const addedFiles = state => changedFiles(state).filter(f => f.tempFile); + +export const modifiedFiles = state => changedFiles(state).filter(f => !f.tempFile); diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js index a41548bd694..fa7f6825d7e 100644 --- a/app/assets/javascripts/right_sidebar.js +++ b/app/assets/javascripts/right_sidebar.js @@ -15,7 +15,7 @@ import Cookies from 'js-cookie'; Sidebar.prototype.removeListeners = function () { this.sidebar.off('click', '.sidebar-collapsed-icon'); - $('.dropdown').off('hidden.gl.dropdown'); + this.sidebar.off('hidden.gl.dropdown'); $('.dropdown').off('loading.gl.dropdown'); $('.dropdown').off('loaded.gl.dropdown'); $(document).off('click', '.js-sidebar-toggle'); @@ -25,7 +25,7 @@ import Cookies from 'js-cookie'; const $document = $(document); this.sidebar.on('click', '.sidebar-collapsed-icon', this, this.sidebarCollapseClicked); - $('.dropdown').on('hidden.gl.dropdown', this, this.onSidebarDropdownHidden); + this.sidebar.on('hidden.gl.dropdown', this, this.onSidebarDropdownHidden); $('.dropdown').on('loading.gl.dropdown', this.sidebarDropdownLoading); $('.dropdown').on('loaded.gl.dropdown', this.sidebarDropdownLoaded); @@ -180,7 +180,7 @@ import Cookies from 'js-cookie'; var $block, sidebar; sidebar = e.data; e.preventDefault(); - $block = $(this).closest('.block'); + $block = $(e.target).closest('.block'); return sidebar.sidebarDropdownHidden($block); }; diff --git a/app/assets/javascripts/search_autocomplete.js b/app/assets/javascripts/search_autocomplete.js index 9dec5d7645a..e40a3596200 100644 --- a/app/assets/javascripts/search_autocomplete.js +++ b/app/assets/javascripts/search_autocomplete.js @@ -1,13 +1,20 @@ -/* eslint-disable comma-dangle, no-return-assign, one-var, no-var, no-underscore-dangle, one-var-declaration-per-line, no-unused-vars, no-cond-assign, consistent-return, object-shorthand, prefer-arrow-callback, func-names, space-before-function-paren, prefer-template, quotes, class-methods-use-this, no-unused-expressions, no-sequences, wrap-iife, no-lonely-if, no-else-return, no-param-reassign, vars-on-top, max-len */ +/* eslint-disable no-return-assign, one-var, no-var, no-underscore-dangle, one-var-declaration-per-line, no-unused-vars, no-cond-assign, consistent-return, object-shorthand, prefer-arrow-callback, func-names, space-before-function-paren, prefer-template, quotes, class-methods-use-this, no-sequences, wrap-iife, no-lonely-if, no-else-return, no-param-reassign, vars-on-top, max-len */ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from './lib/utils/common_utils'; +/** + * Search input in top navigation bar. + * On click, opens a dropdown + * As the user types it filters the results + * When the user clicks `x` button it cleans the input and closes the dropdown. + */ + ((global) => { const KEYCODE = { ESCAPE: 27, BACKSPACE: 8, ENTER: 13, UP: 38, - DOWN: 40 + DOWN: 40, }; class SearchAutocomplete { @@ -19,6 +26,7 @@ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from '. this.projectId = projectId || (this.optsEl.data('autocomplete-project-id') || ''); this.projectRef = projectRef || (this.optsEl.data('autocomplete-project-ref') || ''); this.dropdown = this.wrap.find('.dropdown'); + this.dropdownToggle = this.wrap.find('.js-dropdown-search-toggle'); this.dropdownContent = this.dropdown.find('.dropdown-content'); this.locationBadgeEl = this.getElement('.location-badge'); this.scopeInputEl = this.getElement('#scope'); @@ -29,13 +37,16 @@ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from '. this.repositoryInputEl = this.getElement('#repository_ref'); this.clearInput = this.getElement('.js-clear-input'); this.saveOriginalState(); + // Only when user is logged in if (gon.current_user_id) { this.createAutocomplete(); } + this.searchInput.addClass('disabled'); this.saveTextLength(); this.bindEvents(); + this.dropdownToggle.dropdown(); } // Finds an element inside wrapper element @@ -43,7 +54,6 @@ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from '. this.onSearchInputBlur = this.onSearchInputBlur.bind(this); this.onClearInputClick = this.onClearInputClick.bind(this); this.onSearchInputFocus = this.onSearchInputFocus.bind(this); - this.onSearchInputClick = this.onSearchInputClick.bind(this); this.onSearchInputKeyUp = this.onSearchInputKeyUp.bind(this); this.onSearchInputKeyDown = this.onSearchInputKeyDown.bind(this); } @@ -68,12 +78,12 @@ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from '. enterCallback: false, filterInput: 'input#search', search: { - fields: ['text'] + fields: ['text'], }, id: this.getSearchText, data: this.getData.bind(this), selectable: true, - clicked: this.onClick.bind(this) + clicked: this.onClick.bind(this), }); } @@ -82,32 +92,35 @@ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from '. } getData(term, callback) { - var _this, contents, jqXHR; - _this = this; if (!term) { - if (contents = this.getCategoryContents()) { + const contents = this.getCategoryContents(); + if (contents) { this.searchInput.data('glDropdown').filter.options.callback(contents); this.enableAutocomplete(); } return; } + // Prevent multiple ajax calls if (this.loadingSuggestions) { return; } + this.loadingSuggestions = true; - return jqXHR = $.get(this.autocompletePath, { + + return $.get(this.autocompletePath, { project_id: this.projectId, project_ref: this.projectRef, - term: term - }, function(response) { - var data, firstCategory, i, lastCategory, len, suggestion; + term: term, + }, (response) => { + var firstCategory, i, lastCategory, len, suggestion; // Hide dropdown menu if no suggestions returns if (!response.length) { - _this.disableAutocomplete(); + this.disableAutocomplete(); return; } - data = []; + + const data = []; // List results firstCategory = true; for (i = 0, len = response.length; i < len; i += 1) { @@ -121,7 +134,7 @@ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from '. firstCategory = false; } data.push({ - header: suggestion.category + header: suggestion.category, }); lastCategory = suggestion.category; } @@ -129,7 +142,7 @@ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from '. id: (suggestion.category.toLowerCase()) + "-" + suggestion.id, category: suggestion.category, text: suggestion.label, - url: suggestion.url + url: suggestion.url, }); } // Add option to proceed with the search @@ -137,20 +150,21 @@ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from '. data.push('separator'); data.push({ text: "Result name contains \"" + term + "\"", - url: "/search?search=" + term + "&project_id=" + (_this.projectInputEl.val()) + "&group_id=" + (_this.groupInputEl.val()) + url: "/search?search=" + term + "&project_id=" + (this.projectInputEl.val()) + "&group_id=" + (this.groupInputEl.val()), }); } return callback(data); - }).always(function() { - return _this.loadingSuggestions = false; - }); + }) + .always(() => { this.loadingSuggestions = false; }); } getCategoryContents() { - var dashboardOptions, groupOptions, issuesPath, items, mrPath, name, options, projectOptions, userId, userName; - userId = gon.current_user_id; - userName = gon.current_username; - projectOptions = gl.projectOptions, groupOptions = gl.groupOptions, dashboardOptions = gl.dashboardOptions; + const userId = gon.current_user_id; + const userName = gon.current_username; + const { projectOptions, groupOptions, dashboardOptions } = gl; + + // Get options + let options; if (isInGroupsPage() && groupOptions) { options = groupOptions[getGroupSlug()]; } else if (isInProjectPage() && projectOptions) { @@ -158,37 +172,42 @@ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from '. } else if (dashboardOptions) { options = dashboardOptions; } - issuesPath = options.issuesPath, mrPath = options.mrPath, name = options.name; - items = [ - { - header: "" + name - } - ]; + + const { issuesPath, mrPath, name, issuesDisabled } = options; + const baseItems = []; + + if (name) { + baseItems.push({ + header: `${name}`, + }); + } + const issueItems = [ { text: 'Issues assigned to me', - url: issuesPath + "/?assignee_username=" + userName - }, { + url: `${issuesPath}/?assignee_username=${userName}`, + }, + { text: "Issues I've created", - url: issuesPath + "/?author_username=" + userName - } + url: `${issuesPath}/?author_username=${userName}`, + }, ]; const mergeRequestItems = [ { text: 'Merge requests assigned to me', - url: mrPath + "/?assignee_username=" + userName - }, { + url: `${mrPath}/?assignee_username=${userName}`, + }, + { text: "Merge requests I've created", - url: mrPath + "/?author_username=" + userName - } + url: `${mrPath}/?author_username=${userName}`, + }, ]; - if (options.issuesDisabled) { - items = items.concat(mergeRequestItems); + + let items; + if (issuesDisabled) { + items = baseItems.concat(mergeRequestItems); } else { - items = items.concat(...issueItems, 'separator', ...mergeRequestItems); - } - if (!name) { - items.splice(0, 1); + items = baseItems.concat(...issueItems, 'separator', ...mergeRequestItems); } return items; } @@ -202,39 +221,34 @@ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from '. repository_ref: this.repositoryInputEl.val(), scope: this.scopeInputEl.val(), // Location badge - _location: this.locationBadgeEl.text() + _location: this.locationBadgeEl.text(), }; } bindEvents() { this.searchInput.on('keydown', this.onSearchInputKeyDown); this.searchInput.on('keyup', this.onSearchInputKeyUp); - this.searchInput.on('click', this.onSearchInputClick); this.searchInput.on('focus', this.onSearchInputFocus); this.searchInput.on('blur', this.onSearchInputBlur); this.clearInput.on('click', this.onClearInputClick); - return this.locationBadgeEl.on('click', (function(_this) { - return function() { - return _this.searchInput.focus(); - }; - })(this)); + this.locationBadgeEl.on('click', () => this.searchInput.focus()); } enableAutocomplete() { - var _this; // No need to enable anything if user is not logged in if (!gon.current_user_id) { return; } + + // If the dropdown is closed, we'll open it if (!this.dropdown.hasClass('open')) { - _this = this; this.loadingSuggestions = false; - this.dropdown.addClass('open').trigger('shown.bs.dropdown'); + this.dropdownToggle.dropdown('toggle'); return this.searchInput.removeClass('disabled'); } } - // Saves last length of the entered text + // Saves last length of the entered text onSearchInputKeyDown() { return this.saveTextLength(); } @@ -279,11 +293,6 @@ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from '. this.wrap.toggleClass('has-value', !!e.target.value); } - // Avoid falsy value to be returned - onSearchInputClick(e) { - return e.stopImmediatePropagation(); - } - onSearchInputFocus() { this.isFocused = true; this.wrap.addClass('search-active'); @@ -335,7 +344,7 @@ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from '. return this.locationBadgeEl.hide(); } else { return this.addLocationBadge({ - value: this.originalState._location + value: this.originalState._location, }); } } @@ -387,13 +396,13 @@ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from '. if (item.category === 'Projects') { this.projectInputEl.val(item.id); this.addLocationBadge({ - value: 'This project' + value: 'This project', }); } if (item.category === 'Groups') { this.groupInputEl.val(item.id); this.addLocationBadge({ - value: 'This group' + value: 'This group', }); } } @@ -420,7 +429,7 @@ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from '. name: $projectOptionsDataEl.data('name'), issuesPath: $projectOptionsDataEl.data('issues-path'), issuesDisabled: $projectOptionsDataEl.data('issues-disabled'), - mrPath: $projectOptionsDataEl.data('mr-path') + mrPath: $projectOptionsDataEl.data('mr-path'), }; } @@ -432,14 +441,14 @@ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from '. gl.groupOptions[groupPath] = { name: $groupOptionsDataEl.data('name'), issuesPath: $groupOptionsDataEl.data('issues-path'), - mrPath: $groupOptionsDataEl.data('mr-path') + mrPath: $groupOptionsDataEl.data('mr-path'), }; } if ($dashboardOptionsDataEl.length) { gl.dashboardOptions = { issuesPath: $dashboardOptionsDataEl.data('issues-path'), - mrPath: $dashboardOptionsDataEl.data('mr-path') + mrPath: $dashboardOptionsDataEl.data('mr-path'), }; } }); diff --git a/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue b/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue index 22a9a34dda3..6ee4d487c0b 100644 --- a/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue +++ b/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue @@ -1,10 +1,12 @@ <script> import Flash from '../../../flash'; import editForm from './edit_form.vue'; +import Icon from '../../../vue_shared/components/icon.vue'; export default { components: { editForm, + Icon, }, props: { isConfidential: { @@ -26,11 +28,8 @@ export default { }; }, computed: { - faEye() { - const eye = this.isConfidential ? 'fa-eye-slash' : 'fa-eye'; - return { - [eye]: true, - }; + confidentialityIcon() { + return this.isConfidential ? 'eye-slash' : 'eye'; }, }, methods: { @@ -49,7 +48,11 @@ export default { <template> <div class="block issuable-sidebar-item confidentiality"> <div class="sidebar-collapsed-icon"> - <i class="fa" :class="faEye" aria-hidden="true"></i> + <icon + :name="confidentialityIcon" + :size="16" + aria-hidden="true"> + </icon> </div> <div class="title hide-collapsed"> Confidentiality @@ -70,11 +73,21 @@ export default { :update-confidential-attribute="updateConfidentialAttribute" /> <div v-if="!isConfidential" class="no-value sidebar-item-value"> - <i class="fa fa-eye sidebar-item-icon"></i> + <icon + name="eye" + :size="16" + aria-hidden="true" + class="sidebar-item-icon inline"> + </icon> Not confidential </div> <div v-else class="value sidebar-item-value hide-collapsed"> - <i aria-hidden="true" class="fa fa-eye-slash sidebar-item-icon is-active"></i> + <icon + name="eye-slash" + :size="16" + aria-hidden="true" + class="sidebar-item-icon inline is-active"> + </icon> This issue is confidential </div> </div> diff --git a/app/assets/javascripts/sidebar/components/lock/edit_form.vue b/app/assets/javascripts/sidebar/components/lock/edit_form.vue index c7a6edc7c70..242e826d471 100644 --- a/app/assets/javascripts/sidebar/components/lock/edit_form.vue +++ b/app/assets/javascripts/sidebar/components/lock/edit_form.vue @@ -18,11 +18,6 @@ export default { required: true, type: Function, }, - - issuableType: { - required: true, - type: String, - }, }, mixins: [ @@ -39,13 +34,13 @@ export default { <div class="dropdown open"> <div class="dropdown-menu sidebar-item-warning-message"> <p class="text" v-if="isLocked"> - Unlock this {{ issuableDisplayName(issuableType) }}? + Unlock this {{ issuableDisplayName }}? <strong>Everyone</strong> will be able to comment. </p> <p class="text" v-else> - Lock this {{ issuableDisplayName(issuableType) }}? + Lock this {{ issuableDisplayName }}? Only <strong>project members</strong> will be able to comment. diff --git a/app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue b/app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue index c4b2900e020..04c3a96bf74 100644 --- a/app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue +++ b/app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue @@ -2,6 +2,7 @@ /* global Flash */ import editForm from './edit_form.vue'; import issuableMixin from '../../../vue_shared/mixins/issuable'; +import Icon from '../../../vue_shared/components/icon.vue'; export default { props: { @@ -22,11 +23,6 @@ export default { return mediatorObject.service && mediatorObject.service.update && mediatorObject.store; }, }, - - issuableType: { - required: true, - type: String, - }, }, mixins: [ @@ -35,11 +31,12 @@ export default { components: { editForm, + Icon, }, computed: { - lockIconClass() { - return this.isLocked ? 'fa-lock' : 'fa-unlock'; + lockIcon() { + return this.isLocked ? 'lock' : 'lock-open'; }, isLockDialogOpen() { @@ -57,7 +54,7 @@ export default { discussion_locked: locked, }) .then(() => location.reload()) - .catch(() => Flash(this.__(`Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}`))); + .catch(() => Flash(this.__(`Something went wrong trying to change the locked state of this ${this.issuableDisplayName}`))); }, }, }; @@ -66,15 +63,16 @@ export default { <template> <div class="block issuable-sidebar-item lock"> <div class="sidebar-collapsed-icon"> - <i - class="fa" - :class="lockIconClass" + <icon + :name="lockIcon" + :size="16" aria-hidden="true" - ></i> + class="sidebar-item-icon is-active"> + </icon> </div> <div class="title hide-collapsed"> - Lock {{issuableDisplayName(issuableType) }} + Lock {{ issuableDisplayName }} <button v-if="isEditable" class="pull-right lock-edit btn btn-blank" @@ -98,10 +96,12 @@ export default { v-if="isLocked" class="value sidebar-item-value" > - <i + <icon + name="lock" + :size="16" aria-hidden="true" - class="fa fa-lock sidebar-item-icon is-active" - ></i> + class="sidebar-item-icon inline is-active"> + </icon> {{ __('Locked') }} </div> @@ -109,10 +109,12 @@ export default { v-else class="no-value sidebar-item-value hide-collapsed" > - <i + <icon + name="lock-open" + :size="16" aria-hidden="true" - class="fa fa-unlock sidebar-item-icon" - ></i> + class="sidebar-item-icon inline"> + </icon> {{ __('Unlocked') }} </div> </div> diff --git a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions.vue b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions.vue index 4ad3d469f25..25acc099699 100644 --- a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions.vue +++ b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions.vue @@ -3,6 +3,7 @@ import Store from '../../stores/sidebar_store'; import Mediator from '../../sidebar_mediator'; import eventHub from '../../event_hub'; import Flash from '../../../flash'; +import { __ } from '../../../locale'; import subscriptions from './subscriptions.vue'; export default { @@ -21,7 +22,7 @@ export default { onToggleSubscription() { this.mediator.toggleSubscription() .catch(() => { - Flash('Error occurred when toggling the notification subscription'); + Flash(__('Error occurred when toggling the notification subscription')); }); }, }, diff --git a/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue b/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue index a3a8213d63a..940e1764f3d 100644 --- a/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue +++ b/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue @@ -14,6 +14,10 @@ export default { type: Boolean, required: false, }, + id: { + type: Number, + required: false, + }, }, components: { loadingButton, @@ -32,7 +36,7 @@ export default { }, methods: { toggleSubscription() { - eventHub.$emit('toggleSubscription'); + eventHub.$emit('toggleSubscription', this.id); }, }, }; diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js new file mode 100644 index 00000000000..4032f156b15 --- /dev/null +++ b/app/assets/javascripts/sidebar/mount_sidebar.js @@ -0,0 +1,104 @@ +import Vue from 'vue'; +import SidebarTimeTracking from './components/time_tracking/sidebar_time_tracking'; +import SidebarAssignees from './components/assignees/sidebar_assignees'; +import ConfidentialIssueSidebar from './components/confidential/confidential_issue_sidebar.vue'; +import SidebarMoveIssue from './lib/sidebar_move_issue'; +import LockIssueSidebar from './components/lock/lock_issue_sidebar.vue'; +import sidebarParticipants from './components/participants/sidebar_participants.vue'; +import sidebarSubscriptions from './components/subscriptions/sidebar_subscriptions.vue'; +import Translate from '../vue_shared/translate'; + +Vue.use(Translate); + +function mountConfidentialComponent(mediator) { + const el = document.getElementById('js-confidential-entry-point'); + + if (!el) return; + + const dataNode = document.getElementById('js-confidential-issue-data'); + const initialData = JSON.parse(dataNode.innerHTML); + + const ConfidentialComp = Vue.extend(ConfidentialIssueSidebar); + + new ConfidentialComp({ + propsData: { + isConfidential: initialData.is_confidential, + isEditable: initialData.is_editable, + service: mediator.service, + }, + }).$mount(el); +} + +function mountLockComponent(mediator) { + const el = document.getElementById('js-lock-entry-point'); + + if (!el) return; + + const dataNode = document.getElementById('js-lock-issue-data'); + const initialData = JSON.parse(dataNode.innerHTML); + + const LockComp = Vue.extend(LockIssueSidebar); + + new LockComp({ + propsData: { + isLocked: initialData.is_locked, + isEditable: initialData.is_editable, + mediator, + issuableType: gl.utils.isInIssuePage() ? 'issue' : 'merge_request', + }, + }).$mount(el); +} + +function mountParticipantsComponent() { + const el = document.querySelector('.js-sidebar-participants-entry-point'); + + if (!el) return; + + // eslint-disable-next-line no-new + new Vue({ + el, + components: { + sidebarParticipants, + }, + render: createElement => createElement('sidebar-participants', {}), + }); +} + +function mountSubscriptionsComponent() { + const el = document.querySelector('.js-sidebar-subscriptions-entry-point'); + + if (!el) return; + + // eslint-disable-next-line no-new + new Vue({ + el, + components: { + sidebarSubscriptions, + }, + render: createElement => createElement('sidebar-subscriptions', {}), + }); +} + +function mount(mediator) { + const sidebarAssigneesEl = document.getElementById('js-vue-sidebar-assignees'); + // Only create the sidebarAssignees vue app if it is found in the DOM + // We currently do not use sidebarAssignees for the MR page + if (sidebarAssigneesEl) { + new Vue(SidebarAssignees).$mount(sidebarAssigneesEl); + } + + mountConfidentialComponent(mediator); + mountLockComponent(mediator); + mountParticipantsComponent(); + mountSubscriptionsComponent(); + + new SidebarMoveIssue( + mediator, + $('.js-move-issue'), + $('.js-move-issue-confirmation-button'), + ).init(); + + new Vue(SidebarTimeTracking).$mount('#issuable-time-tracker'); +} + +export default mount; diff --git a/app/assets/javascripts/sidebar/sidebar_bundle.js b/app/assets/javascripts/sidebar/sidebar_bundle.js index 2650bb725d4..f78287e504b 100644 --- a/app/assets/javascripts/sidebar/sidebar_bundle.js +++ b/app/assets/javascripts/sidebar/sidebar_bundle.js @@ -1,110 +1,12 @@ -import Vue from 'vue'; -import SidebarTimeTracking from './components/time_tracking/sidebar_time_tracking'; -import SidebarAssignees from './components/assignees/sidebar_assignees'; -import ConfidentialIssueSidebar from './components/confidential/confidential_issue_sidebar.vue'; -import SidebarMoveIssue from './lib/sidebar_move_issue'; -import LockIssueSidebar from './components/lock/lock_issue_sidebar.vue'; -import sidebarParticipants from './components/participants/sidebar_participants.vue'; -import sidebarSubscriptions from './components/subscriptions/sidebar_subscriptions.vue'; -import Translate from '../vue_shared/translate'; - import Mediator from './sidebar_mediator'; - -Vue.use(Translate); - -function mountConfidentialComponent(mediator) { - const el = document.getElementById('js-confidential-entry-point'); - - if (!el) return; - - const dataNode = document.getElementById('js-confidential-issue-data'); - const initialData = JSON.parse(dataNode.innerHTML); - - const ConfidentialComp = Vue.extend(ConfidentialIssueSidebar); - - new ConfidentialComp({ - propsData: { - isConfidential: initialData.is_confidential, - isEditable: initialData.is_editable, - service: mediator.service, - }, - }).$mount(el); -} - -function mountLockComponent(mediator) { - const el = document.getElementById('js-lock-entry-point'); - - if (!el) return; - - const dataNode = document.getElementById('js-lock-issue-data'); - const initialData = JSON.parse(dataNode.innerHTML); - - const LockComp = Vue.extend(LockIssueSidebar); - - new LockComp({ - propsData: { - isLocked: initialData.is_locked, - isEditable: initialData.is_editable, - mediator, - issuableType: gl.utils.isInIssuePage() ? 'issue' : 'merge_request', - }, - }).$mount(el); -} - -function mountParticipantsComponent() { - const el = document.querySelector('.js-sidebar-participants-entry-point'); - - if (!el) return; - - // eslint-disable-next-line no-new - new Vue({ - el, - components: { - sidebarParticipants, - }, - render: createElement => createElement('sidebar-participants', {}), - }); -} - -function mountSubscriptionsComponent() { - const el = document.querySelector('.js-sidebar-subscriptions-entry-point'); - - if (!el) return; - - // eslint-disable-next-line no-new - new Vue({ - el, - components: { - sidebarSubscriptions, - }, - render: createElement => createElement('sidebar-subscriptions', {}), - }); -} +import mountSidebar from './mount_sidebar'; function domContentLoaded() { const sidebarOptions = JSON.parse(document.querySelector('.js-sidebar-options').innerHTML); const mediator = new Mediator(sidebarOptions); mediator.fetch(); - const sidebarAssigneesEl = document.getElementById('js-vue-sidebar-assignees'); - // Only create the sidebarAssignees vue app if it is found in the DOM - // We currently do not use sidebarAssignees for the MR page - if (sidebarAssigneesEl) { - new Vue(SidebarAssignees).$mount(sidebarAssigneesEl); - } - - mountConfidentialComponent(mediator); - mountLockComponent(mediator); - mountParticipantsComponent(); - mountSubscriptionsComponent(); - - new SidebarMoveIssue( - mediator, - $('.js-move-issue'), - $('.js-move-issue-confirmation-button'), - ).init(); - - new Vue(SidebarTimeTracking).$mount('#issuable-time-tracker'); + mountSidebar(mediator); } document.addEventListener('DOMContentLoaded', domContentLoaded); diff --git a/app/assets/javascripts/sidebar/sidebar_mediator.js b/app/assets/javascripts/sidebar/sidebar_mediator.js index 2bda5a47791..d4c07a188b3 100644 --- a/app/assets/javascripts/sidebar/sidebar_mediator.js +++ b/app/assets/javascripts/sidebar/sidebar_mediator.js @@ -5,19 +5,23 @@ import Store from './stores/sidebar_store'; export default class SidebarMediator { constructor(options) { if (!SidebarMediator.singleton) { - this.store = new Store(options); - this.service = new Service({ - endpoint: options.endpoint, - toggleSubscriptionEndpoint: options.toggleSubscriptionEndpoint, - moveIssueEndpoint: options.moveIssueEndpoint, - projectsAutocompleteEndpoint: options.projectsAutocompleteEndpoint, - }); - SidebarMediator.singleton = this; + this.initSingleton(options); } return SidebarMediator.singleton; } + initSingleton(options) { + this.store = new Store(options); + this.service = new Service({ + endpoint: options.endpoint, + toggleSubscriptionEndpoint: options.toggleSubscriptionEndpoint, + moveIssueEndpoint: options.moveIssueEndpoint, + projectsAutocompleteEndpoint: options.projectsAutocompleteEndpoint, + }); + SidebarMediator.singleton = this; + } + assignYourself() { this.store.addAssignee(this.store.currentUser); } @@ -35,17 +39,21 @@ export default class SidebarMediator { } fetch() { - this.service.get() + return this.service.get() .then(response => response.json()) .then((data) => { - this.store.setAssigneeData(data); - this.store.setTimeTrackingData(data); - this.store.setParticipantsData(data); - this.store.setSubscriptionsData(data); + this.processFetchedData(data); }) .catch(() => new Flash('Error occurred when fetching sidebar data')); } + processFetchedData(data) { + this.store.setAssigneeData(data); + this.store.setTimeTrackingData(data); + this.store.setParticipantsData(data); + this.store.setSubscriptionsData(data); + } + toggleSubscription() { this.store.setFetchingState('subscriptions', true); return this.service.toggleSubscription() diff --git a/app/assets/javascripts/sidebar/stores/sidebar_store.js b/app/assets/javascripts/sidebar/stores/sidebar_store.js index 3150221b685..73eb25e2333 100644 --- a/app/assets/javascripts/sidebar/stores/sidebar_store.js +++ b/app/assets/javascripts/sidebar/stores/sidebar_store.js @@ -15,6 +15,7 @@ export default class SidebarStore { participants: true, subscriptions: true, }; + this.isLoading = {}; this.autocompleteProjects = []; this.moveToProjectId = 0; this.isLockDialogOpen = false; @@ -55,6 +56,10 @@ export default class SidebarStore { this.isFetching[key] = value; } + setLoadingState(key, value) { + this.isLoading[key] = value; + } + addAssignee(assignee) { if (!this.findAssignee(assignee)) { this.assignees.push(assignee); diff --git a/app/assets/javascripts/star.js b/app/assets/javascripts/star.js index 1a8dc085772..d5606e153f6 100644 --- a/app/assets/javascripts/star.js +++ b/app/assets/javascripts/star.js @@ -1,5 +1,6 @@ import Flash from './flash'; import { __, s__ } from './locale'; +import { spriteIcon } from './lib/utils/common_utils'; export default class Star { constructor() { @@ -7,16 +8,18 @@ export default class Star { .on('ajax:success', function handleSuccess(e, data) { const $this = $(this); const $starSpan = $this.find('span'); - const $starIcon = $this.find('i'); + const $startIcon = $this.find('svg'); function toggleStar(isStarred) { $this.parent().find('.star-count').text(data.star_count); if (isStarred) { $starSpan.removeClass('starred').text(s__('StarProject|Star')); - $starIcon.removeClass('fa-star').addClass('fa-star-o'); + $startIcon.remove(); + $this.prepend(spriteIcon('star-o')); } else { $starSpan.addClass('starred').text(__('Unstar')); - $starIcon.removeClass('fa-star-o').addClass('fa-star'); + $startIcon.remove(); + $this.prepend(spriteIcon('star')); } } diff --git a/app/assets/javascripts/subscription.js b/app/assets/javascripts/subscription.js deleted file mode 100644 index bb4d68fcd49..00000000000 --- a/app/assets/javascripts/subscription.js +++ /dev/null @@ -1,45 +0,0 @@ -class Subscription { - constructor(containerElm) { - this.containerElm = containerElm; - - const subscribeButton = containerElm.querySelector('.js-subscribe-button'); - if (subscribeButton) { - // remove class so we don't bind twice - subscribeButton.classList.remove('js-subscribe-button'); - subscribeButton.addEventListener('click', this.toggleSubscription.bind(this)); - } - } - - toggleSubscription(event) { - const button = event.currentTarget; - const buttonSpan = button.querySelector('span'); - if (!buttonSpan || button.classList.contains('disabled')) { - return; - } - button.classList.add('disabled'); - - const isSubscribed = buttonSpan.innerHTML.trim().toLowerCase() !== 'subscribe'; - const toggleActionUrl = this.containerElm.dataset.url; - - $.post(toggleActionUrl, () => { - button.classList.remove('disabled'); - - // hack to allow this to work with the issue boards Vue object - if (document.querySelector('html').classList.contains('issue-boards-page')) { - gl.issueBoards.boardStoreIssueSet( - 'subscribed', - !gl.issueBoards.BoardsStore.detail.issue.subscribed, - ); - } else { - buttonSpan.innerHTML = isSubscribed ? 'Subscribe' : 'Unsubscribe'; - } - }); - } - - static bindAll(selector) { - [].forEach.call(document.querySelectorAll(selector), elm => new Subscription(elm)); - } -} - -window.gl = window.gl || {}; -window.gl.Subscription = Subscription; diff --git a/app/assets/javascripts/subscription_select.js b/app/assets/javascripts/subscription_select.js index 37e39ce5477..1ab4c2229ca 100644 --- a/app/assets/javascripts/subscription_select.js +++ b/app/assets/javascripts/subscription_select.js @@ -1,33 +1,24 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, quotes, object-shorthand, no-unused-vars, no-shadow, one-var, one-var-declaration-per-line, comma-dangle, max-len */ +export default function subscriptionSelect() { + $('.js-subscription-event').each((i, element) => { + const fieldName = $(element).data('field-name'); -class SubscriptionSelect { - constructor() { - $('.js-subscription-event').each(function(i, el) { - var fieldName; - fieldName = $(el).data("field-name"); - return $(el).glDropdown({ - selectable: true, - fieldName: fieldName, - toggleLabel: (function(_this) { - return function(selected, el, instance) { - var $item, label; - label = 'Subscription'; - $item = instance.dropdown.find('.is-active'); - if ($item.length) { - label = $item.text(); - } - return label; - }; - })(this), - clicked: function(options) { - return options.e.preventDefault(); - }, - id: function(obj, el) { - return $(el).data("id"); + return $(element).glDropdown({ + selectable: true, + fieldName, + toggleLabel(selected, el, instance) { + let label = 'Subscription'; + const $item = instance.dropdown.find('.is-active'); + if ($item.length) { + label = $item.text(); } - }); + return label; + }, + clicked(options) { + return options.e.preventDefault(); + }, + id(obj, el) { + return $(el).data('id'); + }, }); - } + }); } - -window.SubscriptionSelect = SubscriptionSelect; diff --git a/app/assets/javascripts/templates/issuable_template_selector.js b/app/assets/javascripts/templates/issuable_template_selector.js index 9dd14488f22..8e167f5bf08 100644 --- a/app/assets/javascripts/templates/issuable_template_selector.js +++ b/app/assets/javascripts/templates/issuable_template_selector.js @@ -1,60 +1,56 @@ -/* eslint-disable comma-dangle, max-len, no-useless-return, no-param-reassign, max-len */ -import Api from '../api'; +/* eslint-disable no-useless-return, max-len */ +import Api from '../api'; import TemplateSelector from '../blob/template_selector'; -((global) => { - class IssuableTemplateSelector extends TemplateSelector { - constructor(...args) { - super(...args); - this.projectPath = this.dropdown.data('project-path'); - this.namespacePath = this.dropdown.data('namespace-path'); - this.issuableType = this.$dropdownContainer.data('issuable-type'); - this.titleInput = $(`#${this.issuableType}_title`); - - const initialQuery = { - name: this.dropdown.data('selected') - }; - - if (initialQuery.name) this.requestFile(initialQuery); - - $('.reset-template', this.dropdown.parent()).on('click', () => { - this.setInputValueToTemplateContent(); - }); - - $('.no-template', this.dropdown.parent()).on('click', () => { - this.currentTemplate.content = ''; - this.setInputValueToTemplateContent(); - $('.dropdown-toggle-text', this.dropdown).text('Choose a template'); - }); - } +export default class IssuableTemplateSelector extends TemplateSelector { + constructor(...args) { + super(...args); + this.projectPath = this.dropdown.data('project-path'); + this.namespacePath = this.dropdown.data('namespace-path'); + this.issuableType = this.$dropdownContainer.data('issuable-type'); + this.titleInput = $(`#${this.issuableType}_title`); + + const initialQuery = { + name: this.dropdown.data('selected'), + }; + + if (initialQuery.name) this.requestFile(initialQuery); + + $('.reset-template', this.dropdown.parent()).on('click', () => { + this.setInputValueToTemplateContent(); + }); + + $('.no-template', this.dropdown.parent()).on('click', () => { + this.currentTemplate.content = ''; + this.setInputValueToTemplateContent(); + $('.dropdown-toggle-text', this.dropdown).text('Choose a template'); + }); + } - requestFile(query) { - this.startLoadingSpinner(); - Api.issueTemplate(this.namespacePath, this.projectPath, query.name, this.issuableType, (err, currentTemplate) => { - this.currentTemplate = currentTemplate; - if (err) return; // Error handled by global AJAX error handler - this.stopLoadingSpinner(); - this.setInputValueToTemplateContent(); - }); - return; - } + requestFile(query) { + this.startLoadingSpinner(); + Api.issueTemplate(this.namespacePath, this.projectPath, query.name, this.issuableType, (err, currentTemplate) => { + this.currentTemplate = currentTemplate; + if (err) return; // Error handled by global AJAX error handler + this.stopLoadingSpinner(); + this.setInputValueToTemplateContent(); + }); + return; + } - setInputValueToTemplateContent() { - // `this.setEditorContent` sets the value of the description input field - // to the content of the template selected. - if (this.titleInput.val() === '') { - // If the title has not yet been set, focus the title input and - // skip focusing the description input by setting `true` as the - // `skipFocus` option to `setEditorContent`. - this.setEditorContent(this.currentTemplate, { skipFocus: true }); - this.titleInput.focus(); - } else { - this.setEditorContent(this.currentTemplate, { skipFocus: false }); - } - return; + setInputValueToTemplateContent() { + // `this.setEditorContent` sets the value of the description input field + // to the content of the template selected. + if (this.titleInput.val() === '') { + // If the title has not yet been set, focus the title input and + // skip focusing the description input by setting `true` as the + // `skipFocus` option to `setEditorContent`. + this.setEditorContent(this.currentTemplate, { skipFocus: true }); + this.titleInput.focus(); + } else { + this.setEditorContent(this.currentTemplate, { skipFocus: false }); } + return; } - - global.IssuableTemplateSelector = IssuableTemplateSelector; -})(window.gl || (window.gl = {})); +} diff --git a/app/assets/javascripts/templates/issuable_template_selectors.js b/app/assets/javascripts/templates/issuable_template_selectors.js index 97f6d37364d..66d868c5839 100644 --- a/app/assets/javascripts/templates/issuable_template_selectors.js +++ b/app/assets/javascripts/templates/issuable_template_selectors.js @@ -1,31 +1,28 @@ -/* eslint-disable no-new, comma-dangle, class-methods-use-this, no-param-reassign */ +/* eslint-disable no-new, class-methods-use-this */ +import IssuableTemplateSelector from './issuable_template_selector'; -((global) => { - class IssuableTemplateSelectors { - constructor({ $dropdowns, editor } = {}) { - this.$dropdowns = $dropdowns || $('.js-issuable-selector'); - this.editor = editor || this.initEditor(); +export default class IssuableTemplateSelectors { + constructor({ $dropdowns, editor } = {}) { + this.$dropdowns = $dropdowns || $('.js-issuable-selector'); + this.editor = editor || this.initEditor(); - this.$dropdowns.each((i, dropdown) => { - const $dropdown = $(dropdown); - new gl.IssuableTemplateSelector({ - pattern: /(\.md)/, - data: $dropdown.data('data'), - wrapper: $dropdown.closest('.js-issuable-selector-wrap'), - dropdown: $dropdown, - editor: this.editor - }); + this.$dropdowns.each((i, dropdown) => { + const $dropdown = $(dropdown); + new IssuableTemplateSelector({ + pattern: /(\.md)/, + data: $dropdown.data('data'), + wrapper: $dropdown.closest('.js-issuable-selector-wrap'), + dropdown: $dropdown, + editor: this.editor, }); - } - - initEditor() { - const editor = $('.markdown-area'); - // Proxy ace-editor's .setValue to jQuery's .val - editor.setValue = editor.val; - editor.getValue = editor.val; - return editor; - } + }); } - global.IssuableTemplateSelectors = IssuableTemplateSelectors; -})(window.gl || (window.gl = {})); + initEditor() { + const editor = $('.markdown-area'); + // Proxy ace-editor's .setValue to jQuery's .val + editor.setValue = editor.val; + editor.getValue = editor.val; + return editor; + } +} diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.js index 219ff94924e..13e4cb5717e 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.js @@ -1,5 +1,5 @@ import tooltip from '../../vue_shared/directives/tooltip'; -import '../../lib/utils/text_utility'; +import { pluralize } from '../../lib/utils/text_utility'; export default { name: 'MRWidgetHeader', @@ -14,7 +14,7 @@ export default { return this.mr.divergedCommitsCount > 0; }, commitsText() { - return gl.text.pluralize('commit', this.mr.divergedCommitsCount); + return pluralize('commit', this.mr.divergedCommitsCount); }, branchNameClipboardData() { // This supports code in app/assets/javascripts/copy_to_clipboard.js that diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.js deleted file mode 100644 index 029832bdd27..00000000000 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.js +++ /dev/null @@ -1,90 +0,0 @@ -import PipelineStage from '../../pipelines/components/stage.vue'; -import ciIcon from '../../vue_shared/components/ci_icon.vue'; -import icon from '../../vue_shared/components/icon.vue'; - -export default { - name: 'MRWidgetPipeline', - props: { - mr: { type: Object, required: true }, - }, - components: { - 'pipeline-stage': PipelineStage, - ciIcon, - icon, - }, - computed: { - hasPipeline() { - return this.mr.pipeline && Object.keys(this.mr.pipeline).length > 0; - }, - hasCIError() { - const { hasCI, ciStatus } = this.mr; - - return hasCI && !ciStatus; - }, - stageText() { - return this.mr.pipeline.details.stages.length > 1 ? 'stages' : 'stage'; - }, - status() { - return this.mr.pipeline.details.status || {}; - }, - }, - template: ` - <div - v-if="hasPipeline || hasCIError" - class="mr-widget-heading"> - <div class="ci-widget media"> - <template v-if="hasCIError"> - <div class="ci-status-icon ci-status-icon-failed ci-error js-ci-error append-right-10"> - <span - aria-hidden="true"> - <icon - name="status_failed"/> - </span> - </div> - <div class="media-body"> - Could not connect to the CI server. Please check your settings and try again - </div> - </template> - <template v-else-if="hasPipeline"> - <div class="ci-status-icon append-right-10"> - <a - class="icon-link" - :href="this.status.details_path"> - <ci-icon :status="status" /> - </a> - </div> - <div class="media-body"> - <span> - Pipeline - <a - :href="mr.pipeline.path" - class="pipeline-id">#{{mr.pipeline.id}}</a> - </span> - <span class="mr-widget-pipeline-graph"> - <span class="stage-cell"> - <div - v-if="mr.pipeline.details.stages.length > 0" - v-for="stage in mr.pipeline.details.stages" - class="stage-container dropdown js-mini-pipeline-graph"> - <pipeline-stage :stage="stage" /> - </div> - </span> - </span> - <span> - {{mr.pipeline.details.status.label}} for - <a - :href="mr.pipeline.commit.commit_path" - class="commit-sha js-commit-link"> - {{mr.pipeline.commit.short_id}}</a>. - </span> - <span - v-if="mr.pipeline.coverage" - class="js-mr-coverage"> - Coverage {{mr.pipeline.coverage}}% - </span> - </div> - </template> - </div> - </div> - `, -}; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue new file mode 100644 index 00000000000..dbc65462377 --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue @@ -0,0 +1,104 @@ +<script> + import pipelineStage from '../../pipelines/components/stage.vue'; + import ciIcon from '../../vue_shared/components/ci_icon.vue'; + import icon from '../../vue_shared/components/icon.vue'; + + export default { + name: 'MRWidgetPipeline', + props: { + pipeline: { + type: Object, + required: true, + }, + // This prop needs to be camelCase, html attributes are case insensive + // https://vuejs.org/v2/guide/components.html#camelCase-vs-kebab-case + hasCi: { + type: Boolean, + required: false, + }, + ciStatus: { + type: String, + required: false, + }, + }, + components: { + pipelineStage, + ciIcon, + icon, + }, + computed: { + hasPipeline() { + return this.pipeline && Object.keys(this.pipeline).length > 0; + }, + hasCIError() { + return this.hasCi && !this.ciStatus; + }, + status() { + return this.pipeline.details && + this.pipeline.details.status ? this.pipeline.details.status : {}; + }, + hasStages() { + return this.pipeline.details && + this.pipeline.details.stages && + this.pipeline.details.stages.length; + }, + }, + }; +</script> + +<template> + <div + v-if="hasPipeline || hasCIError" + class="mr-widget-heading"> + <div class="ci-widget media"> + <template v-if="hasCIError"> + <div class="ci-status-icon ci-status-icon-failed ci-error js-ci-error append-right-10"> + <icon name="status_failed" /> + </div> + <div class="media-body"> + Could not connect to the CI server. Please check your settings and try again + </div> + </template> + <template v-else-if="hasPipeline"> + <a + class="append-right-10" + :href="this.status.details_path"> + <ci-icon :status="status" /> + </a> + + <div class="media-body"> + Pipeline + <a + :href="pipeline.path" + class="pipeline-id"> + #{{pipeline.id}} + </a> + + {{pipeline.details.status.label}} for + + <a + :href="pipeline.commit.commit_path" + class="commit-sha js-commit-link"> + {{pipeline.commit.short_id}}</a>. + + <span class="mr-widget-pipeline-graph"> + <span class="stage-cell"> + <div + v-if="hasStages" + v-for="(stage, i) in pipeline.details.stages" + :key="i" + class="stage-container dropdown js-mini-pipeline-graph"> + <pipeline-stage :stage="stage" /> + </div> + </span> + </span> + + <template v-if="pipeline.coverage"> + Coverage {{pipeline.coverage}}% + </template> + + </div> + </template> + </div> + </div> +</template> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.js index 4998a47b691..eeb990908f6 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.js @@ -14,7 +14,7 @@ export default { statusObj() { return { group: this.status, - icon: `icon_status_${this.status}`, + icon: `status_${this.status}`, }; }, }, diff --git a/app/assets/javascripts/vue_merge_request_widget/dependencies.js b/app/assets/javascripts/vue_merge_request_widget/dependencies.js index 49340c232c8..5bd8b99420a 100644 --- a/app/assets/javascripts/vue_merge_request_widget/dependencies.js +++ b/app/assets/javascripts/vue_merge_request_widget/dependencies.js @@ -13,7 +13,7 @@ export { default as Vue } from 'vue'; export { default as SmartInterval } from '~/smart_interval'; export { default as WidgetHeader } from './components/mr_widget_header'; export { default as WidgetMergeHelp } from './components/mr_widget_merge_help'; -export { default as WidgetPipeline } from './components/mr_widget_pipeline'; +export { default as WidgetPipeline } from './components/mr_widget_pipeline.vue'; export { default as WidgetDeployment } from './components/mr_widget_deployment'; export { default as WidgetRelatedLinks } from './components/mr_widget_related_links'; export { default as MergedState } from './components/states/mr_widget_merged'; diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js index aaff9ee6518..9cb3edead86 100644 --- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js +++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js @@ -1,3 +1,4 @@ +import Project from '~/project'; import SmartInterval from '~/smart_interval'; import Flash from '../flash'; import { @@ -61,7 +62,7 @@ export default { return this.mr.hasCI; }, shouldRenderRelatedLinks() { - return this.mr.relatedLinks; + return !!this.mr.relatedLinks; }, shouldRenderDeployments() { return this.mr.deployments.length; @@ -140,6 +141,7 @@ export default { const el = document.createElement('div'); el.innerHTML = res.body; document.body.appendChild(el); + Project.initRefSwitcher(); } }) .catch(() => { @@ -236,7 +238,10 @@ export default { <mr-widget-header :mr="mr" /> <mr-widget-pipeline v-if="shouldRenderPipelines" - :mr="mr" /> + :pipeline="mr.pipeline" + :ci-status="mr.ciStatus" + :has-ci="mr.hasCI" + /> <mr-widget-deployment v-if="shouldRenderDeployments" :mr="mr" diff --git a/app/assets/javascripts/vue_shared/components/icon.vue b/app/assets/javascripts/vue_shared/components/icon.vue index 2e5f9f1088f..4216660da8c 100644 --- a/app/assets/javascripts/vue_shared/components/icon.vue +++ b/app/assets/javascripts/vue_shared/components/icon.vue @@ -6,13 +6,15 @@ Sample configuration: <icon - :img-src="userAvatarSrc" - :img-alt="tooltipText" - :tooltip-text="tooltipText" - tooltip-placement="top" + name="retry" + :size="32" + css-classes="top" /> */ + // only allow classes in images.scss e.g. s12 + const validSizes = [8, 12, 16, 18, 24, 32, 48, 72]; + export default { props: { name: { @@ -23,7 +25,10 @@ size: { type: Number, required: false, - default: 0, + default: 16, + validator(value) { + return validSizes.includes(value); + }, }, cssClasses: { @@ -43,10 +48,11 @@ }, }; </script> + <template> <svg :class="[iconSizeClass, cssClasses]"> - <use + <use v-bind="{'xlink:href':spriteHref}"/> </svg> </template> diff --git a/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue b/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue index 16c0a8efcd2..564fc5029af 100644 --- a/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue +++ b/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue @@ -1,4 +1,6 @@ <script> + import Icon from '../../../vue_shared/components/icon.vue'; + export default { props: { isLocked: { @@ -14,12 +16,16 @@ }, }, + components: { + Icon, + }, + computed: { - iconClass() { - return { - 'fa-eye-slash': this.isConfidential, - 'fa-lock': this.isLocked, - }; + warningIcon() { + if (this.isConfidential) return 'eye-slash'; + if (this.isLocked) return 'lock'; + + return ''; }, isLockedAndConfidential() { @@ -30,12 +36,13 @@ </script> <template> <div class="issuable-note-warning"> - <i - aria-hidden="true" - class="fa icon" - :class="iconClass" - v-if="!isLockedAndConfidential" - ></i> + <icon + :name="warningIcon" + :size="16" + class="icon inline" + aria-hidden="true" + v-if="!isLockedAndConfidential"> + </icon> <span v-if="isLockedAndConfidential"> {{ __('This issue is confidential and locked.') }} diff --git a/app/assets/javascripts/vue_shared/components/loading_button.vue b/app/assets/javascripts/vue_shared/components/loading_button.vue index 0cc2653761c..247943f83e6 100644 --- a/app/assets/javascripts/vue_shared/components/loading_button.vue +++ b/app/assets/javascripts/vue_shared/components/loading_button.vue @@ -35,6 +35,11 @@ export default { type: String, required: false, }, + containerClass: { + type: String, + required: false, + default: 'btn btn-align-content', + }, }, components: { loadingIcon, @@ -49,9 +54,9 @@ export default { <template> <button - class="btn btn-align-content" @click="onClick" type="button" + :class="containerClass" :disabled="loading || disabled" > <transition name="fade"> diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue index a873e00d0f3..15e3d713448 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/field.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue @@ -25,6 +25,16 @@ type: String, required: false, }, + canAttachFile: { + type: Boolean, + required: false, + default: true, + }, + enableAutocomplete: { + type: Boolean, + required: false, + default: true, + }, }, data() { return { @@ -92,7 +102,7 @@ /* GLForm class handles all the toolbar buttons */ - return new GLForm($(this.$refs['gl-form']), true); + return new GLForm($(this.$refs['gl-form']), this.enableAutocomplete); }, beforeDestroy() { const glForm = $(this.$refs['gl-form']).data('gl-form'); @@ -129,6 +139,7 @@ <markdown-toolbar :markdown-docs-path="markdownDocsPath" :quick-actions-docs-path="quickActionsDocsPath" + :can-attach-file="canAttachFile" /> </div> </div> diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue index 70f5fc1d664..6c575d8eb49 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/header.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue @@ -50,7 +50,9 @@ <template> <div class="md-header"> <ul class="nav-links clearfix"> - <li :class="{ active: !previewMarkdown }"> + <li + class="md-header-tab" + :class="{ active: !previewMarkdown }"> <a class="js-write-link" href="#md-write-holder" @@ -59,7 +61,9 @@ Write </a> </li> - <li :class="{ active: previewMarkdown }"> + <li + class="md-header-tab" + :class="{ active: previewMarkdown }"> <a class="js-preview-link" href="#md-preview-holder" @@ -68,56 +72,52 @@ Preview </a> </li> - <li class="pull-right"> - <div class="toolbar-group"> - <toolbar-button - tag="**" - button-title="Add bold text" - icon="bold" /> - <toolbar-button - tag="*" - button-title="Add italic text" - icon="italic" /> - <toolbar-button - tag="> " - :prepend="true" - button-title="Insert a quote" - icon="quote" /> - <toolbar-button - tag="`" - tag-block="```" - button-title="Insert code" - icon="code" /> - <toolbar-button - tag="* " - :prepend="true" - button-title="Add a bullet list" - icon="list-bulleted" /> - <toolbar-button - tag="1. " - :prepend="true" - button-title="Add a numbered list" - icon="list-numbered" /> - <toolbar-button - tag="* [ ] " - :prepend="true" - button-title="Add a task list" - icon="task-done" /> - </div> - <div class="toolbar-group"> - <button - v-tooltip - aria-label="Go full screen" - class="toolbar-btn js-zen-enter" - data-container="body" - tabindex="-1" - title="Go full screen" - type="button"> - <icon - name="screen-full"> - </icon> - </button> - </div> + <li class="md-header-toolbar"> + <toolbar-button + tag="**" + button-title="Add bold text" + icon="bold" /> + <toolbar-button + tag="*" + button-title="Add italic text" + icon="italic" /> + <toolbar-button + tag="> " + :prepend="true" + button-title="Insert a quote" + icon="quote" /> + <toolbar-button + tag="`" + tag-block="```" + button-title="Insert code" + icon="code" /> + <toolbar-button + tag="* " + :prepend="true" + button-title="Add a bullet list" + icon="list-bulleted" /> + <toolbar-button + tag="1. " + :prepend="true" + button-title="Add a numbered list" + icon="list-numbered" /> + <toolbar-button + tag="* [ ] " + :prepend="true" + button-title="Add a task list" + icon="task-done" /> + <button + v-tooltip + aria-label="Go full screen" + class="toolbar-btn toolbar-fullscreen-btn js-zen-enter" + data-container="body" + tabindex="-1" + title="Go full screen" + type="button"> + <icon + name="screen-full"> + </icon> + </button> </li> </ul> </div> diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue index 65fe7bbd94e..ea2509d2839 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue @@ -9,6 +9,11 @@ type: String, required: false, }, + canAttachFile: { + type: Boolean, + required: false, + default: true, + }, }, }; </script> @@ -41,7 +46,10 @@ are supported </template> </div> - <span class="uploading-container"> + <span + v-if="canAttachFile" + class="uploading-container" + > <span class="uploading-progress-container hide"> <i class="fa fa-file-image-o toolbar-button-icon" diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue index b930fb116a3..e3e41f8f0ca 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue @@ -40,7 +40,7 @@ <button v-tooltip type="button" - class="toolbar-btn js-md hidden-xs" + class="toolbar-btn js-md" tabindex="-1" data-container="body" :data-md-tag="tag" diff --git a/app/assets/javascripts/vue_shared/components/navigation_tabs.vue b/app/assets/javascripts/vue_shared/components/navigation_tabs.vue new file mode 100644 index 00000000000..a2ddd565170 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/navigation_tabs.vue @@ -0,0 +1,76 @@ +<script> + /** + * Given an array of tabs, renders non linked bootstrap tabs. + * When a tab is clicked it will trigger an event and provide the clicked scope. + * + * This component is used in apps that handle the API call. + * If you only need to change the URL this component should not be used. + * + * @example + * <navigation-tabs + * :tabs="[ + * { + * name: String, + * scope: String, + * count: Number || Undefined, + * isActive: Boolean, + * }, + * ]" + * @onChangeTab="onChangeTab" + * /> + */ + export default { + name: 'NavigationTabs', + props: { + tabs: { + type: Array, + required: true, + }, + scope: { + type: String, + required: false, + default: '', + }, + }, + mounted() { + $(document).trigger('init.scrolling-tabs'); + }, + methods: { + shouldRenderBadge(count) { + // 0 is valid in a badge, but evaluates to false, we need to check for undefined + return count !== undefined; + }, + + onTabClick(tab) { + this.$emit('onChangeTab', tab.scope); + }, + }, +}; +</script> +<template> + <ul class="nav-links scrolling-tabs"> + <li + v-for="(tab, i) in tabs" + :key="i" + :class="{ + active: tab.isActive, + }" + > + <a + role="button" + @click="onTabClick(tab)" + :class="`js-${scope}-tab-${tab.scope}`" + > + {{ tab.name }} + + <span + v-if="shouldRenderBadge(tab.count)" + class="badge" + > + {{tab.count}} + </span> + + </a> + </li> + </ul> +</template> diff --git a/app/assets/javascripts/vue_shared/components/notes/system_note.vue b/app/assets/javascripts/vue_shared/components/notes/system_note.vue index 98f8f32557d..2248699c399 100644 --- a/app/assets/javascripts/vue_shared/components/notes/system_note.vue +++ b/app/assets/javascripts/vue_shared/components/notes/system_note.vue @@ -17,7 +17,7 @@ * /> */ import { mapGetters } from 'vuex'; - import issueNoteHeader from '../../../notes/components/issue_note_header.vue'; + import noteHeader from '~/notes/components/note_header.vue'; import { spriteIcon } from '../../../lib/utils/common_utils'; export default { @@ -29,7 +29,7 @@ }, }, components: { - issueNoteHeader, + noteHeader, }, computed: { ...mapGetters([ @@ -60,12 +60,12 @@ </div> <div class="timeline-content"> <div class="note-header"> - <issue-note-header + <note-header :author="note.author" :created-at="note.created_at" :note-id="note.id" :action-text-html="note.note_html" - /> + /> </div> </div> </div> diff --git a/app/assets/javascripts/vue_shared/components/pikaday.vue b/app/assets/javascripts/vue_shared/components/pikaday.vue new file mode 100644 index 00000000000..d8d974a2ff7 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/pikaday.vue @@ -0,0 +1,79 @@ +<script> + import Pikaday from 'pikaday'; + import { parsePikadayDate, pikadayToString } from '../../lib/utils/datefix'; + + export default { + name: 'datePicker', + props: { + label: { + type: String, + required: false, + default: 'Date picker', + }, + selectedDate: { + type: Date, + required: false, + }, + minDate: { + type: Date, + required: false, + }, + maxDate: { + type: Date, + required: false, + }, + }, + methods: { + selected(dateText) { + this.$emit('newDateSelected', this.calendar.toString(dateText)); + }, + toggled() { + this.$emit('hidePicker'); + }, + }, + mounted() { + this.calendar = new Pikaday({ + field: this.$el.querySelector('.dropdown-menu-toggle'), + theme: 'gitlab-theme animate-picker', + format: 'yyyy-mm-dd', + container: this.$el, + defaultDate: this.selectedDate, + setDefaultDate: !!this.selectedDate, + minDate: this.minDate, + maxDate: this.maxDate, + parse: dateString => parsePikadayDate(dateString), + toString: date => pikadayToString(date), + onSelect: this.selected.bind(this), + onClose: this.toggled.bind(this), + }); + + this.$el.append(this.calendar.el); + this.calendar.show(); + }, + beforeDestroy() { + this.calendar.destroy(); + }, + }; +</script> + +<template> + <div class="pikaday-container"> + <div class="dropdown open"> + <button + type="button" + class="dropdown-menu-toggle" + data-toggle="dropdown" + @click="toggled" + > + <span class="dropdown-toggle-text"> + {{label}} + </span> + <i + class="fa fa-chevron-down" + aria-hidden="true" + > + </i> + </button> + </div> + </div> +</template> diff --git a/app/assets/javascripts/vue_shared/components/sidebar/collapsed_calendar_icon.vue b/app/assets/javascripts/vue_shared/components/sidebar/collapsed_calendar_icon.vue new file mode 100644 index 00000000000..a88e1310131 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/sidebar/collapsed_calendar_icon.vue @@ -0,0 +1,46 @@ +<script> + export default { + name: 'collapsedCalendarIcon', + props: { + containerClass: { + type: String, + required: false, + default: '', + }, + text: { + type: String, + required: false, + default: '', + }, + showIcon: { + type: Boolean, + required: false, + default: true, + }, + }, + methods: { + click() { + this.$emit('click'); + }, + }, + }; +</script> + +<template> + <div + :class="containerClass" + @click="click" + > + <i + v-if="showIcon" + class="fa fa-calendar" + aria-hidden="true" + > + </i> + <slot> + <span> + {{ text }} + </span> + </slot> + </div> +</template> diff --git a/app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue b/app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue new file mode 100644 index 00000000000..9ede5553bc5 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue @@ -0,0 +1,109 @@ +<script> + import { dateInWords } from '../../../lib/utils/datetime_utility'; + import toggleSidebar from './toggle_sidebar.vue'; + import collapsedCalendarIcon from './collapsed_calendar_icon.vue'; + + export default { + name: 'sidebarCollapsedGroupedDatePicker', + props: { + collapsed: { + type: Boolean, + required: false, + default: true, + }, + showToggleSidebar: { + type: Boolean, + required: false, + default: false, + }, + minDate: { + type: Date, + required: false, + }, + maxDate: { + type: Date, + required: false, + }, + disableClickableIcons: { + type: Boolean, + required: false, + default: false, + }, + }, + components: { + toggleSidebar, + collapsedCalendarIcon, + }, + computed: { + hasMinAndMaxDates() { + return this.minDate && this.maxDate; + }, + hasNoMinAndMaxDates() { + return !this.minDate && !this.maxDate; + }, + showMinDateBlock() { + return this.minDate || this.hasNoMinAndMaxDates; + }, + showFromText() { + return !this.maxDate && this.minDate; + }, + iconClass() { + const disabledClass = this.disableClickableIcons ? 'disabled' : ''; + return `block sidebar-collapsed-icon calendar-icon ${disabledClass}`; + }, + }, + methods: { + toggleSidebar() { + this.$emit('toggleCollapse'); + }, + dateText(dateType = 'min') { + const date = this[`${dateType}Date`]; + const dateWords = dateInWords(date, true); + const parsedDateWords = dateWords ? dateWords.replace(',', '') : dateWords; + + return date ? parsedDateWords : 'None'; + }, + }, + }; +</script> + +<template> + <div class="block sidebar-grouped-item"> + <div + v-if="showToggleSidebar" + class="issuable-sidebar-header" + > + <toggle-sidebar + :collapsed="collapsed" + @toggle="toggleSidebar" + /> + </div> + <collapsed-calendar-icon + v-if="showMinDateBlock" + :container-class="iconClass" + @click="toggleSidebar" + > + <span class="sidebar-collapsed-value"> + <span v-if="showFromText">From</span> + <span>{{ dateText('min') }}</span> + </span> + </collapsed-calendar-icon> + <div + v-if="hasMinAndMaxDates" + class="text-center sidebar-collapsed-divider" + > + - + </div> + <collapsed-calendar-icon + v-if="maxDate" + :container-class="iconClass" + :show-icon="!minDate" + @click="toggleSidebar" + > + <span class="sidebar-collapsed-value"> + <span v-if="!minDate">Until</span> + <span>{{ dateText('max') }}</span> + </span> + </collapsed-calendar-icon> + </div> +</template> diff --git a/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue b/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue new file mode 100644 index 00000000000..9c3413377a3 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue @@ -0,0 +1,163 @@ +<script> + import datePicker from '../pikaday.vue'; + import loadingIcon from '../loading_icon.vue'; + import toggleSidebar from './toggle_sidebar.vue'; + import collapsedCalendarIcon from './collapsed_calendar_icon.vue'; + import { dateInWords } from '../../../lib/utils/datetime_utility'; + + export default { + name: 'sidebarDatePicker', + props: { + collapsed: { + type: Boolean, + required: false, + default: true, + }, + showToggleSidebar: { + type: Boolean, + required: false, + default: false, + }, + isLoading: { + type: Boolean, + required: false, + default: false, + }, + editable: { + type: Boolean, + required: false, + default: false, + }, + label: { + type: String, + required: false, + default: 'Date picker', + }, + selectedDate: { + type: Date, + required: false, + }, + minDate: { + type: Date, + required: false, + }, + maxDate: { + type: Date, + required: false, + }, + }, + data() { + return { + editing: false, + }; + }, + components: { + datePicker, + toggleSidebar, + loadingIcon, + collapsedCalendarIcon, + }, + computed: { + selectedAndEditable() { + return this.selectedDate && this.editable; + }, + selectedDateWords() { + return dateInWords(this.selectedDate, true); + }, + collapsedText() { + return this.selectedDateWords ? this.selectedDateWords : 'None'; + }, + }, + methods: { + stopEditing() { + this.editing = false; + }, + toggleDatePicker() { + this.editing = !this.editing; + }, + newDateSelected(date = null) { + this.date = date; + this.editing = false; + this.$emit('saveDate', date); + }, + toggleSidebar() { + this.$emit('toggleCollapse'); + }, + }, + }; +</script> + +<template> + <div class="block"> + <div class="issuable-sidebar-header"> + <toggle-sidebar + :collapsed="collapsed" + @toggle="toggleSidebar" + /> + </div> + <collapsed-calendar-icon + class="sidebar-collapsed-icon" + :text="collapsedText" + /> + <div class="title"> + {{ label }} + <loading-icon + v-if="isLoading" + :inline="true" + /> + <div class="pull-right"> + <button + v-if="editable && !editing" + type="button" + class="btn-blank btn-link btn-primary-hover-link btn-sidebar-action" + @click="toggleDatePicker" + > + Edit + </button> + <toggle-sidebar + v-if="showToggleSidebar" + :collapsed="collapsed" + @toggle="toggleSidebar" + /> + </div> + </div> + <div class="value"> + <date-picker + v-if="editing" + :selected-date="selectedDate" + :min-date="minDate" + :max-date="maxDate" + :label="label" + @newDateSelected="newDateSelected" + @hidePicker="stopEditing" + /> + <span + v-else + class="value-content" + > + <template v-if="selectedDate"> + <strong>{{ selectedDateWords }}</strong> + <span + v-if="selectedAndEditable" + class="no-value" + > + - + <button + type="button" + class="btn-blank btn-link btn-secondary-hover-link" + @click="newDateSelected(null)" + > + remove + </button> + </span> + </template> + <span + v-else + class="no-value" + > + None + </span> + </span> + </div> + </div> +</template> diff --git a/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue b/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue new file mode 100644 index 00000000000..5ae76adad71 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue @@ -0,0 +1,30 @@ +<script> + export default { + name: 'toggleSidebar', + props: { + collapsed: { + type: Boolean, + required: true, + }, + }, + methods: { + toggle() { + this.$emit('toggle'); + }, + }, + }; +</script> + +<template> + <button + type="button" + class="btn btn-blank gutter-toggle btn-sidebar-action" + @click="toggle" + > + <i + aria-label="toggle collapse" + class="fa" + :class="{ 'fa-angle-double-right': !collapsed, 'fa-angle-double-left': collapsed }" + ></i> + </button> +</template> diff --git a/app/assets/javascripts/vue_shared/components/toggle_button.vue b/app/assets/javascripts/vue_shared/components/toggle_button.vue new file mode 100644 index 00000000000..ddc9ddbc3a3 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/toggle_button.vue @@ -0,0 +1,77 @@ +<script> + import loadingIcon from './loading_icon.vue'; + + export default { + props: { + name: { + type: String, + required: false, + default: '', + }, + value: { + type: Boolean, + required: true, + }, + disabledInput: { + type: Boolean, + required: false, + default: false, + }, + isLoading: { + type: Boolean, + required: false, + default: false, + }, + enabledText: { + type: String, + required: false, + default: 'Enabled', + }, + disabledText: { + type: String, + required: false, + default: 'Disabled', + }, + }, + + components: { + loadingIcon, + }, + + model: { + prop: 'value', + event: 'change', + }, + + methods: { + toggleFeature() { + if (!this.disabledInput) this.$emit('change', !this.value); + }, + }, + }; +</script> + +<template> + <label class="toggle-wrapper"> + <input + type="hidden" + :name="name" + :value="value" + /> + <button + type="button" + aria-label="Toggle" + class="project-feature-toggle" + :data-enabled-text="enabledText" + :data-disabled-text="disabledText" + :class="{ + 'is-checked': value, + 'is-disabled': disabledInput, + 'is-loading': isLoading + }" + @click="toggleFeature" + > + <loadingIcon class="loading-icon" /> + </button> + </label> +</template> diff --git a/app/assets/javascripts/vue_shared/mixins/ci_pagination_api_mixin.js b/app/assets/javascripts/vue_shared/mixins/ci_pagination_api_mixin.js new file mode 100644 index 00000000000..f94cc670edf --- /dev/null +++ b/app/assets/javascripts/vue_shared/mixins/ci_pagination_api_mixin.js @@ -0,0 +1,42 @@ +/** + * API callbacks for pagination and tabs + * shared between Pipelines and Environments table. + * + * Components need to have `scope`, `page` and `requestData` + */ +import { + historyPushState, + buildUrlWithCurrentLocation, +} from '../../lib/utils/common_utils'; + +export default { + methods: { + onChangeTab(scope) { + this.updateContent({ scope, page: '1' }); + }, + + onChangePage(page) { + /* URLS parameters are strings, we need to parse to match types */ + this.updateContent({ scope: this.scope, page: Number(page).toString() }); + }, + + updateInternalState(parameters) { + // stop polling + this.poll.stop(); + + const queryString = Object.keys(parameters).map((parameter) => { + const value = parameters[parameter]; + // update internal state for UI + this[parameter] = value; + return `${parameter}=${encodeURIComponent(value)}`; + }).join('&'); + + // update polling parameters + this.requestData = parameters; + + historyPushState(buildUrlWithCurrentLocation(`?${queryString}`)); + + this.isLoading = true; + }, + }, +}; diff --git a/app/assets/javascripts/vue_shared/mixins/issuable.js b/app/assets/javascripts/vue_shared/mixins/issuable.js index 263361587e0..fab0919d96e 100644 --- a/app/assets/javascripts/vue_shared/mixins/issuable.js +++ b/app/assets/javascripts/vue_shared/mixins/issuable.js @@ -1,9 +1,14 @@ export default { - methods: { - issuableDisplayName(issuableType) { - const displayName = issuableType.replace(/_/, ' '); + props: { + issuableType: { + required: true, + type: String, + }, + }, - return this.__ ? this.__(displayName) : displayName; + computed: { + issuableDisplayName() { + return this.issuableType.replace(/_/g, ' '); }, }, }; diff --git a/app/assets/javascripts/wikis.js b/app/assets/javascripts/wikis.js index a0025ddb598..7a865587444 100644 --- a/app/assets/javascripts/wikis.js +++ b/app/assets/javascripts/wikis.js @@ -1,4 +1,5 @@ import bp from './breakpoints'; +import { slugify } from './lib/utils/text_utility'; export default class Wikis { constructor() { @@ -23,7 +24,7 @@ export default class Wikis { if (!this.newWikiForm) return; const slugInput = this.newWikiForm.querySelector('#new_wiki_path'); - const slug = gl.text.slugify(slugInput.value); + const slug = slugify(slugInput.value); if (slug.length > 0) { const wikisPath = slugInput.getAttribute('data-wikis-path'); diff --git a/app/assets/javascripts/zen_mode.js b/app/assets/javascripts/zen_mode.js index cba7b9227cd..06a86f3b94a 100644 --- a/app/assets/javascripts/zen_mode.js +++ b/app/assets/javascripts/zen_mode.js @@ -71,7 +71,7 @@ export default class ZenMode { this.active_textarea = this.active_backdrop.find('textarea'); // Prevent a user-resized textarea from persisting to fullscreen this.active_textarea.removeAttr('style'); - return this.active_textarea.focus(); + this.active_textarea.focus(); } exit() { @@ -81,7 +81,11 @@ export default class ZenMode { this.scrollTo(this.active_textarea); this.active_textarea = null; this.active_backdrop = null; - return Dropzone.forElement('.div-dropzone').enable(); + + const $dropzone = $('.div-dropzone'); + if ($dropzone && !$dropzone.hasClass('js-invalid-dropzone')) { + Dropzone.forElement('.div-dropzone').enable(); + } } } diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss index c334f39f416..43b16d3cf7d 100644 --- a/app/assets/stylesheets/framework.scss +++ b/app/assets/stylesheets/framework.scss @@ -34,6 +34,7 @@ @import "framework/modal"; @import "framework/pagination"; @import "framework/panels"; +@import "framework/popup"; @import "framework/secondary-navigation-elements"; @import "framework/selects"; @import "framework/sidebar"; @@ -43,6 +44,7 @@ @import "framework/tabs"; @import "framework/timeline"; @import "framework/tooltips"; +@import "framework/toggle"; @import "framework/typography"; @import "framework/zen"; @import "framework/blank"; diff --git a/app/assets/stylesheets/framework/animations.scss b/app/assets/stylesheets/framework/animations.scss index 374988bb590..728f9a27aca 100644 --- a/app/assets/stylesheets/framework/animations.scss +++ b/app/assets/stylesheets/framework/animations.scss @@ -125,7 +125,7 @@ @include transition(border-color); } -.note-action-button .link-highlight, +.note-action-button, .toolbar-btn, .dropdown-toggle-caret { @include transition(color); diff --git a/app/assets/stylesheets/framework/blank.scss b/app/assets/stylesheets/framework/blank.scss index 6bb096fc5bd..9982a5779af 100644 --- a/app/assets/stylesheets/framework/blank.scss +++ b/app/assets/stylesheets/framework/blank.scss @@ -7,29 +7,76 @@ width: 100%; height: 100%; padding-bottom: 25px; - border: 1px solid $border-color; border-radius: $border-radius-default; } } -.blank-state { - padding-top: 20px; - padding-bottom: 20px; +.blank-state-row { + display: flex; + flex-wrap: wrap; + justify-content: space-around; + height: 100%; +} + +.blank-state-welcome { text-align: center; + padding: 20px 0 40px; + + .blank-state-welcome-title { + font-size: 24px; + } + + .blank-state-text { + margin-bottom: 0; + } +} + +.blank-state-link { + display: block; + color: $gl-text-color; + flex: 0 0 100%; + margin-bottom: 15px; - &.blank-state-welcome { - .blank-state-welcome-title { - font-size: 24px; + @media (min-width: $screen-sm-min) { + flex: 0 0 49%; + + &:nth-child(odd) { + margin-right: 5px; } - .blank-state-text { - margin-bottom: 0; + &:nth-child(even) { + margin-left: 5px; } } - .blank-state-icon { - padding-bottom: 20px; + &:hover { + background-color: $gray-light; + text-decoration: none; + color: $gl-text-color; + } +} +.blank-state-center { + padding-top: 20px; + padding-bottom: 20px; + text-align: center; +} + +.blank-state { + padding: 20px; + border: 1px solid $border-color; + border-radius: $border-radius-default; + + @media (min-width: $screen-sm-min) { + display: flex; + align-items: center; + padding: 50px 30px; + } +} + +.blank-state, +.blank-state-center { + .blank-state-icon { svg { display: block; margin: auto; @@ -38,13 +85,17 @@ .blank-state-title { margin-top: 0; - margin-bottom: 10px; font-size: 18px; } - .blank-state-text { - max-width: $container-text-max-width; - margin: 0 auto $gl-padding; - font-size: 14px; + .blank-state-body { + @media (max-width: $screen-xs-max) { + text-align: center; + margin-top: 20px; + } + + @media (min-width: $screen-sm-min) { + padding-left: 20px; + } } } diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss index 9c1439dfad5..91976ca1f56 100644 --- a/app/assets/stylesheets/framework/blocks.scss +++ b/app/assets/stylesheets/framework/blocks.scss @@ -353,3 +353,7 @@ display: -webkit-flex; display: flex; } + +.flex-right { + margin-left: auto; +} diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss index b2f26cf7159..3f630f82e29 100644 --- a/app/assets/stylesheets/framework/buttons.scss +++ b/app/assets/stylesheets/framework/buttons.scss @@ -88,17 +88,6 @@ border-color: $border-dark; color: $color; } - - svg { - - path { - fill: $color; - } - - use { - stroke: $color; - } - } } @mixin btn-green { @@ -142,6 +131,13 @@ } } +@mixin btn-svg { + height: $gl-padding; + width: $gl-padding; + top: 0; + vertical-align: text-top; +} + .btn { @include btn-default; @include btn-white; @@ -243,6 +239,16 @@ } } + &.dot-highlight::after { + content: ''; + background-color: $blue-500; + width: $gl-padding * 0.5; + height: $gl-padding * 0.5; + display: inline-block; + border-radius: 50%; + margin-left: 3px; + } + svg { height: 15px; width: 15px; @@ -408,6 +414,7 @@ padding: 0; background: transparent; border: 0; + border-radius: 0; &:hover, &:active, @@ -417,3 +424,29 @@ box-shadow: none; } } + +.btn-link.btn-secondary-hover-link { + color: $gl-text-color-secondary; + + &:hover, + &:active, + &:focus { + color: $gl-link-color; + text-decoration: none; + } +} + +.btn-link.btn-primary-hover-link { + color: inherit; + + &:hover, + &:active, + &:focus { + color: $gl-link-color; + text-decoration: none; + } +} + +.btn-svg svg { + @include btn-svg; +} diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 5f5b5657a2f..73524d5cf60 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -4,11 +4,41 @@ .cred { color: $common-red; } .cgreen { color: $common-green; } .cdark { color: $common-gray-dark; } + +.text-plain, +.text-plain:hover { + color: $gl-text-color; +} + .text-secondary { color: $gl-text-color-secondary; } -.underlined-link { text-decoration: underline; } +.text-primary, +.text-primary:hover { + color: $brand-primary; +} + +.text-success, +.text-success:hover { + color: $brand-success; +} + +.text-danger, +.text-danger:hover { + color: $brand-danger; +} + +.text-warning, +.text-warning:hover { + color: $brand-warning; +} + +.text-info, +.text-info:hover { + color: $brand-info; +} + .hint { font-style: italic; color: $hint-color; } .light { color: $common-gray; } @@ -207,19 +237,6 @@ li.note { } } -.browser-alert { - padding: 10px; - text-align: center; - background: $error-bg; - color: $white-light; - font-weight: $gl-font-weight-bold; - - a { - color: $white-light; - text-decoration: underline; - } -} - .warning_message { border-left: 4px solid $warning-message-border; color: $warning-message-color; @@ -428,6 +445,7 @@ img.emoji { /** COMMON CLASSES **/ .prepend-top-0 { margin-top: 0; } .prepend-top-5 { margin-top: 5px; } +.prepend-top-8 { margin-top: $grid-size; } .prepend-top-10 { margin-top: 10px; } .prepend-top-15 { margin-top: 15px; } .prepend-top-default { margin-top: $gl-padding !important; } diff --git a/app/assets/stylesheets/framework/contextual-sidebar.scss b/app/assets/stylesheets/framework/contextual-sidebar.scss index 320f458630a..b73932eb7e1 100644 --- a/app/assets/stylesheets/framework/contextual-sidebar.scss +++ b/app/assets/stylesheets/framework/contextual-sidebar.scss @@ -40,12 +40,6 @@ a:hover { background-color: $link-hover-background; color: $gl-text-color; - - .settings-avatar { - svg { - fill: $gl-text-color; - } - } } .avatar-container { @@ -138,10 +132,6 @@ color: $gl-text-color-secondary; } - svg { - fill: $gl-text-color-secondary; - } - .nav-item-name { flex: 1; } @@ -224,10 +214,6 @@ &:hover { color: $gl-text-color; - - svg { - fill: $gl-text-color; - } } } @@ -338,7 +324,6 @@ align-items: center; svg { - fill: $gl-text-color-secondary; margin-right: 8px; } @@ -349,10 +334,6 @@ &:hover { background-color: $border-color; color: $gl-text-color; - - svg { - fill: $gl-text-color; - } } } diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index 579bd48fac6..8d83554d813 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -608,7 +608,7 @@ } .dropdown-content { - max-height: 215px; + max-height: $dropdown-max-height; overflow-y: auto; } @@ -1002,6 +1002,7 @@ header.header-content .dropdown-menu.projects-dropdown-menu { max-width: 250px; overflow: hidden; text-overflow: ellipsis; + white-space: nowrap; } &:hover { @@ -1029,3 +1030,28 @@ header.header-content .dropdown-menu.projects-dropdown-menu { } } } + +.dropdown-content-faded-mask { + position: relative; + + .dropdown-list { + max-height: $dropdown-max-height; + overflow-y: auto; + position: relative; + } + + &::after { + height: $dropdown-fade-mask-height; + width: 100%; + position: absolute; + bottom: 0; + background: linear-gradient(to top, $white-light 0, rgba($white-light, 0)); + transition: opacity $fade-mask-transition-duration $fade-mask-transition-curve; + content: ''; + pointer-events: none; + } + + &.fade-out::after { + opacity: 0; + } +} diff --git a/app/assets/stylesheets/framework/emoji-sprites.scss b/app/assets/stylesheets/framework/emoji-sprites.scss index 925415f84b1..0174e17b660 100644 --- a/app/assets/stylesheets/framework/emoji-sprites.scss +++ b/app/assets/stylesheets/framework/emoji-sprites.scss @@ -765,1031 +765,1033 @@ .emoji-full_moon { background-position: -160px -540px; } .emoji-full_moon_with_face { background-position: -180px -540px; } .emoji-game_die { background-position: -200px -540px; } -.emoji-gear { background-position: -220px -540px; } -.emoji-gem { background-position: -240px -540px; } -.emoji-gemini { background-position: -260px -540px; } -.emoji-ghost { background-position: -280px -540px; } -.emoji-gift { background-position: -300px -540px; } -.emoji-gift_heart { background-position: -320px -540px; } -.emoji-girl { background-position: -340px -540px; } -.emoji-girl_tone1 { background-position: -360px -540px; } -.emoji-girl_tone2 { background-position: -380px -540px; } -.emoji-girl_tone3 { background-position: -400px -540px; } -.emoji-girl_tone4 { background-position: -420px -540px; } -.emoji-girl_tone5 { background-position: -440px -540px; } -.emoji-globe_with_meridians { background-position: -460px -540px; } -.emoji-goal { background-position: -480px -540px; } -.emoji-goat { background-position: -500px -540px; } -.emoji-golf { background-position: -520px -540px; } -.emoji-golfer { background-position: -540px -540px; } -.emoji-gorilla { background-position: -560px 0; } -.emoji-grapes { background-position: -560px -20px; } -.emoji-green_apple { background-position: -560px -40px; } -.emoji-green_book { background-position: -560px -60px; } -.emoji-green_heart { background-position: -560px -80px; } -.emoji-grey_exclamation { background-position: -560px -100px; } -.emoji-grey_question { background-position: -560px -120px; } -.emoji-grimacing { background-position: -560px -140px; } -.emoji-grin { background-position: -560px -160px; } -.emoji-grinning { background-position: -560px -180px; } -.emoji-guardsman { background-position: -560px -200px; } -.emoji-guardsman_tone1 { background-position: -560px -220px; } -.emoji-guardsman_tone2 { background-position: -560px -240px; } -.emoji-guardsman_tone3 { background-position: -560px -260px; } -.emoji-guardsman_tone4 { background-position: -560px -280px; } -.emoji-guardsman_tone5 { background-position: -560px -300px; } -.emoji-guitar { background-position: -560px -320px; } -.emoji-gun { background-position: -560px -340px; } -.emoji-haircut { background-position: -560px -360px; } -.emoji-haircut_tone1 { background-position: -560px -380px; } -.emoji-haircut_tone2 { background-position: -560px -400px; } -.emoji-haircut_tone3 { background-position: -560px -420px; } -.emoji-haircut_tone4 { background-position: -560px -440px; } -.emoji-haircut_tone5 { background-position: -560px -460px; } -.emoji-hamburger { background-position: -560px -480px; } -.emoji-hammer { background-position: -560px -500px; } -.emoji-hammer_pick { background-position: -560px -520px; } -.emoji-hamster { background-position: -560px -540px; } -.emoji-hand_splayed { background-position: 0 -560px; } -.emoji-hand_splayed_tone1 { background-position: -20px -560px; } -.emoji-hand_splayed_tone2 { background-position: -40px -560px; } -.emoji-hand_splayed_tone3 { background-position: -60px -560px; } -.emoji-hand_splayed_tone4 { background-position: -80px -560px; } -.emoji-hand_splayed_tone5 { background-position: -100px -560px; } -.emoji-handbag { background-position: -120px -560px; } -.emoji-handball { background-position: -140px -560px; } -.emoji-handball_tone1 { background-position: -160px -560px; } -.emoji-handball_tone2 { background-position: -180px -560px; } -.emoji-handball_tone3 { background-position: -200px -560px; } -.emoji-handball_tone4 { background-position: -220px -560px; } -.emoji-handball_tone5 { background-position: -240px -560px; } -.emoji-handshake { background-position: -260px -560px; } -.emoji-handshake_tone1 { background-position: -280px -560px; } -.emoji-handshake_tone2 { background-position: -300px -560px; } -.emoji-handshake_tone3 { background-position: -320px -560px; } -.emoji-handshake_tone4 { background-position: -340px -560px; } -.emoji-handshake_tone5 { background-position: -360px -560px; } -.emoji-hash { background-position: -380px -560px; } -.emoji-hatched_chick { background-position: -400px -560px; } -.emoji-hatching_chick { background-position: -420px -560px; } -.emoji-head_bandage { background-position: -440px -560px; } -.emoji-headphones { background-position: -460px -560px; } -.emoji-hear_no_evil { background-position: -480px -560px; } -.emoji-heart { background-position: -500px -560px; } -.emoji-heart_decoration { background-position: -520px -560px; } -.emoji-heart_exclamation { background-position: -540px -560px; } -.emoji-heart_eyes { background-position: -560px -560px; } -.emoji-heart_eyes_cat { background-position: -580px 0; } -.emoji-heartbeat { background-position: -580px -20px; } -.emoji-heartpulse { background-position: -580px -40px; } -.emoji-hearts { background-position: -580px -60px; } -.emoji-heavy_check_mark { background-position: -580px -80px; } -.emoji-heavy_division_sign { background-position: -580px -100px; } -.emoji-heavy_dollar_sign { background-position: -580px -120px; } -.emoji-heavy_minus_sign { background-position: -580px -140px; } -.emoji-heavy_multiplication_x { background-position: -580px -160px; } -.emoji-heavy_plus_sign { background-position: -580px -180px; } -.emoji-helicopter { background-position: -580px -200px; } -.emoji-helmet_with_cross { background-position: -580px -220px; } -.emoji-herb { background-position: -580px -240px; } -.emoji-hibiscus { background-position: -580px -260px; } -.emoji-high_brightness { background-position: -580px -280px; } -.emoji-high_heel { background-position: -580px -300px; } -.emoji-hockey { background-position: -580px -320px; } -.emoji-hole { background-position: -580px -340px; } -.emoji-homes { background-position: -580px -360px; } -.emoji-honey_pot { background-position: -580px -380px; } -.emoji-horse { background-position: -580px -400px; } -.emoji-horse_racing { background-position: -580px -420px; } -.emoji-horse_racing_tone1 { background-position: -580px -440px; } -.emoji-horse_racing_tone2 { background-position: -580px -460px; } -.emoji-horse_racing_tone3 { background-position: -580px -480px; } -.emoji-horse_racing_tone4 { background-position: -580px -500px; } -.emoji-horse_racing_tone5 { background-position: -580px -520px; } -.emoji-hospital { background-position: -580px -540px; } -.emoji-hot_pepper { background-position: -580px -560px; } -.emoji-hotdog { background-position: 0 -580px; } -.emoji-hotel { background-position: -20px -580px; } -.emoji-hotsprings { background-position: -40px -580px; } -.emoji-hourglass { background-position: -60px -580px; } -.emoji-hourglass_flowing_sand { background-position: -80px -580px; } -.emoji-house { background-position: -100px -580px; } -.emoji-house_abandoned { background-position: -120px -580px; } -.emoji-house_with_garden { background-position: -140px -580px; } -.emoji-hugging { background-position: -160px -580px; } -.emoji-hushed { background-position: -180px -580px; } -.emoji-ice_cream { background-position: -200px -580px; } -.emoji-ice_skate { background-position: -220px -580px; } -.emoji-icecream { background-position: -240px -580px; } -.emoji-id { background-position: -260px -580px; } -.emoji-ideograph_advantage { background-position: -280px -580px; } -.emoji-imp { background-position: -300px -580px; } -.emoji-inbox_tray { background-position: -320px -580px; } -.emoji-incoming_envelope { background-position: -340px -580px; } -.emoji-information_desk_person { background-position: -360px -580px; } -.emoji-information_desk_person_tone1 { background-position: -380px -580px; } -.emoji-information_desk_person_tone2 { background-position: -400px -580px; } -.emoji-information_desk_person_tone3 { background-position: -420px -580px; } -.emoji-information_desk_person_tone4 { background-position: -440px -580px; } -.emoji-information_desk_person_tone5 { background-position: -460px -580px; } -.emoji-information_source { background-position: -480px -580px; } -.emoji-innocent { background-position: -500px -580px; } -.emoji-interrobang { background-position: -520px -580px; } -.emoji-iphone { background-position: -540px -580px; } -.emoji-island { background-position: -560px -580px; } -.emoji-izakaya_lantern { background-position: -580px -580px; } -.emoji-jack_o_lantern { background-position: -600px 0; } -.emoji-japan { background-position: -600px -20px; } -.emoji-japanese_castle { background-position: -600px -40px; } -.emoji-japanese_goblin { background-position: -600px -60px; } -.emoji-japanese_ogre { background-position: -600px -80px; } -.emoji-jeans { background-position: -600px -100px; } -.emoji-joy { background-position: -600px -120px; } -.emoji-joy_cat { background-position: -600px -140px; } -.emoji-joystick { background-position: -600px -160px; } -.emoji-juggling { background-position: -600px -180px; } -.emoji-juggling_tone1 { background-position: -600px -200px; } -.emoji-juggling_tone2 { background-position: -600px -220px; } -.emoji-juggling_tone3 { background-position: -600px -240px; } -.emoji-juggling_tone4 { background-position: -600px -260px; } -.emoji-juggling_tone5 { background-position: -600px -280px; } -.emoji-kaaba { background-position: -600px -300px; } -.emoji-key { background-position: -600px -320px; } -.emoji-key2 { background-position: -600px -340px; } -.emoji-keyboard { background-position: -600px -360px; } -.emoji-kimono { background-position: -600px -380px; } -.emoji-kiss { background-position: -600px -400px; } -.emoji-kiss_mm { background-position: -600px -420px; } -.emoji-kiss_ww { background-position: -600px -440px; } -.emoji-kissing { background-position: -600px -460px; } -.emoji-kissing_cat { background-position: -600px -480px; } -.emoji-kissing_closed_eyes { background-position: -600px -500px; } -.emoji-kissing_heart { background-position: -600px -520px; } -.emoji-kissing_smiling_eyes { background-position: -600px -540px; } -.emoji-kiwi { background-position: -600px -560px; } -.emoji-knife { background-position: -600px -580px; } -.emoji-koala { background-position: 0 -600px; } -.emoji-koko { background-position: -20px -600px; } -.emoji-label { background-position: -40px -600px; } -.emoji-large_blue_circle { background-position: -60px -600px; } -.emoji-large_blue_diamond { background-position: -80px -600px; } -.emoji-large_orange_diamond { background-position: -100px -600px; } -.emoji-last_quarter_moon { background-position: -120px -600px; } -.emoji-last_quarter_moon_with_face { background-position: -140px -600px; } -.emoji-laughing { background-position: -160px -600px; } -.emoji-leaves { background-position: -180px -600px; } -.emoji-ledger { background-position: -200px -600px; } -.emoji-left_facing_fist { background-position: -220px -600px; } -.emoji-left_facing_fist_tone1 { background-position: -240px -600px; } -.emoji-left_facing_fist_tone2 { background-position: -260px -600px; } -.emoji-left_facing_fist_tone3 { background-position: -280px -600px; } -.emoji-left_facing_fist_tone4 { background-position: -300px -600px; } -.emoji-left_facing_fist_tone5 { background-position: -320px -600px; } -.emoji-left_luggage { background-position: -340px -600px; } -.emoji-left_right_arrow { background-position: -360px -600px; } -.emoji-leftwards_arrow_with_hook { background-position: -380px -600px; } -.emoji-lemon { background-position: -400px -600px; } -.emoji-leo { background-position: -420px -600px; } -.emoji-leopard { background-position: -440px -600px; } -.emoji-level_slider { background-position: -460px -600px; } -.emoji-levitate { background-position: -480px -600px; } -.emoji-libra { background-position: -500px -600px; } -.emoji-lifter { background-position: -520px -600px; } -.emoji-lifter_tone1 { background-position: -540px -600px; } -.emoji-lifter_tone2 { background-position: -560px -600px; } -.emoji-lifter_tone3 { background-position: -580px -600px; } -.emoji-lifter_tone4 { background-position: -600px -600px; } -.emoji-lifter_tone5 { background-position: -620px 0; } -.emoji-light_rail { background-position: -620px -20px; } -.emoji-link { background-position: -620px -40px; } -.emoji-lion_face { background-position: -620px -60px; } -.emoji-lips { background-position: -620px -80px; } -.emoji-lipstick { background-position: -620px -100px; } -.emoji-lizard { background-position: -620px -120px; } -.emoji-lock { background-position: -620px -140px; } -.emoji-lock_with_ink_pen { background-position: -620px -160px; } -.emoji-lollipop { background-position: -620px -180px; } -.emoji-loop { background-position: -620px -200px; } -.emoji-loud_sound { background-position: -620px -220px; } -.emoji-loudspeaker { background-position: -620px -240px; } -.emoji-love_hotel { background-position: -620px -260px; } -.emoji-love_letter { background-position: -620px -280px; } -.emoji-low_brightness { background-position: -620px -300px; } -.emoji-lying_face { background-position: -620px -320px; } -.emoji-m { background-position: -620px -340px; } -.emoji-mag { background-position: -620px -360px; } -.emoji-mag_right { background-position: -620px -380px; } -.emoji-mahjong { background-position: -620px -400px; } -.emoji-mailbox { background-position: -620px -420px; } -.emoji-mailbox_closed { background-position: -620px -440px; } -.emoji-mailbox_with_mail { background-position: -620px -460px; } -.emoji-mailbox_with_no_mail { background-position: -620px -480px; } -.emoji-man { background-position: -620px -500px; } -.emoji-man_dancing { background-position: -620px -520px; } -.emoji-man_dancing_tone1 { background-position: -620px -540px; } -.emoji-man_dancing_tone2 { background-position: -620px -560px; } -.emoji-man_dancing_tone3 { background-position: -620px -580px; } -.emoji-man_dancing_tone4 { background-position: -620px -600px; } -.emoji-man_dancing_tone5 { background-position: 0 -620px; } -.emoji-man_in_tuxedo { background-position: -20px -620px; } -.emoji-man_in_tuxedo_tone1 { background-position: -40px -620px; } -.emoji-man_in_tuxedo_tone2 { background-position: -60px -620px; } -.emoji-man_in_tuxedo_tone3 { background-position: -80px -620px; } -.emoji-man_in_tuxedo_tone4 { background-position: -100px -620px; } -.emoji-man_in_tuxedo_tone5 { background-position: -120px -620px; } -.emoji-man_tone1 { background-position: -140px -620px; } -.emoji-man_tone2 { background-position: -160px -620px; } -.emoji-man_tone3 { background-position: -180px -620px; } -.emoji-man_tone4 { background-position: -200px -620px; } -.emoji-man_tone5 { background-position: -220px -620px; } -.emoji-man_with_gua_pi_mao { background-position: -240px -620px; } -.emoji-man_with_gua_pi_mao_tone1 { background-position: -260px -620px; } -.emoji-man_with_gua_pi_mao_tone2 { background-position: -280px -620px; } -.emoji-man_with_gua_pi_mao_tone3 { background-position: -300px -620px; } -.emoji-man_with_gua_pi_mao_tone4 { background-position: -320px -620px; } -.emoji-man_with_gua_pi_mao_tone5 { background-position: -340px -620px; } -.emoji-man_with_turban { background-position: -360px -620px; } -.emoji-man_with_turban_tone1 { background-position: -380px -620px; } -.emoji-man_with_turban_tone2 { background-position: -400px -620px; } -.emoji-man_with_turban_tone3 { background-position: -420px -620px; } -.emoji-man_with_turban_tone4 { background-position: -440px -620px; } -.emoji-man_with_turban_tone5 { background-position: -460px -620px; } -.emoji-mans_shoe { background-position: -480px -620px; } -.emoji-map { background-position: -500px -620px; } -.emoji-maple_leaf { background-position: -520px -620px; } -.emoji-martial_arts_uniform { background-position: -540px -620px; } -.emoji-mask { background-position: -560px -620px; } -.emoji-massage { background-position: -580px -620px; } -.emoji-massage_tone1 { background-position: -600px -620px; } -.emoji-massage_tone2 { background-position: -620px -620px; } -.emoji-massage_tone3 { background-position: -640px 0; } -.emoji-massage_tone4 { background-position: -640px -20px; } -.emoji-massage_tone5 { background-position: -640px -40px; } -.emoji-meat_on_bone { background-position: -640px -60px; } -.emoji-medal { background-position: -640px -80px; } -.emoji-mega { background-position: -640px -100px; } -.emoji-melon { background-position: -640px -120px; } -.emoji-menorah { background-position: -640px -140px; } -.emoji-mens { background-position: -640px -160px; } -.emoji-metal { background-position: -640px -180px; } -.emoji-metal_tone1 { background-position: -640px -200px; } -.emoji-metal_tone2 { background-position: -640px -220px; } -.emoji-metal_tone3 { background-position: -640px -240px; } -.emoji-metal_tone4 { background-position: -640px -260px; } -.emoji-metal_tone5 { background-position: -640px -280px; } -.emoji-metro { background-position: -640px -300px; } -.emoji-microphone { background-position: -640px -320px; } -.emoji-microphone2 { background-position: -640px -340px; } -.emoji-microscope { background-position: -640px -360px; } -.emoji-middle_finger { background-position: -640px -380px; } -.emoji-middle_finger_tone1 { background-position: -640px -400px; } -.emoji-middle_finger_tone2 { background-position: -640px -420px; } -.emoji-middle_finger_tone3 { background-position: -640px -440px; } -.emoji-middle_finger_tone4 { background-position: -640px -460px; } -.emoji-middle_finger_tone5 { background-position: -640px -480px; } -.emoji-military_medal { background-position: -640px -500px; } -.emoji-milk { background-position: -640px -520px; } -.emoji-milky_way { background-position: -640px -540px; } -.emoji-minibus { background-position: -640px -560px; } -.emoji-minidisc { background-position: -640px -580px; } -.emoji-mobile_phone_off { background-position: -640px -600px; } -.emoji-money_mouth { background-position: -640px -620px; } -.emoji-money_with_wings { background-position: 0 -640px; } -.emoji-moneybag { background-position: -20px -640px; } -.emoji-monkey { background-position: -40px -640px; } -.emoji-monkey_face { background-position: -60px -640px; } -.emoji-monorail { background-position: -80px -640px; } -.emoji-mortar_board { background-position: -100px -640px; } -.emoji-mosque { background-position: -120px -640px; } -.emoji-motor_scooter { background-position: -140px -640px; } -.emoji-motorboat { background-position: -160px -640px; } -.emoji-motorcycle { background-position: -180px -640px; } -.emoji-motorway { background-position: -200px -640px; } -.emoji-mount_fuji { background-position: -220px -640px; } -.emoji-mountain { background-position: -240px -640px; } -.emoji-mountain_bicyclist { background-position: -260px -640px; } -.emoji-mountain_bicyclist_tone1 { background-position: -280px -640px; } -.emoji-mountain_bicyclist_tone2 { background-position: -300px -640px; } -.emoji-mountain_bicyclist_tone3 { background-position: -320px -640px; } -.emoji-mountain_bicyclist_tone4 { background-position: -340px -640px; } -.emoji-mountain_bicyclist_tone5 { background-position: -360px -640px; } -.emoji-mountain_cableway { background-position: -380px -640px; } -.emoji-mountain_railway { background-position: -400px -640px; } -.emoji-mountain_snow { background-position: -420px -640px; } -.emoji-mouse { background-position: -440px -640px; } -.emoji-mouse2 { background-position: -460px -640px; } -.emoji-mouse_three_button { background-position: -480px -640px; } -.emoji-movie_camera { background-position: -500px -640px; } -.emoji-moyai { background-position: -520px -640px; } -.emoji-mrs_claus { background-position: -540px -640px; } -.emoji-mrs_claus_tone1 { background-position: -560px -640px; } -.emoji-mrs_claus_tone2 { background-position: -580px -640px; } -.emoji-mrs_claus_tone3 { background-position: -600px -640px; } -.emoji-mrs_claus_tone4 { background-position: -620px -640px; } -.emoji-mrs_claus_tone5 { background-position: -640px -640px; } -.emoji-muscle { background-position: -660px 0; } -.emoji-muscle_tone1 { background-position: -660px -20px; } -.emoji-muscle_tone2 { background-position: -660px -40px; } -.emoji-muscle_tone3 { background-position: -660px -60px; } -.emoji-muscle_tone4 { background-position: -660px -80px; } -.emoji-muscle_tone5 { background-position: -660px -100px; } -.emoji-mushroom { background-position: -660px -120px; } -.emoji-musical_keyboard { background-position: -660px -140px; } -.emoji-musical_note { background-position: -660px -160px; } -.emoji-musical_score { background-position: -660px -180px; } -.emoji-mute { background-position: -660px -200px; } -.emoji-nail_care { background-position: -660px -220px; } -.emoji-nail_care_tone1 { background-position: -660px -240px; } -.emoji-nail_care_tone2 { background-position: -660px -260px; } -.emoji-nail_care_tone3 { background-position: -660px -280px; } -.emoji-nail_care_tone4 { background-position: -660px -300px; } -.emoji-nail_care_tone5 { background-position: -660px -320px; } -.emoji-name_badge { background-position: -660px -340px; } -.emoji-nauseated_face { background-position: -660px -360px; } -.emoji-necktie { background-position: -660px -380px; } -.emoji-negative_squared_cross_mark { background-position: -660px -400px; } -.emoji-nerd { background-position: -660px -420px; } -.emoji-neutral_face { background-position: -660px -440px; } -.emoji-new { background-position: -660px -460px; } -.emoji-new_moon { background-position: -660px -480px; } -.emoji-new_moon_with_face { background-position: -660px -500px; } -.emoji-newspaper { background-position: -660px -520px; } -.emoji-newspaper2 { background-position: -660px -540px; } -.emoji-ng { background-position: -660px -560px; } -.emoji-night_with_stars { background-position: -660px -580px; } -.emoji-nine { background-position: -660px -600px; } -.emoji-no_bell { background-position: -660px -620px; } -.emoji-no_bicycles { background-position: -660px -640px; } -.emoji-no_entry { background-position: 0 -660px; } -.emoji-no_entry_sign { background-position: -20px -660px; } -.emoji-no_good { background-position: -40px -660px; } -.emoji-no_good_tone1 { background-position: -60px -660px; } -.emoji-no_good_tone2 { background-position: -80px -660px; } -.emoji-no_good_tone3 { background-position: -100px -660px; } -.emoji-no_good_tone4 { background-position: -120px -660px; } -.emoji-no_good_tone5 { background-position: -140px -660px; } -.emoji-no_mobile_phones { background-position: -160px -660px; } -.emoji-no_mouth { background-position: -180px -660px; } -.emoji-no_pedestrians { background-position: -200px -660px; } -.emoji-no_smoking { background-position: -220px -660px; } -.emoji-non-potable_water { background-position: -240px -660px; } -.emoji-nose { background-position: -260px -660px; } -.emoji-nose_tone1 { background-position: -280px -660px; } -.emoji-nose_tone2 { background-position: -300px -660px; } -.emoji-nose_tone3 { background-position: -320px -660px; } -.emoji-nose_tone4 { background-position: -340px -660px; } -.emoji-nose_tone5 { background-position: -360px -660px; } -.emoji-notebook { background-position: -380px -660px; } -.emoji-notebook_with_decorative_cover { background-position: -400px -660px; } -.emoji-notepad_spiral { background-position: -420px -660px; } -.emoji-notes { background-position: -440px -660px; } -.emoji-nut_and_bolt { background-position: -460px -660px; } -.emoji-o { background-position: -480px -660px; } -.emoji-o2 { background-position: -500px -660px; } -.emoji-ocean { background-position: -520px -660px; } -.emoji-octagonal_sign { background-position: -540px -660px; } -.emoji-octopus { background-position: -560px -660px; } -.emoji-oden { background-position: -580px -660px; } -.emoji-office { background-position: -600px -660px; } -.emoji-oil { background-position: -620px -660px; } -.emoji-ok { background-position: -640px -660px; } -.emoji-ok_hand { background-position: -660px -660px; } -.emoji-ok_hand_tone1 { background-position: -680px 0; } -.emoji-ok_hand_tone2 { background-position: -680px -20px; } -.emoji-ok_hand_tone3 { background-position: -680px -40px; } -.emoji-ok_hand_tone4 { background-position: -680px -60px; } -.emoji-ok_hand_tone5 { background-position: -680px -80px; } -.emoji-ok_woman { background-position: -680px -100px; } -.emoji-ok_woman_tone1 { background-position: -680px -120px; } -.emoji-ok_woman_tone2 { background-position: -680px -140px; } -.emoji-ok_woman_tone3 { background-position: -680px -160px; } -.emoji-ok_woman_tone4 { background-position: -680px -180px; } -.emoji-ok_woman_tone5 { background-position: -680px -200px; } -.emoji-older_man { background-position: -680px -220px; } -.emoji-older_man_tone1 { background-position: -680px -240px; } -.emoji-older_man_tone2 { background-position: -680px -260px; } -.emoji-older_man_tone3 { background-position: -680px -280px; } -.emoji-older_man_tone4 { background-position: -680px -300px; } -.emoji-older_man_tone5 { background-position: -680px -320px; } -.emoji-older_woman { background-position: -680px -340px; } -.emoji-older_woman_tone1 { background-position: -680px -360px; } -.emoji-older_woman_tone2 { background-position: -680px -380px; } -.emoji-older_woman_tone3 { background-position: -680px -400px; } -.emoji-older_woman_tone4 { background-position: -680px -420px; } -.emoji-older_woman_tone5 { background-position: -680px -440px; } -.emoji-om_symbol { background-position: -680px -460px; } -.emoji-on { background-position: -680px -480px; } -.emoji-oncoming_automobile { background-position: -680px -500px; } -.emoji-oncoming_bus { background-position: -680px -520px; } -.emoji-oncoming_police_car { background-position: -680px -540px; } -.emoji-oncoming_taxi { background-position: -680px -560px; } -.emoji-one { background-position: -680px -580px; } -.emoji-open_file_folder { background-position: -680px -600px; } -.emoji-open_hands { background-position: -680px -620px; } -.emoji-open_hands_tone1 { background-position: -680px -640px; } -.emoji-open_hands_tone2 { background-position: -680px -660px; } -.emoji-open_hands_tone3 { background-position: 0 -680px; } -.emoji-open_hands_tone4 { background-position: -20px -680px; } -.emoji-open_hands_tone5 { background-position: -40px -680px; } -.emoji-open_mouth { background-position: -60px -680px; } -.emoji-ophiuchus { background-position: -80px -680px; } -.emoji-orange_book { background-position: -100px -680px; } -.emoji-orthodox_cross { background-position: -120px -680px; } -.emoji-outbox_tray { background-position: -140px -680px; } -.emoji-owl { background-position: -160px -680px; } -.emoji-ox { background-position: -180px -680px; } -.emoji-package { background-position: -200px -680px; } -.emoji-page_facing_up { background-position: -220px -680px; } -.emoji-page_with_curl { background-position: -240px -680px; } -.emoji-pager { background-position: -260px -680px; } -.emoji-paintbrush { background-position: -280px -680px; } -.emoji-palm_tree { background-position: -300px -680px; } -.emoji-pancakes { background-position: -320px -680px; } -.emoji-panda_face { background-position: -340px -680px; } -.emoji-paperclip { background-position: -360px -680px; } -.emoji-paperclips { background-position: -380px -680px; } -.emoji-park { background-position: -400px -680px; } -.emoji-parking { background-position: -420px -680px; } -.emoji-part_alternation_mark { background-position: -440px -680px; } -.emoji-partly_sunny { background-position: -460px -680px; } -.emoji-passport_control { background-position: -480px -680px; } -.emoji-pause_button { background-position: -500px -680px; } -.emoji-peace { background-position: -520px -680px; } -.emoji-peach { background-position: -540px -680px; } -.emoji-peanuts { background-position: -560px -680px; } -.emoji-pear { background-position: -580px -680px; } -.emoji-pen_ballpoint { background-position: -600px -680px; } -.emoji-pen_fountain { background-position: -620px -680px; } -.emoji-pencil { background-position: -640px -680px; } -.emoji-pencil2 { background-position: -660px -680px; } -.emoji-penguin { background-position: -680px -680px; } -.emoji-pensive { background-position: -700px 0; } -.emoji-performing_arts { background-position: -700px -20px; } -.emoji-persevere { background-position: -700px -40px; } -.emoji-person_frowning { background-position: -700px -60px; } -.emoji-person_frowning_tone1 { background-position: -700px -80px; } -.emoji-person_frowning_tone2 { background-position: -700px -100px; } -.emoji-person_frowning_tone3 { background-position: -700px -120px; } -.emoji-person_frowning_tone4 { background-position: -700px -140px; } -.emoji-person_frowning_tone5 { background-position: -700px -160px; } -.emoji-person_with_blond_hair { background-position: -700px -180px; } -.emoji-person_with_blond_hair_tone1 { background-position: -700px -200px; } -.emoji-person_with_blond_hair_tone2 { background-position: -700px -220px; } -.emoji-person_with_blond_hair_tone3 { background-position: -700px -240px; } -.emoji-person_with_blond_hair_tone4 { background-position: -700px -260px; } -.emoji-person_with_blond_hair_tone5 { background-position: -700px -280px; } -.emoji-person_with_pouting_face { background-position: -700px -300px; } -.emoji-person_with_pouting_face_tone1 { background-position: -700px -320px; } -.emoji-person_with_pouting_face_tone2 { background-position: -700px -340px; } -.emoji-person_with_pouting_face_tone3 { background-position: -700px -360px; } -.emoji-person_with_pouting_face_tone4 { background-position: -700px -380px; } -.emoji-person_with_pouting_face_tone5 { background-position: -700px -400px; } -.emoji-pick { background-position: -700px -420px; } -.emoji-pig { background-position: -700px -440px; } -.emoji-pig2 { background-position: -700px -460px; } -.emoji-pig_nose { background-position: -700px -480px; } -.emoji-pill { background-position: -700px -500px; } -.emoji-pineapple { background-position: -700px -520px; } -.emoji-ping_pong { background-position: -700px -540px; } -.emoji-pisces { background-position: -700px -560px; } -.emoji-pizza { background-position: -700px -580px; } -.emoji-place_of_worship { background-position: -700px -600px; } -.emoji-play_pause { background-position: -700px -620px; } -.emoji-point_down { background-position: -700px -640px; } -.emoji-point_down_tone1 { background-position: -700px -660px; } -.emoji-point_down_tone2 { background-position: -700px -680px; } -.emoji-point_down_tone3 { background-position: 0 -700px; } -.emoji-point_down_tone4 { background-position: -20px -700px; } -.emoji-point_down_tone5 { background-position: -40px -700px; } -.emoji-point_left { background-position: -60px -700px; } -.emoji-point_left_tone1 { background-position: -80px -700px; } -.emoji-point_left_tone2 { background-position: -100px -700px; } -.emoji-point_left_tone3 { background-position: -120px -700px; } -.emoji-point_left_tone4 { background-position: -140px -700px; } -.emoji-point_left_tone5 { background-position: -160px -700px; } -.emoji-point_right { background-position: -180px -700px; } -.emoji-point_right_tone1 { background-position: -200px -700px; } -.emoji-point_right_tone2 { background-position: -220px -700px; } -.emoji-point_right_tone3 { background-position: -240px -700px; } -.emoji-point_right_tone4 { background-position: -260px -700px; } -.emoji-point_right_tone5 { background-position: -280px -700px; } -.emoji-point_up { background-position: -300px -700px; } -.emoji-point_up_2 { background-position: -320px -700px; } -.emoji-point_up_2_tone1 { background-position: -340px -700px; } -.emoji-point_up_2_tone2 { background-position: -360px -700px; } -.emoji-point_up_2_tone3 { background-position: -380px -700px; } -.emoji-point_up_2_tone4 { background-position: -400px -700px; } -.emoji-point_up_2_tone5 { background-position: -420px -700px; } -.emoji-point_up_tone1 { background-position: -440px -700px; } -.emoji-point_up_tone2 { background-position: -460px -700px; } -.emoji-point_up_tone3 { background-position: -480px -700px; } -.emoji-point_up_tone4 { background-position: -500px -700px; } -.emoji-point_up_tone5 { background-position: -520px -700px; } -.emoji-police_car { background-position: -540px -700px; } -.emoji-poodle { background-position: -560px -700px; } -.emoji-poop { background-position: -580px -700px; } -.emoji-popcorn { background-position: -600px -700px; } -.emoji-post_office { background-position: -620px -700px; } -.emoji-postal_horn { background-position: -640px -700px; } -.emoji-postbox { background-position: -660px -700px; } -.emoji-potable_water { background-position: -680px -700px; } -.emoji-potato { background-position: -700px -700px; } -.emoji-pouch { background-position: -720px 0; } -.emoji-poultry_leg { background-position: -720px -20px; } -.emoji-pound { background-position: -720px -40px; } -.emoji-pouting_cat { background-position: -720px -60px; } -.emoji-pray { background-position: -720px -80px; } -.emoji-pray_tone1 { background-position: -720px -100px; } -.emoji-pray_tone2 { background-position: -720px -120px; } -.emoji-pray_tone3 { background-position: -720px -140px; } -.emoji-pray_tone4 { background-position: -720px -160px; } -.emoji-pray_tone5 { background-position: -720px -180px; } -.emoji-prayer_beads { background-position: -720px -200px; } -.emoji-pregnant_woman { background-position: -720px -220px; } -.emoji-pregnant_woman_tone1 { background-position: -720px -240px; } -.emoji-pregnant_woman_tone2 { background-position: -720px -260px; } -.emoji-pregnant_woman_tone3 { background-position: -720px -280px; } -.emoji-pregnant_woman_tone4 { background-position: -720px -300px; } -.emoji-pregnant_woman_tone5 { background-position: -720px -320px; } -.emoji-prince { background-position: -720px -340px; } -.emoji-prince_tone1 { background-position: -720px -360px; } -.emoji-prince_tone2 { background-position: -720px -380px; } -.emoji-prince_tone3 { background-position: -720px -400px; } -.emoji-prince_tone4 { background-position: -720px -420px; } -.emoji-prince_tone5 { background-position: -720px -440px; } -.emoji-princess { background-position: -720px -460px; } -.emoji-princess_tone1 { background-position: -720px -480px; } -.emoji-princess_tone2 { background-position: -720px -500px; } -.emoji-princess_tone3 { background-position: -720px -520px; } -.emoji-princess_tone4 { background-position: -720px -540px; } -.emoji-princess_tone5 { background-position: -720px -560px; } -.emoji-printer { background-position: -720px -580px; } -.emoji-projector { background-position: -720px -600px; } -.emoji-punch { background-position: -720px -620px; } -.emoji-punch_tone1 { background-position: -720px -640px; } -.emoji-punch_tone2 { background-position: -720px -660px; } -.emoji-punch_tone3 { background-position: -720px -680px; } -.emoji-punch_tone4 { background-position: -720px -700px; } -.emoji-punch_tone5 { background-position: 0 -720px; } -.emoji-purple_heart { background-position: -20px -720px; } -.emoji-purse { background-position: -40px -720px; } -.emoji-pushpin { background-position: -60px -720px; } -.emoji-put_litter_in_its_place { background-position: -80px -720px; } -.emoji-question { background-position: -100px -720px; } -.emoji-rabbit { background-position: -120px -720px; } -.emoji-rabbit2 { background-position: -140px -720px; } -.emoji-race_car { background-position: -160px -720px; } -.emoji-racehorse { background-position: -180px -720px; } -.emoji-radio { background-position: -200px -720px; } -.emoji-radio_button { background-position: -220px -720px; } -.emoji-radioactive { background-position: -240px -720px; } -.emoji-rage { background-position: -260px -720px; } -.emoji-railway_car { background-position: -280px -720px; } -.emoji-railway_track { background-position: -300px -720px; } -.emoji-rainbow { background-position: -320px -720px; } -.emoji-raised_back_of_hand { background-position: -340px -720px; } -.emoji-raised_back_of_hand_tone1 { background-position: -360px -720px; } -.emoji-raised_back_of_hand_tone2 { background-position: -380px -720px; } -.emoji-raised_back_of_hand_tone3 { background-position: -400px -720px; } -.emoji-raised_back_of_hand_tone4 { background-position: -420px -720px; } -.emoji-raised_back_of_hand_tone5 { background-position: -440px -720px; } -.emoji-raised_hand { background-position: -460px -720px; } -.emoji-raised_hand_tone1 { background-position: -480px -720px; } -.emoji-raised_hand_tone2 { background-position: -500px -720px; } -.emoji-raised_hand_tone3 { background-position: -520px -720px; } -.emoji-raised_hand_tone4 { background-position: -540px -720px; } -.emoji-raised_hand_tone5 { background-position: -560px -720px; } -.emoji-raised_hands { background-position: -580px -720px; } -.emoji-raised_hands_tone1 { background-position: -600px -720px; } -.emoji-raised_hands_tone2 { background-position: -620px -720px; } -.emoji-raised_hands_tone3 { background-position: -640px -720px; } -.emoji-raised_hands_tone4 { background-position: -660px -720px; } -.emoji-raised_hands_tone5 { background-position: -680px -720px; } -.emoji-raising_hand { background-position: -700px -720px; } -.emoji-raising_hand_tone1 { background-position: -720px -720px; } -.emoji-raising_hand_tone2 { background-position: -740px 0; } -.emoji-raising_hand_tone3 { background-position: -740px -20px; } -.emoji-raising_hand_tone4 { background-position: -740px -40px; } -.emoji-raising_hand_tone5 { background-position: -740px -60px; } -.emoji-ram { background-position: -740px -80px; } -.emoji-ramen { background-position: -740px -100px; } -.emoji-rat { background-position: -740px -120px; } -.emoji-record_button { background-position: -740px -140px; } -.emoji-recycle { background-position: -740px -160px; } -.emoji-red_car { background-position: -740px -180px; } -.emoji-red_circle { background-position: -740px -200px; } -.emoji-registered { background-position: -740px -220px; } -.emoji-relaxed { background-position: -740px -240px; } -.emoji-relieved { background-position: -740px -260px; } -.emoji-reminder_ribbon { background-position: -740px -280px; } -.emoji-repeat { background-position: -740px -300px; } -.emoji-repeat_one { background-position: -740px -320px; } -.emoji-restroom { background-position: -740px -340px; } -.emoji-revolving_hearts { background-position: -740px -360px; } -.emoji-rewind { background-position: -740px -380px; } -.emoji-rhino { background-position: -740px -400px; } -.emoji-ribbon { background-position: -740px -420px; } -.emoji-rice { background-position: -740px -440px; } -.emoji-rice_ball { background-position: -740px -460px; } -.emoji-rice_cracker { background-position: -740px -480px; } -.emoji-rice_scene { background-position: -740px -500px; } -.emoji-right_facing_fist { background-position: -740px -520px; } -.emoji-right_facing_fist_tone1 { background-position: -740px -540px; } -.emoji-right_facing_fist_tone2 { background-position: -740px -560px; } -.emoji-right_facing_fist_tone3 { background-position: -740px -580px; } -.emoji-right_facing_fist_tone4 { background-position: -740px -600px; } -.emoji-right_facing_fist_tone5 { background-position: -740px -620px; } -.emoji-ring { background-position: -740px -640px; } -.emoji-robot { background-position: -740px -660px; } -.emoji-rocket { background-position: -740px -680px; } -.emoji-rofl { background-position: -740px -700px; } -.emoji-roller_coaster { background-position: -740px -720px; } -.emoji-rolling_eyes { background-position: 0 -740px; } -.emoji-rooster { background-position: -20px -740px; } -.emoji-rose { background-position: -40px -740px; } -.emoji-rosette { background-position: -60px -740px; } -.emoji-rotating_light { background-position: -80px -740px; } -.emoji-round_pushpin { background-position: -100px -740px; } -.emoji-rowboat { background-position: -120px -740px; } -.emoji-rowboat_tone1 { background-position: -140px -740px; } -.emoji-rowboat_tone2 { background-position: -160px -740px; } -.emoji-rowboat_tone3 { background-position: -180px -740px; } -.emoji-rowboat_tone4 { background-position: -200px -740px; } -.emoji-rowboat_tone5 { background-position: -220px -740px; } -.emoji-rugby_football { background-position: -240px -740px; } -.emoji-runner { background-position: -260px -740px; } -.emoji-runner_tone1 { background-position: -280px -740px; } -.emoji-runner_tone2 { background-position: -300px -740px; } -.emoji-runner_tone3 { background-position: -320px -740px; } -.emoji-runner_tone4 { background-position: -340px -740px; } -.emoji-runner_tone5 { background-position: -360px -740px; } -.emoji-running_shirt_with_sash { background-position: -380px -740px; } -.emoji-sa { background-position: -400px -740px; } -.emoji-sagittarius { background-position: -420px -740px; } -.emoji-sailboat { background-position: -440px -740px; } -.emoji-sake { background-position: -460px -740px; } -.emoji-salad { background-position: -480px -740px; } -.emoji-sandal { background-position: -500px -740px; } -.emoji-santa { background-position: -520px -740px; } -.emoji-santa_tone1 { background-position: -540px -740px; } -.emoji-santa_tone2 { background-position: -560px -740px; } -.emoji-santa_tone3 { background-position: -580px -740px; } -.emoji-santa_tone4 { background-position: -600px -740px; } -.emoji-santa_tone5 { background-position: -620px -740px; } -.emoji-satellite { background-position: -640px -740px; } -.emoji-satellite_orbital { background-position: -660px -740px; } -.emoji-saxophone { background-position: -680px -740px; } -.emoji-scales { background-position: -700px -740px; } -.emoji-school { background-position: -720px -740px; } -.emoji-school_satchel { background-position: -740px -740px; } -.emoji-scissors { background-position: -760px 0; } -.emoji-scooter { background-position: -760px -20px; } -.emoji-scorpion { background-position: -760px -40px; } -.emoji-scorpius { background-position: -760px -60px; } -.emoji-scream { background-position: -760px -80px; } -.emoji-scream_cat { background-position: -760px -100px; } -.emoji-scroll { background-position: -760px -120px; } -.emoji-seat { background-position: -760px -140px; } -.emoji-second_place { background-position: -760px -160px; } -.emoji-secret { background-position: -760px -180px; } -.emoji-see_no_evil { background-position: -760px -200px; } -.emoji-seedling { background-position: -760px -220px; } -.emoji-selfie { background-position: -760px -240px; } -.emoji-selfie_tone1 { background-position: -760px -260px; } -.emoji-selfie_tone2 { background-position: -760px -280px; } -.emoji-selfie_tone3 { background-position: -760px -300px; } -.emoji-selfie_tone4 { background-position: -760px -320px; } -.emoji-selfie_tone5 { background-position: -760px -340px; } -.emoji-seven { background-position: -760px -360px; } -.emoji-shallow_pan_of_food { background-position: -760px -380px; } -.emoji-shamrock { background-position: -760px -400px; } -.emoji-shark { background-position: -760px -420px; } -.emoji-shaved_ice { background-position: -760px -440px; } -.emoji-sheep { background-position: -760px -460px; } -.emoji-shell { background-position: -760px -480px; } -.emoji-shield { background-position: -760px -500px; } -.emoji-shinto_shrine { background-position: -760px -520px; } -.emoji-ship { background-position: -760px -540px; } -.emoji-shirt { background-position: -760px -560px; } -.emoji-shopping_bags { background-position: -760px -580px; } -.emoji-shopping_cart { background-position: -760px -600px; } -.emoji-shower { background-position: -760px -620px; } -.emoji-shrimp { background-position: -760px -640px; } -.emoji-shrug { background-position: -760px -660px; } -.emoji-shrug_tone1 { background-position: -760px -680px; } -.emoji-shrug_tone2 { background-position: -760px -700px; } -.emoji-shrug_tone3 { background-position: -760px -720px; } -.emoji-shrug_tone4 { background-position: -760px -740px; } -.emoji-shrug_tone5 { background-position: 0 -760px; } -.emoji-signal_strength { background-position: -20px -760px; } -.emoji-six { background-position: -40px -760px; } -.emoji-six_pointed_star { background-position: -60px -760px; } -.emoji-ski { background-position: -80px -760px; } -.emoji-skier { background-position: -100px -760px; } -.emoji-skull { background-position: -120px -760px; } -.emoji-skull_crossbones { background-position: -140px -760px; } -.emoji-sleeping { background-position: -160px -760px; } -.emoji-sleeping_accommodation { background-position: -180px -760px; } -.emoji-sleepy { background-position: -200px -760px; } -.emoji-slight_frown { background-position: -220px -760px; } -.emoji-slight_smile { background-position: -240px -760px; } -.emoji-slot_machine { background-position: -260px -760px; } -.emoji-small_blue_diamond { background-position: -280px -760px; } -.emoji-small_orange_diamond { background-position: -300px -760px; } -.emoji-small_red_triangle { background-position: -320px -760px; } -.emoji-small_red_triangle_down { background-position: -340px -760px; } -.emoji-smile { background-position: -360px -760px; } -.emoji-smile_cat { background-position: -380px -760px; } -.emoji-smiley { background-position: -400px -760px; } -.emoji-smiley_cat { background-position: -420px -760px; } -.emoji-smiling_imp { background-position: -440px -760px; } -.emoji-smirk { background-position: -460px -760px; } -.emoji-smirk_cat { background-position: -480px -760px; } -.emoji-smoking { background-position: -500px -760px; } -.emoji-snail { background-position: -520px -760px; } -.emoji-snake { background-position: -540px -760px; } -.emoji-sneezing_face { background-position: -560px -760px; } -.emoji-snowboarder { background-position: -580px -760px; } -.emoji-snowflake { background-position: -600px -760px; } -.emoji-snowman { background-position: -620px -760px; } -.emoji-snowman2 { background-position: -640px -760px; } -.emoji-sob { background-position: -660px -760px; } -.emoji-soccer { background-position: -680px -760px; } -.emoji-soon { background-position: -700px -760px; } -.emoji-sos { background-position: -720px -760px; } -.emoji-sound { background-position: -740px -760px; } -.emoji-space_invader { background-position: -760px -760px; } -.emoji-spades { background-position: -780px 0; } -.emoji-spaghetti { background-position: -780px -20px; } -.emoji-sparkle { background-position: -780px -40px; } -.emoji-sparkler { background-position: -780px -60px; } -.emoji-sparkles { background-position: -780px -80px; } -.emoji-sparkling_heart { background-position: -780px -100px; } -.emoji-speak_no_evil { background-position: -780px -120px; } -.emoji-speaker { background-position: -780px -140px; } -.emoji-speaking_head { background-position: -780px -160px; } -.emoji-speech_balloon { background-position: -780px -180px; } -.emoji-speedboat { background-position: -780px -200px; } -.emoji-spider { background-position: -780px -220px; } -.emoji-spider_web { background-position: -780px -240px; } -.emoji-spoon { background-position: -780px -260px; } -.emoji-spy { background-position: -780px -280px; } -.emoji-spy_tone1 { background-position: -780px -300px; } -.emoji-spy_tone2 { background-position: -780px -320px; } -.emoji-spy_tone3 { background-position: -780px -340px; } -.emoji-spy_tone4 { background-position: -780px -360px; } -.emoji-spy_tone5 { background-position: -780px -380px; } -.emoji-squid { background-position: -780px -400px; } -.emoji-stadium { background-position: -780px -420px; } -.emoji-star { background-position: -780px -440px; } -.emoji-star2 { background-position: -780px -460px; } -.emoji-star_and_crescent { background-position: -780px -480px; } -.emoji-star_of_david { background-position: -780px -500px; } -.emoji-stars { background-position: -780px -520px; } -.emoji-station { background-position: -780px -540px; } -.emoji-statue_of_liberty { background-position: -780px -560px; } -.emoji-steam_locomotive { background-position: -780px -580px; } -.emoji-stew { background-position: -780px -600px; } -.emoji-stop_button { background-position: -780px -620px; } -.emoji-stopwatch { background-position: -780px -640px; } -.emoji-straight_ruler { background-position: -780px -660px; } -.emoji-strawberry { background-position: -780px -680px; } -.emoji-stuck_out_tongue { background-position: -780px -700px; } -.emoji-stuck_out_tongue_closed_eyes { background-position: -780px -720px; } -.emoji-stuck_out_tongue_winking_eye { background-position: -780px -740px; } -.emoji-stuffed_flatbread { background-position: -780px -760px; } -.emoji-sun_with_face { background-position: 0 -780px; } -.emoji-sunflower { background-position: -20px -780px; } -.emoji-sunglasses { background-position: -40px -780px; } -.emoji-sunny { background-position: -60px -780px; } -.emoji-sunrise { background-position: -80px -780px; } -.emoji-sunrise_over_mountains { background-position: -100px -780px; } -.emoji-surfer { background-position: -120px -780px; } -.emoji-surfer_tone1 { background-position: -140px -780px; } -.emoji-surfer_tone2 { background-position: -160px -780px; } -.emoji-surfer_tone3 { background-position: -180px -780px; } -.emoji-surfer_tone4 { background-position: -200px -780px; } -.emoji-surfer_tone5 { background-position: -220px -780px; } -.emoji-sushi { background-position: -240px -780px; } -.emoji-suspension_railway { background-position: -260px -780px; } -.emoji-sweat { background-position: -280px -780px; } -.emoji-sweat_drops { background-position: -300px -780px; } -.emoji-sweat_smile { background-position: -320px -780px; } -.emoji-sweet_potato { background-position: -340px -780px; } -.emoji-swimmer { background-position: -360px -780px; } -.emoji-swimmer_tone1 { background-position: -380px -780px; } -.emoji-swimmer_tone2 { background-position: -400px -780px; } -.emoji-swimmer_tone3 { background-position: -420px -780px; } -.emoji-swimmer_tone4 { background-position: -440px -780px; } -.emoji-swimmer_tone5 { background-position: -460px -780px; } -.emoji-symbols { background-position: -480px -780px; } -.emoji-synagogue { background-position: -500px -780px; } -.emoji-syringe { background-position: -520px -780px; } -.emoji-taco { background-position: -540px -780px; } -.emoji-tada { background-position: -560px -780px; } -.emoji-tanabata_tree { background-position: -580px -780px; } -.emoji-tangerine { background-position: -600px -780px; } -.emoji-taurus { background-position: -620px -780px; } -.emoji-taxi { background-position: -640px -780px; } -.emoji-tea { background-position: -660px -780px; } -.emoji-telephone { background-position: -680px -780px; } -.emoji-telephone_receiver { background-position: -700px -780px; } -.emoji-telescope { background-position: -720px -780px; } -.emoji-ten { background-position: -740px -780px; } -.emoji-tennis { background-position: -760px -780px; } -.emoji-tent { background-position: -780px -780px; } -.emoji-thermometer { background-position: -800px 0; } -.emoji-thermometer_face { background-position: -800px -20px; } -.emoji-thinking { background-position: -800px -40px; } -.emoji-third_place { background-position: -800px -60px; } -.emoji-thought_balloon { background-position: -800px -80px; } -.emoji-three { background-position: -800px -100px; } -.emoji-thumbsdown { background-position: -800px -120px; } -.emoji-thumbsdown_tone1 { background-position: -800px -140px; } -.emoji-thumbsdown_tone2 { background-position: -800px -160px; } -.emoji-thumbsdown_tone3 { background-position: -800px -180px; } -.emoji-thumbsdown_tone4 { background-position: -800px -200px; } -.emoji-thumbsdown_tone5 { background-position: -800px -220px; } -.emoji-thumbsup { background-position: -800px -240px; } -.emoji-thumbsup_tone1 { background-position: -800px -260px; } -.emoji-thumbsup_tone2 { background-position: -800px -280px; } -.emoji-thumbsup_tone3 { background-position: -800px -300px; } -.emoji-thumbsup_tone4 { background-position: -800px -320px; } -.emoji-thumbsup_tone5 { background-position: -800px -340px; } -.emoji-thunder_cloud_rain { background-position: -800px -360px; } -.emoji-ticket { background-position: -800px -380px; } -.emoji-tickets { background-position: -800px -400px; } -.emoji-tiger { background-position: -800px -420px; } -.emoji-tiger2 { background-position: -800px -440px; } -.emoji-timer { background-position: -800px -460px; } -.emoji-tired_face { background-position: -800px -480px; } -.emoji-tm { background-position: -800px -500px; } -.emoji-toilet { background-position: -800px -520px; } -.emoji-tokyo_tower { background-position: -800px -540px; } -.emoji-tomato { background-position: -800px -560px; } -.emoji-tone1 { background-position: -800px -580px; } -.emoji-tone2 { background-position: -800px -600px; } -.emoji-tone3 { background-position: -800px -620px; } -.emoji-tone4 { background-position: -800px -640px; } -.emoji-tone5 { background-position: -800px -660px; } -.emoji-tongue { background-position: -800px -680px; } -.emoji-tools { background-position: -800px -700px; } -.emoji-top { background-position: -800px -720px; } -.emoji-tophat { background-position: -800px -740px; } -.emoji-track_next { background-position: -800px -760px; } -.emoji-track_previous { background-position: -800px -780px; } -.emoji-trackball { background-position: 0 -800px; } -.emoji-tractor { background-position: -20px -800px; } -.emoji-traffic_light { background-position: -40px -800px; } -.emoji-train { background-position: -60px -800px; } -.emoji-train2 { background-position: -80px -800px; } -.emoji-tram { background-position: -100px -800px; } -.emoji-triangular_flag_on_post { background-position: -120px -800px; } -.emoji-triangular_ruler { background-position: -140px -800px; } -.emoji-trident { background-position: -160px -800px; } -.emoji-triumph { background-position: -180px -800px; } -.emoji-trolleybus { background-position: -200px -800px; } -.emoji-trophy { background-position: -220px -800px; } -.emoji-tropical_drink { background-position: -240px -800px; } -.emoji-tropical_fish { background-position: -260px -800px; } -.emoji-truck { background-position: -280px -800px; } -.emoji-trumpet { background-position: -300px -800px; } -.emoji-tulip { background-position: -320px -800px; } -.emoji-tumbler_glass { background-position: -340px -800px; } -.emoji-turkey { background-position: -360px -800px; } -.emoji-turtle { background-position: -380px -800px; } -.emoji-tv { background-position: -400px -800px; } -.emoji-twisted_rightwards_arrows { background-position: -420px -800px; } -.emoji-two { background-position: -440px -800px; } -.emoji-two_hearts { background-position: -460px -800px; } -.emoji-two_men_holding_hands { background-position: -480px -800px; } -.emoji-two_women_holding_hands { background-position: -500px -800px; } -.emoji-u5272 { background-position: -520px -800px; } -.emoji-u5408 { background-position: -540px -800px; } -.emoji-u55b6 { background-position: -560px -800px; } -.emoji-u6307 { background-position: -580px -800px; } -.emoji-u6708 { background-position: -600px -800px; } -.emoji-u6709 { background-position: -620px -800px; } -.emoji-u6e80 { background-position: -640px -800px; } -.emoji-u7121 { background-position: -660px -800px; } -.emoji-u7533 { background-position: -680px -800px; } -.emoji-u7981 { background-position: -700px -800px; } -.emoji-u7a7a { background-position: -720px -800px; } -.emoji-umbrella { background-position: -740px -800px; } -.emoji-umbrella2 { background-position: -760px -800px; } -.emoji-unamused { background-position: -780px -800px; } -.emoji-underage { background-position: -800px -800px; } -.emoji-unicorn { background-position: -820px 0; } -.emoji-unlock { background-position: -820px -20px; } -.emoji-up { background-position: -820px -40px; } -.emoji-upside_down { background-position: -820px -60px; } -.emoji-urn { background-position: -820px -80px; } -.emoji-v { background-position: -820px -100px; } -.emoji-v_tone1 { background-position: -820px -120px; } -.emoji-v_tone2 { background-position: -820px -140px; } -.emoji-v_tone3 { background-position: -820px -160px; } -.emoji-v_tone4 { background-position: -820px -180px; } -.emoji-v_tone5 { background-position: -820px -200px; } -.emoji-vertical_traffic_light { background-position: -820px -220px; } -.emoji-vhs { background-position: -820px -240px; } -.emoji-vibration_mode { background-position: -820px -260px; } -.emoji-video_camera { background-position: -820px -280px; } -.emoji-video_game { background-position: -820px -300px; } -.emoji-violin { background-position: -820px -320px; } -.emoji-virgo { background-position: -820px -340px; } -.emoji-volcano { background-position: -820px -360px; } -.emoji-volleyball { background-position: -820px -380px; } -.emoji-vs { background-position: -820px -400px; } -.emoji-vulcan { background-position: -820px -420px; } -.emoji-vulcan_tone1 { background-position: -820px -440px; } -.emoji-vulcan_tone2 { background-position: -820px -460px; } -.emoji-vulcan_tone3 { background-position: -820px -480px; } -.emoji-vulcan_tone4 { background-position: -820px -500px; } -.emoji-vulcan_tone5 { background-position: -820px -520px; } -.emoji-walking { background-position: -820px -540px; } -.emoji-walking_tone1 { background-position: -820px -560px; } -.emoji-walking_tone2 { background-position: -820px -580px; } -.emoji-walking_tone3 { background-position: -820px -600px; } -.emoji-walking_tone4 { background-position: -820px -620px; } -.emoji-walking_tone5 { background-position: -820px -640px; } -.emoji-waning_crescent_moon { background-position: -820px -660px; } -.emoji-waning_gibbous_moon { background-position: -820px -680px; } -.emoji-warning { background-position: -820px -700px; } -.emoji-wastebasket { background-position: -820px -720px; } -.emoji-watch { background-position: -820px -740px; } -.emoji-water_buffalo { background-position: -820px -760px; } -.emoji-water_polo { background-position: -820px -780px; } -.emoji-water_polo_tone1 { background-position: -820px -800px; } -.emoji-water_polo_tone2 { background-position: 0 -820px; } -.emoji-water_polo_tone3 { background-position: -20px -820px; } -.emoji-water_polo_tone4 { background-position: -40px -820px; } -.emoji-water_polo_tone5 { background-position: -60px -820px; } -.emoji-watermelon { background-position: -80px -820px; } -.emoji-wave { background-position: -100px -820px; } -.emoji-wave_tone1 { background-position: -120px -820px; } -.emoji-wave_tone2 { background-position: -140px -820px; } -.emoji-wave_tone3 { background-position: -160px -820px; } -.emoji-wave_tone4 { background-position: -180px -820px; } -.emoji-wave_tone5 { background-position: -200px -820px; } -.emoji-wavy_dash { background-position: -220px -820px; } -.emoji-waxing_crescent_moon { background-position: -240px -820px; } -.emoji-waxing_gibbous_moon { background-position: -260px -820px; } -.emoji-wc { background-position: -280px -820px; } -.emoji-weary { background-position: -300px -820px; } -.emoji-wedding { background-position: -320px -820px; } -.emoji-whale { background-position: -340px -820px; } -.emoji-whale2 { background-position: -360px -820px; } -.emoji-wheel_of_dharma { background-position: -380px -820px; } -.emoji-wheelchair { background-position: -400px -820px; } -.emoji-white_check_mark { background-position: -420px -820px; } -.emoji-white_circle { background-position: -440px -820px; } -.emoji-white_flower { background-position: -460px -820px; } -.emoji-white_large_square { background-position: -480px -820px; } -.emoji-white_medium_small_square { background-position: -500px -820px; } -.emoji-white_medium_square { background-position: -520px -820px; } -.emoji-white_small_square { background-position: -540px -820px; } -.emoji-white_square_button { background-position: -560px -820px; } -.emoji-white_sun_cloud { background-position: -580px -820px; } -.emoji-white_sun_rain_cloud { background-position: -600px -820px; } -.emoji-white_sun_small_cloud { background-position: -620px -820px; } -.emoji-wilted_rose { background-position: -640px -820px; } -.emoji-wind_blowing_face { background-position: -660px -820px; } -.emoji-wind_chime { background-position: -680px -820px; } -.emoji-wine_glass { background-position: -700px -820px; } -.emoji-wink { background-position: -720px -820px; } -.emoji-wolf { background-position: -740px -820px; } -.emoji-woman { background-position: -760px -820px; } -.emoji-woman_tone1 { background-position: -780px -820px; } -.emoji-woman_tone2 { background-position: -800px -820px; } -.emoji-woman_tone3 { background-position: -820px -820px; } -.emoji-woman_tone4 { background-position: -840px 0; } -.emoji-woman_tone5 { background-position: -840px -20px; } -.emoji-womans_clothes { background-position: -840px -40px; } -.emoji-womans_hat { background-position: -840px -60px; } -.emoji-womens { background-position: -840px -80px; } -.emoji-worried { background-position: -840px -100px; } -.emoji-wrench { background-position: -840px -120px; } -.emoji-wrestlers { background-position: -840px -140px; } -.emoji-wrestlers_tone1 { background-position: -840px -160px; } -.emoji-wrestlers_tone2 { background-position: -840px -180px; } -.emoji-wrestlers_tone3 { background-position: -840px -200px; } -.emoji-wrestlers_tone4 { background-position: -840px -220px; } -.emoji-wrestlers_tone5 { background-position: -840px -240px; } -.emoji-writing_hand { background-position: -840px -260px; } -.emoji-writing_hand_tone1 { background-position: -840px -280px; } -.emoji-writing_hand_tone2 { background-position: -840px -300px; } -.emoji-writing_hand_tone3 { background-position: -840px -320px; } -.emoji-writing_hand_tone4 { background-position: -840px -340px; } -.emoji-writing_hand_tone5 { background-position: -840px -360px; } -.emoji-x { background-position: -840px -380px; } -.emoji-yellow_heart { background-position: -840px -400px; } -.emoji-yen { background-position: -840px -420px; } -.emoji-yin_yang { background-position: -840px -440px; } -.emoji-yum { background-position: -840px -460px; } -.emoji-zap { background-position: -840px -480px; } -.emoji-zero { background-position: -840px -500px; } -.emoji-zipper_mouth { background-position: -840px -520px; } -.emoji-100 { background-position: -840px -540px; } +.emoji-gay_pride_flag { background-position: -220px -540px; } +.emoji-gear { background-position: -240px -540px; } +.emoji-gem { background-position: -260px -540px; } +.emoji-gemini { background-position: -280px -540px; } +.emoji-ghost { background-position: -300px -540px; } +.emoji-gift { background-position: -320px -540px; } +.emoji-gift_heart { background-position: -340px -540px; } +.emoji-girl { background-position: -360px -540px; } +.emoji-girl_tone1 { background-position: -380px -540px; } +.emoji-girl_tone2 { background-position: -400px -540px; } +.emoji-girl_tone3 { background-position: -420px -540px; } +.emoji-girl_tone4 { background-position: -440px -540px; } +.emoji-girl_tone5 { background-position: -460px -540px; } +.emoji-globe_with_meridians { background-position: -480px -540px; } +.emoji-goal { background-position: -500px -540px; } +.emoji-goat { background-position: -520px -540px; } +.emoji-golf { background-position: -540px -540px; } +.emoji-golfer { background-position: -560px 0; } +.emoji-gorilla { background-position: -560px -20px; } +.emoji-grapes { background-position: -560px -40px; } +.emoji-green_apple { background-position: -560px -60px; } +.emoji-green_book { background-position: -560px -80px; } +.emoji-green_heart { background-position: -560px -100px; } +.emoji-grey_exclamation { background-position: -560px -120px; } +.emoji-grey_question { background-position: -560px -140px; } +.emoji-grimacing { background-position: -560px -160px; } +.emoji-grin { background-position: -560px -180px; } +.emoji-grinning { background-position: -560px -200px; } +.emoji-guardsman { background-position: -560px -220px; } +.emoji-guardsman_tone1 { background-position: -560px -240px; } +.emoji-guardsman_tone2 { background-position: -560px -260px; } +.emoji-guardsman_tone3 { background-position: -560px -280px; } +.emoji-guardsman_tone4 { background-position: -560px -300px; } +.emoji-guardsman_tone5 { background-position: -560px -320px; } +.emoji-guitar { background-position: -560px -340px; } +.emoji-gun { background-position: -560px -360px; } +.emoji-haircut { background-position: -560px -380px; } +.emoji-haircut_tone1 { background-position: -560px -400px; } +.emoji-haircut_tone2 { background-position: -560px -420px; } +.emoji-haircut_tone3 { background-position: -560px -440px; } +.emoji-haircut_tone4 { background-position: -560px -460px; } +.emoji-haircut_tone5 { background-position: -560px -480px; } +.emoji-hamburger { background-position: -560px -500px; } +.emoji-hammer { background-position: -560px -520px; } +.emoji-hammer_pick { background-position: -560px -540px; } +.emoji-hamster { background-position: 0 -560px; } +.emoji-hand_splayed { background-position: -20px -560px; } +.emoji-hand_splayed_tone1 { background-position: -40px -560px; } +.emoji-hand_splayed_tone2 { background-position: -60px -560px; } +.emoji-hand_splayed_tone3 { background-position: -80px -560px; } +.emoji-hand_splayed_tone4 { background-position: -100px -560px; } +.emoji-hand_splayed_tone5 { background-position: -120px -560px; } +.emoji-handbag { background-position: -140px -560px; } +.emoji-handball { background-position: -160px -560px; } +.emoji-handball_tone1 { background-position: -180px -560px; } +.emoji-handball_tone2 { background-position: -200px -560px; } +.emoji-handball_tone3 { background-position: -220px -560px; } +.emoji-handball_tone4 { background-position: -240px -560px; } +.emoji-handball_tone5 { background-position: -260px -560px; } +.emoji-handshake { background-position: -280px -560px; } +.emoji-handshake_tone1 { background-position: -300px -560px; } +.emoji-handshake_tone2 { background-position: -320px -560px; } +.emoji-handshake_tone3 { background-position: -340px -560px; } +.emoji-handshake_tone4 { background-position: -360px -560px; } +.emoji-handshake_tone5 { background-position: -380px -560px; } +.emoji-hash { background-position: -400px -560px; } +.emoji-hatched_chick { background-position: -420px -560px; } +.emoji-hatching_chick { background-position: -440px -560px; } +.emoji-head_bandage { background-position: -460px -560px; } +.emoji-headphones { background-position: -480px -560px; } +.emoji-hear_no_evil { background-position: -500px -560px; } +.emoji-heart { background-position: -520px -560px; } +.emoji-heart_decoration { background-position: -540px -560px; } +.emoji-heart_exclamation { background-position: -560px -560px; } +.emoji-heart_eyes { background-position: -580px 0; } +.emoji-heart_eyes_cat { background-position: -580px -20px; } +.emoji-heartbeat { background-position: -580px -40px; } +.emoji-heartpulse { background-position: -580px -60px; } +.emoji-hearts { background-position: -580px -80px; } +.emoji-heavy_check_mark { background-position: -580px -100px; } +.emoji-heavy_division_sign { background-position: -580px -120px; } +.emoji-heavy_dollar_sign { background-position: -580px -140px; } +.emoji-heavy_minus_sign { background-position: -580px -160px; } +.emoji-heavy_multiplication_x { background-position: -580px -180px; } +.emoji-heavy_plus_sign { background-position: -580px -200px; } +.emoji-helicopter { background-position: -580px -220px; } +.emoji-helmet_with_cross { background-position: -580px -240px; } +.emoji-herb { background-position: -580px -260px; } +.emoji-hibiscus { background-position: -580px -280px; } +.emoji-high_brightness { background-position: -580px -300px; } +.emoji-high_heel { background-position: -580px -320px; } +.emoji-hockey { background-position: -580px -340px; } +.emoji-hole { background-position: -580px -360px; } +.emoji-homes { background-position: -580px -380px; } +.emoji-honey_pot { background-position: -580px -400px; } +.emoji-horse { background-position: -580px -420px; } +.emoji-horse_racing { background-position: -580px -440px; } +.emoji-horse_racing_tone1 { background-position: -580px -460px; } +.emoji-horse_racing_tone2 { background-position: -580px -480px; } +.emoji-horse_racing_tone3 { background-position: -580px -500px; } +.emoji-horse_racing_tone4 { background-position: -580px -520px; } +.emoji-horse_racing_tone5 { background-position: -580px -540px; } +.emoji-hospital { background-position: -580px -560px; } +.emoji-hot_pepper { background-position: 0 -580px; } +.emoji-hotdog { background-position: -20px -580px; } +.emoji-hotel { background-position: -40px -580px; } +.emoji-hotsprings { background-position: -60px -580px; } +.emoji-hourglass { background-position: -80px -580px; } +.emoji-hourglass_flowing_sand { background-position: -100px -580px; } +.emoji-house { background-position: -120px -580px; } +.emoji-house_abandoned { background-position: -140px -580px; } +.emoji-house_with_garden { background-position: -160px -580px; } +.emoji-hugging { background-position: -180px -580px; } +.emoji-hushed { background-position: -200px -580px; } +.emoji-ice_cream { background-position: -220px -580px; } +.emoji-ice_skate { background-position: -240px -580px; } +.emoji-icecream { background-position: -260px -580px; } +.emoji-id { background-position: -280px -580px; } +.emoji-ideograph_advantage { background-position: -300px -580px; } +.emoji-imp { background-position: -320px -580px; } +.emoji-inbox_tray { background-position: -340px -580px; } +.emoji-incoming_envelope { background-position: -360px -580px; } +.emoji-information_desk_person { background-position: -380px -580px; } +.emoji-information_desk_person_tone1 { background-position: -400px -580px; } +.emoji-information_desk_person_tone2 { background-position: -420px -580px; } +.emoji-information_desk_person_tone3 { background-position: -440px -580px; } +.emoji-information_desk_person_tone4 { background-position: -460px -580px; } +.emoji-information_desk_person_tone5 { background-position: -480px -580px; } +.emoji-information_source { background-position: -500px -580px; } +.emoji-innocent { background-position: -520px -580px; } +.emoji-interrobang { background-position: -540px -580px; } +.emoji-iphone { background-position: -560px -580px; } +.emoji-island { background-position: -580px -580px; } +.emoji-izakaya_lantern { background-position: -600px 0; } +.emoji-jack_o_lantern { background-position: -600px -20px; } +.emoji-japan { background-position: -600px -40px; } +.emoji-japanese_castle { background-position: -600px -60px; } +.emoji-japanese_goblin { background-position: -600px -80px; } +.emoji-japanese_ogre { background-position: -600px -100px; } +.emoji-jeans { background-position: -600px -120px; } +.emoji-joy { background-position: -600px -140px; } +.emoji-joy_cat { background-position: -600px -160px; } +.emoji-joystick { background-position: -600px -180px; } +.emoji-juggling { background-position: -600px -200px; } +.emoji-juggling_tone1 { background-position: -600px -220px; } +.emoji-juggling_tone2 { background-position: -600px -240px; } +.emoji-juggling_tone3 { background-position: -600px -260px; } +.emoji-juggling_tone4 { background-position: -600px -280px; } +.emoji-juggling_tone5 { background-position: -600px -300px; } +.emoji-kaaba { background-position: -600px -320px; } +.emoji-key { background-position: -600px -340px; } +.emoji-key2 { background-position: -600px -360px; } +.emoji-keyboard { background-position: -600px -380px; } +.emoji-kimono { background-position: -600px -400px; } +.emoji-kiss { background-position: -600px -420px; } +.emoji-kiss_mm { background-position: -600px -440px; } +.emoji-kiss_ww { background-position: -600px -460px; } +.emoji-kissing { background-position: -600px -480px; } +.emoji-kissing_cat { background-position: -600px -500px; } +.emoji-kissing_closed_eyes { background-position: -600px -520px; } +.emoji-kissing_heart { background-position: -600px -540px; } +.emoji-kissing_smiling_eyes { background-position: -600px -560px; } +.emoji-kiwi { background-position: -600px -580px; } +.emoji-knife { background-position: 0 -600px; } +.emoji-koala { background-position: -20px -600px; } +.emoji-koko { background-position: -40px -600px; } +.emoji-label { background-position: -60px -600px; } +.emoji-large_blue_circle { background-position: -80px -600px; } +.emoji-large_blue_diamond { background-position: -100px -600px; } +.emoji-large_orange_diamond { background-position: -120px -600px; } +.emoji-last_quarter_moon { background-position: -140px -600px; } +.emoji-last_quarter_moon_with_face { background-position: -160px -600px; } +.emoji-laughing { background-position: -180px -600px; } +.emoji-leaves { background-position: -200px -600px; } +.emoji-ledger { background-position: -220px -600px; } +.emoji-left_facing_fist { background-position: -240px -600px; } +.emoji-left_facing_fist_tone1 { background-position: -260px -600px; } +.emoji-left_facing_fist_tone2 { background-position: -280px -600px; } +.emoji-left_facing_fist_tone3 { background-position: -300px -600px; } +.emoji-left_facing_fist_tone4 { background-position: -320px -600px; } +.emoji-left_facing_fist_tone5 { background-position: -340px -600px; } +.emoji-left_luggage { background-position: -360px -600px; } +.emoji-left_right_arrow { background-position: -380px -600px; } +.emoji-leftwards_arrow_with_hook { background-position: -400px -600px; } +.emoji-lemon { background-position: -420px -600px; } +.emoji-leo { background-position: -440px -600px; } +.emoji-leopard { background-position: -460px -600px; } +.emoji-level_slider { background-position: -480px -600px; } +.emoji-levitate { background-position: -500px -600px; } +.emoji-libra { background-position: -520px -600px; } +.emoji-lifter { background-position: -540px -600px; } +.emoji-lifter_tone1 { background-position: -560px -600px; } +.emoji-lifter_tone2 { background-position: -580px -600px; } +.emoji-lifter_tone3 { background-position: -600px -600px; } +.emoji-lifter_tone4 { background-position: -620px 0; } +.emoji-lifter_tone5 { background-position: -620px -20px; } +.emoji-light_rail { background-position: -620px -40px; } +.emoji-link { background-position: -620px -60px; } +.emoji-lion_face { background-position: -620px -80px; } +.emoji-lips { background-position: -620px -100px; } +.emoji-lipstick { background-position: -620px -120px; } +.emoji-lizard { background-position: -620px -140px; } +.emoji-lock { background-position: -620px -160px; } +.emoji-lock_with_ink_pen { background-position: -620px -180px; } +.emoji-lollipop { background-position: -620px -200px; } +.emoji-loop { background-position: -620px -220px; } +.emoji-loud_sound { background-position: -620px -240px; } +.emoji-loudspeaker { background-position: -620px -260px; } +.emoji-love_hotel { background-position: -620px -280px; } +.emoji-love_letter { background-position: -620px -300px; } +.emoji-low_brightness { background-position: -620px -320px; } +.emoji-lying_face { background-position: -620px -340px; } +.emoji-m { background-position: -620px -360px; } +.emoji-mag { background-position: -620px -380px; } +.emoji-mag_right { background-position: -620px -400px; } +.emoji-mahjong { background-position: -620px -420px; } +.emoji-mailbox { background-position: -620px -440px; } +.emoji-mailbox_closed { background-position: -620px -460px; } +.emoji-mailbox_with_mail { background-position: -620px -480px; } +.emoji-mailbox_with_no_mail { background-position: -620px -500px; } +.emoji-man { background-position: -620px -520px; } +.emoji-man_dancing { background-position: -620px -540px; } +.emoji-man_dancing_tone1 { background-position: -620px -560px; } +.emoji-man_dancing_tone2 { background-position: -620px -580px; } +.emoji-man_dancing_tone3 { background-position: -620px -600px; } +.emoji-man_dancing_tone4 { background-position: 0 -620px; } +.emoji-man_dancing_tone5 { background-position: -20px -620px; } +.emoji-man_in_tuxedo { background-position: -40px -620px; } +.emoji-man_in_tuxedo_tone1 { background-position: -60px -620px; } +.emoji-man_in_tuxedo_tone2 { background-position: -80px -620px; } +.emoji-man_in_tuxedo_tone3 { background-position: -100px -620px; } +.emoji-man_in_tuxedo_tone4 { background-position: -120px -620px; } +.emoji-man_in_tuxedo_tone5 { background-position: -140px -620px; } +.emoji-man_tone1 { background-position: -160px -620px; } +.emoji-man_tone2 { background-position: -180px -620px; } +.emoji-man_tone3 { background-position: -200px -620px; } +.emoji-man_tone4 { background-position: -220px -620px; } +.emoji-man_tone5 { background-position: -240px -620px; } +.emoji-man_with_gua_pi_mao { background-position: -260px -620px; } +.emoji-man_with_gua_pi_mao_tone1 { background-position: -280px -620px; } +.emoji-man_with_gua_pi_mao_tone2 { background-position: -300px -620px; } +.emoji-man_with_gua_pi_mao_tone3 { background-position: -320px -620px; } +.emoji-man_with_gua_pi_mao_tone4 { background-position: -340px -620px; } +.emoji-man_with_gua_pi_mao_tone5 { background-position: -360px -620px; } +.emoji-man_with_turban { background-position: -380px -620px; } +.emoji-man_with_turban_tone1 { background-position: -400px -620px; } +.emoji-man_with_turban_tone2 { background-position: -420px -620px; } +.emoji-man_with_turban_tone3 { background-position: -440px -620px; } +.emoji-man_with_turban_tone4 { background-position: -460px -620px; } +.emoji-man_with_turban_tone5 { background-position: -480px -620px; } +.emoji-mans_shoe { background-position: -500px -620px; } +.emoji-map { background-position: -520px -620px; } +.emoji-maple_leaf { background-position: -540px -620px; } +.emoji-martial_arts_uniform { background-position: -560px -620px; } +.emoji-mask { background-position: -580px -620px; } +.emoji-massage { background-position: -600px -620px; } +.emoji-massage_tone1 { background-position: -620px -620px; } +.emoji-massage_tone2 { background-position: -640px 0; } +.emoji-massage_tone3 { background-position: -640px -20px; } +.emoji-massage_tone4 { background-position: -640px -40px; } +.emoji-massage_tone5 { background-position: -640px -60px; } +.emoji-meat_on_bone { background-position: -640px -80px; } +.emoji-medal { background-position: -640px -100px; } +.emoji-mega { background-position: -640px -120px; } +.emoji-melon { background-position: -640px -140px; } +.emoji-menorah { background-position: -640px -160px; } +.emoji-mens { background-position: -640px -180px; } +.emoji-metal { background-position: -640px -200px; } +.emoji-metal_tone1 { background-position: -640px -220px; } +.emoji-metal_tone2 { background-position: -640px -240px; } +.emoji-metal_tone3 { background-position: -640px -260px; } +.emoji-metal_tone4 { background-position: -640px -280px; } +.emoji-metal_tone5 { background-position: -640px -300px; } +.emoji-metro { background-position: -640px -320px; } +.emoji-microphone { background-position: -640px -340px; } +.emoji-microphone2 { background-position: -640px -360px; } +.emoji-microscope { background-position: -640px -380px; } +.emoji-middle_finger { background-position: -640px -400px; } +.emoji-middle_finger_tone1 { background-position: -640px -420px; } +.emoji-middle_finger_tone2 { background-position: -640px -440px; } +.emoji-middle_finger_tone3 { background-position: -640px -460px; } +.emoji-middle_finger_tone4 { background-position: -640px -480px; } +.emoji-middle_finger_tone5 { background-position: -640px -500px; } +.emoji-military_medal { background-position: -640px -520px; } +.emoji-milk { background-position: -640px -540px; } +.emoji-milky_way { background-position: -640px -560px; } +.emoji-minibus { background-position: -640px -580px; } +.emoji-minidisc { background-position: -640px -600px; } +.emoji-mobile_phone_off { background-position: -640px -620px; } +.emoji-money_mouth { background-position: 0 -640px; } +.emoji-money_with_wings { background-position: -20px -640px; } +.emoji-moneybag { background-position: -40px -640px; } +.emoji-monkey { background-position: -60px -640px; } +.emoji-monkey_face { background-position: -80px -640px; } +.emoji-monorail { background-position: -100px -640px; } +.emoji-mortar_board { background-position: -120px -640px; } +.emoji-mosque { background-position: -140px -640px; } +.emoji-motor_scooter { background-position: -160px -640px; } +.emoji-motorboat { background-position: -180px -640px; } +.emoji-motorcycle { background-position: -200px -640px; } +.emoji-motorway { background-position: -220px -640px; } +.emoji-mount_fuji { background-position: -240px -640px; } +.emoji-mountain { background-position: -260px -640px; } +.emoji-mountain_bicyclist { background-position: -280px -640px; } +.emoji-mountain_bicyclist_tone1 { background-position: -300px -640px; } +.emoji-mountain_bicyclist_tone2 { background-position: -320px -640px; } +.emoji-mountain_bicyclist_tone3 { background-position: -340px -640px; } +.emoji-mountain_bicyclist_tone4 { background-position: -360px -640px; } +.emoji-mountain_bicyclist_tone5 { background-position: -380px -640px; } +.emoji-mountain_cableway { background-position: -400px -640px; } +.emoji-mountain_railway { background-position: -420px -640px; } +.emoji-mountain_snow { background-position: -440px -640px; } +.emoji-mouse { background-position: -460px -640px; } +.emoji-mouse2 { background-position: -480px -640px; } +.emoji-mouse_three_button { background-position: -500px -640px; } +.emoji-movie_camera { background-position: -520px -640px; } +.emoji-moyai { background-position: -540px -640px; } +.emoji-mrs_claus { background-position: -560px -640px; } +.emoji-mrs_claus_tone1 { background-position: -580px -640px; } +.emoji-mrs_claus_tone2 { background-position: -600px -640px; } +.emoji-mrs_claus_tone3 { background-position: -620px -640px; } +.emoji-mrs_claus_tone4 { background-position: -640px -640px; } +.emoji-mrs_claus_tone5 { background-position: -660px 0; } +.emoji-muscle { background-position: -660px -20px; } +.emoji-muscle_tone1 { background-position: -660px -40px; } +.emoji-muscle_tone2 { background-position: -660px -60px; } +.emoji-muscle_tone3 { background-position: -660px -80px; } +.emoji-muscle_tone4 { background-position: -660px -100px; } +.emoji-muscle_tone5 { background-position: -660px -120px; } +.emoji-mushroom { background-position: -660px -140px; } +.emoji-musical_keyboard { background-position: -660px -160px; } +.emoji-musical_note { background-position: -660px -180px; } +.emoji-musical_score { background-position: -660px -200px; } +.emoji-mute { background-position: -660px -220px; } +.emoji-nail_care { background-position: -660px -240px; } +.emoji-nail_care_tone1 { background-position: -660px -260px; } +.emoji-nail_care_tone2 { background-position: -660px -280px; } +.emoji-nail_care_tone3 { background-position: -660px -300px; } +.emoji-nail_care_tone4 { background-position: -660px -320px; } +.emoji-nail_care_tone5 { background-position: -660px -340px; } +.emoji-name_badge { background-position: -660px -360px; } +.emoji-nauseated_face { background-position: -660px -380px; } +.emoji-necktie { background-position: -660px -400px; } +.emoji-negative_squared_cross_mark { background-position: -660px -420px; } +.emoji-nerd { background-position: -660px -440px; } +.emoji-neutral_face { background-position: -660px -460px; } +.emoji-new { background-position: -660px -480px; } +.emoji-new_moon { background-position: -660px -500px; } +.emoji-new_moon_with_face { background-position: -660px -520px; } +.emoji-newspaper { background-position: -660px -540px; } +.emoji-newspaper2 { background-position: -660px -560px; } +.emoji-ng { background-position: -660px -580px; } +.emoji-night_with_stars { background-position: -660px -600px; } +.emoji-nine { background-position: -660px -620px; } +.emoji-no_bell { background-position: -660px -640px; } +.emoji-no_bicycles { background-position: 0 -660px; } +.emoji-no_entry { background-position: -20px -660px; } +.emoji-no_entry_sign { background-position: -40px -660px; } +.emoji-no_good { background-position: -60px -660px; } +.emoji-no_good_tone1 { background-position: -80px -660px; } +.emoji-no_good_tone2 { background-position: -100px -660px; } +.emoji-no_good_tone3 { background-position: -120px -660px; } +.emoji-no_good_tone4 { background-position: -140px -660px; } +.emoji-no_good_tone5 { background-position: -160px -660px; } +.emoji-no_mobile_phones { background-position: -180px -660px; } +.emoji-no_mouth { background-position: -200px -660px; } +.emoji-no_pedestrians { background-position: -220px -660px; } +.emoji-no_smoking { background-position: -240px -660px; } +.emoji-non-potable_water { background-position: -260px -660px; } +.emoji-nose { background-position: -280px -660px; } +.emoji-nose_tone1 { background-position: -300px -660px; } +.emoji-nose_tone2 { background-position: -320px -660px; } +.emoji-nose_tone3 { background-position: -340px -660px; } +.emoji-nose_tone4 { background-position: -360px -660px; } +.emoji-nose_tone5 { background-position: -380px -660px; } +.emoji-notebook { background-position: -400px -660px; } +.emoji-notebook_with_decorative_cover { background-position: -420px -660px; } +.emoji-notepad_spiral { background-position: -440px -660px; } +.emoji-notes { background-position: -460px -660px; } +.emoji-nut_and_bolt { background-position: -480px -660px; } +.emoji-o { background-position: -500px -660px; } +.emoji-o2 { background-position: -520px -660px; } +.emoji-ocean { background-position: -540px -660px; } +.emoji-octagonal_sign { background-position: -560px -660px; } +.emoji-octopus { background-position: -580px -660px; } +.emoji-oden { background-position: -600px -660px; } +.emoji-office { background-position: -620px -660px; } +.emoji-oil { background-position: -640px -660px; } +.emoji-ok { background-position: -660px -660px; } +.emoji-ok_hand { background-position: -680px 0; } +.emoji-ok_hand_tone1 { background-position: -680px -20px; } +.emoji-ok_hand_tone2 { background-position: -680px -40px; } +.emoji-ok_hand_tone3 { background-position: -680px -60px; } +.emoji-ok_hand_tone4 { background-position: -680px -80px; } +.emoji-ok_hand_tone5 { background-position: -680px -100px; } +.emoji-ok_woman { background-position: -680px -120px; } +.emoji-ok_woman_tone1 { background-position: -680px -140px; } +.emoji-ok_woman_tone2 { background-position: -680px -160px; } +.emoji-ok_woman_tone3 { background-position: -680px -180px; } +.emoji-ok_woman_tone4 { background-position: -680px -200px; } +.emoji-ok_woman_tone5 { background-position: -680px -220px; } +.emoji-older_man { background-position: -680px -240px; } +.emoji-older_man_tone1 { background-position: -680px -260px; } +.emoji-older_man_tone2 { background-position: -680px -280px; } +.emoji-older_man_tone3 { background-position: -680px -300px; } +.emoji-older_man_tone4 { background-position: -680px -320px; } +.emoji-older_man_tone5 { background-position: -680px -340px; } +.emoji-older_woman { background-position: -680px -360px; } +.emoji-older_woman_tone1 { background-position: -680px -380px; } +.emoji-older_woman_tone2 { background-position: -680px -400px; } +.emoji-older_woman_tone3 { background-position: -680px -420px; } +.emoji-older_woman_tone4 { background-position: -680px -440px; } +.emoji-older_woman_tone5 { background-position: -680px -460px; } +.emoji-om_symbol { background-position: -680px -480px; } +.emoji-on { background-position: -680px -500px; } +.emoji-oncoming_automobile { background-position: -680px -520px; } +.emoji-oncoming_bus { background-position: -680px -540px; } +.emoji-oncoming_police_car { background-position: -680px -560px; } +.emoji-oncoming_taxi { background-position: -680px -580px; } +.emoji-one { background-position: -680px -600px; } +.emoji-open_file_folder { background-position: -680px -620px; } +.emoji-open_hands { background-position: -680px -640px; } +.emoji-open_hands_tone1 { background-position: -680px -660px; } +.emoji-open_hands_tone2 { background-position: 0 -680px; } +.emoji-open_hands_tone3 { background-position: -20px -680px; } +.emoji-open_hands_tone4 { background-position: -40px -680px; } +.emoji-open_hands_tone5 { background-position: -60px -680px; } +.emoji-open_mouth { background-position: -80px -680px; } +.emoji-ophiuchus { background-position: -100px -680px; } +.emoji-orange_book { background-position: -120px -680px; } +.emoji-orthodox_cross { background-position: -140px -680px; } +.emoji-outbox_tray { background-position: -160px -680px; } +.emoji-owl { background-position: -180px -680px; } +.emoji-ox { background-position: -200px -680px; } +.emoji-package { background-position: -220px -680px; } +.emoji-page_facing_up { background-position: -240px -680px; } +.emoji-page_with_curl { background-position: -260px -680px; } +.emoji-pager { background-position: -280px -680px; } +.emoji-paintbrush { background-position: -300px -680px; } +.emoji-palm_tree { background-position: -320px -680px; } +.emoji-pancakes { background-position: -340px -680px; } +.emoji-panda_face { background-position: -360px -680px; } +.emoji-paperclip { background-position: -380px -680px; } +.emoji-paperclips { background-position: -400px -680px; } +.emoji-park { background-position: -420px -680px; } +.emoji-parking { background-position: -440px -680px; } +.emoji-part_alternation_mark { background-position: -460px -680px; } +.emoji-partly_sunny { background-position: -480px -680px; } +.emoji-passport_control { background-position: -500px -680px; } +.emoji-pause_button { background-position: -520px -680px; } +.emoji-peace { background-position: -540px -680px; } +.emoji-peach { background-position: -560px -680px; } +.emoji-peanuts { background-position: -580px -680px; } +.emoji-pear { background-position: -600px -680px; } +.emoji-pen_ballpoint { background-position: -620px -680px; } +.emoji-pen_fountain { background-position: -640px -680px; } +.emoji-pencil { background-position: -660px -680px; } +.emoji-pencil2 { background-position: -680px -680px; } +.emoji-penguin { background-position: -700px 0; } +.emoji-pensive { background-position: -700px -20px; } +.emoji-performing_arts { background-position: -700px -40px; } +.emoji-persevere { background-position: -700px -60px; } +.emoji-person_frowning { background-position: -700px -80px; } +.emoji-person_frowning_tone1 { background-position: -700px -100px; } +.emoji-person_frowning_tone2 { background-position: -700px -120px; } +.emoji-person_frowning_tone3 { background-position: -700px -140px; } +.emoji-person_frowning_tone4 { background-position: -700px -160px; } +.emoji-person_frowning_tone5 { background-position: -700px -180px; } +.emoji-person_with_blond_hair { background-position: -700px -200px; } +.emoji-person_with_blond_hair_tone1 { background-position: -700px -220px; } +.emoji-person_with_blond_hair_tone2 { background-position: -700px -240px; } +.emoji-person_with_blond_hair_tone3 { background-position: -700px -260px; } +.emoji-person_with_blond_hair_tone4 { background-position: -700px -280px; } +.emoji-person_with_blond_hair_tone5 { background-position: -700px -300px; } +.emoji-person_with_pouting_face { background-position: -700px -320px; } +.emoji-person_with_pouting_face_tone1 { background-position: -700px -340px; } +.emoji-person_with_pouting_face_tone2 { background-position: -700px -360px; } +.emoji-person_with_pouting_face_tone3 { background-position: -700px -380px; } +.emoji-person_with_pouting_face_tone4 { background-position: -700px -400px; } +.emoji-person_with_pouting_face_tone5 { background-position: -700px -420px; } +.emoji-pick { background-position: -700px -440px; } +.emoji-pig { background-position: -700px -460px; } +.emoji-pig2 { background-position: -700px -480px; } +.emoji-pig_nose { background-position: -700px -500px; } +.emoji-pill { background-position: -700px -520px; } +.emoji-pineapple { background-position: -700px -540px; } +.emoji-ping_pong { background-position: -700px -560px; } +.emoji-pisces { background-position: -700px -580px; } +.emoji-pizza { background-position: -700px -600px; } +.emoji-place_of_worship { background-position: -700px -620px; } +.emoji-play_pause { background-position: -700px -640px; } +.emoji-point_down { background-position: -700px -660px; } +.emoji-point_down_tone1 { background-position: -700px -680px; } +.emoji-point_down_tone2 { background-position: 0 -700px; } +.emoji-point_down_tone3 { background-position: -20px -700px; } +.emoji-point_down_tone4 { background-position: -40px -700px; } +.emoji-point_down_tone5 { background-position: -60px -700px; } +.emoji-point_left { background-position: -80px -700px; } +.emoji-point_left_tone1 { background-position: -100px -700px; } +.emoji-point_left_tone2 { background-position: -120px -700px; } +.emoji-point_left_tone3 { background-position: -140px -700px; } +.emoji-point_left_tone4 { background-position: -160px -700px; } +.emoji-point_left_tone5 { background-position: -180px -700px; } +.emoji-point_right { background-position: -200px -700px; } +.emoji-point_right_tone1 { background-position: -220px -700px; } +.emoji-point_right_tone2 { background-position: -240px -700px; } +.emoji-point_right_tone3 { background-position: -260px -700px; } +.emoji-point_right_tone4 { background-position: -280px -700px; } +.emoji-point_right_tone5 { background-position: -300px -700px; } +.emoji-point_up { background-position: -320px -700px; } +.emoji-point_up_2 { background-position: -340px -700px; } +.emoji-point_up_2_tone1 { background-position: -360px -700px; } +.emoji-point_up_2_tone2 { background-position: -380px -700px; } +.emoji-point_up_2_tone3 { background-position: -400px -700px; } +.emoji-point_up_2_tone4 { background-position: -420px -700px; } +.emoji-point_up_2_tone5 { background-position: -440px -700px; } +.emoji-point_up_tone1 { background-position: -460px -700px; } +.emoji-point_up_tone2 { background-position: -480px -700px; } +.emoji-point_up_tone3 { background-position: -500px -700px; } +.emoji-point_up_tone4 { background-position: -520px -700px; } +.emoji-point_up_tone5 { background-position: -540px -700px; } +.emoji-police_car { background-position: -560px -700px; } +.emoji-poodle { background-position: -580px -700px; } +.emoji-poop { background-position: -600px -700px; } +.emoji-popcorn { background-position: -620px -700px; } +.emoji-post_office { background-position: -640px -700px; } +.emoji-postal_horn { background-position: -660px -700px; } +.emoji-postbox { background-position: -680px -700px; } +.emoji-potable_water { background-position: -700px -700px; } +.emoji-potato { background-position: -720px 0; } +.emoji-pouch { background-position: -720px -20px; } +.emoji-poultry_leg { background-position: -720px -40px; } +.emoji-pound { background-position: -720px -60px; } +.emoji-pouting_cat { background-position: -720px -80px; } +.emoji-pray { background-position: -720px -100px; } +.emoji-pray_tone1 { background-position: -720px -120px; } +.emoji-pray_tone2 { background-position: -720px -140px; } +.emoji-pray_tone3 { background-position: -720px -160px; } +.emoji-pray_tone4 { background-position: -720px -180px; } +.emoji-pray_tone5 { background-position: -720px -200px; } +.emoji-prayer_beads { background-position: -720px -220px; } +.emoji-pregnant_woman { background-position: -720px -240px; } +.emoji-pregnant_woman_tone1 { background-position: -720px -260px; } +.emoji-pregnant_woman_tone2 { background-position: -720px -280px; } +.emoji-pregnant_woman_tone3 { background-position: -720px -300px; } +.emoji-pregnant_woman_tone4 { background-position: -720px -320px; } +.emoji-pregnant_woman_tone5 { background-position: -720px -340px; } +.emoji-prince { background-position: -720px -360px; } +.emoji-prince_tone1 { background-position: -720px -380px; } +.emoji-prince_tone2 { background-position: -720px -400px; } +.emoji-prince_tone3 { background-position: -720px -420px; } +.emoji-prince_tone4 { background-position: -720px -440px; } +.emoji-prince_tone5 { background-position: -720px -460px; } +.emoji-princess { background-position: -720px -480px; } +.emoji-princess_tone1 { background-position: -720px -500px; } +.emoji-princess_tone2 { background-position: -720px -520px; } +.emoji-princess_tone3 { background-position: -720px -540px; } +.emoji-princess_tone4 { background-position: -720px -560px; } +.emoji-princess_tone5 { background-position: -720px -580px; } +.emoji-printer { background-position: -720px -600px; } +.emoji-projector { background-position: -720px -620px; } +.emoji-punch { background-position: -720px -640px; } +.emoji-punch_tone1 { background-position: -720px -660px; } +.emoji-punch_tone2 { background-position: -720px -680px; } +.emoji-punch_tone3 { background-position: -720px -700px; } +.emoji-punch_tone4 { background-position: 0 -720px; } +.emoji-punch_tone5 { background-position: -20px -720px; } +.emoji-purple_heart { background-position: -40px -720px; } +.emoji-purse { background-position: -60px -720px; } +.emoji-pushpin { background-position: -80px -720px; } +.emoji-put_litter_in_its_place { background-position: -100px -720px; } +.emoji-question { background-position: -120px -720px; } +.emoji-rabbit { background-position: -140px -720px; } +.emoji-rabbit2 { background-position: -160px -720px; } +.emoji-race_car { background-position: -180px -720px; } +.emoji-racehorse { background-position: -200px -720px; } +.emoji-radio { background-position: -220px -720px; } +.emoji-radio_button { background-position: -240px -720px; } +.emoji-radioactive { background-position: -260px -720px; } +.emoji-rage { background-position: -280px -720px; } +.emoji-railway_car { background-position: -300px -720px; } +.emoji-railway_track { background-position: -320px -720px; } +.emoji-rainbow { background-position: -340px -720px; } +.emoji-raised_back_of_hand { background-position: -360px -720px; } +.emoji-raised_back_of_hand_tone1 { background-position: -380px -720px; } +.emoji-raised_back_of_hand_tone2 { background-position: -400px -720px; } +.emoji-raised_back_of_hand_tone3 { background-position: -420px -720px; } +.emoji-raised_back_of_hand_tone4 { background-position: -440px -720px; } +.emoji-raised_back_of_hand_tone5 { background-position: -460px -720px; } +.emoji-raised_hand { background-position: -480px -720px; } +.emoji-raised_hand_tone1 { background-position: -500px -720px; } +.emoji-raised_hand_tone2 { background-position: -520px -720px; } +.emoji-raised_hand_tone3 { background-position: -540px -720px; } +.emoji-raised_hand_tone4 { background-position: -560px -720px; } +.emoji-raised_hand_tone5 { background-position: -580px -720px; } +.emoji-raised_hands { background-position: -600px -720px; } +.emoji-raised_hands_tone1 { background-position: -620px -720px; } +.emoji-raised_hands_tone2 { background-position: -640px -720px; } +.emoji-raised_hands_tone3 { background-position: -660px -720px; } +.emoji-raised_hands_tone4 { background-position: -680px -720px; } +.emoji-raised_hands_tone5 { background-position: -700px -720px; } +.emoji-raising_hand { background-position: -720px -720px; } +.emoji-raising_hand_tone1 { background-position: -740px 0; } +.emoji-raising_hand_tone2 { background-position: -740px -20px; } +.emoji-raising_hand_tone3 { background-position: -740px -40px; } +.emoji-raising_hand_tone4 { background-position: -740px -60px; } +.emoji-raising_hand_tone5 { background-position: -740px -80px; } +.emoji-ram { background-position: -740px -100px; } +.emoji-ramen { background-position: -740px -120px; } +.emoji-rat { background-position: -740px -140px; } +.emoji-record_button { background-position: -740px -160px; } +.emoji-recycle { background-position: -740px -180px; } +.emoji-red_car { background-position: -740px -200px; } +.emoji-red_circle { background-position: -740px -220px; } +.emoji-registered { background-position: -740px -240px; } +.emoji-relaxed { background-position: -740px -260px; } +.emoji-relieved { background-position: -740px -280px; } +.emoji-reminder_ribbon { background-position: -740px -300px; } +.emoji-repeat { background-position: -740px -320px; } +.emoji-repeat_one { background-position: -740px -340px; } +.emoji-restroom { background-position: -740px -360px; } +.emoji-revolving_hearts { background-position: -740px -380px; } +.emoji-rewind { background-position: -740px -400px; } +.emoji-rhino { background-position: -740px -420px; } +.emoji-ribbon { background-position: -740px -440px; } +.emoji-rice { background-position: -740px -460px; } +.emoji-rice_ball { background-position: -740px -480px; } +.emoji-rice_cracker { background-position: -740px -500px; } +.emoji-rice_scene { background-position: -740px -520px; } +.emoji-right_facing_fist { background-position: -740px -540px; } +.emoji-right_facing_fist_tone1 { background-position: -740px -560px; } +.emoji-right_facing_fist_tone2 { background-position: -740px -580px; } +.emoji-right_facing_fist_tone3 { background-position: -740px -600px; } +.emoji-right_facing_fist_tone4 { background-position: -740px -620px; } +.emoji-right_facing_fist_tone5 { background-position: -740px -640px; } +.emoji-ring { background-position: -740px -660px; } +.emoji-robot { background-position: -740px -680px; } +.emoji-rocket { background-position: -740px -700px; } +.emoji-rofl { background-position: -740px -720px; } +.emoji-roller_coaster { background-position: 0 -740px; } +.emoji-rolling_eyes { background-position: -20px -740px; } +.emoji-rooster { background-position: -40px -740px; } +.emoji-rose { background-position: -60px -740px; } +.emoji-rosette { background-position: -80px -740px; } +.emoji-rotating_light { background-position: -100px -740px; } +.emoji-round_pushpin { background-position: -120px -740px; } +.emoji-rowboat { background-position: -140px -740px; } +.emoji-rowboat_tone1 { background-position: -160px -740px; } +.emoji-rowboat_tone2 { background-position: -180px -740px; } +.emoji-rowboat_tone3 { background-position: -200px -740px; } +.emoji-rowboat_tone4 { background-position: -220px -740px; } +.emoji-rowboat_tone5 { background-position: -240px -740px; } +.emoji-rugby_football { background-position: -260px -740px; } +.emoji-runner { background-position: -280px -740px; } +.emoji-runner_tone1 { background-position: -300px -740px; } +.emoji-runner_tone2 { background-position: -320px -740px; } +.emoji-runner_tone3 { background-position: -340px -740px; } +.emoji-runner_tone4 { background-position: -360px -740px; } +.emoji-runner_tone5 { background-position: -380px -740px; } +.emoji-running_shirt_with_sash { background-position: -400px -740px; } +.emoji-sa { background-position: -420px -740px; } +.emoji-sagittarius { background-position: -440px -740px; } +.emoji-sailboat { background-position: -460px -740px; } +.emoji-sake { background-position: -480px -740px; } +.emoji-salad { background-position: -500px -740px; } +.emoji-sandal { background-position: -520px -740px; } +.emoji-santa { background-position: -540px -740px; } +.emoji-santa_tone1 { background-position: -560px -740px; } +.emoji-santa_tone2 { background-position: -580px -740px; } +.emoji-santa_tone3 { background-position: -600px -740px; } +.emoji-santa_tone4 { background-position: -620px -740px; } +.emoji-santa_tone5 { background-position: -640px -740px; } +.emoji-satellite { background-position: -660px -740px; } +.emoji-satellite_orbital { background-position: -680px -740px; } +.emoji-saxophone { background-position: -700px -740px; } +.emoji-scales { background-position: -720px -740px; } +.emoji-school { background-position: -740px -740px; } +.emoji-school_satchel { background-position: -760px 0; } +.emoji-scissors { background-position: -760px -20px; } +.emoji-scooter { background-position: -760px -40px; } +.emoji-scorpion { background-position: -760px -60px; } +.emoji-scorpius { background-position: -760px -80px; } +.emoji-scream { background-position: -760px -100px; } +.emoji-scream_cat { background-position: -760px -120px; } +.emoji-scroll { background-position: -760px -140px; } +.emoji-seat { background-position: -760px -160px; } +.emoji-second_place { background-position: -760px -180px; } +.emoji-secret { background-position: -760px -200px; } +.emoji-see_no_evil { background-position: -760px -220px; } +.emoji-seedling { background-position: -760px -240px; } +.emoji-selfie { background-position: -760px -260px; } +.emoji-selfie_tone1 { background-position: -760px -280px; } +.emoji-selfie_tone2 { background-position: -760px -300px; } +.emoji-selfie_tone3 { background-position: -760px -320px; } +.emoji-selfie_tone4 { background-position: -760px -340px; } +.emoji-selfie_tone5 { background-position: -760px -360px; } +.emoji-seven { background-position: -760px -380px; } +.emoji-shallow_pan_of_food { background-position: -760px -400px; } +.emoji-shamrock { background-position: -760px -420px; } +.emoji-shark { background-position: -760px -440px; } +.emoji-shaved_ice { background-position: -760px -460px; } +.emoji-sheep { background-position: -760px -480px; } +.emoji-shell { background-position: -760px -500px; } +.emoji-shield { background-position: -760px -520px; } +.emoji-shinto_shrine { background-position: -760px -540px; } +.emoji-ship { background-position: -760px -560px; } +.emoji-shirt { background-position: -760px -580px; } +.emoji-shopping_bags { background-position: -760px -600px; } +.emoji-shopping_cart { background-position: -760px -620px; } +.emoji-shower { background-position: -760px -640px; } +.emoji-shrimp { background-position: -760px -660px; } +.emoji-shrug { background-position: -760px -680px; } +.emoji-shrug_tone1 { background-position: -760px -700px; } +.emoji-shrug_tone2 { background-position: -760px -720px; } +.emoji-shrug_tone3 { background-position: -760px -740px; } +.emoji-shrug_tone4 { background-position: 0 -760px; } +.emoji-shrug_tone5 { background-position: -20px -760px; } +.emoji-signal_strength { background-position: -40px -760px; } +.emoji-six { background-position: -60px -760px; } +.emoji-six_pointed_star { background-position: -80px -760px; } +.emoji-ski { background-position: -100px -760px; } +.emoji-skier { background-position: -120px -760px; } +.emoji-skull { background-position: -140px -760px; } +.emoji-skull_crossbones { background-position: -160px -760px; } +.emoji-sleeping { background-position: -180px -760px; } +.emoji-sleeping_accommodation { background-position: -200px -760px; } +.emoji-sleepy { background-position: -220px -760px; } +.emoji-slight_frown { background-position: -240px -760px; } +.emoji-slight_smile { background-position: -260px -760px; } +.emoji-slot_machine { background-position: -280px -760px; } +.emoji-small_blue_diamond { background-position: -300px -760px; } +.emoji-small_orange_diamond { background-position: -320px -760px; } +.emoji-small_red_triangle { background-position: -340px -760px; } +.emoji-small_red_triangle_down { background-position: -360px -760px; } +.emoji-smile { background-position: -380px -760px; } +.emoji-smile_cat { background-position: -400px -760px; } +.emoji-smiley { background-position: -420px -760px; } +.emoji-smiley_cat { background-position: -440px -760px; } +.emoji-smiling_imp { background-position: -460px -760px; } +.emoji-smirk { background-position: -480px -760px; } +.emoji-smirk_cat { background-position: -500px -760px; } +.emoji-smoking { background-position: -520px -760px; } +.emoji-snail { background-position: -540px -760px; } +.emoji-snake { background-position: -560px -760px; } +.emoji-sneezing_face { background-position: -580px -760px; } +.emoji-snowboarder { background-position: -600px -760px; } +.emoji-snowflake { background-position: -620px -760px; } +.emoji-snowman { background-position: -640px -760px; } +.emoji-snowman2 { background-position: -660px -760px; } +.emoji-sob { background-position: -680px -760px; } +.emoji-soccer { background-position: -700px -760px; } +.emoji-soon { background-position: -720px -760px; } +.emoji-sos { background-position: -740px -760px; } +.emoji-sound { background-position: -760px -760px; } +.emoji-space_invader { background-position: -780px 0; } +.emoji-spades { background-position: -780px -20px; } +.emoji-spaghetti { background-position: -780px -40px; } +.emoji-sparkle { background-position: -780px -60px; } +.emoji-sparkler { background-position: -780px -80px; } +.emoji-sparkles { background-position: -780px -100px; } +.emoji-sparkling_heart { background-position: -780px -120px; } +.emoji-speak_no_evil { background-position: -780px -140px; } +.emoji-speaker { background-position: -780px -160px; } +.emoji-speaking_head { background-position: -780px -180px; } +.emoji-speech_balloon { background-position: -780px -200px; } +.emoji-speech_left { background-position: -780px -220px; } +.emoji-speedboat { background-position: -780px -240px; } +.emoji-spider { background-position: -780px -260px; } +.emoji-spider_web { background-position: -780px -280px; } +.emoji-spoon { background-position: -780px -300px; } +.emoji-spy { background-position: -780px -320px; } +.emoji-spy_tone1 { background-position: -780px -340px; } +.emoji-spy_tone2 { background-position: -780px -360px; } +.emoji-spy_tone3 { background-position: -780px -380px; } +.emoji-spy_tone4 { background-position: -780px -400px; } +.emoji-spy_tone5 { background-position: -780px -420px; } +.emoji-squid { background-position: -780px -440px; } +.emoji-stadium { background-position: -780px -460px; } +.emoji-star { background-position: -780px -480px; } +.emoji-star2 { background-position: -780px -500px; } +.emoji-star_and_crescent { background-position: -780px -520px; } +.emoji-star_of_david { background-position: -780px -540px; } +.emoji-stars { background-position: -780px -560px; } +.emoji-station { background-position: -780px -580px; } +.emoji-statue_of_liberty { background-position: -780px -600px; } +.emoji-steam_locomotive { background-position: -780px -620px; } +.emoji-stew { background-position: -780px -640px; } +.emoji-stop_button { background-position: -780px -660px; } +.emoji-stopwatch { background-position: -780px -680px; } +.emoji-straight_ruler { background-position: -780px -700px; } +.emoji-strawberry { background-position: -780px -720px; } +.emoji-stuck_out_tongue { background-position: -780px -740px; } +.emoji-stuck_out_tongue_closed_eyes { background-position: -780px -760px; } +.emoji-stuck_out_tongue_winking_eye { background-position: 0 -780px; } +.emoji-stuffed_flatbread { background-position: -20px -780px; } +.emoji-sun_with_face { background-position: -40px -780px; } +.emoji-sunflower { background-position: -60px -780px; } +.emoji-sunglasses { background-position: -80px -780px; } +.emoji-sunny { background-position: -100px -780px; } +.emoji-sunrise { background-position: -120px -780px; } +.emoji-sunrise_over_mountains { background-position: -140px -780px; } +.emoji-surfer { background-position: -160px -780px; } +.emoji-surfer_tone1 { background-position: -180px -780px; } +.emoji-surfer_tone2 { background-position: -200px -780px; } +.emoji-surfer_tone3 { background-position: -220px -780px; } +.emoji-surfer_tone4 { background-position: -240px -780px; } +.emoji-surfer_tone5 { background-position: -260px -780px; } +.emoji-sushi { background-position: -280px -780px; } +.emoji-suspension_railway { background-position: -300px -780px; } +.emoji-sweat { background-position: -320px -780px; } +.emoji-sweat_drops { background-position: -340px -780px; } +.emoji-sweat_smile { background-position: -360px -780px; } +.emoji-sweet_potato { background-position: -380px -780px; } +.emoji-swimmer { background-position: -400px -780px; } +.emoji-swimmer_tone1 { background-position: -420px -780px; } +.emoji-swimmer_tone2 { background-position: -440px -780px; } +.emoji-swimmer_tone3 { background-position: -460px -780px; } +.emoji-swimmer_tone4 { background-position: -480px -780px; } +.emoji-swimmer_tone5 { background-position: -500px -780px; } +.emoji-symbols { background-position: -520px -780px; } +.emoji-synagogue { background-position: -540px -780px; } +.emoji-syringe { background-position: -560px -780px; } +.emoji-taco { background-position: -580px -780px; } +.emoji-tada { background-position: -600px -780px; } +.emoji-tanabata_tree { background-position: -620px -780px; } +.emoji-tangerine { background-position: -640px -780px; } +.emoji-taurus { background-position: -660px -780px; } +.emoji-taxi { background-position: -680px -780px; } +.emoji-tea { background-position: -700px -780px; } +.emoji-telephone { background-position: -720px -780px; } +.emoji-telephone_receiver { background-position: -740px -780px; } +.emoji-telescope { background-position: -760px -780px; } +.emoji-ten { background-position: -780px -780px; } +.emoji-tennis { background-position: -800px 0; } +.emoji-tent { background-position: -800px -20px; } +.emoji-thermometer { background-position: -800px -40px; } +.emoji-thermometer_face { background-position: -800px -60px; } +.emoji-thinking { background-position: -800px -80px; } +.emoji-third_place { background-position: -800px -100px; } +.emoji-thought_balloon { background-position: -800px -120px; } +.emoji-three { background-position: -800px -140px; } +.emoji-thumbsdown { background-position: -800px -160px; } +.emoji-thumbsdown_tone1 { background-position: -800px -180px; } +.emoji-thumbsdown_tone2 { background-position: -800px -200px; } +.emoji-thumbsdown_tone3 { background-position: -800px -220px; } +.emoji-thumbsdown_tone4 { background-position: -800px -240px; } +.emoji-thumbsdown_tone5 { background-position: -800px -260px; } +.emoji-thumbsup { background-position: -800px -280px; } +.emoji-thumbsup_tone1 { background-position: -800px -300px; } +.emoji-thumbsup_tone2 { background-position: -800px -320px; } +.emoji-thumbsup_tone3 { background-position: -800px -340px; } +.emoji-thumbsup_tone4 { background-position: -800px -360px; } +.emoji-thumbsup_tone5 { background-position: -800px -380px; } +.emoji-thunder_cloud_rain { background-position: -800px -400px; } +.emoji-ticket { background-position: -800px -420px; } +.emoji-tickets { background-position: -800px -440px; } +.emoji-tiger { background-position: -800px -460px; } +.emoji-tiger2 { background-position: -800px -480px; } +.emoji-timer { background-position: -800px -500px; } +.emoji-tired_face { background-position: -800px -520px; } +.emoji-tm { background-position: -800px -540px; } +.emoji-toilet { background-position: -800px -560px; } +.emoji-tokyo_tower { background-position: -800px -580px; } +.emoji-tomato { background-position: -800px -600px; } +.emoji-tone1 { background-position: -800px -620px; } +.emoji-tone2 { background-position: -800px -640px; } +.emoji-tone3 { background-position: -800px -660px; } +.emoji-tone4 { background-position: -800px -680px; } +.emoji-tone5 { background-position: -800px -700px; } +.emoji-tongue { background-position: -800px -720px; } +.emoji-tools { background-position: -800px -740px; } +.emoji-top { background-position: -800px -760px; } +.emoji-tophat { background-position: -800px -780px; } +.emoji-track_next { background-position: 0 -800px; } +.emoji-track_previous { background-position: -20px -800px; } +.emoji-trackball { background-position: -40px -800px; } +.emoji-tractor { background-position: -60px -800px; } +.emoji-traffic_light { background-position: -80px -800px; } +.emoji-train { background-position: -100px -800px; } +.emoji-train2 { background-position: -120px -800px; } +.emoji-tram { background-position: -140px -800px; } +.emoji-triangular_flag_on_post { background-position: -160px -800px; } +.emoji-triangular_ruler { background-position: -180px -800px; } +.emoji-trident { background-position: -200px -800px; } +.emoji-triumph { background-position: -220px -800px; } +.emoji-trolleybus { background-position: -240px -800px; } +.emoji-trophy { background-position: -260px -800px; } +.emoji-tropical_drink { background-position: -280px -800px; } +.emoji-tropical_fish { background-position: -300px -800px; } +.emoji-truck { background-position: -320px -800px; } +.emoji-trumpet { background-position: -340px -800px; } +.emoji-tulip { background-position: -360px -800px; } +.emoji-tumbler_glass { background-position: -380px -800px; } +.emoji-turkey { background-position: -400px -800px; } +.emoji-turtle { background-position: -420px -800px; } +.emoji-tv { background-position: -440px -800px; } +.emoji-twisted_rightwards_arrows { background-position: -460px -800px; } +.emoji-two { background-position: -480px -800px; } +.emoji-two_hearts { background-position: -500px -800px; } +.emoji-two_men_holding_hands { background-position: -520px -800px; } +.emoji-two_women_holding_hands { background-position: -540px -800px; } +.emoji-u5272 { background-position: -560px -800px; } +.emoji-u5408 { background-position: -580px -800px; } +.emoji-u55b6 { background-position: -600px -800px; } +.emoji-u6307 { background-position: -620px -800px; } +.emoji-u6708 { background-position: -640px -800px; } +.emoji-u6709 { background-position: -660px -800px; } +.emoji-u6e80 { background-position: -680px -800px; } +.emoji-u7121 { background-position: -700px -800px; } +.emoji-u7533 { background-position: -720px -800px; } +.emoji-u7981 { background-position: -740px -800px; } +.emoji-u7a7a { background-position: -760px -800px; } +.emoji-umbrella { background-position: -780px -800px; } +.emoji-umbrella2 { background-position: -800px -800px; } +.emoji-unamused { background-position: -820px 0; } +.emoji-underage { background-position: -820px -20px; } +.emoji-unicorn { background-position: -820px -40px; } +.emoji-unlock { background-position: -820px -60px; } +.emoji-up { background-position: -820px -80px; } +.emoji-upside_down { background-position: -820px -100px; } +.emoji-urn { background-position: -820px -120px; } +.emoji-v { background-position: -820px -140px; } +.emoji-v_tone1 { background-position: -820px -160px; } +.emoji-v_tone2 { background-position: -820px -180px; } +.emoji-v_tone3 { background-position: -820px -200px; } +.emoji-v_tone4 { background-position: -820px -220px; } +.emoji-v_tone5 { background-position: -820px -240px; } +.emoji-vertical_traffic_light { background-position: -820px -260px; } +.emoji-vhs { background-position: -820px -280px; } +.emoji-vibration_mode { background-position: -820px -300px; } +.emoji-video_camera { background-position: -820px -320px; } +.emoji-video_game { background-position: -820px -340px; } +.emoji-violin { background-position: -820px -360px; } +.emoji-virgo { background-position: -820px -380px; } +.emoji-volcano { background-position: -820px -400px; } +.emoji-volleyball { background-position: -820px -420px; } +.emoji-vs { background-position: -820px -440px; } +.emoji-vulcan { background-position: -820px -460px; } +.emoji-vulcan_tone1 { background-position: -820px -480px; } +.emoji-vulcan_tone2 { background-position: -820px -500px; } +.emoji-vulcan_tone3 { background-position: -820px -520px; } +.emoji-vulcan_tone4 { background-position: -820px -540px; } +.emoji-vulcan_tone5 { background-position: -820px -560px; } +.emoji-walking { background-position: -820px -580px; } +.emoji-walking_tone1 { background-position: -820px -600px; } +.emoji-walking_tone2 { background-position: -820px -620px; } +.emoji-walking_tone3 { background-position: -820px -640px; } +.emoji-walking_tone4 { background-position: -820px -660px; } +.emoji-walking_tone5 { background-position: -820px -680px; } +.emoji-waning_crescent_moon { background-position: -820px -700px; } +.emoji-waning_gibbous_moon { background-position: -820px -720px; } +.emoji-warning { background-position: -820px -740px; } +.emoji-wastebasket { background-position: -820px -760px; } +.emoji-watch { background-position: -820px -780px; } +.emoji-water_buffalo { background-position: -820px -800px; } +.emoji-water_polo { background-position: 0 -820px; } +.emoji-water_polo_tone1 { background-position: -20px -820px; } +.emoji-water_polo_tone2 { background-position: -40px -820px; } +.emoji-water_polo_tone3 { background-position: -60px -820px; } +.emoji-water_polo_tone4 { background-position: -80px -820px; } +.emoji-water_polo_tone5 { background-position: -100px -820px; } +.emoji-watermelon { background-position: -120px -820px; } +.emoji-wave { background-position: -140px -820px; } +.emoji-wave_tone1 { background-position: -160px -820px; } +.emoji-wave_tone2 { background-position: -180px -820px; } +.emoji-wave_tone3 { background-position: -200px -820px; } +.emoji-wave_tone4 { background-position: -220px -820px; } +.emoji-wave_tone5 { background-position: -240px -820px; } +.emoji-wavy_dash { background-position: -260px -820px; } +.emoji-waxing_crescent_moon { background-position: -280px -820px; } +.emoji-waxing_gibbous_moon { background-position: -300px -820px; } +.emoji-wc { background-position: -320px -820px; } +.emoji-weary { background-position: -340px -820px; } +.emoji-wedding { background-position: -360px -820px; } +.emoji-whale { background-position: -380px -820px; } +.emoji-whale2 { background-position: -400px -820px; } +.emoji-wheel_of_dharma { background-position: -420px -820px; } +.emoji-wheelchair { background-position: -440px -820px; } +.emoji-white_check_mark { background-position: -460px -820px; } +.emoji-white_circle { background-position: -480px -820px; } +.emoji-white_flower { background-position: -500px -820px; } +.emoji-white_large_square { background-position: -520px -820px; } +.emoji-white_medium_small_square { background-position: -540px -820px; } +.emoji-white_medium_square { background-position: -560px -820px; } +.emoji-white_small_square { background-position: -580px -820px; } +.emoji-white_square_button { background-position: -600px -820px; } +.emoji-white_sun_cloud { background-position: -620px -820px; } +.emoji-white_sun_rain_cloud { background-position: -640px -820px; } +.emoji-white_sun_small_cloud { background-position: -660px -820px; } +.emoji-wilted_rose { background-position: -680px -820px; } +.emoji-wind_blowing_face { background-position: -700px -820px; } +.emoji-wind_chime { background-position: -720px -820px; } +.emoji-wine_glass { background-position: -740px -820px; } +.emoji-wink { background-position: -760px -820px; } +.emoji-wolf { background-position: -780px -820px; } +.emoji-woman { background-position: -800px -820px; } +.emoji-woman_tone1 { background-position: -820px -820px; } +.emoji-woman_tone2 { background-position: -840px 0; } +.emoji-woman_tone3 { background-position: -840px -20px; } +.emoji-woman_tone4 { background-position: -840px -40px; } +.emoji-woman_tone5 { background-position: -840px -60px; } +.emoji-womans_clothes { background-position: -840px -80px; } +.emoji-womans_hat { background-position: -840px -100px; } +.emoji-womens { background-position: -840px -120px; } +.emoji-worried { background-position: -840px -140px; } +.emoji-wrench { background-position: -840px -160px; } +.emoji-wrestlers { background-position: -840px -180px; } +.emoji-wrestlers_tone1 { background-position: -840px -200px; } +.emoji-wrestlers_tone2 { background-position: -840px -220px; } +.emoji-wrestlers_tone3 { background-position: -840px -240px; } +.emoji-wrestlers_tone4 { background-position: -840px -260px; } +.emoji-wrestlers_tone5 { background-position: -840px -280px; } +.emoji-writing_hand { background-position: -840px -300px; } +.emoji-writing_hand_tone1 { background-position: -840px -320px; } +.emoji-writing_hand_tone2 { background-position: -840px -340px; } +.emoji-writing_hand_tone3 { background-position: -840px -360px; } +.emoji-writing_hand_tone4 { background-position: -840px -380px; } +.emoji-writing_hand_tone5 { background-position: -840px -400px; } +.emoji-x { background-position: -840px -420px; } +.emoji-yellow_heart { background-position: -840px -440px; } +.emoji-yen { background-position: -840px -460px; } +.emoji-yin_yang { background-position: -840px -480px; } +.emoji-yum { background-position: -840px -500px; } +.emoji-zap { background-position: -840px -520px; } +.emoji-zero { background-position: -840px -540px; } +.emoji-zipper_mouth { background-position: -840px -560px; } +.emoji-100 { background-position: -840px -580px; } .emoji-icon { background-image: image-url('emoji.png'); diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index 1247e5e4876..609f33582e1 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -101,13 +101,13 @@ @for $i from 0 through 5 { .legend-box-#{$i} { - background-color: mix($blame-cyan, $blame-blue, $i / 5.0 * 100%); + background-color: mix($blame-cyan, $blame-blue, $i / 5 * 100%); } } @for $i from 1 through 4 { .legend-box-#{$i + 5} { - background-color: mix($blame-gray, $blame-cyan, $i / 4.0 * 100%); + background-color: mix($blame-gray, $blame-cyan, $i / 4 * 100%); } } } @@ -200,13 +200,13 @@ @for $i from 0 through 5 { td.blame-commit-age-#{$i} { - border-left-color: mix($blame-cyan, $blame-blue, $i / 5.0 * 100%); + border-left-color: mix($blame-cyan, $blame-blue, $i / 5 * 100%); } } @for $i from 1 through 4 { td.blame-commit-age-#{$i + 5} { - border-left-color: mix($blame-gray, $blame-cyan, $i / 4.0 * 100%); + border-left-color: mix($blame-gray, $blame-cyan, $i / 4 * 100%); } } } @@ -364,6 +364,18 @@ span.idiff { float: none; } } + + @media (max-width: $screen-xs-max) { + display: block; + + .file-actions { + white-space: normal; + + .btn-group { + padding-top: 5px; + } + } + } } .is-stl-loading { diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss index 74b6b31b07e..cec38eea464 100644 --- a/app/assets/stylesheets/framework/filters.scss +++ b/app/assets/stylesheets/framework/filters.scss @@ -305,16 +305,11 @@ color: $gl-text-color; border-color: $dropdown-input-focus-border; outline: none; - - svg { - fill: $gl-text-color; - } } svg { height: 14px; width: 14px; - fill: $gl-text-color-secondary; vertical-align: middle; } @@ -437,6 +432,7 @@ border-width: 1px; width: 17px; height: 17px; + top: 0; } &:hover, diff --git a/app/assets/stylesheets/framework/flash.scss b/app/assets/stylesheets/framework/flash.scss index e1b086ebb2b..88ce119ee3a 100644 --- a/app/assets/stylesheets/framework/flash.scss +++ b/app/assets/stylesheets/framework/flash.scss @@ -34,8 +34,15 @@ } } + .flash-success { + @extend .alert; + @extend .alert-success; + margin: 0; + } + .flash-notice, - .flash-alert { + .flash-alert, + .flash-success { border-radius: $border-radius-default; .container-fluid, @@ -48,7 +55,8 @@ margin-bottom: 0; .flash-notice, - .flash-alert { + .flash-alert, + .flash-success { border-radius: 0; } } diff --git a/app/assets/stylesheets/framework/gfm.scss b/app/assets/stylesheets/framework/gfm.scss index 34a35734acc..5621505996d 100644 --- a/app/assets/stylesheets/framework/gfm.scss +++ b/app/assets/stylesheets/framework/gfm.scss @@ -14,6 +14,5 @@ &:hover { background-color: $user-mention-bg-hover; - text-decoration: none; } } diff --git a/app/assets/stylesheets/framework/gitlab-theme.scss b/app/assets/stylesheets/framework/gitlab-theme.scss index dc591c06c88..db36e27fa74 100644 --- a/app/assets/stylesheets/framework/gitlab-theme.scss +++ b/app/assets/stylesheets/framework/gitlab-theme.scss @@ -30,10 +30,6 @@ &.dropdown.open > a { color: $color-900; background-color: $color-alternate; - - svg { - fill: currentColor; - } } &.line-separator { @@ -51,10 +47,6 @@ color: $color-200; > a { - svg { - fill: $color-200; - } - &.header-user-dropdown-toggle { .header-user-avatar { border-color: $color-200; diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index 1cdfa904374..f985a3aea5c 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -129,7 +129,7 @@ margin: 5px 2px 5px -8px; border-radius: $border-radius-default; - svg { + .tanuki-logo { @media (min-width: $screen-sm-min) { margin-right: 8px; } @@ -235,10 +235,6 @@ opacity: 1; color: $white-light; - svg { - fill: currentColor; - } - &.header-user-dropdown-toggle .header-user-avatar { border-color: $white-light; } @@ -269,14 +265,6 @@ font-size: 20px; } } - - &.active > a, - &.dropdown.open > a { - - svg { - fill: currentColor; - } - } } } } @@ -289,10 +277,6 @@ text-decoration: none; outline: 0; color: $white-light; - - svg { - fill: currentColor; - } } > a { @@ -307,10 +291,6 @@ border-radius: $border-radius-default; height: 32px; font-weight: $gl-font-weight-bold; - - svg { - fill: currentColor; - } } &.line-separator { @@ -401,10 +381,13 @@ .breadcrumbs-list { display: -webkit-flex; display: flex; - flex-wrap: wrap; margin-bottom: 0; line-height: 16px; + @media (max-width: $screen-xs-max) { + flex-wrap: wrap; + } + > li { display: flex; align-items: center; @@ -412,24 +395,35 @@ padding: 2px 0; &:not(:last-child) { - margin-right: 20px; + padding-right: 20px; + + &:not(.dropdown) { + overflow: hidden; + } } > a { font-size: 12px; color: currentColor; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + flex: 0 1 auto; } } } .breadcrumb-item-text { - @include str-truncated(128px); text-decoration: inherit; + + @media (max-width: $screen-xs-max) { + @include str-truncated(128px); + } } .breadcrumbs-list-angle { position: absolute; - right: -12px; + right: 7px; top: 50%; color: $gl-text-color-tertiary; transform: translateY(-50%); diff --git a/app/assets/stylesheets/framework/icons.scss b/app/assets/stylesheets/framework/icons.scss index ef864e8f6a9..e2084e8f85f 100644 --- a/app/assets/stylesheets/framework/icons.scss +++ b/app/assets/stylesheets/framework/icons.scss @@ -1,15 +1,11 @@ .ci-status-icon-success, .ci-status-icon-passed { - color: $green-500; - svg { fill: $green-500; } } .ci-status-icon-failed { - color: $gl-danger; - svg { fill: $gl-danger; } @@ -18,16 +14,12 @@ .ci-status-icon-pending, .ci-status-icon-failed_with_warnings, .ci-status-icon-success_with_warnings { - color: $orange-500; - svg { fill: $orange-500; } } .ci-status-icon-running { - color: $blue-400; - svg { fill: $blue-400; } @@ -36,8 +28,6 @@ .ci-status-icon-canceled, .ci-status-icon-disabled, .ci-status-icon-not-found { - color: $gl-text-color; - svg { fill: $gl-text-color; } @@ -45,16 +35,12 @@ .ci-status-icon-created, .ci-status-icon-skipped { - color: $gray-darkest; - svg { fill: $gray-darkest; } } .ci-status-icon-manual { - color: $gl-text-color; - svg { fill: $gl-text-color; } diff --git a/app/assets/stylesheets/framework/images.scss b/app/assets/stylesheets/framework/images.scss index 6819fd88b7f..78a8e57ddbb 100644 --- a/app/assets/stylesheets/framework/images.scss +++ b/app/assets/stylesheets/framework/images.scss @@ -27,6 +27,8 @@ } svg { + fill: currentColor; + &.s8 { @include svg-size(8px); } &.s12 { @include svg-size(12px); } &.s16 { @include svg-size(16px); } diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index ad3bb0e35d1..e6e6c4c3963 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -449,15 +449,19 @@ ul.indent-list { } } +.namespace-title { + .tooltip-inner { + max-width: 350px; + } +} + ul.group-list-tree { li.group-row { - &.has-description { - .title { - line-height: inherit; - } + &.has-description .title { + line-height: inherit; } - .title { + &:not(.has-description) .title { line-height: $list-text-height; } } diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss index cd6f94fb354..5389eb0a5f2 100644 --- a/app/assets/stylesheets/framework/markdown_area.scss +++ b/app/assets/stylesheets/framework/markdown_area.scss @@ -57,6 +57,7 @@ .md-header { .nav-links { a { + width: 100%; padding-top: 0; line-height: 19px; @@ -72,6 +73,28 @@ } } +.md-header-tab { + @media(max-width: $screen-xs-max) { + flex: 1; + width: 100%; + border-bottom: 1px solid $border-color; + text-align: center; + } +} + +.md-header-toolbar { + margin-left: auto; + + @media(max-width: $screen-xs-max) { + flex: none; + display: flex; + justify-content: center; + width: 100%; + padding-top: $gl-padding-top; + padding-bottom: $gl-padding-top; + } +} + .referenced-users { color: $gl-text-color; padding-top: 10px; @@ -126,16 +149,6 @@ } } -.toolbar-group { - float: left; - margin-right: -5px; - margin-left: $gl-padding; - - &:first-child { - margin-left: 0; - } -} - .toolbar-btn { float: left; padding: 0 7px; @@ -158,6 +171,16 @@ } } +.toolbar-fullscreen-btn { + margin-left: $gl-padding; + margin-right: -5px; + + @media(max-width: $screen-xs-max) { + margin-left: 0; + margin-right: 0; + } +} + .atwho-view { overflow-y: auto; overflow-x: hidden; diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss index 16d5edde61e..e12b5aab381 100644 --- a/app/assets/stylesheets/framework/mixins.scss +++ b/app/assets/stylesheets/framework/mixins.scss @@ -130,14 +130,6 @@ background-color: $color-light; color: $color-dark; border-color: $color-dark; - - svg { - fill: $color-dark; - } - } - - svg { - fill: $color-main; } } @@ -180,3 +172,31 @@ display: none; } } + +@mixin triangle($color, $border-color, $size, $border-size) { + &::before, + &::after { + bottom: 100%; + left: 50%; + border: solid transparent; + content: ''; + height: 0; + width: 0; + position: absolute; + pointer-events: none; + } + + &::before { + border-color: transparent; + border-bottom-color: $border-color; + border-width: ($size + $border-size); + margin-left: -($size + $border-size); + } + + &::after { + border-color: transparent; + border-bottom-color: $color; + border-width: $size; + margin-left: -$size; + } +} diff --git a/app/assets/stylesheets/framework/new-nav.scss b/app/assets/stylesheets/framework/new-nav.scss deleted file mode 100644 index e69de29bb2d..00000000000 --- a/app/assets/stylesheets/framework/new-nav.scss +++ /dev/null diff --git a/app/assets/stylesheets/framework/popup.scss b/app/assets/stylesheets/framework/popup.scss new file mode 100644 index 00000000000..5c76205095f --- /dev/null +++ b/app/assets/stylesheets/framework/popup.scss @@ -0,0 +1,15 @@ +.popup { + @include triangle( + $gray-lighter, + $gray-darker, + $popup-triangle-size, + $popup-triangle-border-size + ); + + padding: $gl-padding; + background-color: $gray-lighter; + border: 1px solid $gray-darker; + border-radius: $border-radius-default; + box-shadow: 0 5px 8px $popup-box-shadow-color; + position: relative; +} diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss index bb70b270299..dbee7073975 100644 --- a/app/assets/stylesheets/framework/selects.scss +++ b/app/assets/stylesheets/framework/selects.scss @@ -134,19 +134,22 @@ } .select2-search { - padding: 15px 15px 5px; + padding: $grid-size; .select2-drop-auto-width & { - padding: 15px 15px 5px; + padding: $grid-size; } input { - padding: 2px 25px 2px 5px; + padding: $grid-size; background: $white-light image-url('select2.png'); + background-clip: content-box; + background-origin: content-box; background-repeat: no-repeat; - background-position: right 0 bottom 6px; + background-position: right 0 bottom 0 !important; border: 1px solid $input-border; border-radius: $border-radius-default; + line-height: 16px; transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; &:focus { @@ -156,11 +159,16 @@ &.select2-active { background-color: $white-light; background-image: image-url('select2-spinner.gif') !important; + background-origin: content-box; background-repeat: no-repeat; - background-position: right 5px center !important; + background-position: right 6px center !important; background-size: 16px 16px !important; } } + + + .select2-results { + padding-top: 0; + } } .select2-results { diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index 1a19b7320a0..792981fdc48 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -43,11 +43,13 @@ } .sidebar-collapsed-icon { - cursor: pointer; - .btn { background-color: $gray-light; } + + &:not(.disabled) { + cursor: pointer; + } } } @@ -55,6 +57,10 @@ padding-right: 0; z-index: 300; + .btn-sidebar-action { + display: inline-flex; + } + @media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) { &:not(.wiki-sidebar):not(.build-sidebar):not(.issuable-bulk-update-sidebar) .content-wrapper { padding-right: $gutter_collapsed_width; @@ -136,3 +142,18 @@ .issuable-sidebar { @include new-style-dropdown; } + +.pikaday-container { + .pika-single { + margin-top: 2px; + width: 250px; + } + + .dropdown-menu-toggle { + line-height: 20px; + } +} + +.sidebar-collapsed-icon .sidebar-collapsed-value { + font-size: 12px; +} diff --git a/app/assets/stylesheets/framework/toggle.scss b/app/assets/stylesheets/framework/toggle.scss new file mode 100644 index 00000000000..71765da3908 --- /dev/null +++ b/app/assets/stylesheets/framework/toggle.scss @@ -0,0 +1,138 @@ +/** +* Toggle button +* +* @usage +* ### Active and Inactive text should be provided as data attributes: +* <button type="button" class="project-feature-toggle" data-enabled-text="Enabled" data-disabled-text="Disabled"> +* <i class="fa fa-spinner fa-spin loading-icon hidden"></i> +* </button> + +* ### Checked should have `is-checked` class +* <button type="button" class="project-feature-toggle is-checked" data-enabled-text="Enabled" data-disabled-text="Disabled"> +* <i class="fa fa-spinner fa-spin loading-icon hidden"></i> +* </button> + +* ### Disabled should have `is-disabled` class +* <button type="button" class="project-feature-toggle is-disabled" data-enabled-text="Enabled" data-disabled-text="Disabled" disabled="true"> +* <i class="fa fa-spinner fa-spin loading-icon hidden"></i> +* </button> + +* ### Loading should have `is-loading` and an icon with `loading-icon` class +* <button type="button" class="project-feature-toggle is-loading" data-enabled-text="Enabled" data-disabled-text="Disabled"> +* <i class="fa fa-spinner fa-spin loading-icon"></i> +* </button> +*/ +.project-feature-toggle { + position: relative; + border: 0; + outline: 0; + display: block; + width: 100px; + height: 24px; + cursor: pointer; + user-select: none; + background: $feature-toggle-color-disabled; + border-radius: 12px; + padding: 3px; + transition: all .4s ease; + + &::selection, + &::before::selection, + &::after::selection { + background: none; + } + + &::before { + color: $feature-toggle-text-color; + font-size: 12px; + line-height: 24px; + position: absolute; + top: 0; + left: 25px; + right: 5px; + text-align: center; + overflow: hidden; + text-overflow: ellipsis; + animation: animate-disabled .2s ease-in; + content: attr(data-disabled-text); + } + + &::after { + position: relative; + display: block; + content: ""; + width: 22px; + height: 18px; + left: 0; + border-radius: 9px; + background: $feature-toggle-color; + transition: all .2s ease; + } + + .loading-icon { + display: none; + font-size: 12px; + color: $white-light; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + + } + + &.is-loading { + &::before { + display: none; + } + + .loading-icon { + display: block; + + &::before { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } + } + } + + &.is-checked { + background: $feature-toggle-color-enabled; + + &::before { + left: 5px; + right: 25px; + animation: animate-enabled .2s ease-in; + content: attr(data-enabled-text); + } + + &::after { + left: calc(100% - 22px); + } + } + + &.is-disabled { + opacity: 0.4; + cursor: not-allowed; + } + + @media (max-width: $screen-xs-min) { + width: 50px; + + &::before, + &.is-checked::before { + display: none; + } + } + + @keyframes animate-enabled { + 0%, 35% { opacity: 0; } + 100% { opacity: 1; } + } + + @keyframes animate-disabled { + 0%, 35% { opacity: 0; } + 100% { opacity: 1; } + } +} diff --git a/app/assets/stylesheets/framework/tw_bootstrap.scss b/app/assets/stylesheets/framework/tw_bootstrap.scss index d5c6ddbb4a5..1c6e2bf3074 100644 --- a/app/assets/stylesheets/framework/tw_bootstrap.scss +++ b/app/assets/stylesheets/framework/tw_bootstrap.scss @@ -195,33 +195,6 @@ summary { } } -// Typography ================================================================= - -.text-primary, -.text-primary:hover { - color: $brand-primary; -} - -.text-success, -.text-success:hover { - color: $brand-success; -} - -.text-danger, -.text-danger:hover { - color: $brand-danger; -} - -.text-warning, -.text-warning:hover { - color: $brand-warning; -} - -.text-info, -.text-info:hover { - color: $brand-info; -} - // Prevent datetimes on tooltips to break into two lines .local-timeago { white-space: nowrap; diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 8ab48e4844f..4f99c27eff1 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -163,7 +163,7 @@ $gl-text-color: #2e2e2e; $gl-text-color-secondary: #707070; $gl-text-color-tertiary: #949494; $gl-text-color-quaternary: #d6d6d6; -$gl-text-color-inverted: rgba(255, 255, 255, 1.0); +$gl-text-color-inverted: rgba(255, 255, 255, 1); $gl-text-color-secondary-inverted: rgba(255, 255, 255, .85); $gl-text-green: $green-600; $gl-text-green-hover: $green-700; @@ -337,6 +337,7 @@ $regular_font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-San * Dropdowns */ $dropdown-width: 300px; +$dropdown-max-height: 215px; $dropdown-vertical-offset: 4px; $dropdown-link-color: #555; $dropdown-link-hover-bg: $row-hover; @@ -353,6 +354,7 @@ $dropdown-loading-bg: rgba(#fff, .6); $dropdown-chevron-size: 10px; $dropdown-toggle-active-border-color: darken($border-color, 14%); $dropdown-item-hover-bg: $gray-darker; +$dropdown-fade-mask-height: 32px; /* * Filtered Search @@ -406,7 +408,6 @@ $location-icon-color: #e7e9ed; * Notes */ $notes-light-color: $gl-text-color-secondary; -$notes-role-color: $gl-text-color-secondary; $note-disabled-comment-color: #b2b2b2; $note-targe3-outside: #fffff0; $note-targe3-inside: #ffffd3; @@ -486,8 +487,8 @@ $callout-success-color: $green-700; /* * Commit Page */ -$commit-max-width-marker-color: rgba(0, 0, 0, 0.0); -$commit-message-text-area-bg: rgba(0, 0, 0, 0.0); +$commit-max-width-marker-color: rgba(0, 0, 0, 0); +$commit-message-text-area-bg: rgba(0, 0, 0, 0); /* * Common @@ -555,6 +556,7 @@ $jq-ui-default-color: #777; /* * Label */ +$label-padding: 7px; $label-gray-bg: #f8fafc; $label-inverse-bg: #333; $label-remove-border: rgba(0, 0, 0, .1); @@ -564,6 +566,8 @@ $label-border-radius: 100px; * Animation */ $fade-in-duration: 200ms; +$fade-mask-transition-duration: .1s; +$fade-mask-transition-curve: ease-in-out; /* * Lint @@ -719,3 +723,10 @@ Image Commenting cursor */ $image-comment-cursor-left-offset: 12; $image-comment-cursor-top-offset: 30; + +/* +Popup +*/ +$popup-triangle-size: 15px; +$popup-triangle-border-size: 1px; +$popup-box-shadow-color: rgba(90, 90, 90, 0.05); diff --git a/app/assets/stylesheets/framework/wells.scss b/app/assets/stylesheets/framework/wells.scss index 68824ff8418..735fc4babd7 100644 --- a/app/assets/stylesheets/framework/wells.scss +++ b/app/assets/stylesheets/framework/wells.scss @@ -20,6 +20,11 @@ .ref-name { font-size: 12px; + + &:hover { + text-decoration: underline; + color: $gl-text-color; + } } } diff --git a/app/assets/stylesheets/framework/zen.scss b/app/assets/stylesheets/framework/zen.scss index 5a4d3ba0ee9..dbd3144b9b4 100644 --- a/app/assets/stylesheets/framework/zen.scss +++ b/app/assets/stylesheets/framework/zen.scss @@ -57,15 +57,7 @@ padding: 5px; font-size: 36px; - svg { - fill: $gl-text-color; - } - &:hover { color: $black; - - svg { - fill: $black; - } } } diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss index 27b10b536a2..f139f4ab650 100644 --- a/app/assets/stylesheets/pages/builds.scss +++ b/app/assets/stylesheets/pages/builds.scss @@ -49,6 +49,7 @@ font-size: 12px; border-radius: 0; border: 0; + padding: $grid-size; .bash { display: block; @@ -57,14 +58,13 @@ .top-bar { height: 35px; - display: flex; - justify-content: flex-end; background: $gray-light; border: 1px solid $border-color; color: $gl-text-color; position: sticky; position: -webkit-sticky; top: $header-height; + padding: $grid-size; &.affix { top: $header-height; @@ -90,9 +90,6 @@ } .truncated-info { - margin: 0 auto; - align-self: center; - .truncated-info-size { margin: 0 5px; } @@ -118,7 +115,11 @@ .controllers-buttons { color: $gl-text-color; - margin: 0 10px; + margin: 0 $grid-size; + + &:last-child { + margin-right: 0; + } } .btn-scroll.animate { diff --git a/app/assets/stylesheets/pages/clusters.scss b/app/assets/stylesheets/pages/clusters.scss index e5b9e1f2de6..c303f016ff9 100644 --- a/app/assets/stylesheets/pages/clusters.scss +++ b/app/assets/stylesheets/pages/clusters.scss @@ -8,3 +8,23 @@ // Wait for the Vue to kick-in and render the applications block min-height: 302px; } + +.clusters-dropdown-menu { + max-width: 100%; +} + +@include new-style-dropdown('.clusters-dropdown '); + +.clusters-container { + .nav-bar-right { + padding: $gl-padding-top $gl-padding; + } + + .empty-state .svg-content img { + width: 145px; + } + + .top-area .nav-controls > .btn.btn-add-cluster { + margin-right: 0; + } +} diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index b1850be8a5f..0cba223c6a6 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -189,6 +189,7 @@ .commit-content { padding-right: 10px; + white-space: normal; } .commit-actions { diff --git a/app/assets/stylesheets/pages/detail_page.scss b/app/assets/stylesheets/pages/detail_page.scss index 538e50ee306..52e4d904b9b 100644 --- a/app/assets/stylesheets/pages/detail_page.scss +++ b/app/assets/stylesheets/pages/detail_page.scss @@ -13,6 +13,41 @@ .author_link { white-space: nowrap; } + + @media (max-width: $screen-xs-max) { + display: block; + } +} + +.detail-page-header-body { + position: relative; + line-height: 35px; + display: flex; + flex-grow: 1; + + @media (min-width: $screen-sm-min) { + padding-left: 0; + padding-right: 0; + } +} + +.detail-page-header-actions { + @include new-style-dropdown; + + align-self: center; + flex-shrink: 0; + flex: 0 0 auto; + + @media (max-width: $screen-xs-max) { + width: 100%; + margin-top: 10px; + + > .issue-btn-group { + > .btn { + width: 100%; + } + } + } } .detail-page-description { diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index bce94e09367..848d7f144dc 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -628,21 +628,46 @@ } .diff-file-changes { - width: 450px; + max-width: 560px; + width: 100%; z-index: 150; @media (min-width: $screen-sm-min) { left: $gl-padding; } - a { + .diff-changed-file { + display: flex; padding-top: 8px; padding-bottom: 8px; + min-width: 0; } - .diff-changed-file { + .diff-file-changed-icon { + margin-top: 2px; + } + + .diff-changed-file-content { display: flex; - align-items: center; + flex-direction: column; + min-width: 0; + } + + .diff-changed-file-name, + .diff-changed-file-path { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .diff-changed-file-path { + direction: rtl; + color: $gl-text-color-tertiary; + } + + .diff-changed-stats { + margin-left: auto; + white-space: nowrap; } } diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index 26c5f093c6b..b0795353ec1 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -173,7 +173,7 @@ .prometheus-graph-overlay { fill: none; - opacity: 0.0; + opacity: 0; pointer-events: all; } diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss index 9b7dda9b648..f9a761e85fe 100644 --- a/app/assets/stylesheets/pages/groups.scss +++ b/app/assets/stylesheets/pages/groups.scss @@ -212,3 +212,15 @@ height: 50px; } } + +.user-access-role { + display: inline-block; + color: $gl-text-color-secondary; + font-size: 12px; + line-height: 20px; + margin: -5px 3px; + padding: 0 $label-padding; + border: 1px solid $border-color; + border-radius: $label-border-radius; + font-weight: $gl-font-weight-normal; +} diff --git a/app/assets/stylesheets/pages/help.scss b/app/assets/stylesheets/pages/help.scss index dae8ccdef6c..9cc9e11bcd1 100644 --- a/app/assets/stylesheets/pages/help.scss +++ b/app/assets/stylesheets/pages/help.scss @@ -1,23 +1,3 @@ -.documentation-index { - h1 { - margin: 0; - } - - h2 { - font-size: 20px; - } - - li { - line-height: 24px; - color: $document-index-color; - - a { - margin-right: 3px; - } - } -} - - .shortcut-mappings { font-size: 12px; color: $help-shortcut-mapping-color; diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index 760c7c80aff..11ee1232bfe 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -6,28 +6,20 @@ } .issuable-warning-icon { - color: $orange-600; background-color: $orange-100; border-radius: $border-radius-default; - padding: 5px; margin: 0 $btn-side-margin 0 0; width: $issuable-warning-size; height: $issuable-warning-size; text-align: center; - &:first-of-type { - margin-right: $issuable-warning-icon-margin; + .icon { + fill: $orange-600; + vertical-align: text-bottom; } -} - -.sidebar-item-icon { - border-radius: $border-radius-default; - padding: 5px; - margin: 0 3px 0 -4px; - &.is-active { - color: $orange-600; - background-color: $orange-50; + &:first-of-type { + margin-right: $issuable-warning-icon-margin; } } @@ -78,14 +70,13 @@ .title { padding: 0; - margin-bottom: 16px; + margin-bottom: $gl-padding; border-bottom: 0; } .btn-edit { margin-left: auto; - // Set height to match title height - height: 2em; + height: $gl-padding * 2; } // Border around images in issue and MR descriptions. @@ -119,6 +110,10 @@ padding: 6px 10px; border-radius: $label-border-radius; } + + &:hover .color-label { + text-decoration: underline; + } } &.has-labels { @@ -183,6 +178,14 @@ color: $gray-darkest; } } + + &.assignee { + .author_link:hover { + .author { + text-decoration: underline; + } + } + } } .block-first { @@ -284,10 +287,15 @@ font-weight: $gl-font-weight-normal; } - .no-value { + .no-value, + .btn-secondary-hover-link { color: $gl-text-color-secondary; } + .btn-secondary-hover-link:hover { + color: $gl-link-color; + } + .sidebar-collapsed-icon { display: none; } @@ -295,6 +303,8 @@ .gutter-toggle { margin-top: 7px; border-left: 1px solid $border-gray-normal; + padding-left: 0; + text-align: center; } .title .gutter-toggle { @@ -367,7 +377,7 @@ fill: $issuable-sidebar-color; } - &:hover, + &:hover:not(.disabled), &:hover .todo-undone { color: $gl-text-color; @@ -470,7 +480,6 @@ a:not(.btn-retry) { &:hover { color: $md-link-color; - text-decoration: none; .avatar { border-color: rgba($avatar-border, .2); @@ -615,50 +624,16 @@ margin-top: 0; height: auto; align-self: center; - - @media (max-width: $screen-xs-max) { - position: absolute; - top: 0; - left: 0; - } -} - -.issuable-header { - position: relative; - padding-left: 45px; - padding-right: 45px; - line-height: 35px; - display: flex; - flex-grow: 1; - - @media (min-width: $screen-sm-min) { - float: left; - padding-left: 0; - padding-right: 0; - } -} - -.issuable-actions { - @include new-style-dropdown; - - align-self: center; - flex-shrink: 0; - flex: 0 0 auto; - - @media (min-width: $screen-sm-min) { - float: right; - } } .issuable-gutter-toggle { @media (max-width: $screen-sm-max) { - position: absolute; - top: 0; - right: 0; + margin-left: $btn-side-margin; } } .issuable-meta { + flex: 1; display: inline-block; font-size: 14px; line-height: 24px; @@ -908,3 +883,21 @@ margin: 0 3px; } } + +.right-sidebar-collapsed { + .sidebar-grouped-item { + .sidebar-collapsed-icon { + margin-bottom: 0; + } + + .sidebar-collapsed-divider { + line-height: 5px; + font-size: 12px; + color: $theme-gray-700; + + + .sidebar-collapsed-icon { + padding-top: 0; + } + } + } +} diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index 8bb68ad2425..af1df8b8802 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -134,26 +134,11 @@ ul.related-merge-requests > li { } @media (max-width: $screen-xs-max) { - .detail-page-header, - .issuable-header { - display: block; - + .detail-page-header { .issuable-meta { line-height: 18px; } } - - .issuable-actions { - margin-top: 10px; - - .issue-btn-group { - width: 100%; - - .btn { - width: 100%; - } - } - } } .issue-form { @@ -164,12 +149,7 @@ ul.related-merge-requests > li { } } -.issues-footer { - padding-top: $gl-padding; - padding-bottom: 37px; -} - -.issue-email-modal-btn { +.issuable-email-modal-btn { padding: 0; color: $gl-link-color; background-color: transparent; @@ -203,7 +183,24 @@ ul.related-merge-requests > li { } .create-mr-dropdown-wrap { - @include new-style-dropdown; + .branch-message, + .ref-message { + display: none; + } + + .ref::selection { + color: $placeholder-text-color; + } + + .dropdown { + .dropdown-menu-toggle { + min-width: 285px; + } + + .dropdown-select { + width: 285px; + } + } .btn-group:not(.hide) { display: flex; @@ -214,15 +211,16 @@ ul.related-merge-requests > li { flex-shrink: 0; } - .dropdown-menu { + .create-merge-request-dropdown-menu { width: 300px; opacity: 1; visibility: visible; transform: translateY(0); display: none; + margin-top: 4px; } - .dropdown-toggle { + .create-merge-request-dropdown-toggle { .fa-caret-down { pointer-events: none; color: inherit; @@ -230,18 +228,50 @@ ul.related-merge-requests > li { } } + .droplab-item-ignore { + pointer-events: auto; + } + + .create-item { + cursor: pointer; + margin: 0 1px; + + &:hover, + &:focus { + background-color: $dropdown-item-hover-bg; + color: $gl-text-color; + } + } + + li.divider { + margin: 8px 10px; + } + li:not(.divider) { + padding: 8px 9px; + + &:last-child { + padding-bottom: 8px; + } + &.droplab-item-selected { .icon-container { i { visibility: visible; } } + + .description { + display: block; + } + } + + &.droplab-item-ignore { + padding-top: 8px; } .icon-container { float: left; - padding-left: 6px; i { visibility: hidden; @@ -249,13 +279,12 @@ ul.related-merge-requests > li { } .description { - padding-left: 30px; - font-size: 13px; + padding-left: 22px; + } - strong { - display: block; - font-weight: $gl-font-weight-bold; - } + input, + span { + margin: 4px 0 0; } } } diff --git a/app/assets/stylesheets/pages/labels.scss b/app/assets/stylesheets/pages/labels.scss index 443f5500684..92abe82df4c 100644 --- a/app/assets/stylesheets/pages/labels.scss +++ b/app/assets/stylesheets/pages/labels.scss @@ -104,7 +104,7 @@ } .color-label { - padding: 3px 7px; + padding: 3px $label-padding; border-radius: $label-border-radius; } diff --git a/app/assets/stylesheets/pages/login.scss b/app/assets/stylesheets/pages/login.scss index b7985c4dea5..b2250a1ce2f 100644 --- a/app/assets/stylesheets/pages/login.scss +++ b/app/assets/stylesheets/pages/login.scss @@ -252,6 +252,10 @@ background: $white-light; } + .login-page-broadcast { + margin-top: 50px; + } + .navless-container { padding: 65px 15px; // height of footer + bottom padding of email confirmation link diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index 5832cf4637f..2afb17334e3 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -384,6 +384,12 @@ } } +.nothing-here-block { + img { + width: 230px; + } +} + .mr-list { .merge-request { padding: 10px 0 10px 15px; diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss index 14514b2f193..ebb5d121433 100644 --- a/app/assets/stylesheets/pages/note_form.scss +++ b/app/assets/stylesheets/pages/note_form.scss @@ -7,7 +7,7 @@ .diff-file .diff-content { tr.line_holder:hover > td .line_note_link { - opacity: 1.0; + opacity: 1; filter: alpha(opacity = 100); } } @@ -113,6 +113,8 @@ .icon { margin-right: $issuable-warning-icon-margin; + vertical-align: text-bottom; + fill: $orange-600; } + .md-area { @@ -137,9 +139,21 @@ } } -.sidebar-item-value { - .fa { - background-color: inherit; +.sidebar-item-icon { + border-radius: $border-radius-default; + margin: 0 5px 0 0; + vertical-align: text-bottom; + + &.is-active { + fill: $orange-600; + } + + .sidebar-collapsed-icon & { + margin: 0; + } + + .sidebar-item-value & { + fill: $theme-gray-700; } } diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 9537eeeee97..4d5613c292b 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -208,7 +208,6 @@ ul.notes { a { color: $gl-link-color; - text-decoration: none; } p { @@ -395,6 +394,10 @@ ul.notes { &:focus, &:hover { text-decoration: none; + + .note-header-author-name { + text-decoration: underline; + } } } @@ -461,6 +464,10 @@ ul.notes { .system-note-message { white-space: normal; } + + a:hover { + text-decoration: underline; + } } /** @@ -543,14 +550,7 @@ ul.notes { } svg { - height: 16px; - width: 16px; - top: 0; - vertical-align: text-top; - - path { - fill: currentColor; - } + @include btn-svg; } .award-control-icon-positive, @@ -570,10 +570,6 @@ ul.notes { .link-highlight { color: $gl-link-color; fill: $gl-link-color; - - svg { - fill: $gl-link-color; - } } .award-control-icon-neutral { @@ -623,26 +619,17 @@ ul.notes { } .note-role { + margin: 0 3px; +} + +.note-role-special { position: relative; display: inline-block; - color: $notes-role-color; + color: $gl-text-color-secondary; font-size: 12px; - line-height: 20px; - margin: 0 3px; - - &.note-role-access { - padding: 0 7px; - border: 1px solid $border-color; - border-radius: $label-border-radius; - } - - &.note-role-special { - text-shadow: 0 0 15px $gl-text-color-inverted; - } + text-shadow: 0 0 15px $gl-text-color-inverted; } - - /** * Line note button on the side of diffs */ @@ -788,12 +775,6 @@ ul.notes { } } - svg { - fill: currentColor; - height: 16px; - width: 16px; - } - .loading { margin: 0; height: auto; diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss index 28dc71dc641..ac745019319 100644 --- a/app/assets/stylesheets/pages/profile.scss +++ b/app/assets/stylesheets/pages/profile.scss @@ -73,7 +73,7 @@ .profile-link-holder { display: inline; - a { + a:not(.text-link) { text-decoration: none; } } diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index aaad6dbba8e..674588752d2 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -126,93 +126,6 @@ } } -.project-feature-toggle { - position: relative; - border: 0; - outline: 0; - display: block; - width: 100px; - height: 24px; - cursor: pointer; - user-select: none; - background: $feature-toggle-color-disabled; - border-radius: 12px; - padding: 3px; - transition: all .4s ease; - - &::selection, - &::before::selection, - &::after::selection { - background: none; - } - - &::before { - color: $feature-toggle-text-color; - font-size: 12px; - line-height: 24px; - position: absolute; - top: 0; - left: 25px; - right: 5px; - text-align: center; - overflow: hidden; - text-overflow: ellipsis; - animation: animate-disabled .2s ease-in; - content: attr(data-disabled-text); - } - - &::after { - position: relative; - display: block; - content: ""; - width: 22px; - height: 18px; - left: 0; - border-radius: 9px; - background: $feature-toggle-color; - transition: all .2s ease; - } - - &.checked { - background: $feature-toggle-color-enabled; - - &::before { - left: 5px; - right: 25px; - animation: animate-enabled .2s ease-in; - content: attr(data-enabled-text); - } - - &::after { - left: calc(100% - 22px); - } - } - - &.disabled { - opacity: 0.4; - cursor: not-allowed; - } - - @media (max-width: $screen-xs-min) { - width: 50px; - - &::before, - &.checked::before { - display: none; - } - } - - @keyframes animate-enabled { - 0%, 35% { opacity: 0; } - 100% { opacity: 1; } - } - - @keyframes animate-disabled { - 0%, 35% { opacity: 0; } - 100% { opacity: 1; } - } -} - .project-home-panel, .group-home-panel { padding-top: 24px; @@ -291,14 +204,7 @@ } svg { - - path { - fill: $layout-link-gray; - } - - use { - stroke: $layout-link-gray; - } + fill: $layout-link-gray; } .fa-caret-down { @@ -402,6 +308,18 @@ } } } + + .clone-dropdown-btn { + background-color: $white-light; + } + + .clone-options-dropdown { + min-width: 240px; + + .dropdown-menu-inner-content { + min-width: 320px; + } + } } .project-repo-buttons { @@ -806,6 +724,7 @@ a.deploy-project-label { &:hover, &:focus { color: $gl-text-color; + text-decoration: underline; } } } @@ -886,10 +805,6 @@ pre.light-well { font-size: $gl-font-size; } - a { - color: $gl-text-color; - } - .avatar-container, .controls { flex: 0 0 auto; @@ -1208,3 +1123,8 @@ pre.light-well { border-color: $border-color; } } + +.issuable-footer { + padding-top: $gl-padding; + padding-bottom: 37px; +} diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss index d93c51d5448..402412eae71 100644 --- a/app/assets/stylesheets/pages/repo.scss +++ b/app/assets/stylesheets/pages/repo.scss @@ -35,270 +35,276 @@ } } -.repository-view { - border: 1px solid $border-color; - border-radius: $border-radius-default; - color: $almost-black; +.multi-file { + display: flex; + height: calc(100vh - 145px); + border-top: 1px solid $white-dark; + border-bottom: 1px solid $white-dark; + + &.is-collapsed { + .ide-file-list { + max-width: 250px; + } + } +} - .code.white pre .hll { - background-color: $well-light-border !important; +.ide-file-list { + flex: 1; + overflow: scroll; + + .file { + cursor: pointer; } - .tree-content-holder { - display: -webkit-flex; - display: flex; - min-height: 300px; + a { + color: $gl-text-color; } - .tree-content-holder-mini { - height: 100vh; + th { + position: sticky; + top: 0; } +} - .panel-right { - display: -webkit-flex; - display: flex; - -webkit-flex-direction: column; - flex-direction: column; - width: 80%; - height: 100%; +.multi-file-table-name, +.multi-file-table-col-commit-message { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 0; +} - .monaco-editor.vs { - .current-line { - border: 0; - background: $well-light-border; - } +.multi-file-table-name { + width: 350px; +} - .line-numbers { - cursor: pointer; +.multi-file-table-col-commit-message { + width: 50%; +} - &:hover { - text-decoration: underline; - } - } - } +.multi-file-edit-pane { + display: flex; + flex-direction: column; + flex: 1; + border-left: 1px solid $white-dark; + overflow: hidden; +} - .blob-no-preview { - .vertical-center { - justify-content: center; - width: 100%; - } - } +.multi-file-tabs { + display: flex; + overflow: scroll; + background-color: $white-normal; + box-shadow: inset 0 -1px $white-dark; - &.blob-editor-container { - overflow: hidden; - } + > li { + position: relative; + } +} - .blob-viewer-container { - -webkit-flex: 1; - flex: 1; - overflow: auto; - - > div, - .file-content:not(.wiki) { - display: flex; - } - - > div, - .file-content, - .blob-viewer, - .line-number, - .blob-content, - .code { - min-height: 100%; - width: 100%; - } - - .line-numbers { - min-width: 44px; - } - - .blob-content { - flex: 1; - overflow-x: auto; - } - } +.multi-file-tab { + @include str-truncated(150px); + padding: ($gl-padding / 2) ($gl-padding + 12) ($gl-padding / 2) $gl-padding; + background-color: $gray-normal; + border-right: 1px solid $white-dark; + border-bottom: 1px solid $white-dark; + cursor: pointer; + + &.active { + background-color: $white-light; + border-bottom-color: $white-light; + } +} - #tabs { - position: relative; - flex-shrink: 0; - display: flex; - width: 100%; - padding-left: 0; - margin-bottom: 0; - white-space: nowrap; - overflow-y: hidden; - overflow-x: auto; - - li { - position: relative; - background: $gray-normal; - padding: #{$gl-padding / 2} $gl-padding; - border-right: 1px solid $white-dark; - border-bottom: 1px solid $white-dark; - cursor: pointer; - - &.active { - background: $white-light; - border-bottom: 0; - } - - a { - @include str-truncated(100px); - color: $gl-text-color; - vertical-align: middle; - text-decoration: none; - margin-right: 12px; - - &:focus { - outline: none; - } - } - - .close-btn { - position: absolute; - right: 8px; - top: 50%; - padding: 0; - background: none; - border: 0; - font-size: $gl-font-size; - transform: translateY(-50%); - } - - .close-icon:hover { - color: $hint-color; - } - - .close-icon, - .unsaved-icon { - color: $gray-darkest; - } - - .unsaved-icon { - color: $brand-success; - } - - &.tabs-divider { - width: 100%; - background-color: $white-light; - border-right: 0; - border-top-right-radius: 2px; - } - } - } +.multi-file-tab-close { + position: absolute; + right: 8px; + top: 50%; + padding: 0; + background: none; + border: 0; + font-size: $gl-font-size; + color: $gray-darkest; + transform: translateY(-50%); + + &:not(.modified):hover, + &:not(.modified):focus { + color: $hint-color; + } - .repo-file-buttons { - background-color: $white-light; - padding: 5px 10px; - border-top: 1px solid $white-normal; - } + &.modified { + color: $indigo-700; + } +} - #binary-viewer { - height: 80vh; - overflow: auto; - margin: 0; - - .blob-viewer { - padding-top: 20px; - padding-left: 20px; - } - - .binary-unknown { - text-align: center; - padding-top: 100px; - background: $gray-light; - height: 100%; - font-size: 17px; - - span { - display: block; - } - } - } +.multi-file-edit-pane-content { + flex: 1; + height: 0; +} + +.multi-file-editor-btn-group { + padding: $grid-size; + border-top: 1px solid $white-dark; +} + +// Not great, but this is to deal with our current output +.multi-file-preview-holder { + height: 100%; + overflow: scroll; + + .blob-viewer { + height: 100%; } - #commit-area { - background: $gray-light; - padding: 20px; + .file-content.code { + display: flex; - .help-block { - padding-top: 7px; - margin-top: 0; + i { + margin-left: -10px; } } - #view-toggler { - height: 41px; - position: relative; - display: block; - border-bottom: 1px solid $white-normal; - background: $white-light; - margin-top: -5px; + .line-numbers { + min-width: 50px; } - #binary-viewer { - img { - max-width: 100%; - } + .file-content, + .line-numbers, + .blob-content, + .code { + min-height: 100%; } +} - #sidebar { - flex: 1; - height: 100%; +.multi-file-commit-panel { + display: flex; + flex-direction: column; + height: 100%; + width: 290px; + padding: $gl-padding; + background-color: $gray-light; + border-left: 1px solid $white-dark; + + &.is-collapsed { + width: 60px; + padding: 0; + } +} - &.sidebar-mini { - width: 20%; - border-right: 1px solid $white-normal; - overflow: auto; - } +.multi-file-commit-panel-section { + display: flex; + flex-direction: column; + flex: 1; +} - .table { - margin-bottom: 0; - } +.multi-file-commit-panel-header { + display: flex; + align-items: center; + padding: 0 0 12px; + margin-bottom: 12px; + border-bottom: 1px solid $white-dark; - tr { - .repo-file-options { - padding: 2px 16px; - width: 100%; - } - - .title { - font-size: 10px; - text-transform: uppercase; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - vertical-align: middle; - } - - .file-icon { - margin-right: 5px; - } - - td { - white-space: nowrap; - } - } + &.is-collapsed { + border-bottom: 1px solid $white-dark; - .file { - cursor: pointer; + svg { + margin-left: auto; + margin-right: auto; } + } +} - a { - @include str-truncated(250px); - color: $almost-black; - } +.multi-file-commit-panel-collapse-btn { + padding-top: 0; + padding-bottom: 0; + margin-left: auto; + font-size: 20px; + + &.is-collapsed { + margin-right: auto; + } +} + +.multi-file-commit-list { + flex: 1; + overflow: scroll; +} + +.multi-file-commit-list-item { + display: flex; + align-items: center; +} + +.multi-file-addition { + fill: $green-500; +} + +.multi-file-modified { + fill: $orange-500; +} + +.multi-file-commit-list-collapsed { + display: flex; + flex-direction: column; + + > svg { + margin-left: auto; + margin-right: auto; } } -.render-error { - min-height: calc(100vh - 62px); +.multi-file-commit-list-path { + @include str-truncated(100%); +} + +.multi-file-commit-form { + padding-top: 12px; + border-top: 1px solid $white-dark; +} + +.multi-file-commit-fieldset { + display: flex; + align-items: center; + padding-bottom: 12px; - p { - width: 100%; + .btn { + flex: 1; } } -.multi-file-table-col-name { - width: 350px; +.multi-file-commit-message.form-control { + height: 80px; + resize: none; +} + +.dirty-diff { + // !important need to override monaco inline style + width: 4px !important; + left: 0 !important; + + &-modified { + background-color: $blue-500; + } + + &-added { + background-color: $green-600; + } + + &-removed { + height: 0 !important; + width: 0 !important; + bottom: -2px; + border-style: solid; + border-width: 5px; + border-color: transparent transparent transparent $red-500; + + &::before { + content: ''; + position: absolute; + left: 0; + top: 0; + width: 100px; + height: 1px; + background-color: rgba($red-500, .5); + } + } } diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss index 8b9b47a41bc..5d630c7d61e 100644 --- a/app/assets/stylesheets/pages/settings.scss +++ b/app/assets/stylesheets/pages/settings.scss @@ -249,3 +249,22 @@ } } } + +.modal-doorkeepr-auth, +.doorkeeper-app-form { + .scope-description { + color: $theme-gray-700; + } +} + +.modal-doorkeepr-auth { + .modal-body { + padding: $gl-padding; + } +} + +.doorkeeper-app-form { + .scope-description { + margin: 0 0 5px 17px; + } +} diff --git a/app/assets/stylesheets/pages/status.scss b/app/assets/stylesheets/pages/status.scss index 25c80e1f950..ade5ddd147b 100644 --- a/app/assets/stylesheets/pages/status.scss +++ b/app/assets/stylesheets/pages/status.scss @@ -55,10 +55,6 @@ &:not(span):hover { background-color: rgba($gl-text-color-secondary, .07); } - - svg { - fill: $gl-text-color-secondary; - } } } diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss index 50f0ef4414a..5d14323e4bc 100644 --- a/app/assets/stylesheets/pages/tree.scss +++ b/app/assets/stylesheets/pages/tree.scss @@ -4,6 +4,11 @@ .nav-block { margin: 10px 0; + .btn .fa, + .btn svg { + color: $gl-text-color-secondary; + } + @media (min-width: $screen-sm-min) { display: flex; @@ -91,8 +96,12 @@ } .add-to-tree { - vertical-align: middle; - padding: 6px 10px; + vertical-align: top; + padding: 8px; + + svg { + top: 0; + } } .tree-table { @@ -125,7 +134,7 @@ color: $white-normal; } - &:hover { + &:hover:not(.tree-truncated-warning) { td { background-color: $row-hover; border-top: 1px solid $row-hover-border; @@ -198,6 +207,11 @@ } } + .tree-truncated-warning { + color: $orange-600; + background-color: $orange-100; + } + .tree-time-ago { min-width: 135px; color: $gl-text-color-secondary; diff --git a/app/assets/stylesheets/pages/wiki.scss b/app/assets/stylesheets/pages/wiki.scss index e150f96f3fa..d8fec583121 100644 --- a/app/assets/stylesheets/pages/wiki.scss +++ b/app/assets/stylesheets/pages/wiki.scss @@ -124,7 +124,11 @@ &:hover, &.active { - color: $black; + text-decoration: none; + + span { + text-decoration: underline; + } } } |