settings: add factory reset button that wipes every table incl. config
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
the existing clear-scan button only drops media_items + related; settings survived. useful when schema changes or corrupt state make you want a full do-over on a running container without ssh-ing in to rm data/netfelix.db. POST /api/settings/reset truncates everything (config included) then re-seeds DEFAULT_CONFIG via the exported reseedDefaults helper. env-var overrides keep working through getConfig's env fallback. ui lives next to clear-scan in the danger zone with a double confirm and reload to /, so the setup wizard shows. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "netfelix-audio-fix",
|
||||
"version": "2026.04.13.4",
|
||||
"version": "2026.04.13.5",
|
||||
"scripts": {
|
||||
"dev:server": "NODE_ENV=development bun --hot server/index.tsx",
|
||||
"dev:client": "vite",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Hono } from "hono";
|
||||
import { getAllConfig, getDb, getEnvLockedKeys, setConfig } from "../db/index";
|
||||
import { getAllConfig, getDb, getEnvLockedKeys, reseedDefaults, setConfig } from "../db/index";
|
||||
import { getUsers, testConnection as testJellyfin } from "../services/jellyfin";
|
||||
import { testConnection as testRadarr } from "../services/radarr";
|
||||
import { getScheduleConfig, type ScheduleConfig, updateScheduleConfig } from "../services/scheduler";
|
||||
@@ -122,4 +122,26 @@ app.post("/clear-scan", (c) => {
|
||||
return c.json({ ok: true });
|
||||
});
|
||||
|
||||
/**
|
||||
* Full factory reset. Truncates every table including config, re-seeds the
|
||||
* defaults so the setup wizard reappears, and returns. Env-backed config
|
||||
* keys (JELLYFIN_URL, etc.) continue to resolve via getConfig's env fallback
|
||||
* — they don't live in the DB to begin with.
|
||||
*/
|
||||
app.post("/reset", (c) => {
|
||||
const db = getDb();
|
||||
db.transaction(() => {
|
||||
// Order matters when ON DELETE CASCADE isn't consistent across versions.
|
||||
db.prepare("DELETE FROM stream_decisions").run();
|
||||
db.prepare("DELETE FROM jobs").run();
|
||||
db.prepare("DELETE FROM subtitle_files").run();
|
||||
db.prepare("DELETE FROM review_plans").run();
|
||||
db.prepare("DELETE FROM media_streams").run();
|
||||
db.prepare("DELETE FROM media_items").run();
|
||||
db.prepare("DELETE FROM config").run();
|
||||
})();
|
||||
reseedDefaults();
|
||||
return c.json({ ok: true });
|
||||
});
|
||||
|
||||
export default app;
|
||||
|
||||
@@ -102,6 +102,11 @@ function seedDefaults(db: Database): void {
|
||||
}
|
||||
}
|
||||
|
||||
/** Re-seed config defaults after a truncating reset. Caller owns the delete. */
|
||||
export function reseedDefaults(): void {
|
||||
seedDefaults(getDb());
|
||||
}
|
||||
|
||||
export function getConfig(key: string): string | null {
|
||||
// Env vars take precedence over DB
|
||||
const fromEnv = envValue(key);
|
||||
|
||||
@@ -401,6 +401,20 @@ export function SettingsPage() {
|
||||
setClearStatus("Cleared.");
|
||||
};
|
||||
|
||||
const factoryReset = async () => {
|
||||
if (
|
||||
!confirm(
|
||||
"Reset to first-run state? This wipes EVERYTHING — scan data, settings, languages, schedule, Jellyfin/Radarr/Sonarr credentials. You'll land back on the setup wizard. This cannot be undone.",
|
||||
)
|
||||
)
|
||||
return;
|
||||
if (!confirm("Really reset? Type-nothing-just-click to confirm.")) return;
|
||||
await api.post("/api/settings/reset");
|
||||
// Invalidate client-side caches and reload so the setup gate re-evaluates.
|
||||
settingsCache = null;
|
||||
window.location.href = "/";
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
@@ -487,11 +501,19 @@ export function SettingsPage() {
|
||||
<p className="text-gray-500 text-sm mb-3">
|
||||
These actions are irreversible. Scan data can be regenerated by running a new scan.
|
||||
</p>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-4 mb-3">
|
||||
<Button variant="danger" onClick={clearScan}>
|
||||
Clear all scan data
|
||||
</Button>
|
||||
<span className="text-gray-400 text-sm">Removes all scanned items, review plans, and jobs.</span>
|
||||
<span className="text-gray-400 text-sm">Removes all scanned items, review plans, and jobs. Keeps settings.</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<Button variant="danger" onClick={factoryReset}>
|
||||
Reset to first-run state
|
||||
</Button>
|
||||
<span className="text-gray-400 text-sm">
|
||||
Wipes everything — scan data and settings. Sends you back to the setup wizard.
|
||||
</span>
|
||||
</div>
|
||||
{clearStatus && <p className="text-green-700 text-sm mt-2">{clearStatus}</p>}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user