feat(ST-xmwvqru1): /admin/jobs pagina met status-filter, cancel en delete-dialog
- app/(app)/admin/layout.tsx: sidebar-nav (Gebruikers/Claude Jobs/Producten) - app/(app)/admin/page.tsx: redirect naar /admin/jobs - app/(app)/admin/jobs/page.tsx: server component, query jobs+user+product, status-filter via searchParams - components/admin/jobs-table.tsx: StatusFilter (router.push op select), JobsTable met status-badges (MD3 tokens), CancelButton (disabled in eindstatus), DeleteDialog
This commit is contained in:
parent
788920b790
commit
667b1484f6
4 changed files with 239 additions and 0 deletions
42
app/(app)/admin/jobs/page.tsx
Normal file
42
app/(app)/admin/jobs/page.tsx
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import { requireAdmin } from '@/lib/auth-guard'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
import type { ClaudeJobStatus } from '@prisma/client'
|
||||
import { JobsTable, StatusFilter } from '@/components/admin/jobs-table'
|
||||
|
||||
const VALID_STATUSES = new Set<ClaudeJobStatus>([
|
||||
'QUEUED', 'CLAIMED', 'RUNNING', 'DONE', 'FAILED', 'CANCELLED',
|
||||
])
|
||||
|
||||
export default async function AdminJobsPage({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: Promise<{ status?: string }>
|
||||
}) {
|
||||
await requireAdmin()
|
||||
|
||||
const params = await searchParams
|
||||
const rawStatus = params.status ?? ''
|
||||
const statusFilter = VALID_STATUSES.has(rawStatus as ClaudeJobStatus)
|
||||
? (rawStatus as ClaudeJobStatus)
|
||||
: undefined
|
||||
|
||||
const jobs = await prisma.claudeJob.findMany({
|
||||
where: statusFilter ? { status: statusFilter } : undefined,
|
||||
include: {
|
||||
user: { select: { username: true } },
|
||||
product: { select: { name: true } },
|
||||
},
|
||||
orderBy: { created_at: 'desc' },
|
||||
take: 200,
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h1 className="text-xl font-semibold text-foreground">Claude Jobs</h1>
|
||||
<StatusFilter current={rawStatus} />
|
||||
</div>
|
||||
<JobsTable jobs={jobs} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
16
app/(app)/admin/layout.tsx
Normal file
16
app/(app)/admin/layout.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { requireAdmin } from '@/lib/auth-guard'
|
||||
import Link from 'next/link'
|
||||
|
||||
export default async function AdminLayout({ children }: { children: React.ReactNode }) {
|
||||
await requireAdmin()
|
||||
return (
|
||||
<div className="flex min-h-screen">
|
||||
<nav className="w-48 border-r p-4 flex flex-col gap-2">
|
||||
<Link href="/admin/users" className="text-sm font-medium text-foreground hover:text-primary">Gebruikers</Link>
|
||||
<Link href="/admin/jobs" className="text-sm font-medium text-foreground hover:text-primary">Claude Jobs</Link>
|
||||
<Link href="/admin/products" className="text-sm font-medium text-foreground hover:text-primary">Producten</Link>
|
||||
</nav>
|
||||
<main className="flex-1 p-6">{children}</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
5
app/(app)/admin/page.tsx
Normal file
5
app/(app)/admin/page.tsx
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
import { redirect } from 'next/navigation'
|
||||
|
||||
export default function AdminPage() {
|
||||
redirect('/admin/jobs')
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue