mirror of
https://github.com/Cleanuparr/Cleanuparr.git
synced 2026-03-27 02:23:56 -04:00
187 lines
6.7 KiB
HTML
187 lines
6.7 KiB
HTML
<app-page-header
|
|
title="Events"
|
|
subtitle="System events and notifications"
|
|
/>
|
|
|
|
<div class="page-content">
|
|
<!-- Toolbar -->
|
|
<div class="toolbar">
|
|
<div class="toolbar__filters">
|
|
<app-select
|
|
placeholder="All Severities"
|
|
[options]="severityOptions()"
|
|
[(value)]="selectedSeverity"
|
|
(valueChange)="onFilterChange()"
|
|
/>
|
|
<app-select
|
|
placeholder="All Types"
|
|
[options]="typeOptions()"
|
|
[(value)]="selectedType"
|
|
(valueChange)="onFilterChange()"
|
|
/>
|
|
<app-input
|
|
placeholder="From date"
|
|
type="datetime-local"
|
|
[(value)]="fromDate"
|
|
(blurred)="onFilterChange()"
|
|
/>
|
|
<app-input
|
|
placeholder="To date"
|
|
type="datetime-local"
|
|
[(value)]="toDate"
|
|
(blurred)="onFilterChange()"
|
|
/>
|
|
<app-input
|
|
placeholder="Search events..."
|
|
type="search"
|
|
[(value)]="searchQuery"
|
|
(blurred)="onFilterChange()"
|
|
/>
|
|
</div>
|
|
<div class="toolbar__actions">
|
|
<app-button variant="ghost" size="sm" (clicked)="refresh()">
|
|
Refresh
|
|
</app-button>
|
|
<div class="export-wrapper">
|
|
<app-button variant="ghost" size="sm" (clicked)="showExportMenu.set(!showExportMenu())">
|
|
<ng-icon name="tablerFileExport" />
|
|
Export
|
|
</app-button>
|
|
@if (showExportMenu()) {
|
|
<div class="export-menu">
|
|
<button class="export-menu__item" (click)="exportEvents('json')">JSON</button>
|
|
<button class="export-menu__item" (click)="exportEvents('csv')">CSV</button>
|
|
<button class="export-menu__item" (click)="exportEvents('text')">Text</button>
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Active Job Run Filter -->
|
|
@if (selectedJobRunId()) {
|
|
<div class="active-filter">
|
|
<span>Showing events for job run: {{ selectedJobRunId() }}</span>
|
|
<app-button variant="ghost" size="sm" (clicked)="clearJobRunFilter()">
|
|
Clear filter
|
|
</app-button>
|
|
</div>
|
|
}
|
|
|
|
<!-- Events Count -->
|
|
<div class="event-count">
|
|
<app-animated-counter [value]="totalRecords()" [duration]="400" /> events
|
|
</div>
|
|
|
|
<!-- Events List -->
|
|
<app-card [noPadding]="true">
|
|
<div class="events-list">
|
|
@for (event of events(); track event.id) {
|
|
<div
|
|
class="event-row"
|
|
[class.event-row--expanded]="expandedId() === event.id"
|
|
>
|
|
<div
|
|
class="event-row__main"
|
|
[class.event-row__main--expandable]="isExpandable(event)"
|
|
(click)="isExpandable(event) ? toggleExpand(event.id) : null"
|
|
>
|
|
<button class="event-row__copy" (click)="copyEvent(event); $event.stopPropagation()" title="Copy event">
|
|
<ng-icon name="tablerCopy" />
|
|
</button>
|
|
<span class="event-row__time">{{ event.timestamp | date:'yyyy-MM-dd HH:mm:ss' }}</span>
|
|
<app-badge [severity]="eventSeverity(event.severity)" size="sm">
|
|
{{ event.severity }}
|
|
</app-badge>
|
|
<app-badge [severity]="eventTypeSeverity(event.eventType)" size="sm">
|
|
{{ formatEventType(event.eventType) }}
|
|
</app-badge>
|
|
@if (event.trackingId) {
|
|
<span class="event-row__tracking">{{ event.trackingId }}</span>
|
|
}
|
|
@if (isExpandable(event)) {
|
|
<ng-icon
|
|
[name]="expandedId() === event.id ? 'tablerChevronUp' : 'tablerChevronDown'"
|
|
class="event-row__chevron"
|
|
/>
|
|
}
|
|
</div>
|
|
<div class="event-row__message">{{ event.message }}</div>
|
|
|
|
@if (expandedId() === event.id) {
|
|
<div class="event-row__details">
|
|
@if (event.trackingId) {
|
|
<div class="event-row__detail">
|
|
<span class="event-row__detail-label">Tracking ID</span>
|
|
<span class="event-row__detail-value">{{ event.trackingId }}</span>
|
|
</div>
|
|
}
|
|
@if (event.instanceType || event.downloadClientType) {
|
|
<div class="event-row__detail">
|
|
<span class="event-row__detail-label">Source</span>
|
|
<div class="event-row__source">
|
|
@if (event.instanceType) {
|
|
<app-badge severity="info" size="sm">{{ event.instanceType }}</app-badge>
|
|
@if (event.instanceUrl) {
|
|
<span class="event-row__source-url">{{ event.instanceUrl }}</span>
|
|
}
|
|
}
|
|
@if (event.downloadClientType) {
|
|
<app-badge severity="accent" size="sm">{{ event.downloadClientType }}</app-badge>
|
|
@if (event.downloadClientName) {
|
|
<span class="event-row__source-url">{{ event.downloadClientName }}</span>
|
|
}
|
|
}
|
|
</div>
|
|
</div>
|
|
}
|
|
@if (event.jobRunId) {
|
|
<div class="event-row__detail">
|
|
<span class="event-row__detail-label">Job Run</span>
|
|
<div class="event-row__run-id-actions">
|
|
<button class="event-row__run-id" (click)="filterByJobRunId(event.jobRunId!); $event.stopPropagation()">
|
|
{{ event.jobRunId }}
|
|
</button>
|
|
<a class="event-row__run-id-link" routerLink="/logs" [queryParams]="{ jobRunId: event.jobRunId }" (click)="$event.stopPropagation()">
|
|
View Logs
|
|
</a>
|
|
</div>
|
|
</div>
|
|
}
|
|
@if (parseEventData(event.data); as data) {
|
|
<div class="event-row__detail">
|
|
<span class="event-row__detail-label">Event Data</span>
|
|
<div class="event-row__data">
|
|
@for (key of objectKeys(data); track key) {
|
|
<div class="event-row__data-item">
|
|
<span class="event-row__data-key">{{ key }}</span>
|
|
<span class="event-row__data-value">{{ formatValue(data[key]) }}</span>
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
} @empty {
|
|
<app-empty-state
|
|
icon="tablerBell"
|
|
heading="No events"
|
|
description="No events match your current filters."
|
|
/>
|
|
}
|
|
</div>
|
|
</app-card>
|
|
|
|
<!-- Pagination -->
|
|
@if (totalRecords() > pageSize()) {
|
|
<app-paginator
|
|
[totalRecords]="totalRecords()"
|
|
[pageSize]="pageSize()"
|
|
[currentPage]="currentPage()"
|
|
(pageChange)="onPageChange($event)"
|
|
/>
|
|
}
|
|
</div>
|