listDoorCards (door.operate, service client, masked last4 only) lists active cards with the slot each holds on a connection. /door/manage now passes canOperate (door.operate rpc) and, when set, shows per-connection Open/Unlock/Lock and an expandable card list with Grant/Revoke. Every live action is behind a confirm; grant shows the allocated slot.
31 lines
949 B
TypeScript
31 lines
949 B
TypeScript
import { requireDoorManagerPage } from '@/lib/door-guard'
|
|
import { listDoorConnections, listSecretTitles, listDoorAccessLog } from '@/lib/actions'
|
|
import { DoorManageClient } from './door-manage-client'
|
|
|
|
export const dynamic = 'force-dynamic'
|
|
|
|
export default async function DoorManagePage() {
|
|
const { supabase, member } = await requireDoorManagerPage()
|
|
|
|
const { data: canOperate } = await supabase.rpc('user_has_permission', {
|
|
uid: member.user_id as string,
|
|
sid: member.space_id,
|
|
perm: 'door.operate',
|
|
})
|
|
|
|
const [conns, secrets, log] = await Promise.all([
|
|
listDoorConnections(),
|
|
listSecretTitles(),
|
|
listDoorAccessLog(),
|
|
])
|
|
|
|
return (
|
|
<DoorManageClient
|
|
initial={'data' in conns ? (conns.data as unknown[]) : []}
|
|
secrets={'data' in secrets ? (secrets.data as { id: string; title: string }[]) : []}
|
|
log={'data' in log ? (log.data as unknown[]) : []}
|
|
canOperate={!!canOperate}
|
|
/>
|
|
)
|
|
}
|