feat: enhance booking and audit log functionalities

- Implemented read-only locking for customer-requested container sizes and billing currency in the GlCreateBookingForm component.
- Added functionality to lock partner quantities based on shipment requests in the ConsolidationPartnerPanel.
- Introduced a new Leave action in the LogPassYardWorkModal to unassign bookings from trains.
- Enhanced the AuditLogsPage to support filtering by action and added a Go button for direct navigation to entity detail pages.
- Updated WagonCancellationsPage to handle odd-20ft credits requiring partner selection during rebooking.
- Improved TrainScheduleV2DetailPage to allow manual loading of cargo and display warnings for unassigned bookings.
- Added a new reference field to the audit logs for better searchability and tracking of actions.
- Created a migration to add the reference column to the audit logs table and established an index for efficient querying.
- Defined a registry for audit reference sources to streamline the retrieval of human identifiers for various entities.
This commit is contained in:
Marshal
2026-08-24 23:49:20 +00:00
parent 2a107e8ba3
commit d5a5085d6d
28 changed files with 1356 additions and 86 deletions

View File

@@ -36,6 +36,8 @@ export interface AuditLog {
userName: string | null;
userRole: string | null;
resourceId: string | null;
/** Human identifier of the record (booking reference, train number); '' when unknown. */
reference: string;
/** Sanitized request body; files appear as `__file` descriptors. */
request: Record<string, unknown> | null;
ipAddress: string | null;
@@ -52,6 +54,14 @@ export interface AuditLogQuery {
userId?: string;
method?: AuditMethod;
resourceId?: string;
/** Case-insensitive prefix match on the human identifier. */
reference?: string;
/** Staff name, substring match. */
userName?: string;
/** Action title, substring match. */
title?: string;
/** Free text across reference, record id, staff name and action title. */
q?: string;
/** Omit for "any outcome". */
isSuccess?: boolean;
/** Inclusive ISO 8601 bounds. */
@@ -72,6 +82,10 @@ function toParams(query: AuditLogQuery): Record<string, string | number> {
if (query.userId) params.userId = query.userId;
if (query.method) params.method = query.method;
if (query.resourceId) params.resourceId = query.resourceId;
if (query.reference) params.reference = query.reference;
if (query.userName) params.userName = query.userName;
if (query.title) params.title = query.title;
if (query.q) params.q = query.q;
if (query.isSuccess !== undefined) params.isSuccess = String(query.isSuccess);
if (query.from) params.from = query.from;
if (query.to) params.to = query.to;
@@ -94,4 +108,10 @@ export const auditLogsService = {
const response = await client.get<ApiResponse<string[]>>(`${BASE}/types`);
return unwrap(response.data);
},
/** Distinct action titles present, for the action filter dropdown. */
actions: async (): Promise<string[]> => {
const response = await client.get<ApiResponse<string[]>>(`${BASE}/actions`);
return unwrap(response.data);
},
};