NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Jira next-gen - Dedupe notifications
// @namespace https://blog.vicshih.com/2022/04/jira-next-gen-dedupe-notifications.html
// @version 0.2
// @description Jira next-gen - Hide duplicate notifications for issues.
// @author Victor Shih
// @match https://*.atlassian.net/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=atlassian.net
// @grant none
// @license GPL-3.0-or-later
// ==/UserScript==
/* jshint esversion: 6 */
(function () {
'use strict';
const articleSelector = '[data-testid="notification-item-container"]';
function triggerGroup(event) {
if (localStorage.dedupe != 'true' || event.detail.dispatched) { return }
const theButton = event.currentTarget;
const theHref = theButton.closest(articleSelector).querySelector('a').getAttribute('href');
// Trigger all other (hidden) buttons with the same href.
const feed = document.querySelector('[role="feed"]');
for (let article of feed.querySelectorAll(articleSelector)) {
const button = article.querySelector('[data-testid="read-state-indicator"]'),
href = article.querySelector('a').getAttribute('href').split('?')[0];
if (button != theButton && href == theHref) {
button.dispatchEvent(new CustomEvent(
'click',
{bubbles: true, detail: {dispatched: true}}
));
}
}
}
function handleCheckDedupe(event, checked) {
if (event) {
checked = event.currentTarget.checked;
localStorage.dedupe = checked;
}
const feed = document.querySelector('[role="feed"]');
/* TODO debounce
if (feed.getAttribute('deduped')) { return }
feed.setAttribute('deduped', true);
*/
const articles = feed.querySelectorAll(articleSelector);
if (checked) {
let hrefs = new Set();
for (let article of articles) {
const button = article.querySelector('[data-testid="read-state-indicator"]'),
href = article.querySelector('a').getAttribute('href').split('?')[0];
if (hrefs.has(href)) {
// Hide the (parent) node.
article.parentNode.style.display = 'none';
} else {
hrefs.add(href);
}
if (!button.getAttribute('dedupe-handler')) {
button.setAttribute('dedupe-handler', true);
button.addEventListener('click', triggerGroup, {passive: true});
}
}
} else {
for (let article of articles) {
// Just show every article's direct-parent.
article.parentNode.style.display = '';
}
}
}
function poll() {
let h1 = document.querySelector('#notification-list-header-label');
if (!h1) {
// Notifications not open.
return;
}
const checked = localStorage.dedupe == 'true';
if (h1.nextElementSibling.getAttribute('for') != 'dedupe') {
// Inject dedupe checkbox.
let label = document.createElement('label');
label.setAttribute('for', 'dedupe');
label.innerHTML = `Dedupe <input id="dedupe" type="checkbox" ${checked ? 'checked' : ''}>`;
label.style.marginRight = '15px';
h1.after(label);
// Register handler.
const dedupe = document.querySelector('#dedupe');
dedupe.addEventListener('change', handleCheckDedupe, {passive: true});
}
handleCheckDedupe(null, checked);
}
setInterval(poll, 250);
})();