Do you want to work on this issue?
You can request for a bounty in order to promote it!
Mark/unmark identical files as “Viewed” in the PR files tab #3045
mfulton26 posted onGitHub
Periodically I end up reviewing large PRs that have lots of files that have similar identical diffs (e.g. package rename causes imports and dependencies in package.json files to change, etc.).
I realized it would be great to have a way to mark similar identical files as “Viewed” in the PR files tab.
A neat way to invoke this could be by double-clicking a “Viewed” checkbox.
I ended up doing this through a custom search engine in Chrome for now with the below code as its "URL" (I have its keyword defined as gh+~v
so that on my Mac all I have to do is mark a few files as “Viewed” and then type Command+L
+gh+#v
+Enter
and then all similar identical diffs get marked as “Viewed” too; I have similar shortcuts like gh+v
to mark all files as “Viewed”, ghrd
to display rich diffs for all files, etc.).
javascript: markIdenticalFilesAsViewed();
async function markIdenticalFilesAsViewed() {
const files = document.querySelectorAll(".file");
const { markedFiles, unmarkedFiles } = groupFiles(files);
const markedHashes = new Set(markedFiles.map(getFileDiffHash));
const identicalFiles = unmarkedFiles.filter((file) =>
markedHashes.has(getFileDiffHash(file))
);
const { length: found } = identicalFiles;
if (found === 0) {
alert(`All identical files are marked as “Viewed”.`);
} else if (confirm(`Mark ${found} identical files as “Viewed”?`)) {
const start = Date.now();
for await (const file of periodicEventCycling(identicalFiles)) {
file.querySelector(".js-reviewed-checkbox").click();
}
const end = Date.now();
const elapsed = ((end - start) / 1000).toLocaleString();
alert(`Marked ${found} identical files as “Viewed” in ${elapsed} seconds.`);
}
}
function groupFiles(files) {
const markedFiles = [];
const unmarkedFiles = [];
for (const file of files) {
const group = file.querySelector(".js-reviewed-checkbox[checked]")
? markedFiles
: unmarkedFiles;
group.push(file);
}
return { markedFiles, unmarkedFiles };
}
function getFileDiffHash(file) {
const deletions = Array.from(
file.querySelectorAll(".blob-code-deletion .blob-code-inner"),
(e) => e.innerText
);
const additions = Array.from(
file.querySelectorAll(".blob-code-addition .blob-code-inner"),
(e) => e.innerText
);
return JSON.stringify({ deletions, additions });
}
async function* periodicEventCycling(iterable, delay = 50) {
let updated = Date.now();
for (const value of iterable) {
yield value;
if (Date.now() - updated > delay) {
await new Promise((resolve) => setTimeout(resolve, 0));
updated = Date.now();
}
}
}