Skip to content
Alejandro Barreto edited this page Aug 6, 2020 · 16 revisions

Notes for myself and don't bubble up to issues.

123

Scratch

https://gist.github.com/alejandro5042/96fa381685b77b469b74eddceae13d2c

TODO

Notes from 2019-06-26

  • Document in CONTRIB how to edit the userscript from local disk. But also check in actual path and also a return statement
  • Run npm install when first cloned. Go get npm also
  • If using vscode install this: https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint
  • Caveat checkboxes only work on single domain
  • About local storage space: 10005030
  • Document the weird func pattern
  • More sub-functions? Or use classes?
  • User-visible error handling as a page banner
  • Fully update README and CONTRIB

Useful links for dashboard testing

Useful links for checkbox testing

Random

Also available at: https://cdn.jsdelivr.net/gh/alejandro5042/azdo-userscripts/src/azdo-pr-dashboard.user.js

Babel?

// ==UserScript==
// @name         New ES6-Userscript
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  shows how to use babel compiler
// @author       You
// @require      https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.18.2/babel.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.16.0/polyfill.js
// @match        <$URL$>
// ==/UserScript==

var inline_src = (<><![CDATA[

    // Your code here...

]]></>).toString();
var c = Babel.transform(inline_src, { presets: [ "es2015", "es2016" ] });
eval(c.code);

Blacking out identities

$('.vc-pullrequest-callout-text, .vc-pullrequest-created-by-section, .identity-picture, .vc-pullrequest-detail-branch-name:first, .reviewer-name-status-container div.ms-TooltipHost span, .la-user-icon, .vc-discussion-comment-author, .inline-identity').css('background', 'rgba(0,0,0,0.2)').css('color', 'transparent').filter('img').css('-webkit-filter', 'brightness(0%)').css('opacity', 0.5)

Update checks

console.log(GM_info.script.updateURL);
console.log(GM_info.scriptUpdateURL);
console.log(GM_info.downloadMode);

Caching

  function cacheOne(valueCallback) {
    let value;
    let lastKey;
    let hasLastKey = false;
    return (key) => {
      if (!hasLastKey || lastKey !== key) {
        value = valueCallback(key);
        lastKey = key;
        hasLastKey = true;
      }
      return value;
    };
  }

  // TODO: Bug if update is pushed.
  function cacheForPage(valueCallback) {
    const cacheOneInstance = cacheOne(valueCallback);
    return () => cacheOneInstance(window.location.pathname);
  }

  const getPageData = cacheForPage(() => JSON.parse(document.getElementById('dataProviders').innerHTML).data);

Old Review Code

