feat: RCON API transport, full furnidata translation with LibreTranslate fallback, remove organize feature, bump per-page limit to 500
- Add EMULATOR_MODE=api option with HTTP transport mirroring RCON payload - buildLocalizedFurniDataFiles now falls back to LibreTranslate for customs (incl. pl/ru/ar/ja) - Remove Organiseer import button from studio and Reorganize Catalog from import page - Delete organize API route and PUT handler; remove organizeCatalogAll from catalog-repair.ts - Increase imported-furni list perPage from 50 to 500
This commit is contained in:
1 parent
5668493485
commit
85b5792d40
8 files changed
+146
-768
No files matched your search
@@ -10,7 +10,6 @@ import {
|
||||
Download,
|
||||
ExternalLink,
|
||||
FileWarning,
|
||||
FolderSync,
|
||||
Globe2,
|
||||
ImageDown,
|
||||
LayoutGrid,
|
||||
@@ -141,8 +140,6 @@ export function ImportFurniClient({ source }: { source: FurniImportSource }) {
|
||||
// Nitro editor
|
||||
const [editingClassname, setEditingClassname] = useState<string | null>(null);
|
||||
|
||||
// Reorganize catalog
|
||||
const [reorganizing, setReorganizing] = useState(false);
|
||||
const [confirmRecentResync, setConfirmRecentResync] = useState(false);
|
||||
const [recentResyncing, setRecentResyncing] = useState(false);
|
||||
const [recentResyncResult, setRecentResyncResult] =
|
||||
@@ -157,13 +154,6 @@ export function ImportFurniClient({ source }: { source: FurniImportSource }) {
|
||||
// Confirmation dialogs
|
||||
const [confirmBatch, setConfirmBatch] = useState(false);
|
||||
const [confirmDelete, setConfirmDelete] = useState<FurniItem | null>(null);
|
||||
const [reorgPreview, setReorgPreview] = useState<{
|
||||
moved: number;
|
||||
repriced: number;
|
||||
skipped: number;
|
||||
total: number;
|
||||
categoryCounts: Record<string, number>;
|
||||
} | null>(null);
|
||||
|
||||
const fetchStats = useCallback(async () => {
|
||||
try {
|
||||
@@ -699,31 +689,6 @@ export function ImportFurniClient({ source }: { source: FurniImportSource }) {
|
||||
fetchStats();
|
||||
}
|
||||
|
||||
async function startReorganize() {
|
||||
setReorganizing(true);
|
||||
try {
|
||||
const previewRes = await adminFetch("/api/admin/import/furni?dryrun=1", {
|
||||
method: "PUT",
|
||||
});
|
||||
const previewData = await previewRes.json();
|
||||
if (!previewRes.ok) {
|
||||
toast.error(previewData.error || "Preview failed");
|
||||
return;
|
||||
}
|
||||
if (previewData.moved === 0 && previewData.repriced === 0) {
|
||||
toast.info(
|
||||
previewData.message || "Everything is already correctly organized",
|
||||
);
|
||||
return;
|
||||
}
|
||||
setReorgPreview(previewData);
|
||||
} catch {
|
||||
toast.error("Network error");
|
||||
} finally {
|
||||
setReorganizing(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function resyncRecentImports() {
|
||||
setConfirmRecentResync(false);
|
||||
setRecentResyncing(true);
|
||||
@@ -809,32 +774,6 @@ export function ImportFurniClient({ source }: { source: FurniImportSource }) {
|
||||
}
|
||||
}
|
||||
|
||||
async function applyReorganize() {
|
||||
setReorgPreview(null);
|
||||
setReorganizing(true);
|
||||
try {
|
||||
const res = await adminFetch("/api/admin/import/furni", {
|
||||
method: "PUT",
|
||||
});
|
||||
const d = await res.json();
|
||||
if (res.ok) {
|
||||
const parts: string[] = [];
|
||||
if (d.moved > 0) parts.push(`${d.moved} moved`);
|
||||
if (d.repriced > 0) parts.push(`${d.repriced} repriced`);
|
||||
if (d.skipped > 0) parts.push(`${d.skipped} already ok`);
|
||||
if (d.pagesDeleted > 0)
|
||||
parts.push(`${d.pagesDeleted} empty pages cleaned`);
|
||||
toast.success(`Done! ${parts.join(", ")} (${d.total} total)`);
|
||||
} else {
|
||||
toast.error(d.error || "Failed");
|
||||
}
|
||||
} catch {
|
||||
toast.error("Network error");
|
||||
} finally {
|
||||
setReorganizing(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function doDeleteItem(item: FurniItem) {
|
||||
setConfirmDelete(null);
|
||||
setDeletingItem(item.classname);
|
||||
@@ -1581,10 +1520,6 @@ export function ImportFurniClient({ source }: { source: FurniImportSource }) {
|
||||
? "Updating imported furni..."
|
||||
: "Update imported furni"}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={startReorganize} disabled={reorganizing}>
|
||||
<FolderSync className="w-4 h-4 mr-2" />
|
||||
{reorganizing ? "Reorganizing..." : "Reorganize Catalog"}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={addSize32All} disabled={addingSize32}>
|
||||
<ImageDown className="w-4 h-4 mr-2" />
|
||||
{addingSize32 ? "Adding size 32..." : "Add size 32 to all .nitro"}
|
||||
@@ -2082,82 +2017,6 @@ export function ImportFurniClient({ source }: { source: FurniImportSource }) {
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* Reorganize Preview */}
|
||||
<Dialog open={!!reorgPreview} onOpenChange={() => setReorgPreview(null)}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Reorganize Catalog</DialogTitle>
|
||||
<DialogDescription>
|
||||
Preview of changes to {reorgPreview?.total} imported items:
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
{reorgPreview && (
|
||||
<div className="space-y-3 text-sm">
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
{reorgPreview.moved > 0 && (
|
||||
<div className="rounded-lg border p-3 text-center">
|
||||
<p className="text-lg font-bold text-primary">
|
||||
{reorgPreview.moved}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Items to move
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{reorgPreview.repriced > 0 && (
|
||||
<div className="rounded-lg border p-3 text-center">
|
||||
<p className="text-lg font-bold text-[var(--admin-warning)]">
|
||||
{reorgPreview.repriced}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Prices to update
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{reorgPreview.skipped > 0 && (
|
||||
<div className="rounded-lg border p-3 text-center">
|
||||
<p className="text-lg font-bold text-muted-foreground">
|
||||
{reorgPreview.skipped}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Already correct
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{Object.keys(reorgPreview.categoryCounts || {}).length > 0 && (
|
||||
<div>
|
||||
<p className="text-xs font-medium text-muted-foreground mb-1">
|
||||
Categories:
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{Object.entries(reorgPreview.categoryCounts)
|
||||
.sort(([, a], [, b]) => b - a)
|
||||
.map(([cat, count]) => (
|
||||
<Badge
|
||||
key={cat}
|
||||
variant="secondary"
|
||||
className="text-xs"
|
||||
>
|
||||
{cat}: {count}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setReorgPreview(null)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={applyReorganize}>
|
||||
<FolderSync className="w-4 h-4 mr-1" /> Apply Changes
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user