From a64de5aba31862541ea69049c5a5eafe620f9ce3 Mon Sep 17 00:00:00 2001 From: robbond Date: Thu, 5 Mar 2026 10:17:28 +0000 Subject: [PATCH] Use Plesk CLI subscription info to populate status; domains inherit status; UI badges --- components/dashboard/dashboard-controls.tsx | 4 ++ lib/plesk/client.ts | 50 +++++++++++-------- lib/plesk/sync.ts | 2 +- ...main_status_backfill_from_subscription.sql | 9 +--- 4 files changed, 37 insertions(+), 28 deletions(-) diff --git a/components/dashboard/dashboard-controls.tsx b/components/dashboard/dashboard-controls.tsx index 9af6dbd..54accdb 100644 --- a/components/dashboard/dashboard-controls.tsx +++ b/components/dashboard/dashboard-controls.tsx @@ -60,6 +60,10 @@ function getDomainStatusBadge(status: string | null) { return "bg-emerald-100 text-emerald-700"; } + if (normalized.includes("ok")) { + return "bg-emerald-100 text-emerald-700"; + } + return "bg-slate-100 text-slate-600"; } diff --git a/lib/plesk/client.ts b/lib/plesk/client.ts index 843db76..6b3ebfc 100644 --- a/lib/plesk/client.ts +++ b/lib/plesk/client.ts @@ -138,37 +138,24 @@ export async function testPleskConnection(connection: PleskConnection) { } export async function listPleskSubscriptions(connection: PleskConnection) { - const listOutput = await pleskCliCall(connection, "subscription", ["--list"]); + const listResult = await pleskCliCall(connection, "subscription", ["--list"]); - const subscriptionNames = listOutput + const subscriptionNames = (listResult.stdout ?? "") .split(/\r?\n/) .map((line) => line.trim()) .filter(Boolean); const subscriptions: PleskSubscription[] = []; - for (const subscriptionName of subscriptionNames) { - let status = "unknown"; + for (const subscriptionName of subscriptionNames.slice(0, 500)) { + let status: "active" | "suspended" | "unknown" = "unknown"; try { - const infoOutput = await pleskCliCall(connection, "subscription", [ + const infoResult = await pleskCliCall(connection, "subscription", [ "--info", subscriptionName, ]); - const normalizedInfo = infoOutput.toLowerCase(); - - const hasSuspendedMarker = - normalizedInfo.includes("suspended") || - normalizedInfo.includes("webspace-off") || - normalizedInfo.includes("disabled"); - - const hasActiveMarker = - normalizedInfo.includes("active") || - normalizedInfo.includes("enabled") || - normalizedInfo.includes("ok"); - - if (hasSuspendedMarker) status = "suspended"; - else if (hasActiveMarker || !hasSuspendedMarker) status = "active"; + status = parseSubscriptionStatusFromInfo(infoResult.stdout ?? ""); } catch { status = "unknown"; } @@ -184,6 +171,29 @@ export async function listPleskSubscriptions(connection: PleskConnection) { return subscriptions; } +export function parseSubscriptionStatusFromInfo( + stdout: string, +): "active" | "suspended" | "unknown" { + const line = stdout + .split(/\r?\n/) + .map((entry) => entry.trim()) + .find((entry) => /^domain\s+status\s*:/i.test(entry)); + + if (!line) return "unknown"; + + const value = line + .replace(/^domain\s+status\s*:/i, "") + .trim() + .toLowerCase(); + + if (value.includes("ok")) return "active"; + if (value.includes("suspend") || value.includes("disabled")) { + return "suspended"; + } + + return "unknown"; +} + export async function pleskCliCall( connection: PleskConnection, command: string, @@ -208,7 +218,7 @@ export async function pleskCliCall( ); } - return stdout; + return { code, stdout, stderr }; } export async function listPleskDomains(connection: PleskConnection) { diff --git a/lib/plesk/sync.ts b/lib/plesk/sync.ts index 554b2dd..6976e2c 100644 --- a/lib/plesk/sync.ts +++ b/lib/plesk/sync.ts @@ -94,7 +94,7 @@ export async function syncPleskInstance( plesk_instance_id: instance.id, plesk_subscription_id: String(sourceId), name: item?.name ? String(item.name) : String(sourceId), - status: item?.status ? String(item.status) : null, + status: item?.status ? String(item.status) : "unknown", owner_login: item?.owner_login ? String(item.owner_login) : item?.owner?.login diff --git a/supabase/migrations/CL37_domain_status_backfill_from_subscription.sql b/supabase/migrations/CL37_domain_status_backfill_from_subscription.sql index b662035..a394e26 100644 --- a/supabase/migrations/CL37_domain_status_backfill_from_subscription.sql +++ b/supabase/migrations/CL37_domain_status_backfill_from_subscription.sql @@ -1,11 +1,6 @@ -- One-time backfill: align existing domain status with linked subscription status update public.plesk_domains d -set status = s.status +set status = coalesce(s.status, 'unknown') from public.plesk_subscriptions s where d.subscription_id = s.id - and d.agency_id = s.agency_id - and (d.status is null or d.status = 'unknown'); - -update public.plesk_subscriptions -set status = 'unknown' -where status is null; \ No newline at end of file + and d.agency_id = s.agency_id; \ No newline at end of file