co2 galvo owner test

This commit is contained in:
makearmy 2025-10-01 20:57:05 -04:00
parent f61029a8ca
commit 2e08d68b24
3 changed files with 80 additions and 21 deletions

View file

@ -0,0 +1,23 @@
// app/api/dx/[...path]/route.ts
import { NextResponse } from "next/server";
import { requireBearer } from "@/app/api/_lib/auth";
const BASE = (process.env.DIRECTUS_URL || "").replace(/\/$/, "");
export async function GET(req: Request, { params }: { params: { path: string[] } }) {
const bearer = requireBearer(req);
const search = new URL(req.url).search || "";
const path = params.path.join("/");
const url = `${BASE}/${path}${search}`;
const res = await fetch(url, {
headers: { Accept: "application/json", Authorization: `Bearer ${bearer}` },
cache: "no-store",
});
const body = await res.text();
return new NextResponse(body, {
status: res.status,
headers: { "content-type": res.headers.get("content-type") || "application/json" },
});
}

View file

@ -1,3 +1,4 @@
// app/settings/co2-galvo/[id]/co2-galvo.tsx
"use client";
import { useEffect, useState } from "react";
@ -20,8 +21,12 @@ export default function CO2GalvoSettingDetailPage() {
"submission_id",
"setting_title",
"uploader",
// 👇 include parent + requested subfields
"owner",
"owner.id",
"owner.username",
"setting_notes",
"photo.filename_disk",
"photo.title",
@ -40,17 +45,19 @@ export default function CO2GalvoSettingDetailPage() {
"lens_apt.name",
"lens_exp.name",
"focus",
// string-or-relation safe
"laser_soft",
"laser_soft.name",
"repeat_all",
"fill_settings",
"line_settings",
"raster_settings",
].join(",");
const url =
`/api/dx/items/settings_co2gal/${encodeURIComponent(String(id))}` +
`?fields=${encodeURIComponent(fields)}`;
// use the authenticated proxy (sends ma_at automatically)
const url = `/api/dx/items/settings_co2gal/${encodeURIComponent(String(id))}?fields=${fields}`;
setLoading(true);
fetch(url, { cache: "no-store", credentials: "include" })
@ -72,6 +79,7 @@ export default function CO2GalvoSettingDetailPage() {
if (loading) return <p className="p-6">Loading setting...</p>;
if (!setting) return <p className="p-6">Setting not found.</p>;
// ---- display helpers ----
const ownerDisplay: string =
typeof setting?.owner === "object"
? (setting.owner?.username ?? setting.owner?.id ?? "—")

View file

@ -1,9 +1,9 @@
"use client";
import { useEffect, useState, useMemo } from "react";
import { useSearchParams } from "next/navigation";
import Link from "next/link";
import Image from "next/image";
import { useSearchParams } from "next/navigation";
type Owner = {
id?: string | number;
@ -30,14 +30,13 @@ export default function CO2GalvoSettingsPage() {
}, [query]);
useEffect(() => {
// ✅ use the auth proxy + include cookie so expansions (owner.*) work
const fields = [
"submission_id",
"setting_title",
"uploader",
// ensure relation expands
"owner.id",
"owner.username",
// assets / denorms
"photo.id",
"photo.title",
"mat.name",
@ -46,8 +45,10 @@ export default function CO2GalvoSettingsPage() {
"lens.field_size",
].join(",");
// IMPORTANT: go through our proxy so the user's ma_at cookie is used
const url = `/api/dx/items/settings_co2gal?fields=${encodeURIComponent(fields)}&limit=-1`;
const url =
`/api/dx/items/settings_co2gal` +
`?fields=${encodeURIComponent(fields)}` +
`&limit=-1`;
fetch(url, { cache: "no-store", credentials: "include" })
.then(async (res) => {
@ -65,7 +66,9 @@ export default function CO2GalvoSettingsPage() {
.finally(() => setLoading(false));
}, []);
const ownerLabel = (o?: Owner) => (o?.username ?? "—");
// robust owner label
const ownerLabel = (o?: Owner) =>
(o && (o.username || String(o.id || ""))) || "—";
const highlight = (text?: string) => {
if (!debouncedQuery) return text || "";
@ -92,7 +95,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<string, number>, cur) => {
const v = cur.lens?.field_size;
@ -101,7 +106,9 @@ 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<string, number>, cur) => {
const v = cur.source?.model;
@ -110,9 +117,13 @@ export default function CO2GalvoSettingsPage() {
return acc;
}, {});
const mostCommonSource =
Object.entries(srcCounts).sort((a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0))[0]?.[0] || "—";
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 (
<div className="p-6 max-w-7xl mx-auto">
@ -167,7 +178,10 @@ export default function CO2GalvoSettingsPage() {
<ul className="text-sm space-y-1">
{recent.map((s) => (
<li key={s.submission_id}>
<Link href={detailHref(s.submission_id)} className="underline text-accent">
<Link
href={detailHref(s.submission_id)}
className="underline text-accent"
>
{s.setting_title || "Untitled"}
</Link>{" "}
<span className="text-muted-foreground">
@ -220,32 +234,46 @@ export default function CO2GalvoSettingsPage() {
<Link
href={detailHref(s.submission_id)}
className="text-accent underline"
dangerouslySetInnerHTML={{ __html: highlight(s.setting_title || "—") }}
dangerouslySetInnerHTML={{
__html: highlight(s.setting_title || "—"),
}}
/>
</td>
<td
className="px-2 py-2 whitespace-nowrap"
dangerouslySetInnerHTML={{ __html: highlight(ownerLabel(s.owner)) }}
dangerouslySetInnerHTML={{
__html: highlight(ownerLabel(s.owner)),
}}
/>
<td
className="px-2 py-2 whitespace-nowrap"
dangerouslySetInnerHTML={{ __html: highlight(s.uploader || "—") }}
dangerouslySetInnerHTML={{
__html: highlight(s.uploader || "—"),
}}
/>
<td
className="px-2 py-2 whitespace-nowrap"
dangerouslySetInnerHTML={{ __html: highlight(s.mat?.name || "—") }}
dangerouslySetInnerHTML={{
__html: highlight(s.mat?.name || "—"),
}}
/>
<td
className="px-2 py-2 whitespace-nowrap"
dangerouslySetInnerHTML={{ __html: highlight(s.mat_coat?.name || "—") }}
dangerouslySetInnerHTML={{
__html: highlight(s.mat_coat?.name || "—"),
}}
/>
<td
className="px-2 py-2 whitespace-nowrap"
dangerouslySetInnerHTML={{ __html: highlight(s.source?.model || "—") }}
dangerouslySetInnerHTML={{
__html: highlight(s.source?.model || "—"),
}}
/>
<td
className="px-2 py-2 whitespace-nowrap"
dangerouslySetInnerHTML={{ __html: highlight(s.lens?.field_size || "—") }}
dangerouslySetInnerHTML={{
__html: highlight(s.lens?.field_size || "—"),
}}
/>
</tr>
))}