Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions src/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
"message": "Your GitLab Username",
"description": "Label for the GitLab username input field."
},
"giteeUsernameLabel": {
"message": "Your Gitee Username",
"description": "Label for the Gitee username input field."
},
"githubUsernamePlaceholder": {
"message": "Required for fetching your contributions",
"description": "Placeholder text for the GitHub username input."
Expand Down
4 changes: 2 additions & 2 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ hr,
.dark-mode .bg-white {
background-color: #2d2d2d !important;
border-color: #404040 !important;
transition: background-color 0.3s ease-in-out, color 0.3s ease-in-out;
transition: background-color 0.3s ease-in-out, border-color 0.3s ease-in-out;
}

.dark-mode input[type="text"],
Expand All @@ -98,7 +98,6 @@ hr,
background-color: #404040 !important;
border-color: #505050 !important;
color: #ffffff !important;
transition: background-color 0.3s ease-in-out, color 0.3s ease-in-out;
}

.dark-mode h3,
Expand Down Expand Up @@ -694,6 +693,7 @@ hr,
background-color: #404040 !important;
border-color: #505050 !important;
color: #ffffff !important;
transition: background-color 0.3s ease-in-out, border-color 0.3s ease-in-out, color 0.3s ease-in-out;
}

.dark-mode #platformDropdownBtn:focus {
Expand Down
6 changes: 6 additions & 0 deletions src/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<link rel="stylesheet" href="tailwindcss.css">
<link rel="stylesheet" type="text/css" href="index.css">
<link rel="stylesheet" href="fontawesome/css/all.min.css">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/fonts/remixicon.css" rel="stylesheet">
<style type="text/css">
html,
body {
Expand Down Expand Up @@ -105,6 +106,10 @@ <h3 id="scrumHelperHeading" class="text-3xl font-semibold cursor-pointer">Scrum
class="hover:bg-gray-100" data-value="gitlab">
<i class="fab fa-gitlab" style="margin-right: 12px; font-size: 18px;"></i> GitLab
</li>
<li style="padding-left: 8px; padding-right: 16px; padding-top: 8px; padding-bottom: 8px; display: flex; align-items: center; cursor: pointer;"
class="hover:bg-gray-100" data-value="gitee">
<i class="ri-git-repository-fill" style="margin-right: 12px; font-size: 18px;"></i> Gitee
</li>
</ul>
</div>
</div>
Expand Down Expand Up @@ -412,6 +417,7 @@ <h4 class="font-semibold text-xl" data-i18n="noteTitle">Note:</h4>
<script type="text/javascript" type="text/javascript" src="materialize/js/materialize.min.js"></script>
<script src="scripts/emailClientAdapter.js"></script>
<script src="scripts/main.js"></script>
<script src="scripts/giteeHelper.js"></script>
<script src="scripts/gitlabHelper.js"></script>
<script src="scripts/scrumHelper.js"></script>
<script src="scripts/popup.js"></script>
Expand Down
183 changes: 183 additions & 0 deletions src/scripts/giteeHelper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
// Gitee API Helper for Scrum Helper Extension
class GiteeHelper {
constructor() {
this.baseUrl = 'https://gitee.com/api/v5';
this.cache = {
data: null,
cacheKey: null,
timestamp: 0,
ttl: 10 * 60 * 1000, // 10 minutes
fetching: false,
queue: []
};
}

async getCacheTTL() {
return new Promise((resolve) => {
chrome.storage.local.get(['cacheInput'], (items) => {
const ttl = items.cacheInput ? parseInt(items.cacheInput) * 60 * 1000 : 10 * 60 * 1000;
resolve(ttl);
});
});
}

async saveToStorage(data) {
return new Promise((resolve) => {
chrome.storage.local.set({
giteeCache: {
data: data,
cacheKey: this.cache.cacheKey,
timestamp: this.cache.timestamp
}
}, resolve);
});
}

async loadFromStorage() {
return new Promise((resolve) => {
chrome.storage.local.get(['giteeCache'], (items) => {
if (items.giteeCache) {
this.cache.data = items.giteeCache.data;
this.cache.cacheKey = items.giteeCache.cacheKey;
this.cache.timestamp = items.giteeCache.timestamp;
console.log('Restored Gitee cache from storage');
}
resolve();
});
});
}

async fetchGiteeData(username, startDate, endDate, token = null) {
const cacheKey = `${username}-${startDate}-${endDate}`;
const headers = token ? { Authorization: `token ${token}` } : {};

if (this.cache.fetching || (this.cache.cacheKey === cacheKey && this.cache.data)) {
console.log('Gitee fetch already in progress or data already fetched. Skipping fetch.');
return this.cache.data;
}

console.log('Fetching Gitee data:', { username, startDate, endDate });

if (!this.cache.data && !this.cache.fetching) {
await this.loadFromStorage();
}

const currentTTL = await this.getCacheTTL();
this.cache.ttl = currentTTL;
console.log(`Gitee caching for ${currentTTL / (60 * 1000)} minutes`);

const now = Date.now();
const isCacheFresh = (now - this.cache.timestamp) < this.cache.ttl;
const isCacheKeyMatch = this.cache.cacheKey === cacheKey;

if (this.cache.data && isCacheFresh && isCacheKeyMatch) {
console.log('Using cached Gitee data - cache is fresh and key matches');
return this.cache.data;
}

if (this.cache.fetching) {
console.log('Gitee fetch in progress, queuing requests');
return new Promise((resolve, reject) => {
this.cache.queue.push({ resolve, reject });
});
}

this.cache.fetching = true;
this.cache.cacheKey = cacheKey;

try {
// πŸ”Ή Get user info
const userUrl = `${this.baseUrl}/users/${username}`;
const userRes = await fetch(userUrl, { headers });
if (!userRes.ok) throw new Error(`Error fetching Gitee user: ${userRes.statusText}`);
const user = await userRes.json();

// πŸ”Ή Get user repositories
const repoUrl = `${this.baseUrl}/users/${username}/repos?sort=updated&direction=desc&per_page=100`;
const repoRes = await fetch(repoUrl, { headers });
if (!repoRes.ok) throw new Error(`Error fetching Gitee repositories: ${repoRes.statusText}`);
const repositories = await repoRes.json();

// πŸ”Ή Fetch issues created by the user
const issuesUrl = `${this.baseUrl}/search/issues?q=author:${username}&created_at>${startDate}&created_at<${endDate}&per_page=100`;
const issuesRes = await fetch(issuesUrl, { headers });
const issues = issuesRes.ok ? await issuesRes.json() : [];

// πŸ”Ή Fetch pull requests created by the user
let allPRs = [];
for (const repo of repositories) {
const prUrl = `${this.baseUrl}/repos/${username}/${repo.name}/pulls?state=all&sort=created&direction=desc`;
try {
const prRes = await fetch(prUrl, { headers });
if (prRes.ok) {
const prs = await prRes.json();
const filtered = prs.filter(pr => {
const createdAt = new Date(pr.created_at);
return createdAt >= new Date(startDate) && createdAt <= new Date(endDate);
});
allPRs = allPRs.concat(filtered);
}
} catch (err) {
console.warn(`Error fetching PRs for repo ${repo.name}:`, err);
}
await new Promise(resolve => setTimeout(resolve, 100));
}

const giteeData = {
user: user,
projects: repositories,
mergeRequests: allPRs,
issues: issues,
comments: []
};

this.cache.data = giteeData;
this.cache.timestamp = Date.now();
await this.saveToStorage(giteeData);

this.cache.queue.forEach(({ resolve }) => resolve(giteeData));
this.cache.queue = [];

return giteeData;

} catch (err) {
console.error('Gitee Fetch Failed:', err);
this.cache.queue.forEach(({ reject }) => reject(err));
this.cache.queue = [];
throw err;
} finally {
this.cache.fetching = false;
}
}

formatDate(dateString) {
const date = new Date(dateString);
const options = { day: '2-digit', month: 'short', year: 'numeric' };
return date.toLocaleDateString('en-US', options);
}

processGiteeData(data) {
const processed = {
mergeRequests: data.mergeRequests || [],
issues: data.issues || [],
comments: data.comments || [],
user: data.user
};
console.log('[GITEE-DEBUG] processGiteeData input:', data);
console.log('[GITEE-DEBUG] processGiteeData output:', processed);
console.log('Gitee data processed:', {
mergeRequests: processed.mergeRequests.length,
issues: processed.issues.length,
comments: processed.comments.length,
user: processed.user?.login
});
return processed;
}
}

// Export for browser or Node
if (typeof module !== 'undefined' && module.exports) {
module.exports = GiteeHelper;
} else {
window.GiteeHelper = GiteeHelper;
}
10 changes: 8 additions & 2 deletions src/scripts/popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -1198,6 +1198,8 @@ function updatePlatformUI(platform) {
if (usernameLabel) {
if (platform === 'gitlab') {
usernameLabel.setAttribute('data-i18n', 'gitlabUsernameLabel');
} else if (platform === 'gitee') {
usernameLabel.setAttribute('data-i18n', 'giteeUsernameLabel');
} else {
usernameLabel.setAttribute('data-i18n', 'githubUsernameLabel');
}
Expand All @@ -1210,7 +1212,7 @@ function updatePlatformUI(platform) {

const orgSection = document.querySelector('.orgSection');
if (orgSection) {
if (platform === 'gitlab') {
if (platform === 'gitlab' || platform === 'gitee') {
orgSection.classList.add('hidden');
} else {
orgSection.classList.remove('hidden');
Expand Down Expand Up @@ -1256,7 +1258,9 @@ const platformSelectHidden = document.getElementById('platformSelect');
function setPlatformDropdown(value) {
if (value === 'gitlab') {
dropdownSelected.innerHTML = '<i class="fab fa-gitlab mr-2"></i> GitLab';
} else {
}else if (value === 'gitee') {
dropdownSelected.innerHTML = '<i class="fab ri-git-repository-fill"></i> Gitee';
}else {
dropdownSelected.innerHTML = '<i class="fab fa-github mr-2"></i> GitHub';
}

Expand Down Expand Up @@ -1363,6 +1367,8 @@ chrome.storage.local.get(['platform'], function (result) {
// Just update the UI without clearing username when restoring from storage
if (platform === 'gitlab') {
dropdownSelected.innerHTML = '<i class="fab fa-gitlab mr-2"></i> GitLab';
} else if (platform === 'gitee') {
dropdownSelected.innerHTML = '<i class="fab ri-git-repository-fill"></i> Gitee';
} else {
dropdownSelected.innerHTML = '<i class="fab fa-github mr-2"></i> GitHub';
}
Expand Down
54 changes: 54 additions & 0 deletions src/scripts/scrumHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ let orgName = '';
let platform = 'github';
let platformUsername = '';
let gitlabHelper = null;
let giteeHelper = null;

function allIncluded(outputTarget = 'email') {
// Always re-instantiate gitlabHelper for gitlab platform to ensure fresh cache after refresh
Expand Down Expand Up @@ -314,6 +315,59 @@ function allIncluded(outputTarget = 'email') {
}
scrumGenerationInProgress = false;
}
} else if (platform === 'gitee') {
console.log("Gitee Code is reading...");
if (!giteeHelper)
giteeHelper = new window.GiteeHelper();


if (!platformUsernameLocal) {
if (outputTarget === 'popup') {
const generateBtn = document.getElementById('generateReport');
const scrumReport = document.getElementById('scrumReport');

if (scrumReport) {
scrumReport.innerHTML = `<div class="error-message" style="color: #dc2626; font-weight: bold; padding: 10px;">Please enter your username to generate a report.</div>`;
}

if (generateBtn) {
generateBtn.innerHTML = '<i class="fa fa-refresh"></i> Generate Report';
generateBtn.disabled = false;
}
}

scrumGenerationInProgress = false;
return;
}

if (platformUsernameLocal) {

giteeHelper.fetchGiteeData(platformUsernameLocal, startingDate, endingDate)
.then(data => {
const mappedData = {
githubIssuesData: { items: data.issues || [] },
githubPrsReviewData: { items: data.mergeRequests || [] },
githubUserData: data.user || {},
};
processGithubData(mappedData);
scrumGenerationInProgress = false;
})
.catch(err => {
console.error('Gitee fetch failed:', err);
if (outputTarget === 'popup') {
const generateBtn = document.getElementById('generateReport');
const scrumReport = document.getElementById('scrumReport');
if (generateBtn) {
generateBtn.innerHTML = '<i class="fa fa-refresh"></i> Generate Report';
generateBtn.disabled = false;
}
if (scrumReport) {
scrumReport.innerHTML = `<div class="error-message" style="color: #dc2626; font-weight: bold; padding: 10px;">${err.message || 'An error occurred while fetching Gitee data.'}</div>`;
}
}
scrumGenerationInProgress = false;
});
}
} else {
// Unknown platform
if (outputTarget === 'popup') {
Expand Down