AuditLogDetail kısmı çalışmıyordu düzeltildi.

This commit is contained in:
Sedat Öztürk 2026-05-25 21:30:08 +03:00
parent 0f5d44ceb0
commit d50c62cd1c
6 changed files with 142 additions and 66 deletions

View file

@ -5,11 +5,11 @@ namespace Sozsoft.Platform.AuditLogs;
public class AuditLogActionDto : EntityDto<Guid> public class AuditLogActionDto : EntityDto<Guid>
{ {
public virtual Guid AuditLogId { get; protected set; } public virtual Guid AuditLogId { get; set; }
public virtual string ServiceName { get; protected set; } public virtual string ServiceName { get; set; }
public virtual string MethodName { get; protected set; } public virtual string MethodName { get; set; }
public virtual string Parameters { get; protected set; } public virtual string Parameters { get; set; }
public virtual DateTime ExecutionTime { get; protected set; } public virtual DateTime ExecutionTime { get; set; }
public virtual int ExecutionDuration { get; protected set; } public virtual int ExecutionDuration { get; set; }
} }

View file

@ -13,24 +13,24 @@ public class AuditLogDto : EntityDto<Guid>
} }
public string ApplicationName { get; set; } public string ApplicationName { get; set; }
public Guid? UserId { get; protected set; } public Guid? UserId { get; set; }
public string UserName { get; protected set; } public string UserName { get; set; }
public Guid? TenantId { get; protected set; } public Guid? TenantId { get; set; }
public string TenantName { get; protected set; } public string TenantName { get; set; }
public DateTime ExecutionTime { get; protected set; } public DateTime ExecutionTime { get; set; }
public int ExecutionDuration { get; protected set; } public int ExecutionDuration { get; set; }
public string ClientIpAddress { get; protected set; } public string ClientIpAddress { get; set; }
public string ClientName { get; protected set; } public string ClientName { get; set; }
public string ClientId { get; set; } public string ClientId { get; set; }
public string CorrelationId { get; set; } public string CorrelationId { get; set; }
public string BrowserInfo { get; protected set; } public string BrowserInfo { get; set; }
public string HttpMethod { get; protected set; } public string HttpMethod { get; set; }
public string Url { get; protected set; } public string Url { get; set; }
public string Exceptions { get; protected set; } public string Exceptions { get; set; }
public string Comments { get; protected set; } public string Comments { get; set; }
public int? HttpStatusCode { get; set; } public int? HttpStatusCode { get; set; }
public ICollection<EntityChangeDto> EntityChanges { get; protected set; } public ICollection<EntityChangeDto> EntityChanges { get; set; }
public ICollection<AuditLogActionDto> Actions { get; protected set; } public ICollection<AuditLogActionDto> Actions { get; set; }
public int? EntityChangeCount { get; set; } public int? EntityChangeCount { get; set; }

View file

@ -12,12 +12,12 @@ public class EntityChangeDto : EntityDto<Guid>
PropertyChanges = new List<EntityPropertyChangeDto>(); PropertyChanges = new List<EntityPropertyChangeDto>();
} }
public virtual Guid AuditLogId { get; protected set; } public virtual Guid AuditLogId { get; set; }
public virtual DateTime ChangeTime { get; protected set; } public virtual DateTime ChangeTime { get; set; }
public virtual EntityChangeType ChangeType { get; protected set; } public virtual EntityChangeType ChangeType { get; set; }
public virtual Guid? EntityTenantId { get; protected set; } public virtual Guid? EntityTenantId { get; set; }
public virtual string EntityId { get; protected set; } public virtual string EntityId { get; set; }
public virtual string EntityTypeFullName { get; protected set; } public virtual string EntityTypeFullName { get; set; }
public virtual ICollection<EntityPropertyChangeDto> PropertyChanges { get; protected set; } public virtual ICollection<EntityPropertyChangeDto> PropertyChanges { get; set; }
} }

View file

