Add first-run setup screen when required services aren't configured
Build and Push / build (push) Successful in 1m9s

When Radarr, Sonarr, or Overseerr is missing a URL or API key, the
stats API now returns 428 and the dashboard renders a full-page
setup form instead of the empty shell + fetch-error UI. The form
reuses the existing service/discord inputs (extracted out of the
settings modal so both can share them), and the background poller
skips silently until setup is complete.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-19 10:39:50 -04:00
parent 29e6933505
commit 2b9883d99f
8 changed files with 387 additions and 234 deletions
+6
View File
@@ -71,6 +71,12 @@ export function getSettings(): AppSettings {
};
}
/** Returns true iff the three services required for the dashboard to function (Radarr, Sonarr, Overseerr/Jellyseerr) have both a URL and API key. */
export function isConfigured(s: AppSettings = getSettings()): boolean {
const filled = (c: ServiceConfig) => c.url.trim() !== "" && c.apiKey.trim() !== "";
return filled(s.radarr) && filled(s.sonarr) && filled(s.seerr);
}
/** Saves the provided settings to disk and returns the merged result. */
export function saveSettings(settings: AppSettings): AppSettings {
if (!existsSync(DATA_DIR)) mkdirSync(DATA_DIR, { recursive: true });
+2
View File
@@ -11,6 +11,7 @@ import { buildSonarrMap } from "@/lib/sonarr";
import { fetchAllUsers, fetchUserRequests } from "@/lib/overseerr";
import { buildTautulliMap, lookupTautulliUser, fetchUserWatchHistory } from "@/lib/tautulli";
import { computeStats } from "@/lib/aggregate";
import { isConfigured } from "@/lib/settings";
import {
DashboardStats,
MediaEntry,
@@ -110,6 +111,7 @@ export async function getStats(force = false): Promise<DashboardStats> {
async function poll() {
if (refreshing) return;
if (!isConfigured()) return;
refreshing = true;
try {
const stats = await buildStats();