Replace standalone catalog editor with the unified Visual Catalog studio
CI / check (push) Failing after 26s
CI / preflight (push) Skipped
CI / deploy (push) Skipped
CI / publish-container (push) Skipped

Make /admin/catalog a full-screen catalog studio that replaces the old
listing plus separate [id]/builder-club detail pages:

- Embed CatalogManagerWorkspace on /admin/catalog with a Normal/Builder
  Club toggle, Catalog Sync status, packages (normal), Organize imports
  and a diagnostics link to /admin/studio/maintenance.
- Manage BC items directly in the studio Items tab (new BcItemsEditor,
  CRUD via existing bc actions; /api/admin/catalog/items now serves BC).
- Inline editor: add pageTextTeaser field for both catalogs and remove
  the legacy full-editor links.
- Remove the 'Open full editor' context action from the tree.
- Move catalog-items-table (dir + barrel) and catalog-translate-tab out
  of the app route into src/components/admin/catalog and update all
  importers.
- Keep /admin/catalog/[id], builder-club/[id] and /admin/catalog/maintenance
  as redirects into the new studio; consolidate maintenance panels into
  /admin/studio/maintenance and point the nav item there.
- Delete the old listing/table/tabs/forms and the standalone bc-manager.
This commit is contained in:
openhands committed 2026-09-14 17:20:52 +02:00
1 parent 1a9e1e791a
commit 1bbd809b43
36 files changed
+526 -2750

No files matched your search

@@ -4,7 +4,6 @@ import {
AlertCircle,
ChevronDown,
ChevronRight,
ExternalLink,
Languages,
Loader2,
MonitorPlay,
@@ -20,16 +19,16 @@ import { updateBcPage } from "@/actions/catalog-bc";
import {
type CatalogItemData,
CatalogItemsTable,
} from "@/app/admin/catalog/[id]/catalog-items-table";
import { CatalogTranslateTab } from "@/app/admin/catalog/[id]/catalog-translate-tab";
} from "@/components/admin/catalog/catalog-items-table";
import { CatalogTranslateTab } from "@/components/admin/catalog/catalog-translate-tab";
import { BulkImportItems } from "@/components/admin/catalog/bulk-import-items";
import { CatalogImagePicker } from "@/components/admin/catalog/catalog-image-picker";
import { IconPicker } from "@/components/admin/catalog/icon-picker";
import { QuickAddFurni } from "@/components/admin/catalog/quick-add-furni";
import { AutoOrganize } from "@/components/admin/catalog-manager/auto-organize";
import { BcItemsEditor } from "@/components/admin/catalog-manager/bc-items-editor";
import { LiveCatalogPreview } from "@/components/admin/catalog-manager/live-catalog-preview";
import { CatalogIcon, LAYOUT_COLORS } from "@/components/admin/catalog-tree";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
@@ -133,10 +132,6 @@ function InlineEditorSession({
const [offersDirty, setOffersDirty] = useState(false);
const { dispatch, catalogType, canEdit } = useCatalogManager();
const catQs = catalogTreeQs(catalogType);
const pageHref =
catalogType === "bc"
? `/admin/catalog/builder-club/${pageId}`
: `/admin/catalog/${pageId}`;
const [page, setPage] = useState<PageDetail | null>(null);
const [loading, setLoading] = useState(false);
const [saving, setSaving] = useState(false);
@@ -425,17 +420,7 @@ function InlineEditorSession({
{t("preview.title")}
</Button>
)}
<Link href={pageHref} target="_blank">
<Button
variant="ghost"
size="sm"
className="h-7 text-xs gap-1 text-[var(--admin-text)]"
>
<ExternalLink className="h-3 w-3" />
{t("fullEditor")}
</Button>
</Link>
</div>
</div>
</div>
{/* Dirty banner */}
@@ -671,7 +656,10 @@ function InlineEditorSession({
<ChevronRight className="h-3.5 w-3.5" />
)}
Text fields
{(form.pageText1 || form.pageText2 || form.pageTextDetails) && (
{(form.pageText1 ||
form.pageText2 ||
form.pageTextDetails ||
form.pageTextTeaser) && (
<Badge variant="secondary" className="h-4 px-1 text-[9px]">
has content
</Badge>
@@ -713,6 +701,17 @@ function InlineEditorSession({
className="text-sm"
/>
</div>
<div className="space-y-1.5">
<Label className="text-xs">Text Teaser</Label>
<Textarea
rows={2}
value={String(form.pageTextTeaser || "")}
onChange={(e) =>
update("pageTextTeaser", e.target.value || null)
}
className="text-sm"
/>
</div>
<div className="space-y-1.5">
<Label className="text-xs">Special</Label>
<Input
@@ -750,17 +749,7 @@ function InlineEditorSession({
className="flex-1 overflow-y-auto px-4 pb-4 mt-2"
>
{catalogType === "bc" ? (
<div className="rounded-md border border-dashed px-4 py-8 text-center text-sm text-muted-foreground space-y-3">
<p>
BC items are managed on the full Builder Club page editor.
</p>
<Link href={pageHref} target="_blank">
<Button variant="outline" size="sm" className="gap-1">
<ExternalLink className="h-3 w-3" />
Open BC page editor
</Button>
</Link>
</div>
<BcItemsEditor pageId={page.id} canEdit={canEdit} />
) : itemsError && !itemsData ? (
<div className="flex items-center justify-center py-12">
<Button variant="outline" onClick={reloadItems}>