perf(app): batch catalog updates, tune caches, add captcha env fallback
- catalog: apply bulk offer edits in a single transaction with one RCON refresh instead of N round-trips, virtualize the items table past 150 rows and cap the shop preview at 200 tiles - cache: lift the public cache TTLs and the boot warm-up into env-tunable constants (src/lib/perf-ttls.ts; CMS_*_TTL_SEC, CMS_WARMUP_ENABLED) - auth: resolve the captcha provider, site key and secret from CAPTCHA_PROVIDER, TURNSTILE_SITE_KEY and TURNSTILE_SECRET_KEY when the admin settings are unset; an explicit DB value (including "none") still wins, so Turnstile can be enabled per-deploy without touching the DB.
This commit is contained in:
1 parent
05c2706eaf
commit
9f024dc6ac
15 files changed
+529
-83
No files matched your search
@@ -18,6 +18,14 @@ interface ItemsShopPreviewProps {
|
||||
onItemClick?: (item: CatalogItemData) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* The preview is a visual check, not an editor. Mounting a tile (image, badges,
|
||||
* click handler) per offer made pages with hundreds of items crawl, so the grid
|
||||
* shows a window and states how many are hidden. The table view is the place to
|
||||
* work through the full list.
|
||||
*/
|
||||
const PREVIEW_TILE_LIMIT = 200;
|
||||
|
||||
export function ItemsShopPreview({
|
||||
items,
|
||||
furniRevisionMap,
|
||||
@@ -38,15 +46,23 @@ export function ItemsShopPreview({
|
||||
|
||||
const gridClass = getShopGridClass(layout);
|
||||
const tileSize = getShopTileSize(layout);
|
||||
const visibleItems =
|
||||
items.length > PREVIEW_TILE_LIMIT
|
||||
? items.slice(0, PREVIEW_TILE_LIMIT)
|
||||
: items;
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border bg-gradient-to-b from-[var(--admin-surface)] to-[var(--admin-canvas)] p-4">
|
||||
<div className="mb-3 flex items-center justify-between text-xs text-[var(--admin-text-muted)]">
|
||||
<span className="font-medium">Shop preview · {layout}</span>
|
||||
<span>{items.length} items</span>
|
||||
<span>
|
||||
{items.length} items
|
||||
{visibleItems.length !== items.length &&
|
||||
` · showing first ${visibleItems.length}`}
|
||||
</span>
|
||||
</div>
|
||||
<div className={cn("grid gap-2", gridClass)}>
|
||||
{items.map((item) => {
|
||||
{visibleItems.map((item) => {
|
||||
const firstId = parseFirstItemId(item.itemIds);
|
||||
const furni = firstId != null ? furniRevisionMap[firstId] : undefined;
|
||||
|
||||
@@ -62,6 +78,12 @@ export function ItemsShopPreview({
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{visibleItems.length !== items.length && (
|
||||
<p className="mt-3 text-center text-xs text-[var(--admin-text-muted)]">
|
||||
Preview capped at {PREVIEW_TILE_LIMIT} items — use the table view for
|
||||
the rest.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user