co2 galvo owner test
This commit is contained in:
parent
f61029a8ca
commit
2e08d68b24
3 changed files with 80 additions and 21 deletions
23
app/api/dx/[...path]/route.ts
Normal file
23
app/api/dx/[...path]/route.ts
Normal 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" },
|
||||
});
|
||||
}
|
||||
|
|
@ -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 ?? "—")
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
))}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue