feat(#41): admin/renders pagination + user name link + output + project name
Build backend images / build content-svc (push) Failing after 1m1s
Build backend images / build file-svc (push) Failing after 56s
Build backend images / build gateway (push) Failing after 49s
Build backend images / build identity-svc (push) Failing after 50s
Build backend images / build notification-svc (push) Failing after 49s
Build backend images / build render-svc (push) Failing after 1m2s
Build backend images / build studio-svc (push) Failing after 47s

render-svc admin-renders enriches jobs with user_name/email (cross-schema lookup to
identity.users). Page adds prev/next pagination (page_size 30). Table adds User column
(name → /admin/users?q=email) and Output column (export → /admin/exports), and shows
project_name. Verified: 21 jobs, paginated, names resolved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-07 05:24:47 +03:30
parent d56bcf1b23
commit fca6bcac53
4 changed files with 100 additions and 6 deletions
+30 -4
View File
@@ -10,6 +10,9 @@ export type V2RenderJob = {
id: string;
saved_project_id: string;
user_id: string;
user_name?: string;
user_email?: string;
project_name?: string | null;
status: string;
step: string;
progress: number;
@@ -17,6 +20,7 @@ export type V2RenderJob = {
resolution: string;
frame_rate: number;
node_id: string | null;
export_id?: string | null;
error_message: string | null;
created_at: string;
updated_at: string;
@@ -24,20 +28,26 @@ export type V2RenderJob = {
interface V2RenderList {
data: V2RenderJob[];
meta?: { total?: number };
meta?: { total?: number; page?: number; page_size?: number; has_more?: boolean };
}
const PAGE_SIZE = 30;
export default async function AdminRendersPage({
searchParams,
}: {
searchParams: { step?: string };
searchParams: { step?: string; page?: string };
}) {
const step = searchParams.step ?? "";
const page = Math.max(1, Number(searchParams.page) || 1);
// Admin endpoint → all users' jobs (not just the caller's).
const qs = step ? `?status=${step}&page_size=50` : "?page_size=50";
const data = await adminGet<V2RenderList>(`/v1/admin-renders${qs}`);
const params = new URLSearchParams({ page: String(page), page_size: String(PAGE_SIZE) });
if (step) params.set("status", step);
const data = await adminGet<V2RenderList>(`/v1/admin-renders?${params}`);
const jobs = data?.data ?? [];
const total = data?.meta?.total ?? 0;
const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE));
const stepQs = step ? `&step=${step}` : "";
const t = await getTranslations("auto.appAdminRendersPage");
const steps = ["Queued", "Preparing", "Rendering", "Uploading", "Done", "Failed", "Cancelled"];
@@ -88,6 +98,22 @@ export default async function AdminRendersPage({
</div>
<RenderQueueTable jobs={jobs} />
{totalPages > 1 && (
<div className="flex items-center justify-center gap-3 pt-2 text-sm">
{page > 1 ? (
<a href={`/admin/renders?page=${page - 1}${stepQs}`} className="rounded-lg border border-[#262b40] px-3 py-1.5 text-gray-300 hover:bg-[#161a2e]">قبلی</a>
) : (
<span className="rounded-lg border border-[#1a1d2e] px-3 py-1.5 text-gray-600">قبلی</span>
)}
<span className="text-gray-400">صفحهٔ {page.toLocaleString("fa-IR")} از {totalPages.toLocaleString("fa-IR")}</span>
{page < totalPages ? (
<a href={`/admin/renders?page=${page + 1}${stepQs}`} className="rounded-lg border border-[#262b40] px-3 py-1.5 text-gray-300 hover:bg-[#161a2e]">بعدی</a>
) : (
<span className="rounded-lg border border-[#1a1d2e] px-3 py-1.5 text-gray-600">بعدی</span>
)}
</div>
)}
</div>
);
}