Skip to content

Commit 9876723

Browse files
added a validation for organisation to check if valid or not
1 parent 28c50fe commit 9876723

File tree

1 file changed

+76
-108
lines changed

1 file changed

+76
-108
lines changed

src/scripts/popup.js

Lines changed: 76 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -475,113 +475,8 @@ document.addEventListener('DOMContentLoaded', function () {
475475
projectNameInput.addEventListener('input', function () {
476476
chrome.storage.local.set({ projectName: projectNameInput.value });
477477
});
478-
479-
// Organization validation function (using function expression to avoid hoisting issues)
480-
const validateOrganization = async function(orgName, githubToken = '') {
481-
const validationMessage = document.getElementById('orgValidationMessage');
482-
const validationText = document.getElementById('orgValidationText');
483-
484-
// Safety check - if elements don't exist, return early
485-
if (!validationMessage || !validationText) {
486-
console.warn('Validation elements not found');
487-
return true;
488-
}
489-
490-
// Hide validation for empty input (valid case)
491-
if (!orgName || orgName.trim() === '') {
492-
validationMessage.classList.add('hidden');
493-
return true;
494-
}
495-
496-
const cleanOrgName = orgName.trim();
497-
498-
// GitHub org/username validation: alphanumeric, hyphens, underscores
499-
const validPattern = /^[a-zA-Z0-9\-_]+$/;
500-
if (!validPattern.test(cleanOrgName)) {
501-
showValidationMessage('error', `Organization name contains invalid characters`);
502-
return false;
503-
}
504-
505-
// Check length constraints (GitHub max is 39 characters)
506-
if (cleanOrgName.length > 39) {
507-
showValidationMessage('error', `Organization name too long (max 39 characters)`);
508-
return false;
509-
}
510-
511-
// Optional: Only validate against API if user has provided a token
512-
if (githubToken && githubToken.trim()) {
513-
try {
514-
const headers = { 'Authorization': `token ${githubToken}` };
515-
const response = await fetch(`https://api.github.com/orgs/${cleanOrgName}`, {
516-
method: 'HEAD',
517-
headers
518-
});
519-
520-
if (response.status === 200) {
521-
showValidationMessage('success', `Organization "${cleanOrgName}" verified`);
522-
return true;
523-
} else if (response.status === 404) {
524-
showValidationMessage('warning', `Organization "${cleanOrgName}" not found (will search public repos)`);
525-
return true; // Still allow it - might be private or user/org distinction
526-
} else if (response.status === 403) {
527-
showValidationMessage('warning', `Rate limited or private organization`);
528-
return true;
529-
}
530-
} catch (error) {
531-
// Network error - fail silently, don't block user
532-
console.log('Org validation network error:', error);
533-
}
534-
}
535-
536-
// Default: assume it's valid, user will find out during report generation if not
537-
validationMessage.classList.add('hidden');
538-
return true;
539-
}
540-
541-
const showValidationMessage = function(type, message) {
542-
const validationMessage = document.getElementById('orgValidationMessage');
543-
const validationText = document.getElementById('orgValidationText');
544-
545-
// Safety check
546-
if (!validationMessage || !validationText) return;
547-
548-
validationMessage.className = `${type} text-xs mt-1 mb-2 px-3 py-2 rounded-lg`;
549-
validationText.textContent = message; // Use textContent for security
550-
validationMessage.classList.remove('hidden');
551-
};
552-
553-
// Track the latest validation request to avoid race conditions
554-
let orgValidationRequestId = 0;
555-
556-
// CORRECT IMPLEMENTATION: Save only on blur (when user clicks out)
557-
orgInput.addEventListener('focus', function () {
558-
// Add visual highlight when field becomes active
559-
this.classList.add('org-input-active');
560-
});
561-
562-
orgInput.addEventListener('blur', async function () {
563-
// Remove highlight when field loses focus
564-
this.classList.remove('org-input-active');
565-
566-
// Save to storage only when user finishes editing (clicks out)
567-
const cleanValue = this.value.trim().toLowerCase();
568-
chrome.storage.local.set({
569-
orgName: cleanValue,
570-
githubCache: null // Clear cache when organization changes
571-
});
572-
573-
// Increment validation request id to handle race conditions
574-
const currentRequestId = ++orgValidationRequestId;
575-
576-
// Validate and show feedback only after user finishes editing
577-
const result = await new Promise(resolve => {
578-
chrome.storage.local.get(['githubToken'], resolve);
579-
});
580-
581-
// Only process the result if this is the latest request
582-
if (currentRequestId === orgValidationRequestId) {
583-
await validateOrganization(this.value, result.githubToken);
584-
}
478+
orgInput.addEventListener('input', function () {
479+
chrome.storage.local.set({ orgName: orgInput.value.trim().toLowerCase() });
585480
});
586481
userReasonInput.addEventListener('input', function () {
587482
chrome.storage.local.set({ userReason: userReasonInput.value });
@@ -1630,4 +1525,77 @@ async function triggerRepoFetchIfEnabled() {
16301525
if (window.triggerRepoFetchIfEnabled) {
16311526
await window.triggerRepoFetchIfEnabled();
16321527
}
1633-
}
1528+
}
1529+
1530+
const handleOrgInput = debounce(function () {
1531+
let org = orgInput.value.trim().toLowerCase();
1532+
if (!org) {
1533+
chrome.storage.local.set({ orgName: '' }, () => {
1534+
console.log(`Org cleared, triggering repo fetch for all git`);
1535+
chrome.storage.local.remove(['githubCache', 'repoCache']);
1536+
triggerRepoFetchIfEnabled();
1537+
})
1538+
return;
1539+
}
1540+
console.log('[Org Check] Checking organization:', org);
1541+
fetch(`https://api.github.com/orgs/${org}`)
1542+
.then(res => {
1543+
console.log('[Org Check] Response status for', org, ':', res.status);
1544+
if (res.status === 404) {
1545+
console.log('[Org Check] Organization not found on GitHub:', org);
1546+
const oldToast = document.getElementById('invalid-org-toast');
1547+
if (oldToast) oldToast.parentNode.removeChild(oldToast);
1548+
const toastDiv = document.createElement('div');
1549+
toastDiv.id = 'invalid-org-toast';
1550+
toastDiv.className = 'toast';
1551+
toastDiv.style.background = '#dc2626';
1552+
toastDiv.style.color = '#fff';
1553+
toastDiv.style.fontWeight = 'bold';
1554+
toastDiv.style.padding = '12px 24px';
1555+
toastDiv.style.borderRadius = '8px';
1556+
toastDiv.style.position = 'fixed';
1557+
toastDiv.style.top = '24px';
1558+
toastDiv.style.left = '50%';
1559+
toastDiv.style.transform = 'translateX(-50%)';
1560+
toastDiv.style.zIndex = '9999';
1561+
toastDiv.innerText = chrome.i18n.getMessage('orgNotFoundMessage');
1562+
document.body.appendChild(toastDiv);
1563+
setTimeout(() => {
1564+
if (toastDiv.parentNode) toastDiv.parentNode.removeChild(toastDiv);
1565+
}, 3000);
1566+
return;
1567+
}
1568+
const oldToast = document.getElementById('invalid-org-toast');
1569+
if (oldToast) oldToast.parentNode.removeChild(oldToast);
1570+
console.log('[Org Check] Organisation exists on GitHub:', org);
1571+
chrome.storage.local.set({ orgName: org }, function () {
1572+
// if (window.generateScrumReport) window.generateScrumReport();
1573+
triggerRepoFetchIfEnabled();
1574+
});
1575+
})
1576+
.catch((err) => {
1577+
console.log('[Org Check] Error validating organisation:', org, err);
1578+
const oldToast = document.getElementById('invalid-org-toast');
1579+
if (oldToast) oldToast.parentNode.removeChild(oldToast);
1580+
const toastDiv = document.createElement('div');
1581+
toastDiv.id = 'invalid-org-toast';
1582+
toastDiv.className = 'toast';
1583+
toastDiv.style.background = '#dc2626';
1584+
toastDiv.style.color = '#fff';
1585+
toastDiv.style.fontWeight = 'bold';
1586+
toastDiv.style.padding = '12px 24px';
1587+
toastDiv.style.borderRadius = '8px';
1588+
toastDiv.style.position = 'fixed';
1589+
toastDiv.style.top = '24px';
1590+
toastDiv.style.left = '50%';
1591+
toastDiv.style.transform = 'translateX(-50%)';
1592+
toastDiv.style.zIndex = '9999';
1593+
toastDiv.innerText = chrome.i18n.getMessage('orgValidationErrorMessage');
1594+
document.body.appendChild(toastDiv);
1595+
setTimeout(() => {
1596+
if (toastDiv.parentNode) toastDiv.parentNode.removeChild(toastDiv);
1597+
}, 3000);
1598+
});
1599+
}, 500);
1600+
1601+
orgInput.addEventListener('input', handleOrgInput);

0 commit comments

Comments
 (0)