GitHub PR File Filter

Hide and mark files as viewed using regex pattern.

  1. // ==UserScript==
  2. // @name GitHub PR File Filter
  3. // @namespace btilford
  4. // @author btilford
  5. // @version 0.1
  6. // @license MIT
  7. // @description Hide and mark files as viewed using regex pattern.
  8. // @match https://github.com/*/*/pull/*/files*
  9. // @grant unsafeWindow
  10. // ==/UserScript==
  11.  
  12. (function githubPrFilter() {
  13. 'use strict';
  14. console.debug('Loading PR file filter');
  15. function selectFiles(pattern) {
  16. const regex = new RegExp(pattern);
  17. const files = [...window.document.querySelectorAll('.file')];
  18. console.debug('Filtering %d files in PR with pattern %s', files.length, regex);
  19. return files.filter(_ => {
  20. const link = _.querySelector('.link-gray-dark');
  21. return regex.test(link.title) || regex.test(link.innerText);
  22. });
  23. }
  24.  
  25. const container = unsafeWindow.document.createElement('div');
  26. container.className = 'select-menu-list';
  27. container.style = 'width: 280px; margin-bottom: 8px;';
  28.  
  29. const pattern = unsafeWindow.document.createElement('input');
  30. pattern.name = 'filter-pattern';
  31. pattern.placeholder = 'regex';
  32. pattern.title = 'File matching regex';
  33. pattern.className = 'form-control form-control subnav-search-input input-contrast';
  34. pattern.style = 'margin: 8px 4px; width: 270px;';
  35.  
  36. container.appendChild(pattern);
  37.  
  38.  
  39. const btnClasses = 'js-reviewed-toggle ml-2 mr-1 px-2 py-1 rounded-1 f6 text-normal border js-reviewed-file bg-blue-2 border-blue-light';
  40. const hide = unsafeWindow.document.createElement('button');
  41. hide.style = 'color: rgb(201, 209, 217);';
  42. hide.innerHTML = '<label>hide</label>';
  43. hide.className = btnClasses;
  44. hide.onclick = () => {
  45. const ptn = pattern.value;
  46. const files = selectFiles(ptn);
  47. console.debug('hiding %d files matching pattern %s', files.length, ptn);
  48. files.forEach(_ => {
  49. const open = _.querySelector('.open .file-info button.btn-octicon');
  50. if(open) {
  51. open.click();
  52. }
  53. });
  54. }
  55. container.appendChild(hide);
  56.  
  57. const viewed = unsafeWindow.document.createElement('button');
  58. viewed.style = 'color: rgb(201, 209, 217);';
  59. viewed.innerHTML = '<label>viewed</label>';
  60. viewed.className = btnClasses;
  61. viewed.onclick = () => {
  62. const ptn = pattern.value;
  63. const files = selectFiles(ptn);
  64. console.debug('hiding %d files matching pattern %s', files.length, ptn);
  65. files.forEach(_ => {
  66. const unchecked = _.querySelector('.file-actions input.js-reviewed-checkbox:not(:checked)[type=checkbox]');
  67. if(unchecked) {
  68. //unchecked.checked = true;
  69. unchecked.click();
  70. }
  71. });
  72. }
  73. container.appendChild(viewed);
  74.  
  75. const parent = unsafeWindow.document.querySelector('.diffbar-item.details-overlay.select-menu.js-file-filter .select-menu-modal .select-menu-header');
  76. console.log('Inserting regex filter on %o', parent);
  77. parent.insertAdjacentElement('afterend', container);
  78.  
  79. // Your code here...
  80. })();