@ -5,10 +5,10 @@ namespace Sozsoft.Platform.AuditLogs;
public class EntityPropertyChangeDto : EntityDto<Guid> public class EntityPropertyChangeDto : EntityDto<Guid>
{ {
public virtual Guid EntityChangeId { get; protected set; } public virtual Guid EntityChangeId { get; set; }
public virtual string NewValue { get; protected set; } public virtual string NewValue { get; set; }
public virtual string OriginalValue { get; protected set; } public virtual string OriginalValue { get; set; }
public virtual string PropertyName { get; protected set; } public virtual string PropertyName { get; set; }
public virtual string PropertyTypeFullName { get; protected set; } public virtual string PropertyTypeFullName { get; set; }
} }

View file

@ -1,4 +1,6 @@
export interface AuditLogActionDto { export interface AuditLogActionDto {
id: string
auditLogId: string
serviceName: string serviceName: string
methodName: string methodName: string
executionTime: string // Date string executionTime: string // Date string
@ -7,6 +9,8 @@ export interface AuditLogActionDto {
} }
export interface EntityPropertyChangeDto { export interface EntityPropertyChangeDto {
id: string
entityChangeId: string
propertyName: string propertyName: string
propertyTypeFullName: string propertyTypeFullName: string
originalValue: string | null originalValue: string | null
@ -14,8 +18,11 @@ export interface EntityPropertyChangeDto {
} }
export interface EntityChangeDto { export interface EntityChangeDto {
id: string
auditLogId: string
changeTime: string // Date string changeTime: string // Date string
changeType: number changeType: number
entityTenantId?: string
entityId: string entityId: string
entityTypeFullName: string entityTypeFullName: string
propertyChanges: EntityPropertyChangeDto[] propertyChanges: EntityPropertyChangeDto[]

View file

@ -69,10 +69,40 @@ function AuditLogs({
} }
const formatDuration = (ms: number) => { const formatDuration = (ms: number) => {
if (ms === undefined || ms === null) return 'Unknown'
if (ms < 1000) return `${ms}ms` if (ms < 1000) return `${ms}ms`
return `${(ms / 1000).toFixed(2)}s` return `${(ms / 1000).toFixed(2)}s`
} }
const formatDateTime = (value?: string) => {
if (!value) return 'Unknown'
const date = new Date(value)
if (Number.isNaN(date.getTime()) || date.getFullYear() <= 1) return 'Unknown'
return date.toLocaleString('tr-TR', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
})
}
const formatValue = (value?: string | number | null) => {
if (value === undefined || value === null || value === '') return 'Unknown'
return value
}
const formatJson = (value: string) => {
try {
return JSON.stringify(JSON.parse(value), null, 2)
} catch {
return value
}
}
const InfoRow = ({ icon: Icon, label, value, valueClassName = '' }: any) => ( const InfoRow = ({ icon: Icon, label, value, valueClassName = '' }: any) => (
<div className="flex items-start gap-3 py-2 border-b border-gray-100 last:border-0"> <div className="flex items-start gap-3 py-2 border-b border-gray-100 last:border-0">
<Icon className="w-5 h-5 text-gray-400 mt-0.5 flex-shrink-0" /> <Icon className="w-5 h-5 text-gray-400 mt-0.5 flex-shrink-0" />
@ -86,7 +116,7 @@ function AuditLogs({
return ( return (
<Dialog width="90%" isOpen={open} onClose={onDialogClose} onRequestClose={onDialogClose}> <Dialog width="90%" isOpen={open} onClose={onDialogClose} onRequestClose={onDialogClose}>
{/* Header */} {/* Header */}
<div className="flex items-center justify-between mb-6 pb-4 border-b border-gray-200 dark:border-gray-700"> <div className="flex items-center justify-between mb-2 pb-2 border-b border-gray-200 dark:border-gray-700">
<div> <div>
<h4 className="text-xl font-bold text-gray-800 dark:text-gray-100">Audit Log Details</h4> <h4 className="text-xl font-bold text-gray-800 dark:text-gray-100">Audit Log Details</h4>
{selectedLog?.id && <p className="text-sm text-gray-500 dark:text-gray-400 mt-1">ID: {selectedLog.id}</p>} {selectedLog?.id && <p className="text-sm text-gray-500 dark:text-gray-400 mt-1">ID: {selectedLog.id}</p>}
@ -113,7 +143,7 @@ function AuditLogs({
</div> </div>
) : ( ) : (
<Tabs defaultValue="log" variant="pill"> <Tabs defaultValue="log" variant="pill">
<TabList className="mb-6 bg-gray-50 dark:bg-gray-800 p-1 rounded-lg"> <TabList className="mb-2 bg-gray-50 dark:bg-gray-800 p-1 rounded-lg">
<TabNav value="log"> <TabNav value="log">
<FaRegFileAlt className="w-4 h-4 mr-2" /> <FaRegFileAlt className="w-4 h-4 mr-2" />
<span className="text-gray-700 dark:text-gray-200">Overview</span> <span className="text-gray-700 dark:text-gray-200">Overview</span>
@ -145,7 +175,7 @@ function AuditLogs({
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6"> <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* Request Information */} {/* Request Information */}
<AdaptableCard className="shadow-sm dark:bg-gray-900 dark:border-gray-700"> <AdaptableCard className="shadow-sm dark:bg-gray-900 dark:border-gray-700">
<h6 className="font-semibold text-gray-700 dark:text-gray-200 mb-4 flex items-center gap-2"> <h6 className="font-semibold text-gray-700 dark:text-gray-200 mb-2 flex items-center gap-2">
<FaGlobe className="w-5 h-5 text-blue-500 dark:text-blue-400" /> <FaGlobe className="w-5 h-5 text-blue-500 dark:text-blue-400" />
Request Information Request Information
</h6> </h6>
@ -153,20 +183,13 @@ function AuditLogs({
<InfoRow <InfoRow
icon={FaUser} icon={FaUser}
label="User" label="User"
value={selectedLog.userName || 'Anonymous'} value={selectedLog.userName || selectedLog.userId || 'Anonymous'}
valueClassName="font-medium text-gray-800 dark:text-gray-100" valueClassName="font-medium text-gray-800 dark:text-gray-100"
/> />
<InfoRow <InfoRow
icon={FaRegClock} icon={FaRegClock}
label="Execution Time" label="Execution Time"
value={new Date(selectedLog.executionTime).toLocaleString('tr-TR', { value={formatDateTime(selectedLog.executionTime)}
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
})}
/> />
<InfoRow <InfoRow
icon={FaRegClock} icon={FaRegClock}
@ -181,14 +204,33 @@ function AuditLogs({
<InfoRow <InfoRow
icon={FaGlobe} icon={FaGlobe}
label="Client IP" label="Client IP"
value={selectedLog.clientIpAddress || 'Unknown'} value={formatValue(selectedLog.clientIpAddress)}
/>
<InfoRow
icon={FaRegFileAlt}
label="Client Name"
value={formatValue(selectedLog.clientName)}
/>
<InfoRow
icon={FaRegFileAlt}
label="Client ID"
value={formatValue(selectedLog.clientId)}
/>
<InfoRow
icon={FaUser}
label="Tenant"
value={
selectedLog.tenantName ||
selectedLog.tenantId ||
'Host'
}
/> />
</div> </div>
</AdaptableCard> </AdaptableCard>
{/* HTTP Details */} {/* HTTP Details */}
<AdaptableCard className="shadow-sm dark:bg-gray-900 dark:border-gray-700"> <AdaptableCard className="shadow-sm dark:bg-gray-900 dark:border-gray-700">
<h6 className="font-semibold text-gray-700 dark:text-gray-200 mb-4 flex items-center gap-2"> <h6 className="font-semibold text-gray-700 dark:text-gray-200 mb-2 flex items-center gap-2">
<FaCode className="w-5 h-5 text-green-500 dark:text-green-400" /> <FaCode className="w-5 h-5 text-green-500 dark:text-green-400" />
HTTP Details HTTP Details
</h6> </h6>
@ -197,6 +239,7 @@ function AuditLogs({
icon={FaCode} icon={FaCode}
label="Method" label="Method"
value={ value={
selectedLog.httpMethod ? (
<Badge <Badge
className={ className={
selectedLog.httpMethod === 'POST' selectedLog.httpMethod === 'POST'
@ -211,6 +254,9 @@ function AuditLogs({
} }
content={selectedLog.httpMethod} content={selectedLog.httpMethod}
></Badge> ></Badge>
) : (
'Unknown'
)
} }
/> />
<InfoRow <InfoRow
@ -221,7 +267,7 @@ function AuditLogs({
<InfoRow <InfoRow
icon={FaGlobe} icon={FaGlobe}
label="URL" label="URL"
value={selectedLog.url} value={formatValue(selectedLog.url)}
valueClassName="text-blue-600 dark:text-blue-400 font-mono text-xs" valueClassName="text-blue-600 dark:text-blue-400 font-mono text-xs"
/> />
<InfoRow <InfoRow
@ -233,6 +279,12 @@ function AuditLogs({
</span> </span>
} }
/> />
<InfoRow
icon={FaRegFileAlt}
label="Correlation ID"
value={formatValue(selectedLog.correlationId)}
valueClassName="font-mono text-xs"
/>
</div> </div>
</AdaptableCard> </AdaptableCard>
@ -291,13 +343,25 @@ function AuditLogs({
<div> <div>
<p className="text-xs text-gray-500 dark:text-gray-400 mb-1">Service Name</p> <p className="text-xs text-gray-500 dark:text-gray-400 mb-1">Service Name</p>
<p className="text-sm font-mono text-gray-700 dark:text-gray-200 break-all"> <p className="text-sm font-mono text-gray-700 dark:text-gray-200 break-all">
{action.serviceName} {formatValue(action.serviceName)}
</p>
</div>
<div>
<p className="text-xs text-gray-500 dark:text-gray-400 mb-1">Method Name</p>
<p className="text-sm font-mono text-gray-700 dark:text-gray-200 break-all">
{formatValue(action.methodName)}
</p> </p>
</div> </div>
<div> <div>
<p className="text-xs text-gray-500 dark:text-gray-400 mb-1">Execution Time</p> <p className="text-xs text-gray-500 dark:text-gray-400 mb-1">Execution Time</p>
<p className="text-sm text-gray-700 dark:text-gray-200"> <p className="text-sm text-gray-700 dark:text-gray-200">
{new Date(action.executionTime).toLocaleString('tr-TR')} {formatDateTime(action.executionTime)}
</p>
</div>
<div>
<p className="text-xs text-gray-500 dark:text-gray-400 mb-1">Action ID</p>
<p className="text-sm font-mono text-gray-700 dark:text-gray-200 break-all">
{formatValue(action.id)}
</p> </p>
</div> </div>
</div> </div>
@ -306,7 +370,7 @@ function AuditLogs({
<div> <div>
<p className="text-xs text-gray-500 dark:text-gray-400 mb-2">Parameters</p> <p className="text-xs text-gray-500 dark:text-gray-400 mb-2">Parameters</p>
<pre className="bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 p-3 rounded-lg text-xs overflow-x-auto text-gray-700 dark:text-gray-200"> <pre className="bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 p-3 rounded-lg text-xs overflow-x-auto text-gray-700 dark:text-gray-200">
{JSON.stringify(JSON.parse(action.parameters), null, 2)} {formatJson(action.parameters)}
</pre> </pre>
</div> </div>
)} )}
@ -338,12 +402,17 @@ function AuditLogs({
{change.entityTypeFullName} {change.entityTypeFullName}
</h6> </h6>
<p className="text-xs text-gray-500 dark:text-gray-400">ID: {change.entityId}</p> <p className="text-xs text-gray-500 dark:text-gray-400">ID: {change.entityId}</p>
{change.entityTenantId && (
<p className="text-xs text-gray-500 dark:text-gray-400">
Tenant ID: {change.entityTenantId}
</p>
)}
</div> </div>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{getChangeTypeBadge(change.changeType)} {getChangeTypeBadge(change.changeType)}
<span className="text-xs text-gray-500 dark:text-gray-400"> <span className="text-xs text-gray-500 dark:text-gray-400">
{new Date(change.changeTime).toLocaleTimeString('tr-TR')} {formatDateTime(change.changeTime)}
</span> </span>
</div> </div>
</div> </div>