You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
12 KiB
188 lines
12 KiB
@extends('layouts.app') |
|
|
|
@section('title', 'LDAP Users — ' . config('app.name')) |
|
|
|
@section('content') |
|
<div class="max-w-[1600px] mx-auto px-4 py-8"> |
|
@include('partials.nav') |
|
|
|
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4 mb-8 mt-6"> |
|
<div> |
|
<h1 class="text-3xl font-bold text-white">LDAP Users</h1> |
|
<p class="text-slate-400 mt-1 text-sm"> |
|
Host: <span class="text-cyan-400">{{ $meta['server'] }}</span> |
|
@if ($meta['domain']) |
|
· Domain: <span class="text-cyan-400">{{ $meta['domain'] }}</span> |
|
@endif |
|
</p> |
|
</div> |
|
</div> |
|
|
|
@include('partials.flash') |
|
|
|
@if ($error) |
|
<div class="mb-6 rounded-lg bg-red-950/50 border border-red-800 text-red-200 px-4 py-3"> |
|
{{ $error }} |
|
</div> |
|
@endif |
|
|
|
<div class="flex flex-col xl:flex-row gap-6 items-start xl:items-stretch"> |
|
<div class="flex-1 min-w-0 bg-slate-900 border border-slate-800 rounded-2xl overflow-hidden w-full flex flex-col list-panel xl:sticky xl:top-4"> |
|
<div class="list-panel__toolbar p-4 border-b border-slate-800 flex flex-col md:flex-row gap-3 md:items-center md:justify-between bg-slate-900"> |
|
<form method="GET" class="flex flex-wrap gap-2 w-full md:w-auto"> |
|
<input type="hidden" name="sort" value="{{ $sort }}"> |
|
<input type="hidden" name="dir" value="{{ $dir }}"> |
|
<input name="q" value="{{ $search }}" placeholder="Search user, email, phone, note, or group..." |
|
class="flex-1 min-w-[12rem] md:w-56 rounded-lg bg-slate-800 border border-slate-700 px-4 py-2 text-sm text-white"> |
|
<select name="group" |
|
class="rounded-lg bg-slate-800 border border-slate-700 px-3 py-2 text-sm text-white min-w-[10rem]"> |
|
<option value="">All groups</option> |
|
@foreach ($meta['all_groups'] ?? [] as $groupName) |
|
<option value="{{ $groupName }}" @selected($groupFilter === $groupName)>{{ $groupName }}</option> |
|
@endforeach |
|
</select> |
|
<button class="rounded-lg bg-cyan-600 hover:bg-cyan-500 px-4 py-2 text-sm font-medium">Filter</button> |
|
@if ($search !== '' || $groupFilter !== '') |
|
<a href="{{ route('ldap-users.index', ['sort' => $sort, 'dir' => $dir]) }}" |
|
class="rounded-lg border border-slate-700 px-4 py-2 text-sm text-slate-300 hover:bg-slate-800"> |
|
Clear |
|
</a> |
|
@endif |
|
</form> |
|
<div class="text-sm text-slate-400">{{ $meta['total'] }} users</div> |
|
</div> |
|
|
|
<div class="list-panel__scroll"> |
|
<table class="min-w-full text-sm border-collapse list-table"> |
|
<thead class="text-slate-300"> |
|
<tr> |
|
@php |
|
$columns = [ |
|
'username' => 'Username', |
|
'display_name' => 'Display Name', |
|
'email' => 'Email', |
|
'phone' => 'Phone', |
|
'enabled' => 'Status', |
|
'last_logon' => 'Last Logon', |
|
'groups' => 'Groups', |
|
]; |
|
@endphp |
|
@foreach ($columns as $key => $label) |
|
@php |
|
$nextDir = ($sort === $key && $dir === 'asc') ? 'desc' : 'asc'; |
|
$arrow = $sort === $key ? ($dir === 'asc' ? '↑' : '↓') : ''; |
|
@endphp |
|
<th class="sticky top-0 z-10 px-4 py-3 text-left font-medium whitespace-nowrap bg-slate-800 border-b border-slate-700"> |
|
<a href="?sort={{ $key }}&dir={{ $nextDir }}&q={{ urlencode($search) }}&group={{ urlencode($groupFilter) }}" |
|
class="hover:text-cyan-400">{{ $label }} {{ $arrow }}</a> |
|
</th> |
|
@endforeach |
|
<th class="sticky top-0 z-10 px-4 py-3 text-left font-medium whitespace-nowrap bg-slate-800 border-b border-slate-700">Meta</th> |
|
<th class="sticky top-0 z-10 px-4 py-3 text-left font-medium whitespace-nowrap bg-slate-800 border-b border-slate-700">Actions</th> |
|
</tr> |
|
</thead> |
|
<tbody class="divide-y divide-slate-800"> |
|
@forelse ($users as $user) |
|
<tr class="hover:bg-slate-800/40"> |
|
<td class="px-4 py-3 font-medium text-white whitespace-nowrap">{{ $user['username'] }}</td> |
|
<td class="px-4 py-3 text-slate-300 whitespace-nowrap">{{ $user['display_name'] }}</td> |
|
<td class="px-4 py-3 text-slate-300 whitespace-nowrap">{{ $user['email'] }}</td> |
|
<td class="px-4 py-3 text-slate-300 whitespace-nowrap">{{ $user['phone'] !== '' ? $user['phone'] : '—' }}</td> |
|
<td class="px-4 py-3"> |
|
<span class="inline-flex rounded-full px-2 py-1 text-xs font-medium |
|
{{ $user['enabled'] ? 'bg-emerald-950 text-emerald-300' : 'bg-amber-950 text-amber-300' }}"> |
|
{{ $user['enabled'] ? 'Enabled' : 'Disabled' }} |
|
</span> |
|
</td> |
|
<td class="px-4 py-3 text-slate-300 whitespace-nowrap">{{ $user['last_logon'] ?? '—' }}</td> |
|
<td class="px-4 py-3"> |
|
@if (count($user['groups']) === 0) |
|
<span class="text-slate-500">—</span> |
|
@else |
|
<div class="flex flex-wrap gap-1 max-w-md"> |
|
@foreach ($user['groups'] as $groupName) |
|
<a href="{{ route('ldap-groups.show', $groupName) }}" |
|
class="inline-flex rounded-md bg-slate-800 border border-slate-700 px-2 py-0.5 text-xs text-slate-300 hover:border-cyan-700 hover:text-cyan-300 whitespace-nowrap" |
|
title="View group members"> |
|
{{ $groupName }} |
|
</a> |
|
@endforeach |
|
</div> |
|
@endif |
|
</td> |
|
<td class="px-4 py-3 whitespace-nowrap max-w-[10rem]"> |
|
@if (($user['other_email'] ?? '') !== '' || ($user['admin_note'] ?? '') !== '') |
|
<div class="text-xs text-slate-400 truncate" title="{{ $user['admin_note'] ?? '' }}"> |
|
@if (($user['other_email'] ?? '') !== '') |
|
<span class="text-slate-300">{{ $user['other_email'] }}</span> |
|
@endif |
|
@if (($user['admin_note'] ?? '') !== '') |
|
<span class="block truncate">{{ Str::limit($user['admin_note'], 40) }}</span> |
|
@endif |
|
</div> |
|
@else |
|
<span class="text-slate-500">—</span> |
|
@endif |
|
</td> |
|
<td class="px-4 py-3 whitespace-nowrap"> |
|
<a href="{{ route('ldap-users.show', $user['username']) }}" |
|
class="rounded bg-slate-700 hover:bg-slate-600 text-white text-xs px-2 py-1">View</a> |
|
@if ($user['protected']) |
|
<span class="text-xs text-slate-500 ml-1">Protected</span> |
|
@else |
|
<div class="flex flex-wrap gap-1 mt-1"> |
|
<a href="{{ route('ldap-users.edit', $user['username']) }}" |
|
class="rounded bg-slate-700 hover:bg-slate-600 text-white text-xs px-2 py-1">Edit</a> |
|
<form method="POST" action="{{ route('ldap-users.toggle-enabled', $user['username']) }}" class="inline" |
|
onsubmit="return confirm('{{ $user['enabled'] ? 'Disable' : 'Enable' }} account [{{ $user['username'] }}]?');"> |
|
@csrf |
|
<input type="hidden" name="confirm" value="1"> |
|
<button type="submit" class="rounded text-xs px-2 py-1 text-white |
|
{{ $user['enabled'] ? 'bg-amber-700 hover:bg-amber-600' : 'bg-emerald-700 hover:bg-emerald-600' }}"> |
|
{{ $user['enabled'] ? 'Disable' : 'Enable' }} |
|
</button> |
|
</form> |
|
<a href="{{ route('ldap-users.password', $user['username']) }}" |
|
class="rounded bg-violet-700 hover:bg-violet-600 text-white text-xs px-2 py-1">Password</a> |
|
</div> |
|
@endif |
|
</td> |
|
</tr> |
|
@empty |
|
<tr> |
|
<td colspan="9" class="px-4 py-8 text-center text-slate-400">No users found.</td> |
|
</tr> |
|
@endforelse |
|
</tbody> |
|
</table> |
|
</div> |
|
</div> |
|
|
|
<aside class="w-full xl:w-80 shrink-0 bg-slate-900 border border-slate-800 rounded-2xl p-5 xl:sticky xl:top-4 notes-panel"> |
|
<h2 class="text-lg font-semibold text-white mb-4">Catatan</h2> |
|
<dl class="space-y-4 text-sm"> |
|
<div> |
|
<dt class="font-medium text-cyan-400 mb-1">Data aplikasi</dt> |
|
<dd class="text-slate-400">Phone, other email, dan admin note disimpan di database (bukan LDAP).</dd> |
|
</div> |
|
<div> |
|
<dt class="font-medium text-cyan-400 mb-1">Edit profil</dt> |
|
<dd class="text-slate-400">Ubah display name dan email via LDAP modify.</dd> |
|
</div> |
|
<div> |
|
<dt class="font-medium text-violet-400 mb-1">Reset password</dt> |
|
<dd class="text-slate-400">Membutuhkan LDAPS (port 636). Konfirmasi ganda wajib.</dd> |
|
</div> |
|
<div> |
|
<dt class="font-medium text-cyan-400 mb-1">Groups</dt> |
|
<dd class="text-slate-400">Klik badge group untuk melihat anggota. Filter dropdown untuk analisa per group.</dd> |
|
</div> |
|
<div> |
|
<dt class="font-medium text-amber-400 mb-1">Akun protected</dt> |
|
<dd class="text-slate-400">Administrator, Guest, krbtgt tidak dapat dimodifikasi.</dd> |
|
</div> |
|
</dl> |
|
</aside> |
|
</div> |
|
</div> |
|
@endsection
|
|
|