Files
365devnet/src/pages/[lang]/development.astro
Richard Bergsma 9fd25138e4 Refactor commit fetching in development.astro to implement caching for improved performance
- Introduce a caching mechanism for Gitea commits to reduce API calls across language builds.
- Update the commit fetching logic to handle errors more gracefully and ensure consistent data retrieval.
2025-06-06 23:57:17 +02:00

141 lines
6.0 KiB
Plaintext

---
export const prerender = true;
import Layout from '../../layouts/PageLayout.astro';
import { getPermalink } from '../../utils/permalinks';
import { getTranslation } from '../../i18n/translations';
import React, { useMemo } from 'react';
import dynamic from 'astro/dynamic';
import ContributionCalendar from '../../components/ContributionCalendar.jsx';
import CollapsibleIntro from '../../components/CollapsibleIntro.jsx';
const metadata = {
title: 'Development Progress | 365DevNet',
description: 'See the latest development activity, code contributions, and commit history for the 365DevNet project.',
};
const lang = Astro.params.lang || 'en';
const t = getTranslation(lang);
// Cache Gitea commits across all language builds
let cachedCommits = null;
async function getCachedCommits() {
if (cachedCommits) return cachedCommits;
const GITEA_COMMITS_URL = 'https://git.365devnet.eu/api/v1/repos/365DevNet/365devnet/commits?sha=main&stat=true&verification=true&files=true';
let commits = [];
try {
const headers = { accept: 'application/json' };
if (import.meta.env.GITEA_TOKEN) {
headers['Authorization'] = `token ${import.meta.env.GITEA_TOKEN}`;
}
const commitsResponse = await fetch(GITEA_COMMITS_URL, { headers });
if (commitsResponse.ok) {
commits = await commitsResponse.json();
}
} catch (error) {
console.error('Error fetching commits:', error);
}
cachedCommits = commits;
return commits;
}
// Fetch Git repository data at build time (cached)
const commits = await getCachedCommits();
// Format date to a readable format
const formatDate = (dateString: string) => {
const date = new Date(dateString);
const day = date.toLocaleString(lang, { day: '2-digit' });
const month = date.toLocaleString(lang, { month: 'short' }).toLowerCase().replace('.', '');
const year = date.getFullYear();
return `${day}-${month}-${year}`;
};
// Helper: Group commits by date (YYYY-MM-DD)
function getContributionData(commits) {
const contributions = {};
for (const commit of commits) {
const date = commit.commit?.author?.date?.slice(0, 10);
if (date) {
contributions[date] = (contributions[date] || 0) + 1;
}
}
return contributions;
}
const contributionData = getContributionData(commits);
export async function getStaticPaths() {
return [
{ params: { lang: 'en' } },
{ params: { lang: 'nl' } },
{ params: { lang: 'de' } },
{ params: { lang: 'fr' } },
];
}
---
<Layout metadata={metadata}>
<div class="max-w-4xl mx-auto px-4 py-8">
<h1 class="text-4xl font-bold mb-4">{t.development.title || 'Development Progress'}</h1>
{/* Collapsible Intro */}
<CollapsibleIntro text={t.development.intro} client:only="react" />
{/* Contribution Calendar */}
<div class="mb-8">
<ContributionCalendar data={contributionData} client:only="react" />
</div>
<div class="space-y-8">
<section>
<h2 class="text-2xl font-semibold mb-4">{t.development.latestCommits || 'Latest Commits'}</h2>
{Array.isArray(commits) && commits.length > 0 ? (
<div class="space-y-4">
{commits.slice(0, 10).map((commit) => (
<div class="bg-gray-50 dark:bg-gray-800 p-4 rounded-lg flex flex-col md:flex-row md:items-stretch md:gap-8">
<div class="flex-1">
<h3 class="font-medium">{commit.commit?.message?.split('\n')[0] || 'No message'}</h3>
{/* Format commit description with bullet points on new lines */}
{commit.commit?.message ? (
(() => {
const lines = commit.commit.message.split('\n');
const bullets = lines.filter(line => line.trim().startsWith('- '));
if (bullets.length > 0) {
// Render as a list if there are bullet points
return (
<ul class="text-sm text-gray-600 dark:text-gray-400 list-disc ml-5">
{lines.map((line, idx) =>
line.trim().startsWith('- ')
? <li key={idx}>{line.trim().slice(2)}</li>
: line.trim() !== '' && <li key={idx} class="list-none pl-0">{line}</li>
)}
</ul>
);
} else {
// Render as a paragraph if no bullet points
return <p class="text-sm text-gray-600 dark:text-gray-400">{commit.commit.message}</p>;
}
})()
) : null}
</div>
<div class="flex flex-col items-end min-w-[140px] bg-gray-100 dark:bg-gray-700 rounded-lg px-4 py-2 mt-4 md:mt-0 md:ml-8 shadow-sm border border-gray-200 dark:border-gray-600">
<span class="text-base font-semibold text-gray-800 dark:text-gray-200 mb-1">{commit.commit?.author?.date ? formatDate(commit.commit.author.date) : ''}</span>
{commit.commit?.author?.name && (
<span class="text-xs text-gray-500 dark:text-gray-400 mb-2">{commit.commit.author.name}</span>
)}
{commit.sha && (
<a href={commit.html_url} target="_blank" rel="noopener" class="block mt-1 text-right">
<span class="text-xs text-gray-500 dark:text-gray-300 block">Commit:</span>
<code class="mt-1 px-2 py-1 rounded bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 font-mono text-xs text-blue-700 dark:text-blue-300 hover:bg-blue-50 dark:hover:bg-gray-900 transition-colors cursor-pointer block">
{commit.sha.slice(0, 7)}
</code>
</a>
)}
</div>
</div>
))}
</div>
) : (
<p class="text-gray-600 dark:text-gray-400">Unable to fetch commit history at this time.</p>
)}
</section>
</div>
</div>
</Layout>