feat(housekeeping): cut over administration to ase
This commit is contained in:
1 parent
c9e35cf602
commit
2b8f73a91d
457 files changed
+589
-55936
No files matched your search
@@ -1,24 +0,0 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { AuditClient } from "@/app/admin/import/audit/audit-client";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export default async function StudioAuditPage(_props: {
|
||||
params: Promise<{ locale: string }>;
|
||||
}) {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.ASSETS_IMPORT, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
return (
|
||||
<div className="space-y-6 p-4">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold tracking-tight">Catalog Audit</h1>
|
||||
<p className="mt-1 text-muted-foreground">
|
||||
Scan your entire furniture catalog for missing entries, broken
|
||||
references, missing files, and items available from clone sources.
|
||||
</p>
|
||||
</div>
|
||||
<AuditClient />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { ImportBadgesClient } from "@/app/admin/import/badges/import-badges-client";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export default async function StudioBadgesPage(_props: {
|
||||
params: Promise<{ locale: string }>;
|
||||
}) {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.ASSETS_IMPORT, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
return (
|
||||
<div className="p-4">
|
||||
<ImportBadgesClient />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { ImportCloneClient } from "@/app/admin/import/clone/import-clone-client";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export default async function StudioClonePage(_props: {
|
||||
params: Promise<{ locale: string }>;
|
||||
}) {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.ASSETS_IMPORT, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
return (
|
||||
<div className="p-4">
|
||||
<ImportCloneClient />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { ImportClothingClient } from "@/app/admin/import/clothing/import-clothing-client";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export default async function StudioClothingPage(_props: {
|
||||
params: Promise<{ locale: string }>;
|
||||
}) {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.ASSETS_IMPORT, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
return (
|
||||
<div className="p-4">
|
||||
<ImportClothingClient />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { ImportEffectsClient } from "@/app/admin/import/effects/import-effects-client";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export default async function StudioEffectsPage(_props: {
|
||||
params: Promise<{ locale: string }>;
|
||||
}) {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.ASSETS_IMPORT, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
return (
|
||||
<div className="p-4">
|
||||
<ImportEffectsClient />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
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";
|
||||
import { siteSettings } from "@/lib/services/site-settings";
|
||||
|
||||
export default async function StudioFurniPage(_props: {
|
||||
params: Promise<{ locale: string }>;
|
||||
}) {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.ASSETS_IMPORT, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const [hotel, catalogTree, translateEnabled] = await Promise.all([
|
||||
getHabboGamedataHotel(),
|
||||
getTreeFlat(),
|
||||
siteSettings.getBool("furnidata_translate_enabled", true),
|
||||
]);
|
||||
|
||||
return (
|
||||
<StudioClient
|
||||
source={buildFurniImportSource(hotel)}
|
||||
initialTree={catalogTree}
|
||||
defaultTranslate={translateEnabled}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
BadgeCheck,
|
||||
Cat,
|
||||
ClipboardCheck,
|
||||
Copy,
|
||||
Dumbbell,
|
||||
Image as ImageIcon,
|
||||
type LucideIcon,
|
||||
Puzzle,
|
||||
RefreshCw,
|
||||
Shirt,
|
||||
Upload,
|
||||
Wrench,
|
||||
} from "lucide-react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import Link from "@/components/link";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const TABS: { href: string; label: string; icon: LucideIcon }[] = [
|
||||
{ href: "/admin/studio/furni", label: "Furni", icon: Puzzle },
|
||||
{ href: "/admin/studio/upload", label: "Upload", icon: Upload },
|
||||
{ href: "/admin/studio/badges", label: "Badges", icon: BadgeCheck },
|
||||
{ href: "/admin/studio/clothing", label: "Clothing", icon: Shirt },
|
||||
{ href: "/admin/studio/effects", label: "Effects", icon: Dumbbell },
|
||||
{ href: "/admin/studio/pets", label: "Pets", icon: Cat },
|
||||
{ href: "/admin/studio/clone", label: "Clone", icon: Copy },
|
||||
{ href: "/admin/studio/sync", label: "Sync", icon: RefreshCw },
|
||||
{
|
||||
href: "/admin/studio/repair-icons",
|
||||
label: "Repair Icons",
|
||||
icon: ImageIcon,
|
||||
},
|
||||
{ href: "/admin/studio/audit", label: "Audit", icon: ClipboardCheck },
|
||||
{
|
||||
href: "/admin/studio/maintenance",
|
||||
label: "Catalogus onderhoud",
|
||||
icon: Wrench,
|
||||
},
|
||||
];
|
||||
|
||||
export default function StudioLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const pathname = usePathname() ?? "";
|
||||
return (
|
||||
<div
|
||||
className="flex h-[calc(100dvh-7rem)] min-h-[520px] flex-col overflow-hidden rounded-xl border border-[var(--admin-border)]"
|
||||
style={{ backgroundColor: "var(--admin-canvas)" }}
|
||||
>
|
||||
<div className="flex shrink-0 items-center gap-1 overflow-x-auto border-b border-[var(--admin-border)] bg-[var(--admin-surface)] px-2 py-1.5">
|
||||
{TABS.map(({ href, label, icon: Icon }) => {
|
||||
const active = pathname === href || pathname.startsWith(`${href}/`);
|
||||
return (
|
||||
<Link
|
||||
key={href}
|
||||
href={href}
|
||||
className={cn(
|
||||
"flex shrink-0 items-center gap-1.5 rounded-md px-2.5 py-1.5 text-xs font-medium transition-colors",
|
||||
active
|
||||
? "bg-[var(--admin-accent)] text-[var(--admin-accent-foreground)]"
|
||||
: "text-[var(--admin-text-muted)] hover:bg-[var(--admin-accent)]/10 hover:text-[var(--admin-text)]",
|
||||
)}
|
||||
>
|
||||
<Icon size={13} />
|
||||
{label}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="min-h-0 flex-1 overflow-auto">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { CatalogMaintenancePanel } from "@/components/admin/catalog/catalog-maintenance-panel";
|
||||
|
||||
export default function StudioCatalogMaintenancePage() {
|
||||
return (
|
||||
<div className="min-h-0">
|
||||
<CatalogMaintenancePanel />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default function StudioIndexPage() {
|
||||
redirect("/admin/studio/furni");
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { ImportPetsClient } from "@/app/admin/import/pets/import-pets-client";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export default async function StudioPetsPage(_props: {
|
||||
params: Promise<{ locale: string }>;
|
||||
}) {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.ASSETS_IMPORT, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
return (
|
||||
<div className="p-4">
|
||||
<ImportPetsClient />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { RepairIconsClient } from "@/app/admin/import/repair-icons/repair-icons-client";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export default async function StudioRepairIconsPage(_props: {
|
||||
params: Promise<{ locale: string }>;
|
||||
}) {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.ASSETS_IMPORT, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
return (
|
||||
<div className="space-y-6 p-4">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold tracking-tight">
|
||||
Repair Missing Icons
|
||||
</h1>
|
||||
<p className="mt-1 text-muted-foreground">
|
||||
Scan all existing furniture and download any missing icon files. Icons
|
||||
are extracted from local .nitro bundles or fetched from configured
|
||||
clone sources.
|
||||
</p>
|
||||
</div>
|
||||
<RepairIconsClient />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { SyncAllClient } from "@/app/admin/import/sync/sync-all-client";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export default async function StudioSyncPage(_props: {
|
||||
params: Promise<{ locale: string }>;
|
||||
}) {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.ASSETS_IMPORT, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
return (
|
||||
<div className="space-y-6 p-4">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold tracking-tight">Sync All Sources</h1>
|
||||
<p className="mt-1 text-muted-foreground">
|
||||
Scan all configured clone sources and automatically import any
|
||||
furniture that is not yet present in your hotel. Missing .nitro files,
|
||||
icons, database entries, catalog items, and FurnitureData.json will be
|
||||
added automatically.
|
||||
</p>
|
||||
</div>
|
||||
<SyncAllClient />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { UploadFurniClient } from "@/app/admin/import/furni/upload/upload-furni-client";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export default async function StudioUploadPage(_props: {
|
||||
params: Promise<{ locale: string }>;
|
||||
}) {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.ASSETS_IMPORT, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
return (
|
||||
<div className="space-y-6 p-4">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold tracking-tight">
|
||||
Upload .nitro Furniture
|
||||
</h1>
|
||||
<p className="mt-1 text-muted-foreground">
|
||||
Upload a .nitro bundle and optional icon to import furniture into the
|
||||
hotel. The database entry, catalog item, and FurnitureData.json will
|
||||
be updated automatically.
|
||||
</p>
|
||||
</div>
|
||||
<UploadFurniClient />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user