feat(settings): add filtering and pagination to unified audit tab

This commit is contained in:
Usman Baig
2026-03-25 18:11:01 +01:00
parent 0cb13e08fd
commit 1fef7b175c

View File

@@ -30,18 +30,35 @@ const ACTION_LABELS: Record<string, string> = {
subscription_resumed: 'Resumed subscription', subscription_resumed: 'Resumed subscription',
} }
const PAGE_SIZE = 20
export default function WorkspaceAuditTab() { export default function WorkspaceAuditTab() {
const { user } = useAuth() const { user } = useAuth()
const [entries, setEntries] = useState<AuditLogEntry[]>([]) const [entries, setEntries] = useState<AuditLogEntry[]>([])
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
const [page, setPage] = useState(1)
const [total, setTotal] = useState(0)
const [actionFilter, setActionFilter] = useState('')
const [startDate, setStartDate] = useState('')
const [endDate, setEndDate] = useState('')
useEffect(() => { useEffect(() => {
if (!user?.org_id) return if (!user?.org_id) return
getAuditLog({ limit: 50 }) setLoading(true)
.then(data => setEntries(data.entries)) getAuditLog({
limit: PAGE_SIZE,
offset: (page - 1) * PAGE_SIZE,
...(actionFilter && { action: actionFilter }),
...(startDate && { start_date: startDate }),
...(endDate && { end_date: endDate }),
})
.then(data => {
setEntries(data.entries)
setTotal(data.total)
})
.catch(() => {}) .catch(() => {})
.finally(() => setLoading(false)) .finally(() => setLoading(false))
}, [user?.org_id]) }, [user?.org_id, page, actionFilter, startDate, endDate])
if (loading) return <div className="flex items-center justify-center py-12"><Spinner className="w-6 h-6 text-neutral-500" /></div> if (loading) return <div className="flex items-center justify-center py-12"><Spinner className="w-6 h-6 text-neutral-500" /></div>
@@ -52,6 +69,45 @@ export default function WorkspaceAuditTab() {
<p className="text-sm text-neutral-400">Track who made changes and when.</p> <p className="text-sm text-neutral-400">Track who made changes and when.</p>
</div> </div>
<div className="flex flex-wrap gap-2 items-end">
<div>
<label className="block text-xs text-neutral-500 mb-1">Action</label>
<input
type="text"
value={actionFilter}
onChange={e => { setActionFilter(e.target.value); setPage(1) }}
placeholder="e.g. site_created"
className="px-3 py-1.5 border border-neutral-700 rounded-lg bg-neutral-900 text-white text-sm w-40"
/>
</div>
<div>
<label className="block text-xs text-neutral-500 mb-1">From</label>
<input
type="date"
value={startDate}
onChange={e => { setStartDate(e.target.value); setPage(1) }}
className="px-3 py-1.5 border border-neutral-700 rounded-lg bg-neutral-900 text-white text-sm"
/>
</div>
<div>
<label className="block text-xs text-neutral-500 mb-1">To</label>
<input
type="date"
value={endDate}
onChange={e => { setEndDate(e.target.value); setPage(1) }}
className="px-3 py-1.5 border border-neutral-700 rounded-lg bg-neutral-900 text-white text-sm"
/>
</div>
{(actionFilter || startDate || endDate) && (
<button
onClick={() => { setActionFilter(''); setStartDate(''); setEndDate(''); setPage(1) }}
className="text-xs text-neutral-400 hover:text-white px-3 py-1.5"
>
Clear
</button>
)}
</div>
{entries.length === 0 ? ( {entries.length === 0 ? (
<p className="text-sm text-neutral-500 text-center py-8">No activity recorded yet.</p> <p className="text-sm text-neutral-500 text-center py-8">No activity recorded yet.</p>
) : ( ) : (
@@ -75,6 +131,28 @@ export default function WorkspaceAuditTab() {
))} ))}
</div> </div>
)} )}
<div className="flex items-center justify-between pt-3 border-t border-neutral-800">
<span className="text-xs text-neutral-500">
{total > 0 ? `${(page - 1) * PAGE_SIZE + 1}${Math.min(page * PAGE_SIZE, total)} of ${total}` : 'No entries'}
</span>
<div className="flex gap-2">
<button
onClick={() => setPage(p => Math.max(1, p - 1))}
disabled={page <= 1}
className="px-3 py-1 text-xs text-neutral-400 hover:text-white disabled:opacity-30"
>
Previous
</button>
<button
onClick={() => setPage(p => p + 1)}
disabled={page * PAGE_SIZE >= total}
className="px-3 py-1 text-xs text-neutral-400 hover:text-white disabled:opacity-30"
>
Next
</button>
</div>
</div>
</div> </div>
) )
} }