diff --git a/src/manifests/chrome.json b/src/manifests/chrome.json
index a342f257..e70ddbaa 100644
--- a/src/manifests/chrome.json
+++ b/src/manifests/chrome.json
@@ -32,6 +32,7 @@
"scripts/jquery-3.2.1.min.js",
"scripts/emailClientAdapter.js",
"scripts/gitlabHelper.js",
+ "scripts/utils.js",
"scripts/scrumHelper.js"
]
}
diff --git a/src/manifests/firefox.json b/src/manifests/firefox.json
index 9972205c..0307a4e1 100644
--- a/src/manifests/firefox.json
+++ b/src/manifests/firefox.json
@@ -32,6 +32,7 @@
"scripts/jquery-3.2.1.min.js",
"scripts/emailClientAdapter.js",
"scripts/gitlabHelper.js",
+ "scripts/utils.js",
"scripts/scrumHelper.js"
]
}
diff --git a/src/popup.html b/src/popup.html
index ed324e5c..5582e652 100644
--- a/src/popup.html
+++ b/src/popup.html
@@ -615,6 +615,7 @@
Note:
+
diff --git a/src/scripts/main.js b/src/scripts/main.js
index 7a8e2f5c..fe83206d 100644
--- a/src/scripts/main.js
+++ b/src/scripts/main.js
@@ -118,8 +118,8 @@ function handleYesterdayContributionChange() {
if (value) {
startingDateElement.readOnly = true;
endingDateElement.readOnly = true;
- endingDateElement.value = getToday();
- startingDateElement.value = getYesterday();
+ endingDateElement.value = window.scrumUtils.getTodayDateString();
+ startingDateElement.value = window.scrumUtils.getYesterdayDateString();
handleEndingDateChange();
handleStartingDateChange();
labelElement.classList.add('selectedLabel');
@@ -132,18 +132,6 @@ function handleYesterdayContributionChange() {
}
browser.storage.local.set({ yesterdayContribution: value });
}
-
-function getYesterday() {
- const today = new Date();
- const yesterday = new Date(today);
- yesterday.setDate(today.getDate() - 1);
- return yesterday.toISOString().split('T')[0];
-}
-function getToday() {
- const today = new Date();
- return today.toISOString().split('T')[0];
-}
-
function handlePlatformUsernameChange() {
const value = platformUsernameElement.value;
browser.storage.local.get(['platform']).then((result) => {
diff --git a/src/scripts/popup.js b/src/scripts/popup.js
index 82f28091..f1041845 100644
--- a/src/scripts/popup.js
+++ b/src/scripts/popup.js
@@ -78,18 +78,6 @@ function setupButtonTooltips() {
}
}
-function getToday() {
- const today = new Date();
- return today.toISOString().split('T')[0];
-}
-
-function getYesterday() {
- const today = new Date();
- const yesterday = new Date(today);
- yesterday.setDate(today.getDate() - 1);
- return yesterday.toISOString().split('T')[0];
-}
-
function applyI18n() {
document.querySelectorAll('[data-i18n]').forEach((el) => {
const key = el.getAttribute('data-i18n');
@@ -344,12 +332,8 @@ document.addEventListener('DOMContentLoaded', () => {
}
githubTokenInput.addEventListener('input', checkTokenForFilter);
- githubTokenInput.addEventListener('input', () =>
- checkTokenForShowCommits({ persistState: false }),
- );
- githubTokenInput.addEventListener('input', () =>
- checkTokenForMergedPRs({ persistState: false }),
- );
+ githubTokenInput.addEventListener('input', () => checkTokenForShowCommits({ persistState: false }));
+ githubTokenInput.addEventListener('input', () => checkTokenForMergedPRs({ persistState: false }));
darkModeToggle.addEventListener('click', function () {
body.classList.toggle('dark-mode');
@@ -501,34 +485,37 @@ document.addEventListener('DOMContentLoaded', () => {
'lastScrumReportUsername',
'githubUsername',
'gitlabUsername',
- 'platformUsername'
+ 'platformUsername',
]);
let lastScrumReportHtml = storageValues[`${activePlatform}LastScrumReportHtml`];
let lastScrumReportCacheKey = storageValues[`${activePlatform}LastScrumReportCacheKey`];
let lastScrumReportUsername = storageValues[`${activePlatform}LastScrumReportUsername`];
- if (storageValues.lastScrumReportHtml && (!storageValues.lastScrumReportPlatform || storageValues.lastScrumReportPlatform === activePlatform) && !lastScrumReportHtml) {
+ if (
+ storageValues.lastScrumReportHtml &&
+ (!storageValues.lastScrumReportPlatform || storageValues.lastScrumReportPlatform === activePlatform) &&
+ !lastScrumReportHtml
+ ) {
lastScrumReportHtml = storageValues.lastScrumReportHtml;
lastScrumReportCacheKey = storageValues.lastScrumReportCacheKey;
lastScrumReportUsername = storageValues.lastScrumReportUsername;
}
- const expectedUsername = activePlatform === 'gitlab'
- ? (storageValues.gitlabUsername || storageValues.platformUsername)
- : (storageValues.githubUsername || storageValues.platformUsername);
+ const expectedUsername =
+ activePlatform === 'gitlab'
+ ? storageValues.gitlabUsername || storageValues.platformUsername
+ : storageValues.githubUsername || storageValues.platformUsername;
- const isUsernameMatch = lastScrumReportUsername
+ const isUsernameMatch = lastScrumReportUsername
? lastScrumReportUsername === expectedUsername
- : (lastScrumReportCacheKey && expectedUsername && lastScrumReportCacheKey.startsWith(expectedUsername + '-'));
+ : lastScrumReportCacheKey && expectedUsername && lastScrumReportCacheKey.startsWith(expectedUsername + '-');
if (age < ttlMs) {
const cacheKey = cache?.cacheKey ?? null;
const reportEmpty = !scrumReport.innerHTML || !scrumReport.innerHTML.trim();
- const matches =
- (!lastScrumReportCacheKey || lastScrumReportCacheKey === cacheKey) &&
- isUsernameMatch;
+ const matches = (!lastScrumReportCacheKey || lastScrumReportCacheKey === cacheKey) && isUsernameMatch;
if (reportEmpty && lastScrumReportHtml && matches) {
scrumReport.innerHTML = lastScrumReportHtml;
@@ -658,8 +645,7 @@ document.addEventListener('DOMContentLoaded', () => {
platformUsername.value = result[platformUsernameKey] || '';
checkTokenForShowCommits();
checkTokenForMergedPRs();
- },
- );
+ });
// Button setup
const generateBtn = document.getElementById('generateReport');
@@ -822,8 +808,8 @@ document.addEventListener('DOMContentLoaded', () => {
const endDateInput = document.getElementById('endingDate');
if (items.selectedTimeframe === 'yesterdayContribution') {
- startDateInput.value = getYesterday();
- endDateInput.value = getToday();
+ startDateInput.value = window.scrumUtils.getYesterdayDateString();
+ endDateInput.value = window.scrumUtils.getTodayDateString();
}
startDateInput.readOnly = endDateInput.readOnly = true;
@@ -983,7 +969,9 @@ document.addEventListener('DOMContentLoaded', () => {
// Show notice instead of applying immediately
const modeLabel = mode === 'popup' ? 'Popup' : 'Side Panel';
if (displayModeNotice && displayModeNoticeText) {
- displayModeNoticeText.textContent = chrome?.i18n.getMessage('displayModeNotice', [modeLabel]) || `The extension will open in ${modeLabel} mode on the next launch.`;
+ displayModeNoticeText.textContent =
+ chrome?.i18n.getMessage('displayModeNotice', [modeLabel]) ||
+ `The extension will open in ${modeLabel} mode on the next launch.`;
displayModeNotice.classList.remove('hidden');
}
});
@@ -1083,7 +1071,9 @@ document.addEventListener('DOMContentLoaded', () => {
} catch {}
if (platform !== 'github') {
// Do not run repo fetch for non-GitHub platforms
- if (repoStatus) repoStatus.textContent = chrome?.i18n.getMessage('repoFilteringGithubOnly') || 'Repository filtering is only available for GitHub.';
+ if (repoStatus)
+ repoStatus.textContent =
+ chrome?.i18n.getMessage('repoFilteringGithubOnly') || 'Repository filtering is only available for GitHub.';
return;
}
if (!useRepoFilter.checked) {
@@ -1172,7 +1162,10 @@ document.addEventListener('DOMContentLoaded', () => {
if (platform !== 'github') {
repoFilterContainer.classList.add('hidden');
useRepoFilter.checked = false;
- if (repoStatus) repoStatus.textContent = chrome?.i18n.getMessage('repoFilteringGithubOnly') || 'Repository filtering is only available for GitHub.';
+ if (repoStatus)
+ repoStatus.textContent =
+ chrome?.i18n.getMessage('repoFilteringGithubOnly') ||
+ 'Repository filtering is only available for GitHub.';
return;
}
const enabled = useRepoFilter.checked;
@@ -1202,7 +1195,8 @@ document.addEventListener('DOMContentLoaded', () => {
});
checkTokenForFilter();
if (enabled) {
- repoStatus.textContent = chrome?.i18n.getMessage('loadingReposAutomatically') || 'Loading repos automatically...';
+ repoStatus.textContent =
+ chrome?.i18n.getMessage('loadingReposAutomatically') || 'Loading repos automatically...';
try {
const cacheData = await browser.storage.local.get(['repoCache']);
@@ -1351,7 +1345,9 @@ document.addEventListener('DOMContentLoaded', () => {
platform = items.platform || 'github';
} catch {}
if (platform !== 'github') {
- if (repoStatus) repoStatus.textContent = chrome?.i18n.getMessage('repoLoadingGithubOnly') || 'Repository loading is only available for GitHub.';
+ if (repoStatus)
+ repoStatus.textContent =
+ chrome?.i18n.getMessage('repoLoadingGithubOnly') || 'Repository loading is only available for GitHub.';
return;
}
console.log('window.fetchUserRepositories exists:', !!window.fetchUserRepositories);
@@ -1391,7 +1387,9 @@ document.addEventListener('DOMContentLoaded', () => {
platform = items.platform || 'github';
} catch (e) {}
if (platform !== 'github') {
- if (repoStatus) repoStatus.textContent = chrome?.i18n.getMessage('repoFetchingGithubOnly') || 'Repository fetching is only available for GitHub.';
+ if (repoStatus)
+ repoStatus.textContent =
+ chrome?.i18n.getMessage('repoFetchingGithubOnly') || 'Repository fetching is only available for GitHub.';
return;
}
console.log('[POPUP-DEBUG] performRepoFetch called.');
@@ -1694,11 +1692,11 @@ platformSelect.addEventListener('change', () => {
const platform = platformSelect.value;
browser.storage.local.set({ platform }).then(() => {
const scrumReport = document.getElementById('scrumReport');
- if(scrumReport){
+ if (scrumReport) {
scrumReport.innerHTML = '';
}
const generateBtn = document.getElementById('generateReport');
- if(typeof bootstrapScrumReportOnPopupLoad === 'function'){
+ if (typeof bootstrapScrumReportOnPopupLoad === 'function') {
bootstrapScrumReportOnPopupLoad(generateBtn);
}
});
@@ -1728,11 +1726,7 @@ const platformSelectHidden = document.getElementById('platformSelect');
function buildScrumSubjectFromPopup() {
const projectName = document.getElementById('projectName')?.value?.trim() || '';
- const now = new Date();
- const dateCode =
- String(now.getFullYear()) + String(now.getMonth() + 1).padStart(2, '0') + String(now.getDate()).padStart(2, '0');
-
- return `[Scrum]${projectName ? ' - ' + projectName : ''} - ${dateCode}`;
+ return window.scrumUtils.buildScrumSubject(projectName);
}
function setPlatformDropdown(value) {
@@ -1754,10 +1748,10 @@ function setPlatformDropdown(value) {
platformSelectHidden.value = value;
browser.storage.local.set({ platform: value }).then(() => {
const scrumReport = document.getElementById('scrumReport');
- if(scrumReport) scrumReport.innerHTML = '';
+ if (scrumReport) scrumReport.innerHTML = '';
const generateBtn = document.getElementById('generateReport');
- if(typeof bootstrapScrumReportOnPopupLoad === 'function'){
+ if (typeof bootstrapScrumReportOnPopupLoad === 'function') {
bootstrapScrumReportOnPopupLoad(generateBtn);
}
});
@@ -2009,8 +2003,8 @@ function toggleRadio(radio) {
console.log('Toggling radio:', radio.id);
if (radio.id === 'yesterdayContribution') {
- startDateInput.value = getYesterday();
- endDateInput.value = getToday();
+ startDateInput.value = window.scrumUtils.getYesterdayDateString();
+ endDateInput.value = window.scrumUtils.getTodayDateString();
}
startDateInput.readOnly = endDateInput.readOnly = true;
diff --git a/src/scripts/scrumHelper.js b/src/scripts/scrumHelper.js
index c5fedf2b..7e735555 100644
--- a/src/scripts/scrumHelper.js
+++ b/src/scripts/scrumHelper.js
@@ -255,28 +255,13 @@ function allIncluded(outputTarget = 'email') {
endingDate,
gitlabToken,
);
+ const gitlabApiBase = gitlabHelper?.baseUrl;
- function mapGitLabItem(item, projects, type) {
- const project = projects.find((p) => p.id === item.project_id);
- const repoName = project ? project.name : 'unknown';
-
- return {
- ...item,
- repository_url: `https://gitlab.com/api/v4/projects/${item.project_id}`,
- html_url:
- type === 'issue'
- ? item.web_url || (project ? `${project.web_url}/-/issues/${item.iid}` : '')
- : item.web_url || (project ? `${project.web_url}/-/merge_requests/${item.iid}` : ''),
- number: item.iid,
- title: item.title,
- state: type === 'issue' && item.state === 'opened' ? 'open' : item.state,
- project: repoName,
- pull_request: type === 'mr',
- };
- }
- const mappedIssues = (data.issues || []).map((issue) => mapGitLabItem(issue, data.projects, 'issue'));
+ const mappedIssues = (data.issues || []).map((issue) =>
+ window.scrumUtils.mapGitLabItem(issue, data.projects, 'issue', gitlabApiBase),
+ );
const mappedMRs = (data.mergeRequests || data.mrs || []).map((mr) =>
- mapGitLabItem(mr, data.projects, 'mr'),
+ window.scrumUtils.mapGitLabItem(mr, data.projects, 'mr', gitlabApiBase),
);
const mappedData = {
githubIssuesData: { items: mappedIssues },
@@ -285,18 +270,8 @@ function allIncluded(outputTarget = 'email') {
};
githubUserData = mappedData.githubUserData;
- const name =
- githubUserData?.name || githubUserData?.username || platformUsernameLocal || platformUsername;
const project = projectName;
- const curDate = new Date();
- const year = curDate.getFullYear().toString();
- let date = curDate.getDate();
- let month = curDate.getMonth() + 1;
- if (month < 10) month = '0' + month;
- if (date < 10) date = '0' + date;
- const dateCode = year.toString() + month.toString() + date.toString();
- const subject = `[Scrum]${project ? ' - ' + project : ''} - ${dateCode}`;
- subjectForEmail = subject;
+ subjectForEmail = window.scrumUtils.buildScrumSubject(project);
await processGithubData(mappedData, true, subjectForEmail);
scrumGenerationInProgress = false;
@@ -327,26 +302,12 @@ function allIncluded(outputTarget = 'email') {
gitlabHelper
.fetchGitLabData(platformUsernameLocal, startingDate, endingDate, gitlabToken)
.then((data) => {
- function mapGitLabItem(item, projects, type) {
- const project = projects.find((p) => p.id === item.project_id);
- const repoName = project ? project.name : 'unknown';
- return {
- ...item,
- repository_url: `https://gitlab.com/api/v4/projects/${item.project_id}`,
- html_url:
- type === 'issue'
- ? item.web_url || (project ? `${project.web_url}/-/issues/${item.iid}` : '')
- : item.web_url || (project ? `${project.web_url}/-/merge_requests/${item.iid}` : ''),
- number: item.iid,
- title: item.title,
- state: type === 'issue' && item.state === 'opened' ? 'open' : item.state,
- project: repoName,
- pull_request: type === 'mr',
- };
- }
- const mappedIssues = (data.issues || []).map((issue) => mapGitLabItem(issue, data.projects, 'issue'));
+ const gitlabApiBase = gitlabHelper?.baseUrl;
+ const mappedIssues = (data.issues || []).map((issue) =>
+ window.scrumUtils.mapGitLabItem(issue, data.projects, 'issue', gitlabApiBase),
+ );
const mappedMRs = (data.mergeRequests || data.mrs || []).map((mr) =>
- mapGitLabItem(mr, data.projects, 'mr'),
+ window.scrumUtils.mapGitLabItem(mr, data.projects, 'mr', gitlabApiBase),
);
const mappedData = {
githubIssuesData: { items: mappedIssues },
@@ -413,19 +374,8 @@ function allIncluded(outputTarget = 'email') {
getChromeData();
function handleYesterdayContributionChange() {
- endingDate = getToday();
- startingDate = getYesterday();
- }
-
- function getYesterday() {
- const today = new Date();
- const yesterday = new Date(today);
- yesterday.setDate(today.getDate() - 1);
- return yesterday.toISOString().split('T')[0];
- }
- function getToday() {
- const today = new Date();
- return today.toISOString().split('T')[0];
+ endingDate = window.scrumUtils.getTodayDateString();
+ startingDate = window.scrumUtils.getYesterdayDateString();
}
// Global cache object
@@ -1258,18 +1208,8 @@ ${blockerText}`;
return;
}
setTimeout(() => {
- const name = githubUserData?.name || githubUserData?.username || platformUsernameLocal || platformUsername;
const project = projectName;
- const curDate = new Date();
- const year = curDate.getFullYear().toString();
- let date = curDate.getDate();
- let month = curDate.getMonth();
- month++;
- if (month < 10) month = '0' + month;
- if (date < 10) date = '0' + date;
- const dateCode = year.toString() + month.toString() + date.toString();
-
- const subject = `[Scrum]${project ? ' - ' + project : ''} - ${dateCode}`;
+ const subject = window.scrumUtils.buildScrumSubject(project);
log('Generated subject:', subject);
githubCache.subject = subject;
saveToStorage(githubCache.data, subject);
diff --git a/src/scripts/utils.js b/src/scripts/utils.js
new file mode 100644
index 00000000..0aa0fc3e
--- /dev/null
+++ b/src/scripts/utils.js
@@ -0,0 +1,75 @@
+(function (globalScope) {
+ function formatDateToIsoDay(date) {
+ return date.toISOString().split('T')[0];
+ }
+
+ function getTodayDateString(now = new Date()) {
+ return formatDateToIsoDay(now);
+ }
+
+ function getYesterdayDateString(now = new Date()) {
+ const yesterday = new Date(now);
+ yesterday.setUTCDate(now.getUTCDate() - 1);
+ return formatDateToIsoDay(yesterday);
+ }
+
+ function getScrumDateCode(now = new Date()) {
+ const year = String(now.getUTCFullYear());
+ const month = String(now.getUTCMonth() + 1).padStart(2, '0');
+ const day = String(now.getUTCDate()).padStart(2, '0');
+ return `${year}${month}${day}`;
+ }
+
+ function buildScrumSubject(projectName = '', now = new Date()) {
+ const projectPart = projectName ? ` - ${projectName}` : '';
+ return `[Scrum]${projectPart} - ${getScrumDateCode(now)}`;
+ }
+
+ function normalizeGitLabState(state, type) {
+ if (type === 'issue') {
+ return state === 'opened' ? 'open' : state;
+ }
+
+ if (type === 'mr') {
+ if (state === 'opened') {
+ return 'open';
+ }
+ if (state === 'merged' || state === 'closed') {
+ return 'closed';
+ }
+ }
+
+ return state;
+ }
+
+ function mapGitLabItem(item, projects = [], type, apiBaseUrl = 'https://gitlab.com/api/v4') {
+ const project = projects.find((projectItem) => projectItem.id === item.project_id);
+ const repoName = project ? project.name : 'unknown';
+ const normalizedApiBase = apiBaseUrl.replace(/\/+$/, '');
+ const normalizedState = normalizeGitLabState(item.state, type);
+ const pullRequestData = type === 'mr' ? { merged_at: item.merged_at || null } : false;
+
+ return {
+ ...item,
+ repository_url: `${normalizedApiBase}/projects/${item.project_id}`,
+ html_url:
+ type === 'issue'
+ ? item.web_url || (project ? `${project.web_url}/-/issues/${item.iid}` : '')
+ : item.web_url || (project ? `${project.web_url}/-/merge_requests/${item.iid}` : ''),
+ number: item.iid,
+ title: item.title,
+ state: normalizedState,
+ project: repoName,
+ pull_request: pullRequestData,
+ };
+ }
+
+ globalScope.scrumUtils = {
+ ...(globalScope.scrumUtils || {}),
+ getTodayDateString,
+ getYesterdayDateString,
+ getScrumDateCode,
+ buildScrumSubject,
+ mapGitLabItem,
+ };
+})(typeof window !== 'undefined' ? window : globalThis);