- Changed the title and description in development.astro to reflect the 365DevNet ecosystem. - Updated translation files to include new page title and description for multiple languages. - Renamed '365DevNet' to 'Dev Dashboard' in navigation for better user understanding.
208 lines
9.3 KiB
Plaintext
208 lines
9.3 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: '365DevNet Ecosystem: Development Overview',
|
|
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);
|
|
|
|
// Fetch Gitea user heatmap at build time (cached)
|
|
async function getUserHeatmap(username) {
|
|
const url = `https://git.365devnet.eu/api/v1/users/${username}/heatmap`;
|
|
let heatmap = [];
|
|
try {
|
|
const headers = { accept: 'application/json' };
|
|
if (import.meta.env.GITEA_TOKEN) {
|
|
headers['Authorization'] = `token ${import.meta.env.GITEA_TOKEN}`;
|
|
}
|
|
const response = await fetch(url, { headers });
|
|
if (response.ok) {
|
|
heatmap = await response.json();
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching user heatmap:', error);
|
|
}
|
|
// Aggregate by date
|
|
const contributions = {};
|
|
for (const entry of heatmap) {
|
|
const date = new Date(entry.timestamp * 1000).toISOString().slice(0, 10);
|
|
contributions[date] = (contributions[date] || 0) + entry.contributions;
|
|
}
|
|
return contributions;
|
|
}
|
|
|
|
const contributionData = await getUserHeatmap('Richard');
|
|
|
|
// Fetch latest user commits from activities/feeds
|
|
async function getUserCommits(username) {
|
|
const url = `https://git.365devnet.eu/api/v1/users/${username}/activities/feeds`;
|
|
let feeds = [];
|
|
try {
|
|
const headers = { accept: 'application/json' };
|
|
if (import.meta.env.GITEA_TOKEN) {
|
|
headers['Authorization'] = `token ${import.meta.env.GITEA_TOKEN}`;
|
|
}
|
|
const response = await fetch(url, { headers });
|
|
if (response.ok) {
|
|
feeds = await response.json();
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching user feeds:', error);
|
|
}
|
|
// Only keep commit_repo events
|
|
const commits = [];
|
|
for (const feed of feeds) {
|
|
if (feed.op_type === 'commit_repo' && feed.content) {
|
|
let content;
|
|
try {
|
|
content = JSON.parse(feed.content);
|
|
} catch (e) {
|
|
continue;
|
|
}
|
|
// Each feed may have multiple commits
|
|
if (content.Commits && Array.isArray(content.Commits)) {
|
|
for (const commit of content.Commits) {
|
|
commits.push({
|
|
sha: commit.Sha1,
|
|
message: commit.Message,
|
|
author: commit.AuthorName,
|
|
date: commit.Timestamp,
|
|
repo: feed.repo ? feed.repo.full_name : '',
|
|
repo_url: feed.repo ? feed.repo.html_url : '',
|
|
compare_url: content.CompareURL ? `https://git.365devnet.eu/${content.CompareURL}` : '',
|
|
});
|
|
}
|
|
}
|
|
}
|
|
if (commits.length >= 10) break;
|
|
}
|
|
return commits.slice(0, 10);
|
|
}
|
|
|
|
const userCommits = await getUserCommits('Richard');
|
|
|
|
export async function getStaticPaths() {
|
|
return [
|
|
{ params: { lang: 'en' } },
|
|
{ params: { lang: 'nl' } },
|
|
{ params: { lang: 'de' } },
|
|
{ params: { lang: 'fr' } },
|
|
];
|
|
}
|
|
|
|
// Format date to a readable format
|
|
const formatDate = (dateString) => {
|
|
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}`;
|
|
};
|
|
---
|
|
|
|
<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>
|
|
<p class="text-gray-600 dark:text-gray-400 mb-4">Showing contributions for user <b>Richard</b> (all repositories).</p>
|
|
{Array.isArray(userCommits) && userCommits.length > 0 ? (
|
|
<div class="space-y-4">
|
|
{userCommits.map((commit) => (
|
|
<div class="bg-white/90 dark:bg-slate-900/90 p-6 rounded-2xl shadow-lg hover:shadow-xl transition-shadow duration-200 border border-gray-100 dark:border-slate-800 flex flex-col gap-4 md:flex-row md:items-stretch md:gap-8 mb-6">
|
|
<div class="flex-1">
|
|
<h3 class="font-semibold text-lg md:text-xl text-gray-900 dark:text-white mb-1">{commit.message.split('\n')[0] || 'No message'}</h3>
|
|
{/* Format commit description with bullet points on new lines */}
|
|
{commit.message ? (
|
|
(() => {
|
|
const lines = 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-300 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-300">{commit.message}</p>;
|
|
}
|
|
})()
|
|
) : null}
|
|
</div>
|
|
{/* Desktop commit info card */}
|
|
<div class="hidden md:flex flex-col items-end min-w-[180px] bg-gray-50 dark:bg-slate-800 rounded-xl px-5 py-3 mt-4 md:mt-0 md:ml-8 shadow border border-gray-200 dark:border-gray-700">
|
|
<span class="text-base font-semibold text-gray-800 dark:text-gray-200 mb-1">{commit.date ? formatDate(commit.date) : ''}</span>
|
|
{commit.author && (
|
|
<span class="text-xs text-gray-500 dark:text-gray-400 mb-2">{commit.author === 'becarta' ? 'Richard Bergsma' : commit.author}</span>
|
|
)}
|
|
{commit.repo && (
|
|
<span class="text-xs text-gray-500 dark:text-gray-400 mb-2">
|
|
<a href={commit.repo_url} target="_blank" rel="noopener">{commit.repo}</a>
|
|
</span>
|
|
)}
|
|
{commit.sha && (
|
|
<a href={commit.compare_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="px-3 py-1 rounded-full bg-blue-50 dark:bg-blue-900 border border-blue-200 dark:border-blue-700 font-mono text-xs text-blue-700 dark:text-blue-300 hover:bg-blue-100 dark:hover:bg-blue-800 transition-colors cursor-pointer block">
|
|
{commit.sha.slice(0, 7)}
|
|
</code>
|
|
</a>
|
|
)}
|
|
</div>
|
|
{/* Mobile commit info area, visually separated and two rows with left/right alignment */}
|
|
<div class="md:hidden border-t border-gray-200 dark:border-gray-700 pt-3 px-1 bg-gray-50 dark:bg-slate-800 rounded-b-xl text-xs text-gray-700 dark:text-gray-300">
|
|
<div class="flex flex-row justify-between items-center mb-1">
|
|
<span class="font-semibold">{commit.date ? formatDate(commit.date) : ''}</span>
|
|
{commit.author && (
|
|
<span>{commit.author === 'becarta' ? 'Richard Bergsma' : commit.author}</span>
|
|
)}
|
|
</div>
|
|
<div class="flex flex-row justify-between items-center">
|
|
{commit.repo && (
|
|
<span>
|
|
<a href={commit.repo_url} target="_blank" rel="noopener">{commit.repo}</a>
|
|
</span>
|
|
)}
|
|
{commit.sha && (
|
|
<a href={commit.compare_url} target="_blank" rel="noopener">
|
|
<span class="sr-only">Commit:</span>
|
|
<code class="px-3 py-1 rounded-full bg-blue-50 dark:bg-blue-900 border border-blue-200 dark:border-blue-700 font-mono text-xs text-blue-700 dark:text-blue-300 hover:bg-blue-100 dark:hover:bg-blue-800 transition-colors cursor-pointer">
|
|
{commit.sha.slice(0, 7)}
|
|
</code>
|
|
</a>
|
|
)}
|
|
</div>
|
|
</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> |