From bac2f653af71061e944a313aaed4a71ae7b162c9 Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Sun, 2 Aug 2026 14:59:31 +0200 Subject: [PATCH] feat: add manual recent furni resync action --- .../import/furni/import-furni-client.tsx | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/src/app/admin/import/furni/import-furni-client.tsx b/src/app/admin/import/furni/import-furni-client.tsx index dcde3aae..47c46b05 100644 --- a/src/app/admin/import/furni/import-furni-client.tsx +++ b/src/app/admin/import/furni/import-furni-client.tsx @@ -6,6 +6,7 @@ import { BarChart3, Check, CheckCheck, + DatabaseZap, Download, ExternalLink, FileWarning, @@ -53,6 +54,10 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; +import { + type RecentFurniResyncResult, + requestRecentFurniResync, +} from "@/lib/admin/recent-furni-resync"; import { adminFetch } from "@/lib/admin-fetch"; import type { FurniImportSource } from "@/lib/habbo-gamedata-hotel"; import { NitroEditorDialog } from "./nitro-editor-dialog"; @@ -211,6 +216,10 @@ export function ImportFurniClient({ source }: { source: FurniImportSource }) { // Reorganize catalog const [reorganizing, setReorganizing] = useState(false); + const [confirmRecentResync, setConfirmRecentResync] = useState(false); + const [recentResyncing, setRecentResyncing] = useState(false); + const [recentResyncResult, setRecentResyncResult] = + useState(null); const searchRef = useRef(null); const batchAbortRef = useRef(null); @@ -792,6 +801,30 @@ export function ImportFurniClient({ source }: { source: FurniImportSource }) { } } + async function resyncRecentImports() { + setConfirmRecentResync(false); + setRecentResyncing(true); + setRecentResyncResult(null); + try { + const result = await requestRecentFurniResync(adminFetch); + setRecentResyncResult(result); + if (result.examined === 0) { + toast.info("No imported furni found in the last 7 days"); + } else if (result.failed > 0 || !result.rconOk) { + toast.warning("Furni resync completed with warnings"); + } else { + toast.success(`Updated ${result.resynced} imported furni`); + } + fetchStats(); + } catch (error) { + toast.error( + error instanceof Error ? error.message : "Furni resync failed", + ); + } finally { + setRecentResyncing(false); + } + } + async function applyReorganize() { setReorgPreview(null); setReorganizing(true); @@ -1038,6 +1071,56 @@ export function ImportFurniClient({ source }: { source: FurniImportSource }) { )} + {recentResyncResult && ( +
+
+

Imported Furni Update

+ +
+
+ {recentResyncResult.examined} examined + + {recentResyncResult.resynced} updated + + + {recentResyncResult.failed} failed + + + RCON {recentResyncResult.rconOk ? "refreshed" : "not refreshed"} + +
+ {recentResyncResult.errors.length > 0 && ( +
+ + View errors + +
+ {recentResyncResult.errors.map((error) => ( +

+ {error.classname}:{" "} + {error.message} +

+ ))} +
+
+ )} +
+ )} + {/* Batch Summary */} {batchSummary && (
@@ -1535,6 +1618,19 @@ export function ImportFurniClient({ source }: { source: FurniImportSource }) { + setConfirmRecentResync(true)} + disabled={recentResyncing} + > + {recentResyncing ? ( + + ) : ( + + )} + {recentResyncing + ? "Updating imported furni..." + : "Update imported furni"} + {reorganizing ? "Reorganizing..." : "Reorganize Catalog"} @@ -1936,6 +2032,30 @@ export function ImportFurniClient({ source }: { source: FurniImportSource }) { + + + + Update imported furni? + + This updates FurnitureData for furni imported during the last 7 + days, then refreshes the emulator catalog and item caches. No + database rows or asset files are deleted. + + + + + + + + + {/* Delete Confirmation */}