Add all-in-one Studio merging furni import and catalog management
CI / check (push) Successful in 33s
CI / release (push) Skipped
CI / deploy (push) Successful in 1m1s

Add a full-viewport /admin/studio workspace that unifies the import and
catalog systems into a single automated flow:

- Furni library browser against official Habbo furnidata with search,
  type/status filters, live previews and pagination
- Catalog structure rail showing where imported furniture lands
- Detail drawer with automatic placement preview (category + price via
  classifyFurni/autoPriceFurni) and one-click import that downloads
  assets, converts SWF to nitro, writes items_base, updates
  FurnitureData.json and creates an auto-priced catalog entry
- Batch auto-import with SSE progress and RCON cache refresh
- Nitro editor integration and imported-item deletion

Extract pure auto-catalog helpers (CATEGORY_PAGE, CLASSNAME_RULES,
classifyFurni, autoPriceFurni) into a client-safe module shared by the
server pipeline and the Studio UI so the preview always matches what the
emulator import applies.
This commit is contained in:
openhands committed 2026-08-15 15:34:07 +02:00
1 parent e31f6d985c
commit 5b09179404
7 files changed
+1297 -107

No files matched your search

+27
View File
@@ -0,0 +1,27 @@
import { redirect } from "next/navigation";
import { StudioClient } from "@/components/admin/studio/studio-client";
import { buildFurniImportSource } from "@/lib/habbo-gamedata-hotel";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
import { getTreeFlat } from "@/lib/services/catalog-tree";
import { getHabboGamedataHotel } from "@/lib/services/habbo-gamedata-hotel";
export default async function StudioPage(_props: {
params: Promise<{ locale: string }>;
}) {
const { session, permissions } = await getAdminContext();
if (!canAccess(permissions, PERMS.ASSETS_IMPORT, session.user.rank)) {
redirect("/admin");
}
const [hotel, catalogTree] = await Promise.all([
getHabboGamedataHotel(),
getTreeFlat(),
]);
return (
<StudioClient
source={buildFurniImportSource(hotel)}
initialTree={catalogTree}
/>
);
}
File diff suppressed because it is too large. Load diff
+8
View File
@@ -23,6 +23,7 @@ import {
Monitor, Monitor,
Newspaper, Newspaper,
Package, Package,
Palette,
Radio, Radio,
Server, Server,
Settings, Settings,
@@ -622,6 +623,13 @@ export const ADMIN_NAV_GROUPS: AdminNavGroup[] = [
permission: PERMS.ROOMS_VIEW, permission: PERMS.ROOMS_VIEW,
matchPrefixes: ["/admin/rooms"], matchPrefixes: ["/admin/rooms"],
}, },
{
href: "/admin/studio",
labelKey: "studio",
icon: Palette,
permission: PERMS.ASSETS_IMPORT,
matchPrefixes: ["/admin/studio"],
},
{ {
href: "/admin/import", href: "/admin/import",
labelKey: "import", labelKey: "import",
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+1
View File
@@ -2597,6 +2597,7 @@
"commando": "Commando", "commando": "Commando",
"rooms": "Rooms", "rooms": "Rooms",
"import": "Import", "import": "Import",
"studio": "Studio",
"importOverview": "Overview", "importOverview": "Overview",
"importBadges": "Badges", "importBadges": "Badges",
"importFurni": "Furni", "importFurni": "Furni",
+1
View File
@@ -2854,6 +2854,7 @@
"commando": "Commando", "commando": "Commando",
"rooms": "Kamers", "rooms": "Kamers",
"import": "Import", "import": "Import",
"studio": "Studio",
"importOverview": "Overzicht", "importOverview": "Overzicht",
"importBadges": "Badges", "importBadges": "Badges",
"importFurni": "Meubels", "importFurni": "Meubels",