From 8069c6287b20287615b50facb4ed5613ebd55abe Mon Sep 17 00:00:00 2001 From: makearmy Date: Wed, 1 Oct 2025 17:22:46 -0400 Subject: [PATCH] settings list fix for stable build --- app/settings/co2-galvo/[id]/co2-galvo.tsx | 35 +- app/settings/co2-galvo/page.tsx | 332 +++++++++-------- app/settings/co2-galvo/page.tsx.bak | 228 ------------ app/settings/co2-gantry/[id]/co2-gantry.tsx | 20 +- app/settings/co2-gantry/page.tsx | 379 +++++++++++--------- app/settings/fiber/[id]/fiber.tsx | 24 +- app/settings/uv/[id]/uv.tsx | 27 +- 7 files changed, 438 insertions(+), 607 deletions(-) delete mode 100644 app/settings/co2-galvo/page.tsx.bak diff --git a/app/settings/co2-galvo/[id]/co2-galvo.tsx b/app/settings/co2-galvo/[id]/co2-galvo.tsx index 9bbeaa7e..492ad601 100644 --- a/app/settings/co2-galvo/[id]/co2-galvo.tsx +++ b/app/settings/co2-galvo/[id]/co2-galvo.tsx @@ -25,15 +25,16 @@ export default function CO2GalvoSettingDetailPage() { "submission_id", "setting_title", "uploader", + // ✅ Owner (M2O) — request username explicitly "owner.id", - "owner.first_name", - "owner.last_name", - "owner.email", + "owner.username", + // Content & assets "setting_notes", "photo.filename_disk", "photo.title", "screen.filename_disk", "screen.title", + // Denormalized relations / fields "mat.name", "mat_coat.name", "mat_color.name", @@ -41,13 +42,14 @@ export default function CO2GalvoSettingDetailPage() { "mat_thickness", "source.make", "source.model", + // ✅ laser_soft is a STRING, not a relation + "laser_soft", "lens.field_size", "lens.focal_length", "lens_conf.name", "lens_apt.name", "lens_exp.name", "focus", - "laser_soft.name", "repeat_all", "fill_settings", "line_settings", @@ -67,11 +69,11 @@ export default function CO2GalvoSettingDetailPage() { if (loading) return

Loading setting...

; if (!setting) return

Setting not found.

; + // ✅ Prefer the owner's username (string). Return null if absent so claim UI shows. const ownerName = (row: any) => { const o = row?.owner; if (!o) return null; - const name = [o.first_name, o.last_name].filter(Boolean).join(" ").trim(); - return name || o.email || null; + return o.username || null; }; const formatBoolean = (val: any) => @@ -107,9 +109,10 @@ export default function CO2GalvoSettingDetailPage() { ); }; + // ✅ Point searches back to the list route under /settings const openSearchInNewTab = (value: string) => { if (!value || typeof window === "undefined") return; - const url = new URL("/co2-galvo-settings", window.location.origin); + const url = new URL("/settings/co2-galvo", window.location.origin); url.searchParams.set("query", value); const a = document.createElement("a"); a.href = url.toString(); @@ -185,8 +188,9 @@ export default function CO2GalvoSettingDetailPage() { )} + {/* ✅ Back link to list route */} ← Back to CO₂ Galvo Settings @@ -249,8 +253,9 @@ export default function CO2GalvoSettingDetailPage() { {/* Setup */}

Setup

+ {/* ✅ laser_soft is a string field */}

- Software: {setting.laser_soft?.name || "—"} + Software: {setting.laser_soft || "—"}

Repeat All (global): {setting.repeat_all ?? "—"} @@ -385,16 +390,8 @@ export default function CO2GalvoSettingDetailPage() { { key: "pulse", label: "Pulse Width (ns)" }, { key: "type", label: "Type" }, { key: "dither", label: "Dither" }, - { - key: "halftone_cell", - label: "Cell Size (mm)", - condition: (e: any) => e.dither === "halftone", - }, - { - key: "halftone_angle", - label: "Halftone Angle", - condition: (e: any) => e.dither === "halftone", - }, + { key: "halftone_cell", label: "Cell Size (mm)", condition: (e: any) => e.dither === "halftone" }, + { key: "halftone_angle", label: "Halftone Angle", condition: (e: any) => e.dither === "halftone" }, { key: "inversion", label: "Image Inverted" }, { key: "interval", label: "Interval (mm)" }, { key: "dot", label: "Dot-width Adjustment (mm)" }, diff --git a/app/settings/co2-galvo/page.tsx b/app/settings/co2-galvo/page.tsx index 7630ed49..adb3cd9f 100644 --- a/app/settings/co2-galvo/page.tsx +++ b/app/settings/co2-galvo/page.tsx @@ -6,8 +6,9 @@ import Link from "next/link"; import Image from "next/image"; type Owner = { - username?: string | null; id?: string | number; + username?: string | null; + // keep extras harmlessly if API returns them first_name?: string | null; last_name?: string | null; email?: string | null; @@ -37,10 +38,10 @@ export default function CO2GalvoSettingsPage() { "submission_id", "setting_title", "uploader", - "owner.id", "owner.username", - "owner.first_name", - "owner.last_name", - "owner.email", + // owner (M2O) – ensure username is requested + "owner.id", + "owner.username", + // assets / denorms "photo.id", "photo.title", "mat.name", @@ -63,10 +64,7 @@ export default function CO2GalvoSettingsPage() { .finally(() => setLoading(false)); }, []); - const ownerLabel = (o?: Owner) => { - if (!o) return "—"; - return o.username || "—"; - }; + const ownerLabel = (o?: Owner) => (o?.username ?? "—"); const highlight = (text?: string) => { if (!debouncedQuery) return text || ""; @@ -93,7 +91,9 @@ export default function CO2GalvoSettingsPage() { }, [settings, debouncedQuery]); const total = settings.length; - const uniqueMaterials = new Set(settings.map((s) => s.mat?.name).filter(Boolean)).size; + const uniqueMaterials = new Set( + settings.map((s) => s.mat?.name).filter(Boolean) + ).size; const lensCounts = settings.reduce((acc: Record, cur) => { const v = cur.lens?.field_size; @@ -102,161 +102,181 @@ export default function CO2GalvoSettingsPage() { return acc; }, {}); const mostCommonLens = - Object.entries(lensCounts).sort((a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0))[0]?.[0] || - "—"; + Object.entries(lensCounts).sort( + (a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0) + )[0]?.[0] || "—"; -const srcCounts = settings.reduce((acc: Record, cur) => { - const v = cur.source?.model; - if (!v) return acc; - acc[v] = (acc[v] || 0) + 1; - return acc; -}, {}); -const mostCommonSource = -Object.entries(srcCounts).sort((a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0))[0]?.[0] || -"—"; + const srcCounts = settings.reduce((acc: Record, cur) => { + const v = cur.source?.model; + if (!v) return acc; + acc[v] = (acc[v] || 0) + 1; + return acc; + }, {}); + const mostCommonSource = + Object.entries(srcCounts).sort( + (a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0) + )[0]?.[0] || "—"; -const recent = [...settings] -.sort((a, b) => Number(b.submission_id) - Number(a.submission_id)) -.slice(0, 5); + const recent = [...settings] + .sort((a, b) => Number(b.submission_id) - Number(a.submission_id)) + .slice(0, 5); -return ( -

- + return ( +
+ - {/* Header / Search */} -
-
-

CO₂ Galvo Settings

- setQuery(e.target.value)} - placeholder="Search by material, owner, uploader, model, lens…" - className="w-full mb-4 dark:bg-background border border-border rounded-md p-2" - /> -

- View and explore detailed CO₂ galvo settings with context. -

-
+ {/* Header / Search */} +
+
+

CO₂ Galvo Settings

+ setQuery(e.target.value)} + placeholder="Search by material, owner, uploader, model, lens…" + className="w-full mb-4 dark:bg-background border border-border rounded-md p-2" + /> +

+ View and explore detailed CO₂ galvo settings with context. +

+
- {/* How to use */} -
-

How to Use

-

- Browse community CO₂ galvo settings. Use search to narrow results. Click a row to view full configuration, - notes, and photos. -

-
+ {/* How to use */} +
+

How to Use

+

+ Browse community CO₂ galvo settings. Use search to narrow results. + Click a row to view full configuration, notes, and photos. +

+
- {/* Stats */} -
-

Stats Summary

-
    -
  • Total Settings: {total}
  • -
  • Unique Materials: {uniqueMaterials}
  • -
  • Most Common Lens: {mostCommonLens}
  • -
  • Most Used Source: {mostCommonSource}
  • -
-
+ {/* Stats */} +
+

Stats Summary

+
    +
  • Total Settings: {total}
  • +
  • Unique Materials: {uniqueMaterials}
  • +
  • Most Common Lens: {mostCommonLens}
  • +
  • Most Used Source: {mostCommonSource}
  • +
+
- {/* Recently Added */} -
-

Recently Added

-
    - {recent.map((s) => ( -
  • - - {s.setting_title || "Untitled"} - {" "} - - by {ownerLabel(s.owner)}{s.uploader ? ` (uploader: ${s.uploader})` : ""} - -
  • - ))} -
-
-
- - {/* Table */} - {loading ? ( -

Loading settings...

- ) : filtered.length === 0 ? ( -

No CO₂ galvo settings found.

- ) : ( -
- - - - - - - - - - - - - - - {filtered.map((s) => ( - - - - + className="underline text-accent" + > + {s.setting_title || "Untitled"} + {" "} + + by {ownerLabel(s.owner)} + {s.uploader ? ` (uploader: ${s.uploader})` : ""} + + ))} - -
PhotoTitleOwnerUploaderMaterialCoatingSourceLens
- {s.photo?.id ? ( - {s.photo.title - ) : ( - "—" - )} - + {/* Recently Added */} +
+

Recently Added

+
    + {recent.map((s) => ( +
  • -
- - - - - -
+
- )} -
-); +
+ + {/* Table */} + {loading ? ( +

Loading settings...

+ ) : filtered.length === 0 ? ( +

No CO₂ galvo settings found.

+ ) : ( +
+ + + + + + + + + + + + + + + {filtered.map((s) => ( + + + + + ))} + +
PhotoTitleOwnerUploaderMaterialCoatingSourceLens
+ {s.photo?.id ? ( + {s.photo.title + ) : ( + "—" + )} + + + + + + + + +
+
+ )} +
+ ); } diff --git a/app/settings/co2-galvo/page.tsx.bak b/app/settings/co2-galvo/page.tsx.bak deleted file mode 100644 index f87996fc..00000000 --- a/app/settings/co2-galvo/page.tsx.bak +++ /dev/null @@ -1,228 +0,0 @@ -"use client"; - -import { useEffect, useState, useMemo } from "react"; -import { useSearchParams } from "next/navigation"; -import Link from "next/link"; -import Image from "next/image"; - -export default function CO2GalvoSettingsPage() { - const searchParams = useSearchParams(); - const initialQuery = searchParams.get("query") || ""; - - const [query, setQuery] = useState(initialQuery); - const [debouncedQuery, setDebouncedQuery] = useState(initialQuery); - const [settings, setSettings] = useState([]); - const [loading, setLoading] = useState(true); - - useEffect(() => { - const timer = setTimeout(() => setDebouncedQuery(query), 300); - return () => clearTimeout(timer); - }, [query]); - - useEffect(() => { - fetch( - `${process.env.NEXT_PUBLIC_API_BASE_URL}/items/settings_co2gal?fields=submission_id,setting_title,uploader,photo.filename_disk,photo.title,mat.name,mat_coat.name,source.model,lens.field_size&limit=-1` - ) - .then((res) => res.json()) - .then((data) => { - setSettings(data.data || []); - setLoading(false); - }) - .catch(() => setLoading(false)); - }, []); - - const highlight = (text) => { - if (!debouncedQuery) return text; - const regex = new RegExp(`(${debouncedQuery})`, "gi"); - return text?.replace(regex, "$1"); - }; - - const filtered = useMemo(() => { - const q = debouncedQuery.toLowerCase(); - return settings.filter((entry) => { - const fieldsToSearch = [ - entry.setting_title, - entry.uploader, - entry.mat?.name, - entry.mat_coat?.name, - entry.source?.model, - entry.lens?.field_size, - ]; - return fieldsToSearch.filter(Boolean).some((field) => - String(field).toLowerCase().includes(q) - ); - }); - }, [settings, debouncedQuery]); - - const totalSettings = settings.length; - const uniqueMaterials = new Set(settings.map((s) => s.mat?.name).filter(Boolean)).size; - - const commonLens = settings.reduce((acc, cur) => { - const lens = cur.lens?.field_size; - if (!lens) return acc; - acc[lens] = (acc[lens] || 0) + 1; - return acc; - }, {}); - const mostCommonLens = Object.entries(commonLens) - .sort((a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0))[0]?.[0] || "—"; - - const sourceModels = settings.reduce((acc, cur) => { - const model = cur.source?.model; - if (!model) return acc; - acc[model] = (acc[model] || 0) + 1; - return acc; - }, {}); - const mostCommonSource = Object.entries(sourceModels) - .sort((a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0))[0]?.[0] || "—"; - - const recentSettings = [...settings] - .sort((a, b) => b.submission_id - a.submission_id) - .slice(0, 5); - - return ( -
- - -
-
-

CO₂ Galvo Settings

- setQuery(e.target.value)} - placeholder="Search settings by material, uploader, etc..." - className="w-full mb-4 dark:bg-background border border-border rounded-md p-2" - /> -

- View and explore detailed CO₂ galvo settings with context. -

-
- ← Back to Main Menu - -
- -
-

How to Use

-

- Browse real-world CO₂ galvo settings from the community. Use the search to narrow results. Click any setting to view its full configuration, notes, and photos. Click any linked term to find related settings. -

-
- -
-

Stats Summary

-
    -
  • Total Settings: {totalSettings}
  • -
  • Unique Materials: {uniqueMaterials}
  • -
  • Most Common Lens: {mostCommonLens}
  • -
  • Most Used Source: {mostCommonSource}
  • -
-
- -
-

Recently Added

-
    - {recentSettings.map((s) => ( -
  • - - {s.setting_title || "Untitled"} - {" "} - by {s.uploader || "—"} -
  • - ))} -
-
- -
-

Resources

- -
- -
-
-

Submit a Setting

-

- Have a reliable galvo setting to share? Contribute to the community database. -

-
- -
-
- - {loading ? ( -

Loading settings...

- ) : filtered.length === 0 ? ( -

No CO₂ galvo settings found.

- ) : ( -
- - - - - - - - - - - - - - {filtered.map((setting) => ( - - - - - ))} - -
PhotoTitleUploaderMaterialCoatingSourceLens
- {setting.photo?.filename_disk ? ( - {setting.photo.title - ) : ( - "—" - )} - - - - - - - -
-
- )} -
- ); -} - diff --git a/app/settings/co2-gantry/[id]/co2-gantry.tsx b/app/settings/co2-gantry/[id]/co2-gantry.tsx index 5a2d841b..c1359191 100644 --- a/app/settings/co2-gantry/[id]/co2-gantry.tsx +++ b/app/settings/co2-gantry/[id]/co2-gantry.tsx @@ -25,15 +25,19 @@ export default function CO2GantrySettingDetailPage() { "submission_id", "setting_title", "uploader", + // owner (M2O) — include username explicitly "owner.id", + "owner.username", "owner.first_name", "owner.last_name", "owner.email", + // content & assets "setting_notes", "photo.filename_disk", "photo.title", "screen.filename_disk", "screen.title", + // denormalized relations "mat.name", "mat_coat.name", "mat_color.name", @@ -41,9 +45,12 @@ export default function CO2GantrySettingDetailPage() { "mat_thickness", "source.make", "source.model", - "laser_soft.name", + // NOTE: laser_soft is a STRING field (not relation) + "laser_soft", + // gantry uses lens.name (not field_size) "lens.name", "lens_conf.name", + // misc fields "focus", "repeat_all", "fill_settings", @@ -66,11 +73,11 @@ export default function CO2GantrySettingDetailPage() { if (loading) return
Loading…
; if (!setting) return
Setting not found.
; + // Prefer owner's username per schema; return null when absent so claim UI shows const ownerName = (row: any) => { const o = row?.owner; if (!o) return null; - const name = [o.first_name, o.last_name].filter(Boolean).join(" ").trim(); - return name || o.email || null; + return o.username || null; }; const formatBoolean = (val: any) => @@ -108,7 +115,7 @@ export default function CO2GantrySettingDetailPage() { const openSearchInNewTab = (value: string) => { if (!value || typeof window === "undefined") return; - const url = new URL("/co2-gantry-settings", window.location.origin); + const url = new URL("/settings/co2-gantry", window.location.origin); url.searchParams.set("query", value); window.open(url.toString(), "_blank", "noopener,noreferrer"); }; @@ -181,7 +188,7 @@ export default function CO2GantrySettingDetailPage() {
← Back to CO₂ Gantry Settings @@ -239,7 +246,8 @@ export default function CO2GantrySettingDetailPage() { {/* Setup */}

Setup

-

Software: {setting.laser_soft?.name || "—"}

+ {/* laser_soft is a string field */} +

Software: {setting.laser_soft || "—"}

Repeat All (global): {setting.repeat_all ?? "—"}

Focus: {setting.focus ?? "—"} mm

-Values Focus Closer | +Values Focus Further diff --git a/app/settings/co2-gantry/page.tsx b/app/settings/co2-gantry/page.tsx index 367f42ae..c6381196 100644 --- a/app/settings/co2-gantry/page.tsx +++ b/app/settings/co2-gantry/page.tsx @@ -8,6 +8,7 @@ import Image from "next/image"; type Owner = { username?: string | null; id?: string | number; + // keep extras harmlessly in case API returns them first_name?: string | null; last_name?: string | null; email?: string | null; @@ -37,10 +38,10 @@ export default function CO2GantrySettingsPage() { "submission_id", "setting_title", "uploader", - "owner.id", "owner.username", - "owner.first_name", - "owner.last_name", - "owner.email", + // owner (M2O) – ensure username is requested + "owner.id", + "owner.username", + // assets / denorms "photo.id", "photo.title", "mat.name", @@ -64,10 +65,7 @@ export default function CO2GantrySettingsPage() { .finally(() => setLoading(false)); }, []); - const ownerLabel = (o?: Owner) => { - if (!o) return "—"; - return o.username || "—"; - }; + const ownerLabel = (o?: Owner) => (o?.username ?? "—"); const highlight = (text?: string) => { if (!debouncedQuery) return text || ""; @@ -94,7 +92,9 @@ export default function CO2GantrySettingsPage() { }, [settings, debouncedQuery]); const total = settings.length; - const uniqueMaterials = new Set(settings.map((s) => s.mat?.name).filter(Boolean)).size; + const uniqueMaterials = new Set( + settings.map((s) => s.mat?.name).filter(Boolean) + ).size; const lensCounts = settings.reduce((acc: Record, cur) => { const v = cur.lens?.name; @@ -103,179 +103,210 @@ export default function CO2GantrySettingsPage() { return acc; }, {}); const mostCommonLens = - Object.entries(lensCounts).sort((a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0))[0]?.[0] || - "—"; + Object.entries(lensCounts).sort( + (a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0) + )[0]?.[0] || "—"; -const srcCounts = settings.reduce((acc: Record, cur) => { - const v = cur.source?.model; - if (!v) return acc; - acc[v] = (acc[v] || 0) + 1; - return acc; -}, {}); -const mostCommonSource = -Object.entries(srcCounts).sort((a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0))[0]?.[0] || -"—"; + const srcCounts = settings.reduce((acc: Record, cur) => { + const v = cur.source?.model; + if (!v) return acc; + acc[v] = (acc[v] || 0) + 1; + return acc; + }, {}); + const mostCommonSource = + Object.entries(srcCounts).sort( + (a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0) + )[0]?.[0] || "—"; -const recent = [...settings] -.sort((a, b) => Number(b.submission_id) - Number(a.submission_id)) -.slice(0, 5); + const recent = [...settings] + .sort((a, b) => Number(b.submission_id) - Number(a.submission_id)) + .slice(0, 5); -return ( -
- + return ( +
+ - {/* Header / Search */} -
-
-

CO₂ Gantry Settings

- setQuery(e.target.value)} - placeholder="Search by material, owner, uploader, model, lens…" - className="w-full mb-4 dark:bg-background border border-border rounded-md p-2" - /> -

- Explore curated CO₂ gantry settings. Click any row to see full details. -

-
+ {/* Header / Search */} +
+
+

CO₂ Gantry Settings

+ setQuery(e.target.value)} + placeholder="Search by material, owner, uploader, model, lens…" + className="w-full mb-4 dark:bg-background border border-border rounded-md p-2" + /> +

+ Explore curated CO₂ gantry settings. Click any row to see full + details. +

+
- {/* Stats */} -
-

Stats Summary

-
    -
  • Total Settings: {total}
  • -
  • Unique Materials: {uniqueMaterials}
  • -
  • Most Common Lens: {mostCommonLens}
  • -
  • Most Used Source: {mostCommonSource}
  • -
-
+ {/* Stats */} +
+

Stats Summary

+
    +
  • Total Settings: {total}
  • +
  • Unique Materials: {uniqueMaterials}
  • +
  • Most Common Lens: {mostCommonLens}
  • +
  • Most Used Source: {mostCommonSource}
  • +
+
- {/* Recently Added */} -
-

Recently Added

-
    - {recent.map((s) => ( -
  • - - {s.setting_title || "Untitled"} - {" "} - - by {ownerLabel(s.owner)}{s.uploader ? ` (uploader: ${s.uploader})` : ""} - -
  • - ))} -
-
- - {/* Resources */} -
-
- - {/* Table */} - {loading ? ( -

Loading settings...

- ) : filtered.length === 0 ? ( -

No gantry settings found.

- ) : ( -
- - - - - - - - - - - - - - - {filtered.map((s) => ( - - - - + className="underline text-accent" + > + {s.setting_title || "Untitled"} + {" "} + + by {ownerLabel(s.owner)} + {s.uploader ? ` (uploader: ${s.uploader})` : ""} + + ))} - -
PhotoTitleOwnerUploaderMaterialCoatingSourceLens
- {s.photo?.id ? ( - {s.photo.title - ) : ( - "—" - )} - + {/* Recently Added */} +
+

Recently Added

+
    + {recent.map((s) => ( +
  • -
- - - - - -
+
- )} -
-); + + {/* Resources */} +
+

Resources

+ +
+
+ + {/* Table */} + {loading ? ( +

Loading settings...

+ ) : filtered.length === 0 ? ( +

No gantry settings found.

+ ) : ( +
+ + + + + + + + + + + + + + + {filtered.map((s) => ( + + + + + ))} + +
PhotoTitleOwnerUploaderMaterialCoatingSourceLens
+ {s.photo?.id ? ( + {s.photo.title + ) : ( + "—" + )} + + + + + + + + +
+
+ )} +
+ ); } diff --git a/app/settings/fiber/[id]/fiber.tsx b/app/settings/fiber/[id]/fiber.tsx index 20b6dfd5..7fdf8ee9 100644 --- a/app/settings/fiber/[id]/fiber.tsx +++ b/app/settings/fiber/[id]/fiber.tsx @@ -16,6 +16,8 @@ export default function FiberSettingDetailPage() { const [claimErr, setClaimErr] = useState(null); useEffect(() => { + if (!id) return; + const url = `${process.env.NEXT_PUBLIC_API_BASE_URL}/items/settings_fiber/${id}` + `?fields=` + @@ -23,15 +25,16 @@ export default function FiberSettingDetailPage() { "submission_id", "setting_title", "uploader", + // Owner (M2O): prefer username "owner.id", - "owner.first_name", - "owner.last_name", - "owner.email", + "owner.username", + // Content & assets "setting_notes", "photo.filename_disk", "photo.title", "screen.filename_disk", "screen.title", + // Relations / denorms "mat.name", "mat_coat.name", "mat_color.name", @@ -41,8 +44,9 @@ export default function FiberSettingDetailPage() { "source.model", "lens.field_size", "lens.focal_length", + // laser_soft is a STRING field + "laser_soft", "focus", - "laser_soft.name", "repeat_all", "fill_settings", "line_settings", @@ -62,11 +66,11 @@ export default function FiberSettingDetailPage() { if (loading) return

Loading setting...

; if (!setting) return

Setting not found.

; + // Prefer owner's username per schema const ownerName = (row: any) => { const o = row?.owner; if (!o) return null; - const name = [o.first_name, o.last_name].filter(Boolean).join(" ").trim(); - return name || o.email || null; + return o.username || null; }; const formatBoolean = (val: any) => @@ -103,7 +107,8 @@ export default function FiberSettingDetailPage() { }; const openSearchInNewTab = (value: string) => { - const url = new URL("/fiber-settings", window.location.origin); + if (!value || typeof window === "undefined") return; + const url = new URL("/settings/fiber", window.location.origin); url.searchParams.set("query", value); const a = document.createElement("a"); a.href = url.toString(); @@ -180,7 +185,7 @@ export default function FiberSettingDetailPage() {
← Back to Fiber Settings @@ -243,8 +248,9 @@ export default function FiberSettingDetailPage() { {/* Setup */}

Setup

+ {/* laser_soft is a string field */}

- Software: {setting.laser_soft?.name || "—"} + Software: {setting.laser_soft || "—"}

Repeat All (global): {setting.repeat_all ?? "—"} diff --git a/app/settings/uv/[id]/uv.tsx b/app/settings/uv/[id]/uv.tsx index f540cea7..6fc89d56 100644 --- a/app/settings/uv/[id]/uv.tsx +++ b/app/settings/uv/[id]/uv.tsx @@ -25,15 +25,16 @@ export default function UVSettingDetailPage() { "submission_id", "setting_title", "uploader", + // ✅ Owner (M2O) — use username (string) "owner.id", - "owner.first_name", - "owner.last_name", - "owner.email", + "owner.username", + // content & assets "setting_notes", "photo.filename_disk", "photo.title", "screen.filename_disk", "screen.title", + // relations / denorms "mat.name", "mat_coat.name", "mat_color.name", @@ -42,6 +43,7 @@ export default function UVSettingDetailPage() { "source.model", "lens.field_size", "lens.focal_length", + // misc "focus", "fill_settings", "line_settings", @@ -61,12 +63,8 @@ export default function UVSettingDetailPage() { if (loading) return

Loading setting...

; if (!setting) return

Setting not found.

; - const ownerName = (row: any) => { - const o = row?.owner; - if (!o) return null; - const name = [o.first_name, o.last_name].filter(Boolean).join(" ").trim(); - return name || o.email || null; - }; + // ✅ Prefer owner's username per schema + const ownerName = (row: any) => row?.owner?.username ?? null; const formatBoolean = (val: any) => val ? "Enabled" : val === false ? "Disabled" : "—"; @@ -88,10 +86,8 @@ export default function UVSettingDetailPage() { return (

{label}:{" "} - {typeof value === "boolean" - ? formatBoolean(value) - : value ?? "—"} -

+ {typeof value === "boolean" ? formatBoolean(value) : value ?? "—"} +

); })}
@@ -101,9 +97,10 @@ export default function UVSettingDetailPage() { ); }; + // ✅ Point searches/back link to /settings/uv const openSearchInNewTab = (value: string) => { if (!value || typeof window === "undefined") return; - const url = new URL("/uv-settings", window.location.origin); + const url = new URL("/settings/uv", window.location.origin); url.searchParams.set("query", value); const a = document.createElement("a"); a.href = url.toString(); @@ -180,7 +177,7 @@ export default function UVSettingDetailPage() {
← Back to UV Settings