Files
siti-plugin-repo/src/pages/PluginDetail.jsx
Roberto Guagliardo 29cd473190 Add repository management functionality with CRUD operations
- Implemented repoService for database interactions including count, list, get, create, update, and delete operations.
- Created RepoManager component for managing repositories with a user interface.
- Added forms for creating and editing repositories, including validation and error handling.
- Integrated API calls for fetching, creating, updating, and deleting repositories.
- Enhanced user experience with loading states and action feedback messages.
2026-02-01 04:30:17 +00:00

160 lines
6.9 KiB
JavaScript

import { useEffect, useMemo, useState } from "react";
import { Link, useParams, useSearchParams } from "react-router-dom";
export default function PluginDetail() {
const { owner, repo } = useParams();
const [searchParams] = useSearchParams();
const provider = (searchParams.get("provider") || "github").toLowerCase();
const baseUrl = searchParams.get("baseUrl") || "";
const repoId = searchParams.get("repoId") || "";
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function loadDetail() {
try {
const query = new URLSearchParams();
if (provider) {
query.set("provider", provider);
}
if (baseUrl) {
query.set("baseUrl", baseUrl);
}
if (repoId) {
query.set("repoId", repoId);
}
const search = query.toString();
const response = await fetch(
`/api/plugins/${owner}/${repo}${search.length > 0 ? `?${search}` : ""}`
);
if (!response.ok) {
throw new Error("Kon details niet laden");
}
const detail = await response.json();
setData(detail);
} catch (err) {
setError("Laden van plugin details is mislukt.");
} finally {
setLoading(false);
}
}
loadDetail();
}, [owner, repo, provider, baseUrl]);
const manifest = data?.manifest;
const displayName = data?.label || manifest?.plugin_name || data?.name || repo;
const description = manifest?.description || data?.description;
const author = manifest?.author || "-";
const version = manifest?.version || "-";
const repositoryLabel = data?.provider === "gitea" ? "Gitea" : "GitHub";
const latestDownload = data?.download;
const releases = useMemo(() => data?.releases || [], [data]);
const commits = useMemo(() => data?.commits || [], [data]);
return (
<div className="page">
<header className="detail-hero">
<div>
<p className="eyebrow">Plugin details</p>
<h1>{displayName}</h1>
<p className="subtitle">{description}</p>
</div>
<div className="detail-actions">
<Link className="ghost" to="/"> Terug</Link>
{data?.repoUrl && (
<a className="ghost" href={data.repoUrl} target="_blank" rel="noreferrer">
{repositoryLabel}
</a>
)}
{latestDownload?.url && (
<a className="cta" href={latestDownload.url} target="_blank" rel="noreferrer">
Download {latestDownload.version}
</a>
)}
</div>
</header>
{loading && <div className="state">Bezig met laden</div>}
{error && <div className="state error">{error}</div>}
{!loading && !error && data && (
<section className="detail-grid">
<div className="card">
<h2>Manifest</h2>
<div className="detail-list">
<div>
<span>Naam</span>
<strong>{displayName}</strong>
</div>
<div>
<span>Versie</span>
<strong>{version}</strong>
</div>
<div>
<span>Auteur</span>
<strong>{author}</strong>
</div>
<div>
<span>Repository</span>
<strong>{data.fullName}</strong>
</div>
</div>
{manifest?.author_url && (
<a className="link" href={manifest.author_url} target="_blank" rel="noreferrer">
Auteur website
</a>
)}
</div>
<div className="card">
<h2>Releases</h2>
{releases.length === 0 && <p>Geen releases gevonden.</p>}
<ul className="list">
{releases.map((release) => {
const key = release.tag || release.name || release.url;
return (
<li key={key}>
<div>
<a href={release.url} target="_blank" rel="noreferrer">
{release.name}
</a>
<span>
{release.publishedAt
? new Date(release.publishedAt).toLocaleDateString("nl-NL")
: "-"}
</span>
</div>
{release.downloadUrl && (
<a className="ghost" href={release.downloadUrl} target="_blank" rel="noreferrer">
Download
</a>
)}
</li>
);
})}
</ul>
</div>
<div className="card">
<h2>Recente commits</h2>
{commits.length === 0 && <p>Geen commits gevonden.</p>}
<ul className="list">
{commits.map((commit) => (
<li key={commit.sha}>
<a href={commit.url} target="_blank" rel="noreferrer">
{commit.message?.split("\n")[0] || commit.sha.slice(0, 7)}
</a>
<span>{commit.author || "-"}</span>
</li>
))}
</ul>
</div>
</section>
)}
</div>
);
}