Give Jira issue page an update button, in the top navigation bar, when the issue is updated while the page is shown. Also update the title.
Versión del día
// ==UserScript== // @name Jira issue page updated notification // @description Give Jira issue page an update button, in the top navigation bar, when the issue is updated while the page is shown. Also update the title. // @author Marnix Klooster <[email protected]> // @copyright public domain // @version 0.4 // @include /^https?://(jira\.[^/]*|[^/]*\.atlassian\.net)/browse// // @require https://cdn.jsdelivr.net/npm/[email protected]/build/global/luxon.min.js // @grant none // @namespace https://greasyfork.org/users/1047370 // ==/UserScript== /// TODO list: /// * Also handle pages like https://jira.example.org/projects/PROJ/issues/PROJ-64201 /// * Better error handling around unexpected URLs; stop retrying if no issue name can be found? /// * Robustness in case `aui-nav` element does not exist. /// * Perhaps: Wait longer after an error response? /// * Perhaps: If another update is done, update the time on the button. "use strict"; /// configuration settings /// (also look at @include and @match in the manifest above, /// which you can usually override in your userscript browser extension configuration) var timeBetweenChecksInSeconds = 10; var issueUpdateDelayInSeconds = 2; // to prevent the update button after you edit the issue page yourself /// From https://stackoverflow.com/a/35385518/223837 function htmlToElement(html) { var template = document.createElement('template'); html = html.trim(); // Never return a text node of whitespace as the result template.innerHTML = html; return template.content.firstChild; } (function () { var pageLastUpdatedInMillis = Date.now(); // `undefined` means that we are not checking for issue updates function regularlyCheckForUpdates() { if (!pageLastUpdatedInMillis) { console.log(`ERROR: internal inconsistency, we don't know when this page was last updated...`); return; } var issueNumber = new URL(window.location.href).pathname.split('/')[2]; console.log(`Checking whether issue ${issueNumber} has been recently updated`); $.ajax({url:`/rest/api/latest/issue/${issueNumber}?fields=updated`, type:"GET", dataType:"json", contenType: "application/json", success: function(response) { var issueLastUpdated = luxon.DateTime.fromISO(response.fields.updated); console.log(`Issue ${issueNumber} was updated ${(Date.now() - issueLastUpdated.toMillis())/1000} seconds ago`); console.log(`This page was updated ${(Date.now() - pageLastUpdatedInMillis)/1000} seconds ago`); if (pageLastUpdatedInMillis + issueUpdateDelayInSeconds*1000 < issueLastUpdated.toMillis()) { // issue was updated after the page was loaded var issueLastUpdatedText = issueLastUpdated.toLocaleString(luxon.DateTime.TIME_WITH_SHORT_OFFSET, {}); console.log(`Issue updated after last page update, just now at ${issueLastUpdatedText}: showing update button and updating title`); document.title = `\u21BB ${document.title}`; // We put the button as the last in the <ul class="aui-nav"> top navigation bar. // (The button is the same as the 'Create' button; `href="#"` is needed for the correct hover color.) var updateButtonElement = htmlToElement(` <li id="marnix_update_page_button"> <a href="#" class="aui-button aui-button-primary aui-style" title="Update page" >Update page (issue changed ${issueLastUpdatedText})</a> </li> `); updateButtonElement.addEventListener("click", updateThisPage); document.getElementsByClassName("aui-nav")[0].appendChild(updateButtonElement); // From now on leave the page alone, the `REFRESH_ISSUE_PAGE` handler (below) will re-enable the regular check pageLastUpdatedInMillis = undefined; return; } console.log(`No recent issue ${issueNumber} update, will check again in a little while.`); setTimeout(regularlyCheckForUpdates, timeBetweenChecksInSeconds*1000); }, error: function(xhr, textStatus, errorThrown) { console.log(`Something went wrong checking for updates of issue ${issueNumber}, will retry in a little while: ${textStatus} : ${errorThrown}`); setTimeout(regularlyCheckForUpdates, timeBetweenChecksInSeconds*1000); } }); } function updateThisPage() { console.log(`Let this page update its information (which also updates the title)`); JIRA.trigger(JIRA.Events.REFRESH_ISSUE_PAGE, [JIRA.Issue.getIssueId()]); // this event is caught by the event handler below, which will re-enable the regular check for issue updates // (or it triggers a full page reload, sometimes) } JIRA.bind(JIRA.Events.ISSUE_REFRESHED, function (e, context) { console.log(`Something triggered a refresh of this page`); if (!pageLastUpdatedInMillis) { console.log(`We will start to look for issue updates again in a little while`); setTimeout(regularlyCheckForUpdates, timeBetweenChecksInSeconds*1000); } pageLastUpdatedInMillis = Date.now(); var updateButtonElement = document.getElementById('marnix_update_page_button') if (updateButtonElement) { console.log(`We can remove the update button again`); updateButtonElement.remove(); } }); regularlyCheckForUpdates(); })();