Mark All Merged/Closed Notifications Done

Marks all merged and closed notifications as "done" on GitHub (client-side) and only shows UI when needed. Includes console logging and error handling.

  1. // ==UserScript==
  2. // @name Mark All Merged/Closed Notifications Done
  3. // @namespace typpi.online
  4. // @version 1.8
  5. // @description Marks all merged and closed notifications as "done" on GitHub (client-side) and only shows UI when needed. Includes console logging and error handling.
  6. // @author Nick2bad4u
  7. // @match https://github.com/notifications
  8. // @grant GM_addStyle
  9. // @grant GM_xmlhttpRequest
  10. // @connect api.github.com
  11. // @license Unlicense
  12. // @tag github
  13. // @icon https://www.google.com/s2/favicons?sz=64&domain=github.com
  14. // @homepageURL https://github.com/Nick2bad4u/UserStyles
  15. // @supportURL https://github.com/Nick2bad4u/UserStyles/issues
  16. //
  17. // ==/UserScript==
  18.  
  19. (function() {
  20. 'use strict';
  21.  
  22. const DONE_BUTTON_SELECTOR = 'button[aria-label="Done"]';
  23. const NOTIFICATION_SELECTOR = '.notifications-list-item';
  24. const MERGED_ICON_SELECTOR = 'svg.octicon-git-merge';
  25. const CLOSED_ICON_SELECTOR = 'svg.octicon-git-pull-request-closed';
  26. const DELAY_MS = 500; // Delay after each action (adjust as needed)
  27.  
  28. let markAsDoneButton; // Declare the button outside the function
  29.  
  30. function addButton() {
  31. try {
  32. markAsDoneButton = document.createElement('button');
  33. markAsDoneButton.textContent = 'Mark All Merged/Closed Done';
  34. markAsDoneButton.classList.add('mark-merged-done-button');
  35. markAsDoneButton.addEventListener('click', markAllMergedAndClosedAsDone);
  36. markAsDoneButton.style.display = 'none'; // Initially hide the button
  37.  
  38. const notificationsToolbar = document.querySelector('.js-socket-channel.js-updatable-content');
  39. if (notificationsToolbar) {
  40. notificationsToolbar.appendChild(markAsDoneButton);
  41. console.log('Mark All Merged/Closed Done button added to notifications toolbar.');
  42. } else {
  43. console.warn('Could not find notifications toolbar. Button may not be visible.');
  44. document.body.appendChild(markAsDoneButton); // Fallback
  45. console.log('Mark All Merged/Closed Done button added to document body as fallback.');
  46. }
  47.  
  48. // Check for relevant notifications and show the button if needed
  49. checkForMergedAndClosedNotifications();
  50. } catch (error) {
  51. console.error('Error in addButton function:', error);
  52. }
  53. }
  54.  
  55. function checkForMergedAndClosedNotifications() {
  56. try {
  57. const notifications = document.querySelectorAll(NOTIFICATION_SELECTOR);
  58. let hasRelevantNotifications = false;
  59.  
  60. for (const notification of notifications) {
  61. if (notification.querySelector(MERGED_ICON_SELECTOR) || notification.querySelector(CLOSED_ICON_SELECTOR)) {
  62. hasRelevantNotifications = true;
  63. break; // No need to continue checking
  64. }
  65. }
  66.  
  67. if (hasRelevantNotifications) {
  68. markAsDoneButton.style.display = 'block'; // Show the button
  69. console.log('Relevant notifications found. Showing Mark All Merged/Closed Done button.');
  70. } else {
  71. markAsDoneButton.style.display = 'none'; // Hide the button
  72. console.log('No relevant notifications found. Hiding Mark All Merged/Closed Done button.');
  73. }
  74. } catch (error) {
  75. console.error('Error in checkForMergedAndClosedNotifications function:', error);
  76. }
  77. }
  78.  
  79. async function markAllMergedAndClosedAsDone() {
  80. try {
  81. const notifications = document.querySelectorAll(NOTIFICATION_SELECTOR);
  82. console.log(`Found ${notifications.length} notifications.`);
  83.  
  84. for (const notification of notifications) {
  85. const isMerged = notification.querySelector(MERGED_ICON_SELECTOR);
  86. const isClosed = notification.querySelector(CLOSED_ICON_SELECTOR);
  87.  
  88. if (isMerged || isClosed) {
  89. console.log(`Marking ${isMerged ? 'merged' : 'closed'} notification as done`);
  90. const doneButton = notification.querySelector(DONE_BUTTON_SELECTOR);
  91.  
  92. if (doneButton) {
  93. doneButton.click();
  94. await delay(DELAY_MS); // Wait for the UI to update
  95. } else {
  96. console.warn('Could not find "Done" button for notification.');
  97. }
  98. }
  99. }
  100.  
  101. console.log('Finished processing notifications.');
  102. checkForMergedAndClosedNotifications(); // Recheck after marking
  103. } catch (error) {
  104. console.error('Error in markAllMergedAndClosedAsDone function:', error);
  105. }
  106. }
  107.  
  108. // Helper function to introduce a delay
  109. function delay(ms) {
  110. return new Promise(resolve => setTimeout(resolve, ms));
  111. }
  112.  
  113. const style = document.createElement('style');
  114. document.head.appendChild(style);
  115. style.textContent = `
  116. .mark-merged-done-button {
  117. position: fixed;
  118. bottom: 50px; /* Adjusted bottom position */
  119. right: 10px;
  120. z-index: 999; /* Ensure it's below the other button if necessary */
  121. background-color: #2ea44f; /* Same color as the other script */
  122. color: #ffffff;
  123. border: none;
  124. padding: 10px;
  125. border-radius: 5px;
  126. cursor: pointer;
  127. }
  128. .mark-merged-done-button:hover {
  129. background-color: #79e4f2; /* Same hover color as the other script */
  130. }
  131. `;
  132.  
  133. window.addEventListener('load', addButton);
  134. })();