Skip to content

Commit 528787b

Browse files
committed
Added refresh button in UI, turned logging off using DEBUG = false, working caching feature
Signed-off-by: Vedansh Saini <[email protected]>
1 parent 94a8915 commit 528787b

File tree

6 files changed

+124
-45
lines changed

6 files changed

+124
-45
lines changed

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@
3232
- Ensure the Scrum Helper settings are applied (follow step 6 above)
3333
- The extension will prefill scrum content for you to edit
3434

35+
## New Features
36+
- The extension now uses parallel modern API requests along with data caching with a TTL(Time to Live) of 10 minutes.
37+
- New fetch requests will be made if input data by user is changed.
38+
- The cache data can be manually refreshed using the `Refresh Data` button.
39+
3540
## Setting up the code locally
3641

3742
```
@@ -42,7 +47,7 @@ $ npm install
4247
## Screenshots
4348
![SCRUM](/docs/images/scrum.png)
4449

45-
![POPUP](/docs/images/popup.png)
50+
![POPUP](docs/images/popup.png)
4651

4752
## About contributing
4853
- Follow the Issues and PRs templates as far as possible.

docs/images/popup.png

9.21 KB
Loading

src/index.css

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,34 @@ li {
6464
transition: color 0.3s ease-in-out, font-weight 0.3s ease-in-out;
6565
}
6666

67+
.refresh-btn {
68+
transition: all 0.3s ease;
69+
position: relative;
70+
overflow: hidden;
71+
background-color: #d2d2d2;
72+
}
73+
74+
.refresh-btn:hover {
75+
background-color: #999bac;
76+
transform: translateY(-1px);
77+
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
78+
}
79+
80+
.refresh-btn:active {
81+
transform: translateY(1px);
82+
box-shadow: none;
83+
}
84+
85+
.refresh-btn.loading {
86+
pointer-events: none;
87+
opacity: 0.8;
88+
}
89+
90+
.refresh-btn.loading .fa-refresh {
91+
animation: spin 1s linear infinite;
92+
}
93+
94+
@keyframes spin {
95+
100% { transform: rotate(360deg); }
96+
}
97+

src/popup.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ <h6 class="center">
6464
<div>Ending Date</div>
6565
<input id="endingDate" type="date" class="datepicker" placeholder=" ">
6666
</div>
67+
<button id="refreshCache" class="btn-small waves-effect waves-light refresh-btn" title="Force refresh Github data">
68+
<i class="material-icons left">Refresh Data (bypass cache)</i>
69+
</button>
6770
<div class="col s12">
6871
<br />
6972
<input type="checkbox" class="filled-in" id="showOpenLabel"/>

src/scripts/main.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,36 @@ function handleBodyOnLoad() {
7878
},
7979
);
8080
}
81+
82+
document.getElementById('refreshCache').addEventListener('click', async (e) => {
83+
const button = e.currentTarget;
84+
button.classList.add('loading');
85+
button.disabled = true;
86+
87+
try {
88+
const tabs = await chrome.tabs.query({active: true, currentWindow: true});
89+
const response = await chrome.tabs.sendMessage(tabs[0].id, {
90+
action: 'forceRefresh',
91+
timestamp: Date.now() // Pass timestamp to ensure cache invalidation
92+
});
93+
94+
if (response.success) {
95+
M.toast({html: 'Data refreshed successfully!', classes: 'green'});
96+
} else {
97+
throw new Error(response.error || 'Refresh failed');
98+
}
99+
} catch (err) {
100+
console.error('Refresh failed:', err);
101+
M.toast({html: 'Failed to refresh data', classes: 'red'});
102+
} finally {
103+
// Reset button state after a slight delay
104+
setTimeout(() => {
105+
button.classList.remove('loading');
106+
button.disabled = false;
107+
}, 500);
108+
}
109+
});
110+
81111
function handleEnableChange() {
82112
let value = enableToggleElement.checked;
83113
chrome.storage.local.set({ enableToggle: value });

src/scripts/scrumHelper.js

Lines changed: 54 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ function allIncluded() {
142142
return WeekDisplayPadded;
143143
}
144144

145-
const DEBUG = true;
145+
const DEBUG = false;
146146
function log( ...args) {
147147
if(DEBUG) {
148148
console.log(`[SCRUM-HELPER]:`, ...args);
@@ -165,13 +165,8 @@ function allIncluded() {
165165
errorTTL: 60*1000, // 1 min error cache
166166
subject: null,
167167
};
168-
const MAX_CACHE_SIZE = 50 * 1024 * 1024; //50mb max cache
169-
168+
170169
function saveToStorage(data, subject = null) {
171-
if(data === githubCache.data && subject === githubCache.subject) {
172-
log('Skipping cache save - no changes');
173-
return Promise.resolve(true);
174-
}
175170
const cacheData = {
176171
data: data,
177172
cacheKey: githubCache.cacheKey,
@@ -191,6 +186,8 @@ function allIncluded() {
191186
resolve(false);
192187
} else {
193188
log('Cache saved successfuly');
189+
githubCache.data = data;
190+
githubCache.subject = subject;
194191
resolve(true);
195192
}
196193
});
@@ -201,19 +198,19 @@ function allIncluded() {
201198
log('Loading cache from storage');
202199
return new Promise((resolve) => {
203200
chrome.storage.local.get('githubCache', (result) => {
204-
if(chrome.runtime.lastError) {
205-
logError('Storage load failed:', chrome.runtime.lastError);
206-
resolve(false);
207-
return;
208-
}
209-
210201
const cache = result.githubCache;
211202
if (!cache) {
212203
log('No cache found in storage');
213204
resolve(false);
214205
return;
215206
}
216-
log('Found cache:', {
207+
const isCacheExpired = (Date.now() - cache.timestamp) > githubCache.ttl;
208+
if(isCacheExpired){
209+
log('Cached data is expired');
210+
resolve(false);
211+
return;
212+
}
213+
log('Found valid cache:', {
217214
cacheKey: cache.cacheKey,
218215
age: `${((Date.now() - cache.timestamp) / 1000 / 60).toFixed(1)} minutes` ,
219216
});
@@ -223,28 +220,15 @@ function allIncluded() {
223220
githubCache.timestamp = cache.timestamp;
224221
githubCache.subject = cache.subject;
225222

226-
// use cached subject element
227223
if(cache.subject && scrumSubject) {
228224
scrumSubject.value = cache.subject;
229225
scrumSubject.dispatchEvent(new Event('input', { bubbles: true }));
230226
}
231-
232227
resolve(true);
233228
})
234229
})
235230
}
236-
237-
function updateCache(data) {
238-
const cacheSize = new Blob([JSON.stringify(data)]).size;
239-
if(cacheSize > MAX_CACHE_SIZE) {
240-
console.wanr(`Cache data too large, not caching`);
241-
return;
242-
}
243-
githubCache.data = data;
244-
githubCache.timestamp = Date.now();
245-
}
246-
247-
// fetch github data
231+
248232
async function fetchGithubData() {
249233
const cacheKey = `${githubUsername}-${startingDate}-${endingDate}`;
250234

@@ -322,8 +306,7 @@ function allIncluded() {
322306
githubCache.data = { githubIssuesData, githubPrsReviewData, githubUserData };
323307
githubCache.timestamp = Date.now();
324308

325-
// updateCache({ githubIssuesData, githubPrsReviewData, githubUserData });
326-
await saveToStorage(githubCache.data); // Save to storage
309+
await saveToStorage(githubCache.data);
327310
processGithubData(githubCache.data);
328311

329312
// Resolve queued calls
@@ -362,6 +345,38 @@ function allIncluded() {
362345
}
363346
verifyCacheStatus();
364347

348+
async function forceGithubDataRefresh() {
349+
log('Force refreshing GitHub data');
350+
// clear cache
351+
githubCache = {
352+
data: null,
353+
cacheKey: null,
354+
timestamp: 0,
355+
ttl: 10*60*1000,
356+
fetching: false,
357+
queue: [],
358+
errors: {},
359+
errorTTL: 60*1000,
360+
subject: null
361+
};
362+
await new Promise(resolve => {
363+
chrome.storage.local.remove('githubCache', resolve);
364+
});
365+
366+
log('Cache cleared, fetching fresh data');
367+
try {
368+
await fetchGithubData();
369+
await saveToStorage();
370+
return { success: true, timestamp: Date.now() };
371+
} catch (err) {
372+
logError('Force refresh failed:', err);
373+
throw err;
374+
}
375+
}
376+
if(typeof window !== 'undefined') {
377+
window.forceGithubDataRefresh = forceGithubDataRefresh;
378+
}
379+
365380
function processGithubData(data) {
366381
log('Processing Github data');
367382
githubIssuesData = data.githubIssuesData;
@@ -433,24 +448,11 @@ function allIncluded() {
433448
});
434449
}
435450

436-
// depriciate this
437-
// function getProject() {
438-
// if (projectName != '') return projectName;
439-
440-
// let project = '<project name>';
441-
// let url = window.location.href;
442-
// let projectUrl = url.substr(url.lastIndexOf('/') + 1);
443-
// if (projectUrl === 'susiai') project = 'SUSI.AI';
444-
// else if (projectUrl === 'open-event') project = 'Open Event';
445-
// return project;
446-
// }
447-
448451
//load initial scrum subject
449452
function scrumSubjectLoaded() {
450453
if (!enableToggle) return;
451454
setTimeout(() => {
452455
let name = githubUserData.name || githubUsername;
453-
// let project = getProject();
454456
let project = projectName || '<project name>';
455457
let curDate = new Date();
456458
let year = curDate.getFullYear().toString();
@@ -463,7 +465,6 @@ function allIncluded() {
463465

464466
const subject = `[Scrum] ${name} - ${project} - ${dateCode} - False`;
465467
log('Generated subject:', subject);
466-
// Save subject to cache
467468
githubCache.subject = subject;
468469
saveToStorage(githubCache.data, subject);
469470

@@ -738,3 +739,12 @@ $('button>span:contains(New conversation)')
738739
allIncluded();
739740
});
740741

742+
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
743+
if(request.action === 'forceRefresh') {
744+
forceGithubDataRefresh().then(result => sendResponse(result)).catch(err => {
745+
console.error('Force refresh failed:', err);
746+
sendResponse({ success: false, error: err.message });
747+
});
748+
return true;
749+
}
750+
})

0 commit comments

Comments
 (0)