Skip to content

Commit b8daf6f

Browse files
committed
Refactor storage and options page with improved type safety and GitHub-like styling
- Introduced STORAGE_KEYS constant for consistent key management - Enhanced options page with GitHub-inspired design and color scheme - Improved storage utilities with better error handling and cache management - Added dark mode support for options page - Simplified token validation and storage processes - Implemented more robust cache clearing mechanism
1 parent 83d86c7 commit b8daf6f

6 files changed

Lines changed: 623 additions & 277 deletions

File tree

src/action.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
/* global chrome */
22

3+
/**
4+
* Contributors on GitHub - Browser Extension
5+
* Opens the options page when the extension icon is clicked
6+
*/
7+
38
// Open options page when extension icon is clicked
49
chrome.action.onClicked.addListener(() => {
510
chrome.runtime.openOptionsPage();

src/content.js

Lines changed: 66 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* global getSyncStorage, setStorage, getStorage, gitHubInjection */
1+
/* global getSyncStorage, setStorage, getStorage, STORAGE_KEYS */
22

33
// Define key selectors as constants for easier maintenance
44
const SELECTORS = {
@@ -26,7 +26,7 @@ const ELEMENT_IDS = {
2626

2727
// Configuration constants
2828
const CONFIG = {
29-
CACHE_EXPIRATION: 7 * 24 * 60 * 60 * 1000, // 7 days in milliseconds (was 24 hours)
29+
CACHE_EXPIRATION: 7 * 24 * 60 * 60 * 1000, // 7 days in milliseconds
3030
HOVER_DELAY: 100, // milliseconds to wait before hiding panel
3131
STAT_PADDING: 3, // number of digits to pad stats to
3232
};
@@ -66,7 +66,7 @@ function getPathInfo() {
6666

6767
function buildUrl({
6868
base,
69-
q: { type, filterUser, author, repo, user },
69+
q: { type, filterUser, author, repo, user, created },
7070
sort,
7171
order,
7272
per_page,
@@ -77,21 +77,22 @@ function buildUrl({
7777
query += `${user ? `+user:${user}` : ""}`;
7878
query += `${type ? `+type:${type}` : ""}`;
7979
query += `${filterUser ? `+-user:${filterUser}` : ""}`;
80+
query += `${created ? `+created:${created}` : ""}`;
8081
query += `${order ? `&order=${order}` : ""}`;
8182
query += `${per_page ? `&per_page=${per_page}` : ""}`;
8283
query += `${sort ? `&sort=${sort}` : ""}`;
8384

8485
return query;
8586
}
8687

87-
function contributorCount({
88+
async function contributorCount({
8889
access_token,
8990
contributor,
9091
user,
9192
repoPath,
9293
old = {},
9394
type,
94-
scope,
95+
scope
9596
}) {
9697
let repo = repoPath;
9798

@@ -108,43 +109,46 @@ function contributorCount({
108109
type,
109110
repo,
110111
author: contributor,
111-
user: user,
112+
user: user
112113
},
113114
sort: "created",
114115
});
115116

116-
return fetch(searchURL, {
117-
headers: {
118-
Authorization: `token ${access_token}`,
119-
},
120-
})
121-
.then((res) => res.json())
122-
.then((json) => {
123-
if (json.errors || json.message) {
124-
return json;
125-
}
117+
try {
118+
const response = await fetch(searchURL, {
119+
headers: {
120+
Authorization: `token ${access_token}`,
121+
},
122+
});
123+
const json = await response.json();
126124

127-
let obj = {
128-
lastUpdate: Date.now(),
129-
};
125+
if (json.errors || json.message) {
126+
return json;
127+
}
130128

131-
if (type === "pr") {
132-
obj.prs = json.total_count;
133-
} else if (type === "issue") {
134-
obj.issues = json.total_count;
135-
}
129+
let obj = {
130+
lastUpdate: Date.now()
131+
};
136132

137-
if (json.items?.length) {
138-
obj[`first${type[0].toUpperCase() + type.slice(1)}Number`] =
139-
json.items[0].number;
140-
}
133+
if (type === "pr") {
134+
obj.prs = json.total_count;
135+
} else if (type === "issue") {
136+
obj.issues = json.total_count;
137+
}
141138

142-
obj = Object.assign(old, obj);
139+
if (json.items?.length) {
140+
obj[`first${type[0].toUpperCase() + type.slice(1)}Number`] =
141+
json.items[0].number;
142+
}
143143

144-
setStorage(contributor, repoPath, obj);
144+
obj = Object.assign(old, obj);
145145

146-
return obj;
147-
});
146+
setStorage(contributor, repoPath, obj);
147+
148+
return obj;
149+
} catch (error) {
150+
console.error(error);
151+
}
148152
}
149153

150154
function formatText(count, firstNumber, currentNum, scope) {
@@ -346,16 +350,27 @@ function setupHoverBehavior() {
346350
function setupSyncButton({ contributor, repoPath, currentNum, org }) {
347351
const $syncButton = document.getElementById(ELEMENT_IDS.SYNC_BUTTON);
348352
$syncButton.addEventListener("click", () => {
349-
// Clear all stats and fetch fresh data
350-
setStorage(contributor, repoPath, {});
351-
setStorage(contributor, org, {});
352-
setStorage(contributor, "__self", {});
353+
// Clear local cache for this contributor
354+
clearContributorCache(contributor);
353355

354356
// Fetch all scopes
355357
fetchAllStats({ contributor, repoPath, currentNum, org });
356358
});
357359
}
358360

361+
// Clear cache for a specific contributor
362+
function clearContributorCache(contributor) {
363+
try {
364+
for (const key of Object.keys(localStorage)) {
365+
if (key.startsWith('gce-cache-') && key.includes(contributor)) {
366+
localStorage.removeItem(key);
367+
}
368+
}
369+
} catch (e) {
370+
console.error("Error clearing contributor cache:", e);
371+
}
372+
}
373+
359374
// Check if cache is expired
360375
function isCacheExpired(lastUpdate) {
361376
if (!lastUpdate) return true;
@@ -457,25 +472,25 @@ function fetchStats({ contributor, repoPath, currentNum, scope, user }) {
457472
updateStatsDisplay({ prText, issueText, scope, lastUpdate: storageRes.lastUpdate });
458473
} else {
459474
// If cache is expired or no data, fetch fresh data
460-
getSyncStorage({ access_token: null }).then((res) => {
475+
getSyncStorage({ [STORAGE_KEYS.ACCESS_TOKEN]: null }).then((res) => {
461476
Promise.all([
462477
contributorCount({
463478
old: storageRes,
464479
user,
465-
access_token: res.access_token,
480+
access_token: res[STORAGE_KEYS.ACCESS_TOKEN],
466481
type: "pr",
467482
contributor,
468483
repoPath,
469-
scope,
484+
scope
470485
}),
471486
contributorCount({
472487
old: storageRes,
473488
user,
474-
access_token: res.access_token,
489+
access_token: res[STORAGE_KEYS.ACCESS_TOKEN],
475490
type: "issue",
476491
contributor,
477492
repoPath,
478-
scope,
493+
scope
479494
}),
480495
])
481496
.then(([prInfo, issueInfo]) => {
@@ -629,9 +644,9 @@ function showToast(message, type = "error") {
629644
// Main initialization function
630645
function initializeContributorStats() {
631646
if (isPR(location.pathname) || isIssue(location.pathname)) {
632-
getSyncStorage({ _showPrivateRepos: null }).then(
633-
({ _showPrivateRepos }) => {
634-
if (!_showPrivateRepos && isPrivate()) return;
647+
getSyncStorage({ [STORAGE_KEYS.SHOW_PRIVATE_REPOS]: null }).then(
648+
(result) => {
649+
if (!result[STORAGE_KEYS.SHOW_PRIVATE_REPOS] && isPrivate()) return;
635650

636651
if (getFirstContributor()) {
637652
injectInitialUI(getPathInfo());
@@ -643,5 +658,11 @@ function initializeContributorStats() {
643658

644659
// Initialize when DOM is ready
645660
document.addEventListener("DOMContentLoaded", () => {
646-
gitHubInjection(initializeContributorStats);
661+
// Check if gitHubInjection is available
662+
if (typeof gitHubInjection === 'function') {
663+
gitHubInjection(initializeContributorStats);
664+
} else {
665+
// Fallback to direct initialization
666+
initializeContributorStats();
667+
}
647668
});

0 commit comments

Comments
 (0)