Files
SkinbaseNova/resources/js/Pages/Moderation/Enhance/Show.jsx

118 lines
8.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React from 'react'
import { Head, Link, router, usePage } from '@inertiajs/react'
import BeforeAfterSlider from '../../../components/enhance/BeforeAfterSlider'
import EnhanceStatusBadge from '../../../components/enhance/EnhanceStatusBadge'
import EnhanceStubWarning from '../../../components/enhance/EnhanceStubWarning'
import { formatEnhanceDate } from '../../../utils/enhanceFormatting'
function formatDate(value) {
return formatEnhanceDate(value)
}
function DetailRow({ label, value }) {
return (
<div className="flex items-start justify-between gap-4 border-b border-white/[0.06] py-3 last:border-b-0 last:pb-0">
<dt className="text-sm text-slate-400">{label}</dt>
<dd className="text-right text-sm text-white">{value}</dd>
</div>
)
}
export default function ModerationEnhanceShow() {
const { props } = usePage()
const job = props.job || {}
const flash = props.flash || {}
const errors = props.errors || {}
return (
<div className="w-full px-6 pb-16 pt-8">
<Head title={`Enhance Job #${job.id || ''}`} />
<section className="rounded-[32px] border border-white/10 bg-[radial-gradient(circle_at_top_left,rgba(56,189,248,0.16),transparent_36%),linear-gradient(180deg,rgba(15,23,42,0.96),rgba(2,6,23,0.92))] p-6 shadow-[0_24px_70px_rgba(2,6,23,0.32)]">
<div className="flex flex-col gap-4 xl:flex-row xl:items-end xl:justify-between">
<div>
<div className="flex flex-wrap items-center gap-2">
<EnhanceStatusBadge status={job.status} />
<span className="rounded-full border border-white/10 bg-white/[0.05] px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-200">{job.scale}x</span>
<span className="rounded-full border border-white/10 bg-white/[0.05] px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-200">{job.mode}</span>
<span className="rounded-full border border-white/10 bg-white/[0.05] px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-200">{job.engine}</span>
</div>
<h1 className="mt-3 text-3xl font-semibold tracking-[-0.04em] text-white">Enhance job #{job.id}</h1>
<p className="mt-2 max-w-3xl text-sm leading-relaxed text-slate-300">Created by {job.user?.name || 'Unknown user'} {job.user?.username ? `(@${job.user.username})` : ''}.</p>
</div>
<div className="flex flex-wrap gap-3">
<Link href={props.indexUrl} className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.05] px-5 py-3 text-xs font-semibold uppercase tracking-[0.14em] text-white transition hover:bg-white/[0.09]">
<i className="fa-solid fa-arrow-left text-[10px]" />
Back to list
</Link>
{job.download_url ? <a href={job.download_url} className="inline-flex items-center gap-2 rounded-full border border-emerald-300/20 bg-emerald-400/12 px-5 py-3 text-xs font-semibold uppercase tracking-[0.14em] text-emerald-50 transition hover:bg-emerald-400/20">Download output</a> : null}
{job.can_retry ? <button type="button" onClick={() => router.post(job.retry_url)} className="inline-flex items-center gap-2 rounded-full border border-amber-300/20 bg-amber-400/12 px-5 py-3 text-xs font-semibold uppercase tracking-[0.14em] text-amber-50 transition hover:bg-amber-400/20">Retry</button> : null}
{job.can_mark_failed ? <button type="button" onClick={() => router.post(job.mark_failed_url)} className="inline-flex items-center gap-2 rounded-full border border-rose-300/20 bg-rose-400/12 px-5 py-3 text-xs font-semibold uppercase tracking-[0.14em] text-rose-100 transition hover:bg-rose-400/20">Mark failed</button> : null}
<button type="button" onClick={() => {
if (!window.confirm('Delete this enhance job and any owned enhance files?')) return
router.delete(job.delete_url)
}} className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.05] px-5 py-3 text-xs font-semibold uppercase tracking-[0.14em] text-white transition hover:bg-white/[0.09]">Delete</button>
</div>
</div>
</section>
<EnhanceStubWarning config={props.enhanceConfig} moderation className="mt-6" />
{flash.success ? <div className="mt-6 rounded-2xl border border-emerald-300/20 bg-emerald-400/10 px-4 py-3 text-sm text-emerald-50">{flash.success}</div> : null}
{flash.error ? <div className="mt-6 rounded-2xl border border-rose-300/20 bg-rose-400/10 px-4 py-3 text-sm text-rose-100">{flash.error}</div> : null}
{errors.job ? <div className="mt-6 rounded-2xl border border-rose-300/20 bg-rose-400/10 px-4 py-3 text-sm text-rose-100">{errors.job}</div> : null}
{job.source_url && job.output_url ? <div className="mt-8"><BeforeAfterSlider beforeUrl={job.source_url} afterUrl={job.output_url} /></div> : null}
<div className="mt-8 grid gap-6 xl:grid-cols-[minmax(0,1.2fr)_380px]">
<div className="space-y-6">
<section className="rounded-[30px] border border-white/10 bg-[#08111d] p-6 shadow-[0_18px_48px_rgba(2,6,23,0.2)]">
<div className="grid gap-6 lg:grid-cols-2">
<div>
<div className="mb-3 text-[11px] font-semibold uppercase tracking-[0.22em] text-slate-400">Source image</div>
<div className="overflow-hidden rounded-[24px] border border-white/10 bg-black/20">
{job.source_url ? <img src={job.source_url} alt="Enhance source" className="w-full object-cover" /> : <div className="flex min-h-[280px] items-center justify-center text-white/20"><i className="fa-solid fa-image text-4xl" /></div>}
</div>
</div>
<div>
<div className="mb-3 text-[11px] font-semibold uppercase tracking-[0.22em] text-slate-400">Output image</div>
<div className="overflow-hidden rounded-[24px] border border-white/10 bg-black/20">
{job.output_url ? <img src={job.output_url} alt="Enhance output" className="w-full object-cover" /> : <div className="flex min-h-[280px] items-center justify-center text-white/20"><i className="fa-solid fa-hourglass-half text-4xl" /></div>}
</div>
</div>
</div>
</section>
<section className="rounded-[30px] border border-white/10 bg-[#08111d] p-6 shadow-[0_18px_48px_rgba(2,6,23,0.2)]">
<div className="text-[11px] font-semibold uppercase tracking-[0.22em] text-slate-400">Metadata</div>
<div className="mt-4 rounded-[24px] border border-white/10 bg-black/20 p-4 text-sm text-slate-200">
<pre className="overflow-x-auto whitespace-pre-wrap break-words">{JSON.stringify(job.metadata || {}, null, 2)}</pre>
</div>
</section>
{job.error_message ? <section className="rounded-[30px] border border-rose-300/20 bg-rose-400/10 p-6 text-sm text-rose-100 shadow-[0_18px_48px_rgba(2,6,23,0.2)]">{job.error_message}</section> : null}
</div>
<aside className="rounded-[30px] border border-white/10 bg-[#08111d] p-6 shadow-[0_18px_48px_rgba(2,6,23,0.2)]">
<div className="text-[11px] font-semibold uppercase tracking-[0.22em] text-slate-400">Processing details</div>
<dl className="mt-4">
<DetailRow label="Created" value={formatDate(job.created_at)} />
<DetailRow label="Queued" value={formatDate(job.queued_at)} />
<DetailRow label="Started" value={formatDate(job.started_at)} />
<DetailRow label="Finished" value={formatDate(job.finished_at)} />
<DetailRow label="Expires" value={formatDate(job.expires_at)} />
<DetailRow label="Input mime" value={job.input_mime || '—'} />
<DetailRow label="Input size" value={job.input_filesize ? `${(job.input_filesize / 1024 / 1024).toFixed(2)} MB` : '—'} />
<DetailRow label="Input dimensions" value={job.input_width && job.input_height ? `${job.input_width} × ${job.input_height}` : '—'} />
<DetailRow label="Output mime" value={job.output_mime || '—'} />
<DetailRow label="Output size" value={job.output_filesize ? `${(job.output_filesize / 1024 / 1024).toFixed(2)} MB` : '—'} />
<DetailRow label="Output dimensions" value={job.output_width && job.output_height ? `${job.output_width} × ${job.output_height}` : '—'} />
<DetailRow label="Processing seconds" value={job.processing_seconds ?? '—'} />
<DetailRow label="Artwork" value={job.artwork?.title ? <a href={job.artwork.url} className="text-sky-300 hover:text-sky-200">{job.artwork.title}</a> : 'Standalone upload'} />
</dl>
</aside>
</div>
</div>
)
}