we do a little exporting
This commit is contained in:
@@ -2,9 +2,13 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from flask import Blueprint, flash, redirect, render_template, url_for
|
||||
import json
|
||||
|
||||
from flask import Blueprint, flash, redirect, render_template, request, url_for
|
||||
from flask import Response
|
||||
|
||||
from physcom.seed.transport_example import load_transport_seed
|
||||
from physcom.snapshot import export_snapshot, import_snapshot
|
||||
from physcom_web.app import get_repo
|
||||
|
||||
bp = Blueprint("admin", __name__, url_prefix="/admin")
|
||||
@@ -38,14 +42,50 @@ def reseed():
|
||||
return redirect(url_for("admin.admin_index"))
|
||||
|
||||
|
||||
@bp.route("/wipe-and-reseed", methods=["POST"])
|
||||
def wipe_and_reseed():
|
||||
@bp.route("/wipe", methods=["POST"])
|
||||
def wipe():
|
||||
repo = get_repo()
|
||||
repo.clear_all()
|
||||
counts = load_transport_seed(repo)
|
||||
total = counts["platforms"] + counts["actuators"] + counts["energy_storages"]
|
||||
flash("Wiped all data.", "success")
|
||||
return redirect(url_for("admin.admin_index"))
|
||||
|
||||
|
||||
@bp.route("/snapshot/export")
|
||||
def snapshot_export():
|
||||
repo = get_repo()
|
||||
data = export_snapshot(repo)
|
||||
body = json.dumps(data, indent=2)
|
||||
return Response(
|
||||
body,
|
||||
mimetype="application/json",
|
||||
headers={"Content-Disposition": "attachment; filename=physcom_snapshot.json"},
|
||||
)
|
||||
|
||||
|
||||
@bp.route("/snapshot/import", methods=["POST"])
|
||||
def snapshot_import():
|
||||
repo = get_repo()
|
||||
clear = "clear" in request.form
|
||||
|
||||
file = request.files.get("file")
|
||||
if not file or not file.filename:
|
||||
flash("No file selected.", "error")
|
||||
return redirect(url_for("admin.admin_index"))
|
||||
|
||||
try:
|
||||
raw = file.read().decode("utf-8")
|
||||
data = json.loads(raw)
|
||||
except (UnicodeDecodeError, json.JSONDecodeError) as exc:
|
||||
flash(f"Invalid JSON file: {exc}", "error")
|
||||
return redirect(url_for("admin.admin_index"))
|
||||
|
||||
counts = import_snapshot(repo, data, clear=clear)
|
||||
mode = "Cleared DB and imported" if clear else "Merged"
|
||||
flash(
|
||||
f"Wiped all data and reseeded — {total} entities, {counts['domains']} domains.",
|
||||
f"{mode} snapshot — {counts['dimensions']} dimensions, "
|
||||
f"{counts['entities']} entities, {counts['domains']} domains, "
|
||||
f"{counts['combinations']} combinations, {counts['results']} results, "
|
||||
f"{counts['scores']} scores.",
|
||||
"success",
|
||||
)
|
||||
return redirect(url_for("admin.admin_index"))
|
||||
|
||||
@@ -37,14 +37,49 @@
|
||||
</div>
|
||||
|
||||
<div class="card warning-box">
|
||||
<h3>Wipe & Reseed</h3>
|
||||
<h3>Wipe All Data</h3>
|
||||
<p class="subtitle">
|
||||
Delete <strong>all</strong> data — entities, domains, combinations,
|
||||
pipeline runs — then reload seed data from scratch.
|
||||
pipeline runs. Use Reseed afterwards to restore seed data.
|
||||
</p>
|
||||
<form method="post" action="{{ url_for('admin.wipe_and_reseed') }}" style="margin-top: 0.75rem"
|
||||
onsubmit="return confirm('This will permanently delete ALL data and reseed from scratch. Continue?')">
|
||||
<button type="submit" class="btn btn-danger">Wipe & Reseed</button>
|
||||
<form method="post" action="{{ url_for('admin.wipe') }}" style="margin-top: 0.75rem"
|
||||
onsubmit="return confirm('This will permanently delete ALL data. Continue?')">
|
||||
<button type="submit" class="btn btn-danger">Wipe</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Snapshots</h2>
|
||||
<div class="card-grid">
|
||||
<div class="card">
|
||||
<h3>Export Snapshot</h3>
|
||||
<p class="subtitle">
|
||||
Download the full database state as a JSON file — entities,
|
||||
domains, combinations, results, and scores.
|
||||
</p>
|
||||
<div style="margin-top: 0.75rem">
|
||||
<a href="{{ url_for('admin.snapshot_export') }}" class="btn btn-primary">Download JSON</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>Import Snapshot</h3>
|
||||
<p class="subtitle">
|
||||
Upload a previously exported JSON snapshot. Merge adds new data
|
||||
alongside existing; clear wipes everything first.
|
||||
</p>
|
||||
<form method="post" action="{{ url_for('admin.snapshot_import') }}"
|
||||
enctype="multipart/form-data" style="margin-top: 0.75rem">
|
||||
<div class="form-group">
|
||||
<input type="file" name="file" accept=".json" required>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center; gap: 0.75rem">
|
||||
<button type="submit" class="btn btn-primary">Import (Merge)</button>
|
||||
<button type="submit" name="clear" value="1" class="btn btn-danger"
|
||||
onclick="return confirm('This will wipe ALL existing data before importing. Continue?')">
|
||||
Import (Clear & Replace)
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user