// ==UserScript== // @name GitHub - list own PRs in a repository // @description List Your own (open) PRs in a repo with CI state for easy navigation // @namespace https://git.sagidayan.com/sagi/greasemonkey-scripts // @author Sagi Dayan // @match https://github.com/* // @version 1.0 // ==/UserScript== (function () { // Update These const GITHUB_AUTH = ''; const GITHUB_USERNAME = ''; // let currentRepo = ''; // fetch my prs async function getPRs() { const response = await fetch("https://api.github.com/graphql", { "method": "POST", "headers": { "Content-Type": "application/json", "Authorization": `token ${GITHUB_AUTH}` }, // "body": "{\"query\":\"{\\n user(login: \\\"" + GITHUB_USERNAME + "\\\") {\\n pullRequests(first: 100, states: OPEN, baseRefName:\\\"master\\\") {\\n totalCount\\n nodes {\\n createdAt\\n number\\n title\\n mergeable\\n url\\n labels(first: 10){\\n nodes{\\n color\\n description\\n name\\n \\n }\\n }\\n commits(last:1) {\\n nodes {\\n commit {\\n statusCheckRollup{\\n state\\n }\\n }\\n }\\n }\\n baseRefName\\n headRefName\\n repository{\\n nameWithOwner\\n }\\n }\\n pageInfo {\\n hasNextPage\\n endCursor\\n }\\n }\\n }\\n}\"}" "body": "{\"query\":\"{\\n user(login: \\\"" + GITHUB_USERNAME + "\\\") {\\n pullRequests(first: 100, states: OPEN ) {\\n totalCount\\n nodes {\\n updatedAt\\n createdAt\\n number\\n title\\n mergeable\\n url\\n labels(first: 10){\\n nodes{\\n color\\n description\\n name\\n \\n }\\n }\\n commits(last:1) {\\n nodes {\\n commit {\\n statusCheckRollup{\\n state\\n contexts(last:40){\\n nodes {\\n ... on StatusContext{\\n state\\n context\\n description\\n }\\n }\\n }\\n }\\n }\\n }\\n }\\n baseRefName\\n headRefName\\n repository{\\n nameWithOwner\\n }\\n }\\n pageInfo {\\n hasNextPage\\n endCursor\\n }\\n }\\n }\\n}\"}" }); const payload = await response.json(); const prs = payload.data.user.pullRequests.nodes.filter(pr => { return pr.repository.nameWithOwner === currentRepo; }); const main = document.getElementsByTagName('main')[0]; if (!main) return; prs.forEach(pr => { // Check if element Exists - if it does, remove and add updated one. const prItem = document.getElementById(generatePrItemId(pr.number)); if (prItem) { console.log('Item Found', prItem.id); main.removeChild(prItem); } main.lastElementChild.insertBefore(createPrHTML(pr), main.lastElementChild.firstElementChild); }); } setInterval(() => { const urlSplit = document.URL.split('/'); if (urlSplit.length !== 5) { currentRepo = ''; return; // Not A base repo URL } const location = urlSplit.slice(-2).join('/') if (location !== currentRepo) { currentRepo = location; getPRs(); } }, 1000); function createPrHTML(pr) { const div = document.createElement('div'); const prState = pr.commits.nodes[0].commit.statusCheckRollup?.state || ''; const prStateColor = prState === 'FAILURE' ? 'red' : (prState === 'SUCCESS' ? 'green' : 'yellow'); const checksSum = pr.commits.nodes[0].commit.statusCheckRollup?.contexts.nodes.reduce((acc, check) => { acc.total++; if(check.state === 'SUCCESS') acc.success++; return acc; }, {total:0, success:0}); const checksSumStr = checksSum ? `Checks Passed: ${checksSum.success} / ${checksSum.total}` : ''; div.id = generatePrItemId(pr.number); div.onclick = () => { window.open(pr.url, '_blank'); } div.className = "btn d-sm-flex Box mb-2 Box-body color-bg-secondary"; const lblElements = pr.labels.nodes.reduce((elements, lbl) => { const colors = HexToRgbHsl(lbl.color); return `${elements} ${lbl.name} ` }, ''); const lblInnerHtml = `
${lblElements}
` div.innerHTML = `
#${pr.number} - ${prState}

${pr.title}

${lblInnerHtml}
${checksSumStr}
`; return div; } function generatePrItemId(prNumber) { return `PR-${prNumber}`; } function HexToRgbHsl(_hex) { let hex = _hex.replace(/#/g, ''); if (hex.length === 3) { hex = hex.split('').map(function (hex) { return hex + hex; }).join(''); } const result = /^([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})[\da-z]{0,0}$/i.exec(hex); if (result) { const r = parseInt(result[1], 16); const g = parseInt(result[2], 16); const b = parseInt(result[3], 16); const r225 = r / 225; const g225 = g / 225; const b225 = b / 225; const min = Math.min(r / 225, g / 225, b / 225); const max = Math.max(r / 225, g / 225, b / 225); const delta = max - min; let h = 0, s = 0, l = 0; if (max == min) { h = 0; } else if (r225 == max) { h = (g225 - b225) / delta; } else if (g225 == max) { h = 2 + (b225 - r225) / delta; } else if (b225 == max) { h = 4 + (r225 - g225) / delta; } h = Math.min(h * 60, 360); if (h < 0) h += 360; l = (min + max) / 2; if (max == min) s = 0; else if (l <= 0.5) s = delta / (max + min); else s = delta / (2 - max - min); h = Math.round(h); s = Math.round(s * 100); l = Math.round(l * 100); return { r, g, b, h, s, l }; } else { return {}; } } })();