Jira Tweaks

Userscript adding some jira tweaks (for devs?)

  1. // ==UserScript==
  2. // @name Jira Tweaks
  3. // @namespace Violentmonkey Scripts
  4. // @description Userscript adding some jira tweaks (for devs?)
  5. // @match https://*.atlassian.net/*
  6. // @version 0.0.1
  7. // @author Fabio T <iam@f4b.io> (https://iam.f4b.io)
  8. // @license AGPL-3
  9. // @require https://cdn.jsdelivr.net/npm/@violentmonkey/dom@2
  10. // @require https://cdn.jsdelivr.net/npm/@violentmonkey/ui@0.7
  11. // @require https://cdn.jsdelivr.net/npm/slugify@1.6.6
  12. // @grant GM_setClipboard
  13. // ==/UserScript==
  14.  
  15. (function (VM$2, VM$1) {
  16. 'use strict';
  17.  
  18. function formatName(id, name) {
  19. const _id = id.replace(" ", "-");
  20. const _name = slugify(name, {
  21. lower: true,
  22. strict: true
  23. });
  24. return `${_id}/${_name}`;
  25. }
  26. function copyToClipboard(content) {
  27. VM$1.showToast(VM$1.h("div", null, "copied to `", content, "` clipboard"), {
  28. theme: "dark",
  29. duration: 2000
  30. });
  31. GM_setClipboard(content, "text/plain");
  32. }
  33.  
  34. function IconButton({
  35. Icon,
  36. name,
  37. title,
  38. handleClick
  39. }) {
  40. return VM.h("div", {
  41. role: "presentation"
  42. }, VM.h("button", {
  43. "aria-label": "BranchName",
  44. "aria-busy": "false",
  45. class: "css-1xewsy6",
  46. tabindex: "0",
  47. type: "button",
  48. onClick: handleClick(name),
  49. title: title
  50. }, VM.h("span", {
  51. class: "css-bwxjrz"
  52. }, VM.h("span", {
  53. class: "_ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _18u0myb0 _2hwx12gs"
  54. }, VM.h("span", {
  55. "aria-hidden": "true",
  56. class: "css-1afrefi",
  57. style: "--icon-primary-color: currentColor; --icon-secondary-color: var(--ds-surface, #FFFFFF);"
  58. }, VM.h(Icon, null)))), VM.h("span", {
  59. class: "css-178ag6o"
  60. }, name)));
  61. }
  62.  
  63. function _extends() {
  64. _extends = Object.assign ? Object.assign.bind() : function (target) {
  65. for (var i = 1; i < arguments.length; i++) {
  66. var source = arguments[i];
  67. for (var key in source) {
  68. if (Object.prototype.hasOwnProperty.call(source, key)) {
  69. target[key] = source[key];
  70. }
  71. }
  72. }
  73. return target;
  74. };
  75. return _extends.apply(this, arguments);
  76. }
  77.  
  78. function BranchIcon(props) {
  79. return VM.h("svg", _extends({
  80. xmlns: "http://www.w3.org/2000/svg",
  81. width: "24",
  82. height: "24",
  83. viewBox: "0 0 24 24",
  84. role: "presentation"
  85. }, props), VM.h("path", {
  86. d: "M19 11c0 1.3-.8 2.4-2 2.8V15c0 2.2-1.8 4-4 4h-2.2c-.4 1.2-1.5 2-2.8 2-1.7 0-3-1.3-3-3 0-1.3.8-2.4 2-2.8V8.8C5.9 8.4 5 7.3 5 6c0-1.7 1.3-3 3-3s3 1.3 3 3c0 1.3-.8 2.4-2.1 2.8v6.4c.9.3 1.6.9 1.9 1.8H13c1.1 0 2-.9 2-2v-1.2c-1.2-.4-2-1.5-2-2.8 0-1.7 1.3-3 3-3s3 1.3 3 3zM8 5c-.5 0-1 .4-1 1s.4 1 1 1 1-.4 1-1-.4-1-1-1zm8 7c.6 0 1-.4 1-1s-.4-1-1-1-1 .4-1 1 .4 1 1 1zm-8 7c.6 0 1-.4 1-1s-.4-1-1-1-1 .4-1 1 .4 1 1 1z",
  87. fill: "currentColor",
  88. "fill-rule": "evenodd"
  89. }));
  90. }
  91.  
  92. VM$2.observe(document.body, () => {
  93. var _document$querySelect;
  94. const taskId = () => {
  95. const taskId = document.querySelector("a[data-testid='issue.views.issue-base.foundation.breadcrumbs.current-issue.item'] > span");
  96. return taskId == null ? void 0 : taskId.innerHTML;
  97. };
  98. const taskName = () => {
  99. const taskName = document.querySelector("h1[data-testid='issue.views.issue-base.foundation.summary.heading']");
  100. return taskName == null ? void 0 : taskName.innerHTML;
  101. };
  102.  
  103. /* remove upgrade warning */
  104. const upgradeWarningContainer = document.querySelector("div[class='_1e0c1txw _2lx21bp4 _1bah1h6o _4cvr1y6m _1yt41e2i _zulpu2gc _otyrpxbi']");
  105. if (upgradeWarningContainer) {
  106. upgradeWarningContainer.remove();
  107. }
  108.  
  109. /* add branch name button */
  110. const attachButtonContainer = (_document$querySelect = document.querySelector("button[aria-label='Attach']")) == null ? void 0 : _document$querySelect.closest("div[role='presentation']");
  111. const actionsContainer = attachButtonContainer == null ? void 0 : attachButtonContainer.parentNode;
  112. if (actionsContainer) {
  113. const branchName = formatName(taskId(), taskName());
  114. actionsContainer.insertBefore(VM$2.m(VM$2.h(IconButton, {
  115. handleClick: copyToClipboard(branchName),
  116. Icon: BranchIcon,
  117. name: branchName,
  118. title: "Copy branch name to clipboard"
  119. })), attachButtonContainer.nextSibling);
  120. // disconnect observer
  121. return true;
  122. }
  123. });
  124.  
  125. // You can also disconnect the observer explicitly when it's not used any more
  126. // disconnect();
  127.  
  128. })(VM, VM);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址