diff --git a/backend/src/tools/snippets/routes.js b/backend/src/tools/snippets/routes.js index 7e5b5f5..8897a4c 100644 --- a/backend/src/tools/snippets/routes.js +++ b/backend/src/tools/snippets/routes.js @@ -98,6 +98,13 @@ router.put('/:id', authenticate, (req, res) => { }); // ── Löschen ────────────────────────────────────────────────────────────────── +router.delete('/:id/history/:hid', authenticate, (req, res) => { + const s = db.prepare('SELECT * FROM snippets WHERE id=? AND user_id=?').get(req.params.id, uid(req)); + if (!s) return res.status(403).json({ error: 'Kein Zugriff' }); + db.prepare('DELETE FROM snippet_history WHERE id=? AND snippet_id=?').run(req.params.hid, s.id); + res.json({ ok: true }); +}); + router.delete('/:id', authenticate, (req, res) => { const r = db.prepare('DELETE FROM snippets WHERE id=? AND user_id=?').run(req.params.id, uid(req)); if (!r.changes) return res.status(404).json({ error: 'Nicht gefunden' }); diff --git a/frontend/src/tools/codeschnipsel.jsx b/frontend/src/tools/codeschnipsel.jsx index 94f5a73..99c7801 100644 --- a/frontend/src/tools/codeschnipsel.jsx +++ b/frontend/src/tools/codeschnipsel.jsx @@ -140,66 +140,124 @@ function DiffView({ oldCode, newCode }) { } function HistoryModal({ snippet, onClose, onRestore, toast }) { const [history, setHistory] = useState([]); - const [selected, setSelected] = useState(null); + const [selectedIdx, setSelectedIdx] = useState(0); // 0 = Aktuell (current) const [showDiff, setShowDiff] = useState(true); - useEffect(()=>{ - api(`/tools/snippets/${snippet.id}/history`).then(h=>{ setHistory(h); if(h.length) setSelected(h[0]); }).catch(()=>{}); - },[]); const isMob = window.innerWidth < 768; - const getOlderCode = (h) => { - const idx = history.indexOf(h); - // Newest history entry (idx=0) compares against CURRENT snippet code - if (idx === 0) return snippet.code; - // Older entries compare against the next newer history entry - return history[idx - 1].code; + + const load = () => api(`/tools/snippets/${snippet.id}/history`).then(setHistory).catch(()=>{}); + useEffect(()=>{ load(); },[]); + + // Entries: [current, ...history] where index 0 = current + // entries[i].code, entries[i].label + const entries = [ + { id:'current', code: snippet.code, language: snippet.language, + saved_at: snippet.updated_at, label:'Aktuell', isCurrent: true }, + ...history.map((h,i) => ({ ...h, label:`v${history.length - i}`, isCurrent: false })), + ]; + + const selected = entries[selectedIdx]; + // Diff: what changed FROM previous version TO selected (selected is newer) + const prevEntry = entries[selectedIdx + 1]; // one step older + const oldCode = prevEntry?.code ?? null; // null = älteste, kein Diff + + const delHistory = async (hid) => { + try { + await api(`/tools/snippets/${snippet.id}/history/${hid}`, { method:'DELETE' }); + await load(); + // If deleted entry was selected, jump to current + setSelectedIdx(0); + toast('Version gelöscht'); + } catch(e) { toast(e.message,'error'); } }; + return (
e.target===e.currentTarget&&onClose()}>
+ + {/* Header */}
-
📜 Versionshistorie
+
+ 📜 Versionshistorie · {snippet.title} +
- +
- {history.length===0 ? ( -
Keine älteren Versionen vorhanden.
+ + {entries.length <= 1 ? ( +
+ Keine älteren Versionen vorhanden. +
) : (
-
- {history.map((h,i)=>( - + + {/* Versions-Liste */} +
+ {entries.map((e,i) => ( +
+ + {/* Löschen nur für Altversionen, nicht Aktuell */} + {!e.isCurrent && !snippet.is_shared && ( + + )} +
))}
+ + {/* Detail */}
{selected && ( <>
- - {getLangLabel(selected.language)} · {fmtDt(selected.saved_at)} - {history.indexOf(selected) === history.length-1 && (älteste Version)} - - {!snippet.is_shared && selected.code !== snippet.code && ( +
+ + {getLangLabel(selected.language)} · {fmtDt(selected.saved_at)} + + {showDiff && oldCode===null && ( + älteste Version – kein Diff verfügbar + )} + {showDiff && oldCode!==null && prevEntry && ( + + Änderungen gegenüber {prevEntry.label} + + )} +
+ {/* Wiederherstellen nur für Altversionen die vom aktuellen abweichen */} + {!selected.isCurrent && !snippet.is_shared && selected.code !== snippet.code && ( )}
- {showDiff - ? - :
+
+                  {showDiff && oldCode!==null
+                    ? 
+                    : 
                         {selected.code}
                       
}