Extract types, constants, helpers, and UI pieces (shared LoadingSkeleton/ EmptyState/StatusBadge/CopyButton, SSOConfigFormModal, DeleteConfirmModal, ConnectionTestPanel, SSOConfigCard, SSOUsersTable, SSOInfoSection) into _components/ and _types.ts to bring page.tsx from 1482 LOC to 339 LOC (under the 500 hard cap). Behavior preserved. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
88 lines
3.3 KiB
TypeScript
88 lines
3.3 KiB
TypeScript
'use client'
|
|
|
|
import { CheckCircle2, Users, XCircle } from 'lucide-react'
|
|
import type { SSOUser } from '../_types'
|
|
import { formatDate } from './helpers'
|
|
import { EmptyState, LoadingSkeleton } from './shared'
|
|
|
|
export function SSOUsersTable({
|
|
users,
|
|
loading,
|
|
}: {
|
|
users: SSOUser[]
|
|
loading: boolean
|
|
}) {
|
|
if (loading) {
|
|
return <LoadingSkeleton rows={4} />
|
|
}
|
|
|
|
if (users.length === 0) {
|
|
return (
|
|
<EmptyState
|
|
icon={<Users className="w-8 h-8 text-slate-400" />}
|
|
title="Keine SSO-Benutzer"
|
|
description="Es wurden noch keine Benutzer ueber SSO provisioniert. Benutzer erscheinen hier nach dem ersten Login."
|
|
/>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="overflow-x-auto">
|
|
<table className="w-full">
|
|
<thead>
|
|
<tr className="border-b border-slate-200">
|
|
<th className="text-left py-3 px-4 text-sm font-medium text-slate-500">Name</th>
|
|
<th className="text-left py-3 px-4 text-sm font-medium text-slate-500">E-Mail</th>
|
|
<th className="text-left py-3 px-4 text-sm font-medium text-slate-500">Externe ID</th>
|
|
<th className="text-left py-3 px-4 text-sm font-medium text-slate-500">Gruppen</th>
|
|
<th className="text-left py-3 px-4 text-sm font-medium text-slate-500">Letzter Login</th>
|
|
<th className="text-left py-3 px-4 text-sm font-medium text-slate-500">Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{users.map(user => (
|
|
<tr key={user.id} className="border-b border-slate-100 hover:bg-slate-50">
|
|
<td className="py-3 px-4">
|
|
<div className="font-medium text-slate-900">{user.display_name}</div>
|
|
</td>
|
|
<td className="py-3 px-4 text-sm text-slate-600">{user.email}</td>
|
|
<td className="py-3 px-4">
|
|
<span className="text-xs text-slate-500 font-mono">{user.external_id}</span>
|
|
</td>
|
|
<td className="py-3 px-4">
|
|
<div className="flex gap-1 flex-wrap">
|
|
{user.groups.length > 0 ? (
|
|
user.groups.map(group => (
|
|
<span key={group} className="px-2 py-0.5 bg-slate-100 text-slate-600 rounded text-xs">
|
|
{group}
|
|
</span>
|
|
))
|
|
) : (
|
|
<span className="text-xs text-slate-400">-</span>
|
|
)}
|
|
</div>
|
|
</td>
|
|
<td className="py-3 px-4 text-sm text-slate-500">
|
|
{formatDate(user.last_login)}
|
|
</td>
|
|
<td className="py-3 px-4">
|
|
{user.is_active ? (
|
|
<span className="inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-green-100 text-green-700 rounded-full">
|
|
<CheckCircle2 className="w-3 h-3" />
|
|
Aktiv
|
|
</span>
|
|
) : (
|
|
<span className="inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-slate-100 text-slate-500 rounded-full">
|
|
<XCircle className="w-3 h-3" />
|
|
Inaktiv
|
|
</span>
|
|
)}
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
)
|
|
}
|