Audit log viewer

A filterable security log table with severity badges, row-level background tinting for critical entries, a fixed header so column names stay visible while scrolling, and a live search that filters across multiple fields at once.

Timestamp
Severity
User
Action
Resource
IP
2024-05-16 09:01:12
info
aria.chen
LOGIN
/dashboard
10.0.1.42
2024-05-16 09:03:44
info
marcus.webb
VIEW
/reports/q1
10.0.1.18
2024-05-16 09:12:05
warning
aria.chen
EXPORT
/users/all
10.0.1.42
2024-05-16 09:15:30
error
unknown
LOGIN_FAILED
/auth
203.0.113.7
2024-05-16 09:15:31
error
unknown
LOGIN_FAILED
/auth
203.0.113.7
2024-05-16 09:15:32
critical
unknown
BRUTE_FORCE
/auth
203.0.113.7
2024-05-16 09:22:18
info
priya.kapoor
UPDATE
/settings/theme
10.0.1.55
2024-05-16 09:31:00
warning
jordan.ellis
DELETE
/reports/draft-4
10.0.2.11
2024-05-16 09:45:09
info
sam.rivera
DEPLOY
/infra/staging
10.0.1.99
2024-05-16 10:02:44
critical
system
DB_CONN_LOST
/db/primary
10.0.0.1
2024-05-16 10:03:01
critical
system
FAILOVER
/db/replica
10.0.0.2
2024-05-16 10:15:22
info
aria.chen
LOGOUT
/auth
10.0.1.42
2024-05-16 10:28:33
warning
taylor.brooks
PERMISSION_DENY
/admin/users
10.0.1.77
2024-05-16 10:55:50
error
system
DISK_FULL
/storage/logs
10.0.0.5
2024-05-16 11:10:04
info
marcus.webb
LOGIN
/dashboard
10.0.1.18

Fixed header with capped scroll height

Set fixedHeader and fixedHeaderScrollHeight so the table body scrolls independently while the column headers stay pinned:

<DataTable
  fixedHeader
  fixedHeaderScrollHeight="340px"
  columns={columns}
  data={logs}
/>

Severity row tinting

Use conditionalRowStyles to give critical and error rows a distinct background without adding a visual column:

const conditionalRowStyles: ConditionalStyles<LogEntry>[] = [
  { when: r => r.severity === 'critical', style: { backgroundColor: '#fef2f2' } },
  { when: r => r.severity === 'error',    style: { backgroundColor: '#fff7f7' } },
];

Multi-field live search

Filter client-side across several fields by combining a search string with a severity toggle — no extra library needed:

const filtered = logs.filter(r => {
  if (severity !== 'all' && r.severity !== severity) return false;
  if (search) {
    const q = search.toLowerCase();
    return r.user.includes(q) || r.action.includes(q)
      || r.resource.includes(q) || r.ip.includes(q);
  }
  return true;
});