if (reviewProperties && reviewProperties.version < 4 && reviewProperties.fileProperties) {
  for (const file of reviewProperties.fileProperties) {
    for (const reviewer of [file.Owner, file.Alternate, file.Reviewers].flat()) {
      if (reviewer.includes(currentUser.uniqueName)) {
        filesToReview.push(file.Path);
      }
    }
    if (file.Owner.includes(currentUser.uniqueName)) {
      filesToRoles[file.Path] = 'O';
    }
    if (file.Alternate.includes(currentUser.uniqueName)) {
      filesToRoles[file.Path] = 'A';
    }
    if (_(file.Reviewers).some(r => r.includes(currentUser.uniqueName))) {
      filesToRoles[file.Path] = 'R';
    }
    // eslint-disable-next-line no-inner-declarations
    function fromEmail(role, fullEmail) {
      const email = fullEmail.match(/<(.*)>/)[1];
      const reviewer = _(pr.reviewers).find(r => r.uniqueName === email);
      let vote = reviewer ? reviewer.vote : -100;
      const voteStrs = { 10: '✓', 5: '✓', 0: '', '-5': '⏲', '-10': '⨉', '-100': '?' };
      vote = voteStrs[vote];

      const name = fullEmail.replace(/<.*/, '').replace(/"/g, '');
      return `${name} (${vote})`;
    }
    filesToAllRoles[file.Path] = `${fromEmail('O', file.Owner)}<br>${fromEmail('A', file.Alternate)}<br>${file.Reviewers.sort().map(r => `R: ${fromEmail('R', r)}`).join('<br>')}`;
  }
} else {
  # New stuff here...
}

Other

      // session.onEveryNew(document, '.view-lines', diff => {
      //   let alreadyHasHighlighting = false;
      //   let lineCount = 0;
      //   let lastLine = null;
      //   for (const line of diff.querySelectorAll('.view-line > span > span')) {
      //     lineCount += 1;
      //     lastLine = line;
      //     if (line.className !== 'mtk1') {
      //       alreadyHasHighlighting = true;
      //       break;
      //     }
      //   }
      //   if (alreadyHasHighlighting) return;
      //   if (lineCount === 0) return;
      //   if (lineCount === 1 && lastLine.innerText === 'Loading...') return;

      //   const container = diff.closest('body'); // TODO: HACK
      //   const fileName = container.querySelector('.full-path').innerText;
      //   const ext = /(?:\.([^.]+))?$/.exec(fileName)[1];

      //   console.debug('Trying to highlight:', fileName);

      //   let language = ext;
      //   if (language === 'vhd') {
      //     language = 'lua';
      //   }
      //   if (!hljs.getLanguage(language)) {
      //     let code = '';
      //     for (const line of diff.querySelectorAll('.view-line')) {
      //       code += `${line.innerText}\n`;
      //     }
      //     const result = hljs.highlightAuto(code);
      //     language = result.language;
      //   }

      //   if (language) {
      //     console.debug(`Highlighting <${fileName}> as ${language}`);
      //     let stack = null;
      //     for (const line of diff.querySelectorAll('.view-line')) {
      //       const highlight = hljs.highlight(language, line.innerText, true, stack);
      //       line.innerHTML = highlight.value;
      //       stack = highlight.top;
      //     }
      //   } else {
      //     console.debug(`Not highlighting <${fileName}>. A language was not auto-detected.`);
      //   }
      // });



      
      session.onEveryNew(section, 'colgroup', colgroup => {
            colgroup.querySelector('col:nth-of-type(4)').insertAdjacentHTML('afterend', '<col style="width: 5rem;">');
            colgroup.querySelector('col:nth-of-type(4)').insertAdjacentHTML('afterend', '<col style="width: 5rem;">');
          });


  function annotatePullRequestRow(pullRequestRow, html) {
    annotatePullRequestTitle(pullRequestRow, html);
    // const precedingColumn = pullRequestRow.querySelector('td[data-column-index="2"]');
    // precedingColumn.insertAdjacentHTML('afterend', `
    //     <td class="bolt-table-cell bolt-list-cell" role="gridcell">
    //       <div class="bolt-table-cell-content flex-row flex-center">
    //         <div class="flex-row flex-center">
    //           ${html}
    //         </div>
    //       </div>
    //     </td>`);
  }


  
      // Get non-deleted pr threads, ordered from newest to oldest.
      // const prThreads = (await $.get(`${pr.url}/threads?api-version=5.0`)).value.filter(x => !x.isDeleted).reverse();
      // assignSortOrderToPullRequest(row, getReviewerAddedOrResetTimestamp(prThreads, currentUser.uniqueName) || pr.createdDate);


      function assignSortOrderToPullRequest(pullRequestRow, sortingTimestampAscending) {
        // Order the reviews by when the current user was added (reviews that the user was added to most recently are listed last). We do this by ordering the rows inside a reversed-order flex container.
        // The order property is a 32-bit integer. If treat it as number of seconds, that allows a range of 68 years (2147483647 / (60 * 60 * 24 * 365)) in the positive values alone.
        // Dates values are number of milliseconds since 1970, so we wouldn't overflow until 2038. Still, we might as well subtract a more recent reference date, i.e. 2019.
        const secondsSince2019 = Math.trunc((Date.parse(sortingTimestampAscending) - Date.parse('2019-01-01')) / 1000);
        pullRequestRow.style.order = secondsSince2019;
      }
      
      function getReviewerAddedOrResetTimestamp(prThreadsNewestFirst, reviewerUniqueName) {
        for (const thread of prThreadsNewestFirst) {
          if (thread.properties) {
            if (Object.prototype.hasOwnProperty.call(thread.properties, 'CodeReviewReviewersUpdatedAddedIdentity')) {
              const addedReviewer = thread.identities[thread.properties.CodeReviewReviewersUpdatedAddedIdentity.$value];
              if (addedReviewer.uniqueName === reviewerUniqueName) {
                return thread.publishedDate;
              }
            } else if (Object.prototype.hasOwnProperty.call(thread.properties, 'CodeReviewResetMultipleVotesExampleVoterIdentities')) {
              if (Object.keys(thread.identities).filter(x => thread.identities[x].uniqueName === reviewerUniqueName)) {
                return thread.publishedDate;
              }
            }
          }
        }
        return null;
      }

Please refer documentation in the README.md.

Clone this wiki locally