Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix K2 for new GitHub UI #226

Merged
merged 17 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ module.exports = {
'comma-dangle': ['error', 'always-multiline'],
'rulesdir/no-api-in-views': 'off',
'rulesdir/no-multiple-api-calls': 'off',
'@lwc/lwc/no-async-await': 'off',
'es/no-nullish-coalescing-operators' : 'off'
},
settings: {
'import/resolver': {
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#1.4.0
- Updated the extension to work with new GitHub UI
- Updated the extension to work with GitHub's new PR merge experience

#1.3.74
- Moved the previous query string params to Onyx

Expand Down
2 changes: 1 addition & 1 deletion assets/manifest-firefox.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"manifest_version": 3,

"name": "K2 for GitHub",
"version": "1.3.74",
"version": "1.4.0",
"description": "Manage your Kernel Scheduling from directly inside GitHub",

"browser_specific_settings": {
Expand Down
2 changes: 1 addition & 1 deletion assets/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"manifest_version": 3,

"name": "K2 for GitHub",
"version": "1.3.74",
"version": "1.4.0",
"description": "Manage your Kernel Scheduling from directly inside GitHub",

"icons": {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "k2-extension",
"version": "1.3.74",
"version": "1.4.0",
"description": "A Chrome Extension for Kernel Schedule",
"private": true,
"scripts": {
Expand Down
25 changes: 25 additions & 0 deletions src/css/content.scss
Original file line number Diff line number Diff line change
Expand Up @@ -570,3 +570,28 @@ $color-dark-yellow: #DAA520;
color: rgb(230, 237, 243)
}
}

.loader {
width: 14px;
aspect-ratio: 1;
border-radius: 50%;
border: 2px solid #514b82;
animation:
l20-1 0.8s infinite linear alternate,
l20-2 1.6s infinite linear;
}
@keyframes l20-1{
0% {clip-path: polygon(50% 50%,0 0, 50% 0%, 50% 0%, 50% 0%, 50% 0%, 50% 0% )}
12.5% {clip-path: polygon(50% 50%,0 0, 50% 0%, 100% 0%, 100% 0%, 100% 0%, 100% 0% )}
25% {clip-path: polygon(50% 50%,0 0, 50% 0%, 100% 0%, 100% 100%, 100% 100%, 100% 100% )}
50% {clip-path: polygon(50% 50%,0 0, 50% 0%, 100% 0%, 100% 100%, 50% 100%, 0% 100% )}
62.5% {clip-path: polygon(50% 50%,100% 0, 100% 0%, 100% 0%, 100% 100%, 50% 100%, 0% 100% )}
75% {clip-path: polygon(50% 50%,100% 100%, 100% 100%, 100% 100%, 100% 100%, 50% 100%, 0% 100% )}
100% {clip-path: polygon(50% 50%,50% 100%, 50% 100%, 50% 100%, 50% 100%, 50% 100%, 0% 100% )}
}
@keyframes l20-2{
0% {transform:scaleY(1) rotate(0deg)}
49.99%{transform:scaleY(1) rotate(135deg)}
50% {transform:scaleY(-1) rotate(0deg)}
100% {transform:scaleY(-1) rotate(-135deg)}
}
74 changes: 72 additions & 2 deletions src/js/lib/pages/github/_base.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import $ from 'jquery';
import * as API from '../../api';

/**
* This class is to be extended by each of the distinct types of webpages that the extension works on
Expand All @@ -7,6 +8,54 @@ import $ from 'jquery';
export default function () {
const Page = {};

const REVIEWER_CHECKLIST_URL = 'https://raw.githubusercontent.com/Expensify/App/main/contributingGuides/REVIEWER_CHECKLIST.md';
const BUGZERO_CHECKLIST_URL = 'https://raw.githubusercontent.com/Expensify/App/main/contributingGuides/BUGZERO_CHECKLIST.md';

/**
* Gets the contents of the reviewer checklist from GitHub and then posts it as a comment to the current PR
* @param {Event} e
* @param {'bugzero' | 'reviewer'} checklistType Type of target checklist
*/
const copyReviewerChecklist = async (e, checklistType) => {
const checklistUrl = checklistType === 'bugzero' ? BUGZERO_CHECKLIST_URL : REVIEWER_CHECKLIST_URL;

e.preventDefault();

// Get the button element
const button = e.target;

// Save the original content of the button
const originalContent = button.innerHTML;

// Replace the button content with a loader
button.innerHTML = '<div class="loader"></div>';

try {
// Fetch the checklist contents
const response = await fetch(checklistUrl);

if (!response.ok) {
console.error(`Failed to load contents of ${checklistUrl}: ${response.statusText}`);
return;
}

const fileContents = await response.text();

if (!fileContents) {
console.error(`Could not load contents of ${checklistUrl} for some reason`);
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In these error cases we should revert the loader. So instead of logging and returning we could throw an error and have the catch and finally block handle things.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the original code moved to a different function, but I changed it to:

        try {
            // Fetch the checklist contents
            const response = await fetch(checklistUrl);
            const fileContents = await response.text();

            // Call the API to add the comment
            await API.addComment(fileContents);
        } catch (error) {
            console.error('Error fetching the checklist:', error);
        } finally {
            // Restore the original button content
            button.innerHTML = originalContent;
        }

this way the loader will always be reverted, and:

  1. If fetch() returns something other than 200, it will throw anyway
  2. If fetched text is empty, then API.addComment() will throw due to incorrect parameters

So all error cases are covered now.

}

// Call the API to add the comment
await API.addComment(fileContents);
} catch (error) {
console.error('Error fetching the checklist:', error);
} finally {
// Restore the original button content
button.innerHTML = originalContent;
}
};

/**
* A unique identifier for each page
*/
Expand Down Expand Up @@ -47,11 +96,32 @@ export default function () {
Page.setup = function () {};

Page.getRepoOwner = function () {
return $('.author a span').text();
return document.querySelectorAll('.AppHeader-context-item-label.Truncate-text')[0].textContent.trim();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NAB, I wonder if we could keep the repeatedly used selectors as constant with meaningful names of what we are selecting - For example - const selectorForRepoLabel = '.AppHeader-context-item-label.Truncate-text'; , so next time github changes UI, we could simply change the constant instead of going all over the code, and hopefully it should be simple to transition and works 🙏

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For sure, I agree with that. Once we get this PR of the gate I'll spend some time to reorganize the selectors a little bit.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be great. Thank you!!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NAB ➕ I would also like to see this. Is it easy enough to do in this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The repeating selectors are now removed, but I've added a bunch of comments for existing selectors to clarify what exactly they are selecting.

I chose comments over variables to not have to introduce additional null checks to satisfy ESLint for selectors that turn out empty.

};

Page.getRepo = function () {
return $('.js-current-repository').text();
return document.querySelectorAll('.AppHeader-context-item-label.Truncate-text')[1].textContent.trim();
};

/**
* Renders buttons for copying checklists in issue/PR bodies
* @param {'bugzero' | 'reviewer'} checklistType Type of target checklist
*/
Page.renderCopyChecklistButtons = function (checklistType) {
// Look through all the comments on the page to find one that has the template for the copy/paste checklist button
// eslint-disable-next-line rulesdir/prefer-underscore-method
$('.markdown-body > p').each((i, el) => {
const commentHtml = $(el).html();

// When the button template is found, replace it with an HTML button and then put that back into the DOM so someone can click on it
if (commentHtml && commentHtml.indexOf('you can simply click: [this button]') > -1) {
const newHtml = commentHtml.replace('[this button]', '<button type="button" class="btn btn-sm k2-copy-checklist">HERE</button>');
$(el).html(newHtml);

// Now that the button is on the page, add a click handler to it (always remove all handlers first so that we know there will always be one handler attached)
$('.k2-copy-checklist').off().on('click', e => copyReviewerChecklist(e, checklistType));
}
});
};

return Page;
Expand Down
30 changes: 0 additions & 30 deletions src/js/lib/pages/github/createpr.js

This file was deleted.

Loading
Loading