@@ -3168,26 +3169,119 @@ function selectVersion(id) {
async function restoreVersion() {
if (!selectedVersionId) return;
- if (!confirm('Restaurer cette version ? L\u2019état actuel sera sauvegardé avant la restauration.')) return;
+ const isArchive = versionType === 'archive';
+ const msg = isArchive
+ ? 'Restaurer cette fiche supprimée ? Elle sera recréée dans la frise.'
+ : 'Restaurer cette version ? L\u2019état actuel sera sauvegardé avant la restauration.';
+ if (!confirm(msg)) return;
try {
- const r = await fetch(`/api/versions/${selectedVersionId}/restore`, { method: 'POST' });
- if (r.ok) {
- closeVersionPanel();
- if (versionType === 'frise') {
+ if (isArchive) {
+ // Re-create the card from snapshot
+ const v = versionList.find(x => x.Id === selectedVersionId);
+ if (!v) return;
+ const snap = JSON.parse(v.Snapshot);
+ const { Title, Acte, Ordre, Personnage, Tags, Notes } = snap;
+ const data = { Title, Acte: Acte || 'En attente', Ordre: Ordre || 999, Personnage, Tags, Notes, 'Résumé': snap['Résumé'], 'Intérêt narratif': snap['Intérêt narratif'], Implications: snap.Implications, Origine: snap.Origine, 'Lien rédaction': snap['Lien rédaction'] };
+ const r = await fetch('/api/records', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) });
+ if (r.ok) {
+ closeVersionPanel();
await loadData();
- if (editingId) openEdit(editingId);
- } else if (versionType === 'redaction' && currentSceneId) {
- const scene = records.find(rec => rec.Id === currentSceneId);
- if (scene) openScene(scene);
+ } else {
+ alert('Erreur lors de la restauration');
}
} else {
- alert('Erreur lors de la restauration');
+ const r = await fetch(`/api/versions/${selectedVersionId}/restore`, { method: 'POST' });
+ if (r.ok) {
+ closeVersionPanel();
+ if (versionType === 'frise') {
+ await loadData();
+ if (editingId) openEdit(editingId);
+ } else if (versionType === 'redaction' && currentSceneId) {
+ const scene = records.find(rec => rec.Id === currentSceneId);
+ if (scene) openScene(scene);
+ }
+ } else {
+ alert('Erreur lors de la restauration');
+ }
}
} catch (e) {
alert('Erreur : ' + e.message);
}
}
+// ── Archives (deleted cards) ──
+async function openArchives() {
+ versionType = 'archive';
+ versionRecordId = null;
+ selectedVersionId = null;
+ document.getElementById('version-panel-title').textContent = 'Archives — Fiches supprimées';
+ document.getElementById('version-list').innerHTML = '
Chargement...
';
+ document.getElementById('version-preview').style.display = 'none';
+ document.getElementById('version-actions').style.display = 'none';
+ document.getElementById('version-panel').classList.add('open');
+
+ try {
+ const r = await fetch('/api/archives');
+ const data = await r.json();
+ versionList = data.list || [];
+ renderArchiveList();
+ } catch (e) {
+ document.getElementById('version-list').innerHTML = '
Erreur de chargement
';
+ }
+}
+
+function renderArchiveList() {
+ const container = document.getElementById('version-list');
+ if (versionList.length === 0) {
+ container.innerHTML = '
Aucune fiche supprimée.
';
+ return;
+ }
+ container.innerHTML = '';
+ for (const v of versionList) {
+ const div = document.createElement('div');
+ div.className = 'version-item';
+ div.dataset.id = v.Id;
+ const date = new Date(v.CreatedAt);
+ const dateStr = date.toLocaleDateString('fr-FR', { day: 'numeric', month: 'long', year: 'numeric', hour: '2-digit', minute: '2-digit' });
+ let title = '', preview = '';
+ try {
+ const snap = JSON.parse(v.Snapshot);
+ title = snap.Title || snap.Titre || 'Sans titre';
+ preview = [snap.Acte, snap['Résumé']].filter(Boolean).join(' — ');
+ } catch (e) { title = 'Fiche'; }
+ div.innerHTML = `
${dateStr}
` +
+ `
${title.replace(/` +
+ (preview ? `
${preview.replace(/` : '');
+ div.onclick = () => selectArchive(v.Id);
+ container.appendChild(div);
+ }
+}
+
+function selectArchive(id) {
+ selectedVersionId = id;
+ versionType = 'archive';
+ document.querySelectorAll('.version-item').forEach(el => el.classList.toggle('selected', Number(el.dataset.id) === id));
+ const v = versionList.find(x => x.Id === id);
+ if (!v) return;
+ try {
+ const snap = JSON.parse(v.Snapshot);
+ const content = document.getElementById('version-preview-content');
+ const parts = [];
+ if (snap.Title) parts.push(`${snap.Title.replace(/`);
+ if (snap.Acte) parts.push(`${snap.Acte}`);
+ if (snap.Personnage) parts.push('Personnages : ' + snap.Personnage.replace(/Intérêt : ' + snap['Intérêt narratif'].replace(/Tags : ' + snap.Tags.replace(/');
+ if (snap.Notes) parts.push('Notes : ' + snap.Notes.replace(/');
+ document.getElementById('version-preview').style.display = '';
+ document.getElementById('version-actions').style.display = '';
+ } catch (e) {
+ document.getElementById('version-preview').style.display = 'none';
+ }
+}
+
// Close popup on version panel click outside
document.addEventListener('click', (e) => {
const panel = document.getElementById('version-panel');
diff --git a/server.js b/server.js
index 14a79ea..a11d5d4 100644
--- a/server.js
+++ b/server.js
@@ -385,6 +385,19 @@ app.post('/api/versions/:id/restore', requireAuth, async (req, res) => {
}
});
+// List archived (deleted) frise cards
+app.get('/api/archives', requireAuth, async (req, res) => {
+ if (!NOCODB_VERSIONS_TABLE_ID) return res.json({ list: [] });
+ try {
+ const url = `${NOCODB_URL}/api/v1/db/data/noco/${NOCODB_BASE_ID}/${NOCODB_VERSIONS_TABLE_ID}?where=(Type,eq,frise)~and(Label,like,%25supprimé%25)&sort=-CreatedAt&limit=100`;
+ const r = await fetch(url, { headers: { 'xc-token': NOCODB_TOKEN } });
+ const data = await r.json();
+ res.json(data);
+ } catch (e) {
+ res.status(500).json({ error: e.message });
+ }
+});
+
// ── Personnages API ──
function personnagesProxy(tableIdVar) {