Improvements: remove dead config, fix ESM, add URL validation, unify types, add missing logging
- Remove .prettierrc (dead config, Biome replaces Prettier) - Rename lighthouserc.json to lighthouserc.cjs with module.exports for ESM compat - Add logger.warn to empty catch blocks in auth, register, site-settings, prisma-cache, redis, security, rate-limit - Unify ActionResult type: action-helper.ts uses 'ok' consistent with safe-action-shared.ts - Add noUnusedLocals + noUnusedParameters to tsconfig + fix 25 pre-existing unused vars - Replace barrel export src/types/index.ts with direct @/types/common imports - Make trustHost conditional (development only) in auth.ts - Add pre-flight URL validation to update-Nitrov3.sh to catch image.library.url misconfigurations - Improve NITRO_IMAGE_LIBRARY_URL content validation in pre-flight & post-compute checks
This commit is contained in:
1 parent
b922f6d49f
commit
17847545dd
292 files changed
+69195
-67915
No files matched your search
@@ -15,8 +15,8 @@ import { RootTabs } from "./root-tabs";
|
||||
import { SortableTree } from "./sortable-tree";
|
||||
import { type CatalogStatsTotals, StatsBar } from "./stats-bar";
|
||||
import {
|
||||
CatalogManagerProvider,
|
||||
type CatalogManagerMode,
|
||||
CatalogManagerProvider,
|
||||
catalogTreeQs,
|
||||
useCatalogManager,
|
||||
} from "./use-catalog-store";
|
||||
@@ -58,8 +58,7 @@ export function CatalogManagerDialog({
|
||||
};
|
||||
}, [open]);
|
||||
|
||||
const title =
|
||||
catalogType === "bc" ? "BC Visual Manager" : "Visual Manager";
|
||||
const title = catalogType === "bc" ? "BC Visual Manager" : "Visual Manager";
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -120,9 +119,7 @@ function CatalogManagerInner({
|
||||
const loadRootPages = useCallback(async () => {
|
||||
dispatch({ type: "SET_LOADING_ROOT", loading: true });
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/admin/catalog/tree?parentId=-1${catQs}`,
|
||||
);
|
||||
const res = await fetch(`/api/admin/catalog/tree?parentId=-1${catQs}`);
|
||||
const data = await res.json().catch(() => ({}));
|
||||
if (!res.ok) throw new Error(data.error || "Failed to load roots");
|
||||
const pages: RootTab[] = (data.pages || []).map(
|
||||
@@ -163,17 +160,21 @@ function CatalogManagerInner({
|
||||
}
|
||||
}
|
||||
void loadRootPages();
|
||||
}, [open, initialRoots, state.rootPages.length, state.activeTabId, dispatch, loadRootPages]);
|
||||
}, [
|
||||
open,
|
||||
initialRoots,
|
||||
state.rootPages.length,
|
||||
state.activeTabId,
|
||||
dispatch,
|
||||
loadRootPages,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) dispatch({ type: "ON_DIALOG_CLOSE" });
|
||||
}, [open, dispatch]);
|
||||
|
||||
const handleTabClick = (id: number) => {
|
||||
if (
|
||||
state.editorDirty &&
|
||||
!confirm("You have unsaved changes. Discard?")
|
||||
) {
|
||||
if (state.editorDirty && !confirm("You have unsaved changes. Discard?")) {
|
||||
return;
|
||||
}
|
||||
dispatch({ type: "SET_ACTIVE_TAB", id });
|
||||
@@ -203,10 +204,7 @@ function CatalogManagerInner({
|
||||
};
|
||||
|
||||
const handleSelectPage = (id: number) => {
|
||||
if (
|
||||
state.editorDirty &&
|
||||
!confirm("You have unsaved changes. Discard?")
|
||||
) {
|
||||
if (state.editorDirty && !confirm("You have unsaved changes. Discard?")) {
|
||||
return;
|
||||
}
|
||||
dispatch({ type: "SELECT_PAGE", id: id > 0 ? id : null });
|
||||
@@ -216,10 +214,7 @@ function CatalogManagerInner({
|
||||
if (state.activeTabId !== id) {
|
||||
dispatch({ type: "SET_ACTIVE_TAB", id });
|
||||
}
|
||||
if (
|
||||
state.editorDirty &&
|
||||
!confirm("You have unsaved changes. Discard?")
|
||||
) {
|
||||
if (state.editorDirty && !confirm("You have unsaved changes. Discard?")) {
|
||||
return;
|
||||
}
|
||||
dispatch({ type: "SELECT_PAGE", id });
|
||||
|
||||
@@ -150,9 +150,7 @@ export function InlineEditor({ pageId, onSaved }: InlineEditorProps) {
|
||||
async (id: number) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/admin/catalog/tree?pageId=${id}${catQs}`,
|
||||
);
|
||||
const res = await fetch(`/api/admin/catalog/tree?pageId=${id}${catQs}`);
|
||||
if (!res.ok) throw new Error();
|
||||
const data = await res.json();
|
||||
const p = data.page as PageDetail;
|
||||
@@ -653,9 +651,7 @@ export function InlineEditor({ pageId, onSaved }: InlineEditorProps) {
|
||||
>
|
||||
{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>
|
||||
<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" />
|
||||
|
||||
@@ -30,8 +30,8 @@ import {
|
||||
reorderBcTreePage,
|
||||
toggleBcPage,
|
||||
} from "@/actions/catalog-bc";
|
||||
import { useConfirmDialog } from "@/components/admin/confirm-dialog";
|
||||
import { CatalogIcon } from "@/components/admin/catalog-tree";
|
||||
import { useConfirmDialog } from "@/components/admin/confirm-dialog";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
ContextMenu,
|
||||
|
||||
@@ -125,20 +125,23 @@ export function SortableTree({
|
||||
useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
|
||||
);
|
||||
|
||||
const normalizePages = useCallback((pages: TreeNodeData[]): TreeNodeData[] => {
|
||||
return pages.map((p) => ({
|
||||
...p,
|
||||
id: Number(p.id),
|
||||
parentId: Number(p.parentId),
|
||||
enabled: String(p.enabled ?? "0"),
|
||||
visible: String(p.visible ?? "0"),
|
||||
iconImage: Number(p.iconImage) || 0,
|
||||
iconColor: Number(p.iconColor) || 0,
|
||||
childCount: Number(p.childCount) || 0,
|
||||
itemCount: Number(p.itemCount) || 0,
|
||||
orderNum: Number(p.orderNum) || 0,
|
||||
}));
|
||||
}, []);
|
||||
const normalizePages = useCallback(
|
||||
(pages: TreeNodeData[]): TreeNodeData[] => {
|
||||
return pages.map((p) => ({
|
||||
...p,
|
||||
id: Number(p.id),
|
||||
parentId: Number(p.parentId),
|
||||
enabled: String(p.enabled ?? "0"),
|
||||
visible: String(p.visible ?? "0"),
|
||||
iconImage: Number(p.iconImage) || 0,
|
||||
iconColor: Number(p.iconColor) || 0,
|
||||
childCount: Number(p.childCount) || 0,
|
||||
itemCount: Number(p.itemCount) || 0,
|
||||
orderNum: Number(p.orderNum) || 0,
|
||||
}));
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
/**
|
||||
* Load children of a page — same endpoint CatalogTree uses successfully.
|
||||
@@ -227,11 +230,7 @@ export function SortableTree({
|
||||
}
|
||||
const node = nodes.get(id);
|
||||
const existing = childrenMap.get(id);
|
||||
if (
|
||||
node &&
|
||||
node.childCount > 0 &&
|
||||
(!existing || existing.length === 0)
|
||||
) {
|
||||
if (node && node.childCount > 0 && (!existing || existing.length === 0)) {
|
||||
dispatch({
|
||||
type: "SET_LOADING_IDS",
|
||||
ids: new Set([...loadingIds, id]),
|
||||
@@ -591,9 +590,7 @@ export function SortableTree({
|
||||
const handleDuplicate = async (id: number) => {
|
||||
if (!canEdit) return;
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/admin/catalog/tree?pageId=${id}${catQs}`,
|
||||
);
|
||||
const res = await fetch(`/api/admin/catalog/tree?pageId=${id}${catQs}`);
|
||||
if (!res.ok) throw new Error();
|
||||
const { page } = await res.json();
|
||||
const result =
|
||||
@@ -662,7 +659,7 @@ export function SortableTree({
|
||||
// Lazy-load each first-level node's children in background
|
||||
for (const id of firstLevel) {
|
||||
const node = nodes.get(id);
|
||||
if (node && node.childCount > 0 && !(childrenMap.get(id)?.length)) {
|
||||
if (node && node.childCount > 0 && !childrenMap.get(id)?.length) {
|
||||
void loadChildren(id)
|
||||
.then((pages) => {
|
||||
dispatch({ type: "SET_CHILDREN", parentId: id, children: pages });
|
||||
@@ -1132,7 +1129,6 @@ export function SortableTree({
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user