- Gitea-Release-Webhook: Releases werden archiviert (releases-Tabelle) und neue 'published'-Releases als oranges 🚀-Embed mit Buttons angekündigt - Release-Kanal auf der Setup-Seite wählbar (leer = Feature aus) + Test-Button - /changelog: öffentliche Seite mit Tag-Chips, Pre-Release-Badge, Release-Notes - /api/releases öffentlich; Updates/Redeliveries posten nicht doppelt Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
77 lines
3.4 KiB
React
77 lines
3.4 KiB
React
import { useEffect, useState } from 'react';
|
|
import { apiGet } from '../api.js';
|
|
import { Markdown } from '../markdown.jsx';
|
|
|
|
const dateFmt = new Intl.DateTimeFormat('de-DE', {
|
|
day: '2-digit', month: 'long', year: 'numeric',
|
|
});
|
|
|
|
export default function Changelog() {
|
|
const [data, setData] = useState(null);
|
|
const [page, setPage] = useState(1);
|
|
const [error, setError] = useState(false);
|
|
|
|
useEffect(() => {
|
|
setError(false);
|
|
apiGet(`/api/releases?page=${page}`).then(setData).catch(() => setError(true));
|
|
window.scrollTo(0, 0);
|
|
}, [page]);
|
|
|
|
const pages = data ? Math.ceil(data.total / data.pageSize) : 0;
|
|
|
|
return (
|
|
<>
|
|
<section className="page-header">
|
|
<div className="page-bg-text">CHANGELOG</div>
|
|
<div className="page-header-grid" aria-hidden="true" />
|
|
<div className="page-header-content">
|
|
<div className="page-tag">// Releases</div>
|
|
<h1 className="page-title">Changelog</h1>
|
|
<p className="page-subtitle">Alle Versionen und Release-Notes.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<section className="content">
|
|
{error && <p className="notice">Changelog konnte nicht geladen werden.</p>}
|
|
{!error && !data && <p className="notice">Lade …</p>}
|
|
{data?.total === 0 && <p className="notice">Noch keine Releases veröffentlicht.</p>}
|
|
|
|
{data?.total > 0 &&
|
|
data.items.map((r) => (
|
|
<article className="card release-card" key={`${r.repo}/${r.tag}`}>
|
|
<div className="card-meta">
|
|
<span className="release-tag">{r.tag}</span>
|
|
{r.prerelease ? <span className="chip chip-branch">Pre-Release</span> : null}
|
|
<span className="chip chip-repo">{r.repo.split('/').pop()}</span>
|
|
<span className="card-rel">{dateFmt.format(new Date(r.published_at))}</span>
|
|
</div>
|
|
{r.name && r.name !== r.tag && <h3 className="release-name">{r.name}</h3>}
|
|
<div className="card-body">
|
|
<Markdown text={r.body || '*Keine Release-Notes.*'} />
|
|
</div>
|
|
{r.url && (
|
|
<div className="card-footer">
|
|
<a href={r.url} target="_blank" rel="noreferrer">Release in Gitea ansehen →</a>
|
|
</div>
|
|
)}
|
|
</article>
|
|
))}
|
|
|
|
{pages > 1 && (
|
|
<div className="pager">
|
|
<button className="btn" disabled={page <= 1} onClick={() => setPage(page - 1)}>
|
|
← Neuere
|
|
</button>
|
|
<span className="pager-info">
|
|
{String(page).padStart(2, '0')} / {String(pages).padStart(2, '0')}
|
|
</span>
|
|
<button className="btn" disabled={page >= pages} onClick={() => setPage(page + 1)}>
|
|
Ältere →
|
|
</button>
|
|
</div>
|
|
)}
|
|
</section>
|
|
</>
|
|
);
|
|
}
|