Spaces:
Running
Running
import { Component, EventEmitter, Output, inject, OnInit } from '@angular/core'; | |
import { CommonModule } from '@angular/common'; | |
import { HttpClient } from '@angular/common/http'; | |
interface ActivityLog { | |
id: number; | |
timestamp: string; | |
user: string; | |
action: string; | |
entity_type: string; | |
entity_id: any; | |
entity_name: string; | |
details?: string; | |
} | |
({ | |
selector: 'app-activity-log', | |
standalone: true, | |
imports: [CommonModule], | |
template: ` | |
<div class="activity-log-dropdown" (click)="$event.stopPropagation()"> | |
<div class="activity-header"> | |
<h3>π Recent Activities</h3> | |
<button class="close-btn" (click)="close.emit()">Γ</button> | |
</div> | |
<div class="activity-list"> | |
@if (loading) { | |
<div class="loading">Loading...</div> | |
} @else if (activities.length === 0) { | |
<div class="empty">No recent activities</div> | |
} @else { | |
@for (activity of activities; track activity.id) { | |
<div class="activity-item"> | |
<div class="activity-time">{{ getRelativeTime(activity.timestamp) }}</div> | |
<div class="activity-content"> | |
<strong>{{ activity.user }}</strong> {{ getActionText(activity) }} | |
<em>{{ activity.entity_name }}</em> | |
</div> | |
</div> | |
} | |
} | |
</div> | |
<div class="activity-footer"> | |
<button class="btn btn-secondary" (click)="loadMore()">View All Activities</button> | |
</div> | |
</div> | |
`, | |
styles: [` | |
.activity-log-dropdown { | |
position: absolute; | |
top: 100%; | |
right: 0; | |
width: 350px; | |
background: white; | |
border: 1px solid #dee2e6; | |
border-radius: 8px; | |
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); | |
z-index: 1000; | |
margin-top: 0.5rem; | |
} | |
.activity-header { | |
padding: 1rem; | |
border-bottom: 1px solid #dee2e6; | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
h3 { | |
margin: 0; | |
font-size: 1.1rem; | |
} | |
.close-btn { | |
background: none; | |
border: none; | |
font-size: 1.5rem; | |
cursor: pointer; | |
color: #6c757d; | |
&:hover { | |
color: #333; | |
} | |
} | |
} | |
.activity-list { | |
max-height: 300px; | |
overflow-y: auto; | |
} | |
.activity-item { | |
padding: 0.75rem 1rem; | |
border-bottom: 1px solid #f0f0f0; | |
&:hover { | |
background-color: #f8f9fa; | |
} | |
.activity-time { | |
font-size: 0.85rem; | |
color: #6c757d; | |
margin-bottom: 0.25rem; | |
} | |
.activity-content { | |
font-size: 0.9rem; | |
em { | |
color: #007bff; | |
font-style: normal; | |
} | |
} | |
} | |
.activity-footer { | |
padding: 0.75rem; | |
border-top: 1px solid #dee2e6; | |
text-align: center; | |
} | |
.loading, .empty { | |
padding: 2rem; | |
text-align: center; | |
color: #6c757d; | |
} | |
`] | |
}) | |
export class ActivityLogComponent implements OnInit { | |
new EventEmitter<void>(); | () close =|
private http = inject(HttpClient); | |
activities: ActivityLog[] = []; | |
loading = true; | |
ngOnInit() { | |
this.loadActivities(); | |
} | |
loadActivities() { | |
this.loading = true; | |
this.http.get<ActivityLog[]>('/api/activity-log?limit=10') | |
.subscribe({ | |
next: (data) => { | |
this.activities = data; | |
this.loading = false; | |
}, | |
error: () => { | |
this.loading = false; | |
} | |
}); | |
} | |
loadMore() { | |
// TODO: Implement full activity log view | |
console.log('Load more activities'); | |
} | |
getRelativeTime(timestamp: string): string { | |
const date = new Date(timestamp); | |
const now = new Date(); | |
const diff = now.getTime() - date.getTime(); | |
const minutes = Math.floor(diff / 60000); | |
const hours = Math.floor(diff / 3600000); | |
const days = Math.floor(diff / 86400000); | |
if (minutes < 1) return 'just now'; | |
if (minutes < 60) return `${minutes} min ago`; | |
if (hours < 24) return `${hours} hour${hours > 1 ? 's' : ''} ago`; | |
return `${days} day${days > 1 ? 's' : ''} ago`; | |
} | |
getActionText(activity: ActivityLog): string { | |
const actions: Record<string, string> = { | |
'CREATE_PROJECT': 'created project', | |
'UPDATE_PROJECT': 'updated project', | |
'DELETE_PROJECT': 'deleted project', | |
'PUBLISH_VERSION': 'published version', | |
'CREATE_VERSION': 'created version', | |
'UPDATE_VERSION': 'updated version', | |
'CREATE_API': 'created API', | |
'UPDATE_API': 'updated API', | |
'DELETE_API': 'deleted API', | |
'UPDATE_ENVIRONMENT': 'updated environment', | |
'IMPORT_PROJECT': 'imported project' | |
}; | |
return actions[activity.action] || activity.action.toLowerCase().replace('_', ' '); | |
} | |
} |