feat: replace eager in-memory GitHub commit fetching with on-demand retrieval and add a fallback UI for missing commits.
This commit is contained in:
@@ -733,6 +733,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="git-commits-fallback-container" class="hidden p-4 bg-slate-50 border border-slate-200/60 rounded-2xl text-xs space-y-3">
|
||||||
|
<div class="flex justify-between items-center pb-2 border-b border-slate-200">
|
||||||
|
<span class="font-extrabold text-slate-700 flex items-center gap-1.5">
|
||||||
|
<i class="uil uil-info-circle text-blue-600 text-sm"></i>
|
||||||
|
<span>Seçilen güne ait otomatik commit bulunamadı. Son 10 commit'iniz:</span>
|
||||||
|
</span>
|
||||||
|
<button type="button" onclick="hideFallbackCommits()" class="text-slate-400 hover:text-slate-600 font-extrabold">Kapat</button>
|
||||||
|
</div>
|
||||||
|
<div id="git-commits-fallback-list" class="space-y-2 max-h-[150px] overflow-y-auto pr-1 no-scrollbar">
|
||||||
|
<!-- items dynamically populated -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<div id="save-status" class="text-xs font-semibold text-slate-400"></div>
|
<div id="save-status" class="text-xs font-semibold text-slate-400"></div>
|
||||||
<button type="button" id="save-btn" onclick="saveActiveDay()" class="px-5 py-2.5 bg-blue-600 hover:bg-blue-700 text-white font-bold rounded-xl text-xs transition-all shadow-md shadow-blue-500/10">
|
<button type="button" id="save-btn" onclick="saveActiveDay()" class="px-5 py-2.5 bg-blue-600 hover:bg-blue-700 text-white font-bold rounded-xl text-xs transition-all shadow-md shadow-blue-500/10">
|
||||||
@@ -855,56 +868,55 @@
|
|||||||
// Handle initial state of date logic
|
// Handle initial state of date logic
|
||||||
calculateEndDateFrontend();
|
calculateEndDateFrontend();
|
||||||
|
|
||||||
// Fetch Github commits in memory if repo is set
|
|
||||||
fetchAllCommitsInMemory();
|
|
||||||
|
|
||||||
// Select first day of the notebook workspace on load
|
// Select first day of the notebook workspace on load
|
||||||
selectNotebookDay(0);
|
selectNotebookDay(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
const githubRepoUrl = @json($intern->github_repo);
|
const githubRepoUrl = @json($intern->github_repo);
|
||||||
let allGithubCommits = {};
|
|
||||||
let activeDayIdx = 0;
|
let activeDayIdx = 0;
|
||||||
|
|
||||||
function fetchAllCommitsInMemory() {
|
function hideFallbackCommits() {
|
||||||
if (!githubRepoUrl) return;
|
const container = document.getElementById('git-commits-fallback-container');
|
||||||
|
if (container) {
|
||||||
|
container.classList.add('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let repoClean = githubRepoUrl.replace(/https?:\/\/(www\.)?github\.com\//i, '');
|
function formatDateToIstanbul(d) {
|
||||||
repoClean = repoClean.replace(/\/$/, '');
|
try {
|
||||||
const parts = repoClean.split('/');
|
const formatter = new Intl.DateTimeFormat('en-US', {
|
||||||
if (parts.length < 2) return;
|
timeZone: 'Europe/Istanbul',
|
||||||
|
year: 'numeric',
|
||||||
const owner = parts[0];
|
month: '2-digit',
|
||||||
const repo = parts[1].replace(/\.git$/i, '');
|
day: '2-digit'
|
||||||
|
|
||||||
fetch(`https://api.github.com/repos/${owner}/${repo}/commits?per_page=100`)
|
|
||||||
.then(response => {
|
|
||||||
if (!response.ok) throw new Error('API Error');
|
|
||||||
return response.json();
|
|
||||||
})
|
|
||||||
.then(commits => {
|
|
||||||
if (!Array.isArray(commits)) return;
|
|
||||||
commits.forEach(item => {
|
|
||||||
const dateStr = item.commit.author.date;
|
|
||||||
if (dateStr) {
|
|
||||||
const d = new Date(dateStr);
|
|
||||||
const formatter = new Intl.DateTimeFormat('fr-CA', {
|
|
||||||
timeZone: 'Europe/Istanbul',
|
|
||||||
year: 'numeric',
|
|
||||||
month: '2-digit',
|
|
||||||
day: '2-digit'
|
|
||||||
});
|
|
||||||
const dateOnly = formatter.format(d);
|
|
||||||
if (!allGithubCommits[dateOnly]) {
|
|
||||||
allGithubCommits[dateOnly] = [];
|
|
||||||
}
|
|
||||||
allGithubCommits[dateOnly].push(item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.warn('Commits could not be pre-loaded in memory.', err);
|
|
||||||
});
|
});
|
||||||
|
const parts = formatter.formatToParts(d);
|
||||||
|
const year = parts.find(p => p.type === 'year').value;
|
||||||
|
const month = parts.find(p => p.type === 'month').value;
|
||||||
|
const day = parts.find(p => p.type === 'day').value;
|
||||||
|
return `${year}-${month}-${day}`;
|
||||||
|
} catch (e) {
|
||||||
|
return d.toISOString().split('T')[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendCommitToQuill(sha, time, msg) {
|
||||||
|
const escapedMsg = msg.replace(/</g, "<").replace(/>/g, ">");
|
||||||
|
const commitHtml = `<li><strong>[${time}]</strong> (<em>${sha}</em>) ${escapedMsg}</li>`;
|
||||||
|
|
||||||
|
const currentHtml = quill.root.innerHTML.trim();
|
||||||
|
const hasHeader = currentHtml.includes("Git Commit Mesajları:");
|
||||||
|
const headerHtml = hasHeader ? "" : "<p><strong>Git Commit Mesajları:</strong></p>";
|
||||||
|
|
||||||
|
let newHtml = "";
|
||||||
|
if (currentHtml !== "" && currentHtml !== "<p><br></p>") {
|
||||||
|
newHtml = currentHtml + "<br><br>" + headerHtml + "<ul>" + commitHtml + "</ul>";
|
||||||
|
} else {
|
||||||
|
newHtml = headerHtml + "<ul>" + commitHtml + "</ul>";
|
||||||
|
}
|
||||||
|
|
||||||
|
quill.setContents([]);
|
||||||
|
quill.clipboard.dangerouslyPasteHTML(newHtml);
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectNotebookDay(idx) {
|
function selectNotebookDay(idx) {
|
||||||
@@ -938,8 +950,12 @@
|
|||||||
document.getElementById('editor-day-title').textContent = `${dayNum}. Gün`;
|
document.getElementById('editor-day-title').textContent = `${dayNum}. Gün`;
|
||||||
document.getElementById('editor-day-date').textContent = dateFormatted;
|
document.getElementById('editor-day-date').textContent = dateFormatted;
|
||||||
|
|
||||||
quill.root.innerHTML = savedContent || '';
|
quill.setContents([]);
|
||||||
|
if (savedContent) {
|
||||||
|
quill.clipboard.dangerouslyPasteHTML(savedContent);
|
||||||
|
}
|
||||||
document.getElementById('save-status').textContent = '';
|
document.getElementById('save-status').textContent = '';
|
||||||
|
hideFallbackCommits();
|
||||||
|
|
||||||
// Future validation
|
// Future validation
|
||||||
const dateParts = dateVal.split('-');
|
const dateParts = dateVal.split('-');
|
||||||
@@ -979,34 +995,160 @@
|
|||||||
if (!btn) return;
|
if (!btn) return;
|
||||||
|
|
||||||
const dateVal = btn.getAttribute('data-date');
|
const dateVal = btn.getAttribute('data-date');
|
||||||
const dayCommits = allGithubCommits[dateVal] || [];
|
const formattedDate = btn.getAttribute('data-formatted-date');
|
||||||
|
|
||||||
if (dayCommits.length === 0) {
|
if (!githubRepoUrl) {
|
||||||
alert("Bu staj gününe ait GitHub commit'i bulunamadı. Lütfen commit attığınızdan ve tarihin doğru olduğundan emin olun.");
|
alert("Lütfen önce GitHub depo URL'nizi kaydedin.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let commitHtml = "<ul>";
|
let repoClean = githubRepoUrl.replace(/https?:\/\/(www\.)?github\.com\//i, '');
|
||||||
const sorted = [...dayCommits].reverse();
|
repoClean = repoClean.replace(/\/$/, '');
|
||||||
sorted.forEach(c => {
|
const parts = repoClean.split('/');
|
||||||
const msg = c.commit.message;
|
if (parts.length < 2) {
|
||||||
const sha = c.sha.substring(0, 7);
|
alert("Geçersiz GitHub URL'si.");
|
||||||
const authorDate = new Date(c.commit.author.date);
|
return;
|
||||||
const time = authorDate.toLocaleTimeString('tr-TR', { timeZone: 'Europe/Istanbul', hour: '2-digit', minute: '2-digit' });
|
|
||||||
commitHtml += `<li><strong>[${time}]</strong> (<em>${sha}</em>) ${msg}</li>`;
|
|
||||||
});
|
|
||||||
commitHtml += "</ul>";
|
|
||||||
|
|
||||||
const currentHtml = quill.root.innerHTML.trim();
|
|
||||||
if (currentHtml !== "" && currentHtml !== "<p><br></p>") {
|
|
||||||
if (confirm("Mevcut rapor içeriğinizin sonuna bu günün commitlerini eklemek ister misiniz? (Hayır derseniz mevcut içerik silinip commitler yazılır.)")) {
|
|
||||||
quill.root.innerHTML = currentHtml + "<br><br>" + commitHtml;
|
|
||||||
} else {
|
|
||||||
quill.root.innerHTML = commitHtml;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
quill.root.innerHTML = commitHtml;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const owner = parts[0];
|
||||||
|
const repo = parts[1].replace(/\.git$/i, '');
|
||||||
|
let branch = '';
|
||||||
|
|
||||||
|
// Parse branch if /tree/{branch} or /commits/{branch} is used
|
||||||
|
if (parts.length >= 4 && (parts[2] === 'tree' || parts[2] === 'commits')) {
|
||||||
|
branch = parts.slice(3).join('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
const gitBtn = document.querySelector('button[onclick="fillFromGithub()"]');
|
||||||
|
const originalContent = gitBtn.innerHTML;
|
||||||
|
gitBtn.disabled = true;
|
||||||
|
gitBtn.innerHTML = `<i class="uil uil-spinner text-xs animate-spin"></i> <span>Çekiliyor...</span>`;
|
||||||
|
|
||||||
|
hideFallbackCommits();
|
||||||
|
|
||||||
|
fetch(`https://api.github.com/repos/${owner}/${repo}/commits?per_page=100${branch ? `&sha=${branch}` : ''}`)
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
if (response.status === 404) {
|
||||||
|
throw new Error("Depo bulunamadı veya herkese açık (public) değil.");
|
||||||
|
} else if (response.status === 403) {
|
||||||
|
throw new Error("GitHub API istek limitine ulaşıldı. Lütfen daha sonra tekrar deneyin.");
|
||||||
|
} else {
|
||||||
|
throw new Error(`GitHub API Hatası (Kod: ${response.status})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(commits => {
|
||||||
|
if (!Array.isArray(commits)) {
|
||||||
|
throw new Error("Geçersiz API yanıtı.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter commits by the selected date
|
||||||
|
const dayCommits = commits.filter(item => {
|
||||||
|
const dateStr = item.commit.author.date;
|
||||||
|
if (!dateStr) return false;
|
||||||
|
const d = new Date(dateStr);
|
||||||
|
const dateOnly = formatDateToIstanbul(d);
|
||||||
|
return dateOnly === dateVal;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (dayCommits.length === 0) {
|
||||||
|
// No commits found for this date. Show fallback list of latest 10 commits.
|
||||||
|
const fallbackContainer = document.getElementById('git-commits-fallback-container');
|
||||||
|
const fallbackList = document.getElementById('git-commits-fallback-list');
|
||||||
|
|
||||||
|
if (fallbackContainer && fallbackList) {
|
||||||
|
fallbackList.innerHTML = '';
|
||||||
|
|
||||||
|
const latestCommits = commits.slice(0, 10);
|
||||||
|
if (latestCommits.length === 0) {
|
||||||
|
fallbackList.innerHTML = `<p class="text-slate-400 italic">Depoda hiç commit bulunamadı.</p>`;
|
||||||
|
} else {
|
||||||
|
latestCommits.forEach(c => {
|
||||||
|
const msg = c.commit.message;
|
||||||
|
const sha = c.sha.substring(0, 7);
|
||||||
|
const authorDate = new Date(c.commit.author.date);
|
||||||
|
const time = authorDate.toLocaleTimeString('tr-TR', { timeZone: 'Europe/Istanbul', hour: '2-digit', minute: '2-digit' });
|
||||||
|
const commitDateOnly = formatDateToIstanbul(authorDate);
|
||||||
|
// format date to d.m.Y
|
||||||
|
const [cy, cm, cd] = commitDateOnly.split('-');
|
||||||
|
const formattedCommitDate = `${cd}.${cm}.${cy}`;
|
||||||
|
|
||||||
|
const row = document.createElement('div');
|
||||||
|
row.className = "flex items-center justify-between gap-3 p-2 hover:bg-slate-100 rounded-lg border border-slate-100 transition-colors";
|
||||||
|
|
||||||
|
const infoDiv = document.createElement('div');
|
||||||
|
infoDiv.className = "flex-grow min-w-0";
|
||||||
|
|
||||||
|
const timeSpan = document.createElement('span');
|
||||||
|
timeSpan.className = "font-bold text-slate-700 select-all";
|
||||||
|
timeSpan.textContent = `[${formattedCommitDate} ${time}] `;
|
||||||
|
|
||||||
|
const shaSpan = document.createElement('span');
|
||||||
|
shaSpan.className = "text-slate-500 font-semibold select-all";
|
||||||
|
shaSpan.textContent = `(${sha}) `;
|
||||||
|
|
||||||
|
const msgSpan = document.createElement('span');
|
||||||
|
msgSpan.className = "text-slate-600 truncate block sm:inline-block max-w-full font-medium ml-1";
|
||||||
|
msgSpan.textContent = msg;
|
||||||
|
|
||||||
|
infoDiv.appendChild(timeSpan);
|
||||||
|
infoDiv.appendChild(shaSpan);
|
||||||
|
infoDiv.appendChild(msgSpan);
|
||||||
|
|
||||||
|
const addBtn = document.createElement('button');
|
||||||
|
addBtn.type = 'button';
|
||||||
|
addBtn.className = "px-2 py-1 bg-blue-50 text-blue-600 hover:bg-blue-600 hover:text-white font-extrabold rounded transition-all flex-shrink-0 text-[10px]";
|
||||||
|
addBtn.textContent = "Ekle";
|
||||||
|
addBtn.addEventListener('click', () => {
|
||||||
|
appendCommitToQuill(sha, `${formattedCommitDate} ${time}`, msg);
|
||||||
|
});
|
||||||
|
|
||||||
|
row.appendChild(infoDiv);
|
||||||
|
row.appendChild(addBtn);
|
||||||
|
fallbackList.appendChild(row);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fallbackContainer.classList.remove('hidden');
|
||||||
|
alert(`Bu staj gününe (${formattedDate}) ait otomatik GitHub commit'i bulunamadı. Son 10 commit'iniz aşağıda listelenmiştir, rapora eklemek istediklerinizi seçebilirsiniz.`);
|
||||||
|
} else {
|
||||||
|
alert(`Bu staj gününe (${formattedDate}) ait GitHub commit'i bulunamadı. Lütfen commit attığınızdan ve tarihin doğru olduğundan emin olun.`);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let commitHtml = "<ul>";
|
||||||
|
const sorted = [...dayCommits].reverse();
|
||||||
|
sorted.forEach(c => {
|
||||||
|
const msg = c.commit.message;
|
||||||
|
const sha = c.sha.substring(0, 7);
|
||||||
|
const authorDate = new Date(c.commit.author.date);
|
||||||
|
const time = authorDate.toLocaleTimeString('tr-TR', { timeZone: 'Europe/Istanbul', hour: '2-digit', minute: '2-digit' });
|
||||||
|
commitHtml += `<li><strong>[${time}]</strong> (<em>${sha}</em>) ${msg}</li>`;
|
||||||
|
});
|
||||||
|
commitHtml += "</ul>";
|
||||||
|
|
||||||
|
const currentHtml = quill.root.innerHTML.trim();
|
||||||
|
const headerHtml = "<p><strong>Git Commit Mesajları:</strong></p>";
|
||||||
|
|
||||||
|
let newHtml = "";
|
||||||
|
if (currentHtml !== "" && currentHtml !== "<p><br></p>") {
|
||||||
|
newHtml = currentHtml + "<br><br>" + headerHtml + commitHtml;
|
||||||
|
} else {
|
||||||
|
newHtml = headerHtml + commitHtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
quill.setContents([]);
|
||||||
|
quill.clipboard.dangerouslyPasteHTML(newHtml);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
alert("Commitler çekilirken hata oluştu: " + err.message);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
gitBtn.disabled = false;
|
||||||
|
gitBtn.innerHTML = originalContent;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveActiveDay() {
|
function saveActiveDay() {
|
||||||
|
|||||||
Reference in New Issue
Block a user