fix: route manufacturing audit logs to shared Postgres audit log

- Manufacturing router now uses shared/audit.log_action (Postgres) instead
  of the separate manufacturing/audit.py (SQLite mfg_audit_log), so all
  manufacturing events appear in the Log Viewer
- Added log_action calls to 5 previously unlogged endpoints: lifecycle
  patch, lifecycle create, lifecycle delete, flash asset upload, flash
  asset note
- Removed the now-redundant /manufacturing/audit-log endpoint
- Log Viewer restricted to sysadmin only: backend uses require_sysadmin
  (was require_admin_or_above), frontend adds role guard on the page
- Fixed Action badge column clipping: table-layout auto + whiteSpace nowrap
  so the column sizes to fit the widest badge (Status Change)
- Added device_batch entity type to Log Viewer entity labels and filters

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-14 19:21:39 +03:00
parent 9a213e93f8
commit 024ba88470
3 changed files with 173 additions and 85 deletions

View File

@@ -32,17 +32,18 @@ const ACTION_META = {
}
const ENTITY_LABELS = {
customer: 'Customer',
order: 'Order',
device: 'Device',
melody: 'Melody',
product: 'Product',
staff: 'Staff',
ticket: 'Ticket',
note: 'Note',
quotation: 'Quotation',
firmware: 'Firmware',
archetype: 'Archetype',
customer: 'Customer',
order: 'Order',
device: 'Device',
device_batch: 'Device Batch',
melody: 'Melody',
product: 'Product',
staff: 'Staff',
ticket: 'Ticket',
note: 'Note',
quotation: 'Quotation',
firmware: 'Firmware',
archetype: 'Archetype',
}
const ACTION_OPTIONS = [
@@ -246,7 +247,7 @@ function LogRow({ entry, isExpanded, onToggle }) {
</td>
{/* Action badge */}
<td className="log-cell">
<td className="log-cell" style={{ whiteSpace: 'nowrap' }}>
<StatusBadge variant={variant}>{label}</StatusBadge>
</td>
@@ -492,9 +493,7 @@ const INITIAL_FILTERS = {
offset: 0,
}
export default function LogViewerPage() {
const { user } = useAuth()
function LogViewerContent() {
const [entries, setEntries] = useState([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
@@ -592,7 +591,7 @@ export default function LogViewerPage() {
.log-table {
width: 100%;
border-collapse: collapse;
table-layout: fixed;
table-layout: auto;
}
.log-table thead th {
padding: var(--space-2) var(--space-4);
@@ -668,7 +667,7 @@ export default function LogViewerPage() {
<tr>
<th style={{ width: 148 }}>Timestamp</th>
<th style={{ width: 160 }}>Staff</th>
<th style={{ width: 110 }}>Action</th>
<th style={{ whiteSpace: 'nowrap' }}>Action</th>
<th>Entity</th>
<th style={{ width: 120 }}>ID</th>
<th style={{ width: 40 }} />
@@ -752,3 +751,20 @@ export default function LogViewerPage() {
</>
)
}
export default function LogViewerPage() {
const { hasRole } = useAuth()
if (!hasRole('sysadmin')) {
return (
<div className="page-wrapper">
<PageHeader title="Log Viewer" subtitle="Staff actions and system events across the console" />
<div style={{ padding: 'var(--space-12)', textAlign: 'center', color: 'var(--color-text-muted)', fontSize: 'var(--font-size-sm)' }}>
Access restricted to system administrators.
</div>
</div>
)
}
return <LogViewerContent />
}