Devlog-Löschung: Discord-Delete-Sync + Admin-Button im Webinterface
- MessageDelete-Listener (mit Partials): in Discord gelöschte Devlogs verschwinden automatisch aus dem Archiv, inkl. lokaler Bilder - DELETE /api/devlogs/:id (nur Admin) + ✕-Button auf den Karten (nur für Admin sichtbar) - Anlass: Test-Post mit Commit-Liste von vor der Prosa-Sperre stand noch im Archiv Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -89,7 +89,7 @@ export default function App() {
|
||||
<main className="main">
|
||||
<Routes>
|
||||
<Route path="/" element={<Navigate to="/devlogs" replace />} />
|
||||
<Route path="/devlogs" element={<Devlogs />} />
|
||||
<Route path="/devlogs" element={<Devlogs me={me} />} />
|
||||
<Route path="/commits" element={<Commits me={me} />} />
|
||||
<Route path="*" element={<Navigate to="/devlogs" replace />} />
|
||||
</Routes>
|
||||
|
||||
+5
-2
@@ -1,6 +1,6 @@
|
||||
// Kleiner Fetch-Wrapper — Cookies (Session) laufen automatisch mit (same-origin)
|
||||
export async function apiGet(path) {
|
||||
const res = await fetch(path, { headers: { Accept: 'application/json' } });
|
||||
async function api(path, options = {}) {
|
||||
const res = await fetch(path, { headers: { Accept: 'application/json' }, ...options });
|
||||
if (!res.ok) {
|
||||
const error = new Error(`API ${res.status}`);
|
||||
error.status = res.status;
|
||||
@@ -8,3 +8,6 @@ export async function apiGet(path) {
|
||||
}
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export const apiGet = (path) => api(path);
|
||||
export const apiDelete = (path) => api(path, { method: 'DELETE' });
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { apiGet } from '../api.js';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { apiGet, apiDelete } from '../api.js';
|
||||
import { Markdown } from '../markdown.jsx';
|
||||
|
||||
const dateFmt = new Intl.DateTimeFormat('de-DE', {
|
||||
@@ -40,17 +40,32 @@ function splitContent(raw) {
|
||||
return { project, footer, body: blocks.join('\n\n') };
|
||||
}
|
||||
|
||||
export default function Devlogs() {
|
||||
export default function Devlogs({ me }) {
|
||||
const [data, setData] = useState(null);
|
||||
const [page, setPage] = useState(1);
|
||||
const [error, setError] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const load = useCallback(() => {
|
||||
setError(false);
|
||||
apiGet(`/api/devlogs?page=${page}`).then(setData).catch(() => setError(true));
|
||||
window.scrollTo(0, 0);
|
||||
}, [page]);
|
||||
|
||||
useEffect(() => {
|
||||
load();
|
||||
window.scrollTo(0, 0);
|
||||
}, [load]);
|
||||
|
||||
// Admin: Devlog aus dem Archiv entfernen (löscht auch die lokalen Bilder)
|
||||
async function remove(id) {
|
||||
if (!window.confirm('Dieses Devlog aus dem Archiv löschen?')) return;
|
||||
try {
|
||||
await apiDelete(`/api/devlogs/${id}`);
|
||||
load();
|
||||
} catch {
|
||||
window.alert('Löschen fehlgeschlagen.');
|
||||
}
|
||||
}
|
||||
|
||||
const pages = data ? Math.ceil(data.total / data.pageSize) : 0;
|
||||
|
||||
// Monats-Trenner in der Timeline
|
||||
@@ -92,6 +107,15 @@ export default function Devlogs() {
|
||||
</span>
|
||||
{project && <span className="card-project">{project}</span>}
|
||||
<span className="card-rel">{relative(d.posted_at)}</span>
|
||||
{me?.admin && (
|
||||
<button
|
||||
className="card-delete"
|
||||
title="Aus dem Archiv löschen"
|
||||
onClick={() => remove(d.message_id)}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<Markdown text={body} />
|
||||
|
||||
@@ -246,6 +246,15 @@ body::after {
|
||||
padding: .1rem .5rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.card-delete {
|
||||
font-family: var(--mono);
|
||||
font-size: .7rem;
|
||||
color: var(--muted2);
|
||||
background: none; border: 1px solid transparent;
|
||||
padding: .05rem .4rem;
|
||||
transition: color .2s, border-color .2s;
|
||||
}
|
||||
.card-delete:hover { color: var(--neon2); border-color: rgba(255, 77, 0, .4); }
|
||||
|
||||
.card-body { color: var(--text); font-weight: 300; font-size: 1.08rem; }
|
||||
.card-body p { margin: .55rem 0; }
|
||||
|
||||
Reference in New Issue
Block a user