Add entry_id relationship links to Entries
- Introduce reusable EntryLink component - Use EntryLink in Releases and Label detail tables - Link both ID and title to /zxdb/entries/[id] for consistency Signed-off-by: Junie@MacOS
This commit is contained in:
18
src/app/zxdb/components/EntryLink.tsx
Normal file
18
src/app/zxdb/components/EntryLink.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
|
||||
type Props = {
|
||||
id: number;
|
||||
title?: string;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export default function EntryLink({ id, title, className }: Props) {
|
||||
const text = typeof title === "string" && title.length > 0 ? title : `#${id}`;
|
||||
return (
|
||||
<Link href={`/zxdb/entries/${id}`} className={className}>
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import Link from "next/link";
|
||||
import EntryLink from "../components/EntryLink";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
|
||||
type Item = {
|
||||
@@ -244,9 +245,9 @@ export default function EntriesExplorer({
|
||||
<tbody>
|
||||
{data.items.map((it) => (
|
||||
<tr key={it.id}>
|
||||
<td>{it.id}</td>
|
||||
<td><EntryLink id={it.id} /></td>
|
||||
<td>
|
||||
<Link href={`/zxdb/entries/${it.id}`}>{it.title}</Link>
|
||||
<EntryLink id={it.id} title={it.title} />
|
||||
</td>
|
||||
<td>
|
||||
{it.machinetypeId != null ? (
|
||||
|
||||
@@ -66,6 +66,9 @@ export type EntryDetailData = {
|
||||
year: number | null;
|
||||
}[];
|
||||
}[];
|
||||
// Additional relationships
|
||||
aliases?: { releaseSeq: number; languageId: string; title: string }[];
|
||||
webrefs?: { link: string; languageId: string; website: { id: number; name: string; link?: string | null } }[];
|
||||
};
|
||||
|
||||
export default function EntryDetailClient({ data }: { data: EntryDetailData | null }) {
|
||||
@@ -286,6 +289,74 @@ export default function EntryDetailClient({ data }: { data: EntryDetailData | nu
|
||||
|
||||
<hr />
|
||||
|
||||
{/* Aliases (alternative titles) */}
|
||||
<div>
|
||||
<h5>Aliases</h5>
|
||||
{(!data.aliases || data.aliases.length === 0) && <div className="text-secondary">No aliases</div>}
|
||||
{data.aliases && data.aliases.length > 0 && (
|
||||
<div className="table-responsive">
|
||||
<table className="table table-sm table-striped align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={{ width: 90 }}>Release #</th>
|
||||
<th style={{ width: 120 }}>Language</th>
|
||||
<th>Title</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.aliases.map((a, idx) => (
|
||||
<tr key={`${a.releaseSeq}-${a.languageId}-${idx}`}>
|
||||
<td>#{a.releaseSeq}</td>
|
||||
<td>{a.languageId}</td>
|
||||
<td>{a.title}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
{/* Web links (external references) */}
|
||||
<div>
|
||||
<h5>Web links</h5>
|
||||
{(!data.webrefs || data.webrefs.length === 0) && <div className="text-secondary">No web links</div>}
|
||||
{data.webrefs && data.webrefs.length > 0 && (
|
||||
<div className="table-responsive">
|
||||
<table className="table table-sm table-striped align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Website</th>
|
||||
<th style={{ width: 120 }}>Language</th>
|
||||
<th>URL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.webrefs.map((w, idx) => (
|
||||
<tr key={`${w.website.id}-${idx}`}>
|
||||
<td>
|
||||
{w.website.link ? (
|
||||
<a href={w.website.link} target="_blank" rel="noopener noreferrer">{w.website.name}</a>
|
||||
) : (
|
||||
<span>{w.website.name}</span>
|
||||
)}
|
||||
</td>
|
||||
<td>{w.languageId}</td>
|
||||
<td>
|
||||
<a href={w.link} target="_blank" rel="noopener noreferrer">{w.link}</a>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div>
|
||||
<h5>Files</h5>
|
||||
{(!data.files || data.files.length === 0) && <div className="text-secondary">No files linked</div>}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import EntryLink from "../../components/EntryLink";
|
||||
import { useMemo, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
@@ -69,8 +70,8 @@ export default function LabelDetailClient({ id, initial, initialTab, initialQ }:
|
||||
<tbody>
|
||||
{current.items.map((it) => (
|
||||
<tr key={it.id}>
|
||||
<td>{it.id}</td>
|
||||
<td><Link href={`/zxdb/entries/${it.id}`}>{it.title}</Link></td>
|
||||
<td><EntryLink id={it.id} /></td>
|
||||
<td><EntryLink id={it.id} title={it.title} /></td>
|
||||
<td>
|
||||
{it.machinetypeId != null ? (
|
||||
it.machinetypeName ? (
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import Link from "next/link";
|
||||
import EntryLink from "../components/EntryLink";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
|
||||
type Item = {
|
||||
@@ -313,9 +314,11 @@ export default function ReleasesExplorer({
|
||||
<tbody>
|
||||
{data.items.map((it) => (
|
||||
<tr key={`${it.entryId}-${it.releaseSeq}`}>
|
||||
<td>{it.entryId}</td>
|
||||
<td>
|
||||
<Link href={`/zxdb/entries/${it.entryId}`}>{it.entryTitle}</Link>
|
||||
<EntryLink id={it.entryId} />
|
||||
</td>
|
||||
<td>
|
||||
<EntryLink id={it.entryId} title={it.entryTitle} />
|
||||
</td>
|
||||
<td>#{it.releaseSeq}</td>
|
||||
<td>{it.year ?? <span className="text-secondary">-</span>}</td>
|
||||
|
||||
Reference in New Issue
Block a user