import { Component, OnInit, inject, signal } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RouterModule } from '@angular/router'; import { MatCardModule } from '@angular/material/card'; import { MatTableModule } from '@angular/material/table'; import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; import { MatChipsModule } from '@angular/material/chips'; import { MatMenuModule } from '@angular/material/menu'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatDialog, MatDialogModule } from '@angular/material/dialog'; import { PageHeaderComponent } from '../../../shared/components/page-header/page-header.component'; import { StatusBadgeComponent } from '../../../shared/components/status-badge/status-badge.component'; import { EmptyStateComponent } from '../../../shared/components/empty-state/empty-state.component'; import { ConfirmDialogComponent } from '../../../shared/components/confirm-dialog/confirm-dialog.component'; import { WebhookService } from '../services/webhook.service'; import { NotificationService } from '../../../core/services/notification.service'; import { WebhookResponseDto } from '../../../api/models'; @Component({ selector: 'app-webhook-list', standalone: true, imports: [ CommonModule, RouterModule, MatCardModule, MatTableModule, MatButtonModule, MatIconModule, MatChipsModule, MatMenuModule, MatProgressSpinnerModule, MatDialogModule, PageHeaderComponent, StatusBadgeComponent, EmptyStateComponent, ], template: `
@if (loading()) {
} @else if (webhooks().length === 0) { } @else {
URL {{ row.url }} Events
@for (event of row.events.slice(0, 2); track event) { {{ formatEvent(event) }} } @if (row.events.length > 2) { +{{ row.events.length - 2 }} }
Status
}
`, styles: [ ` .loading-container { display: flex; justify-content: center; padding: 48px; } table { width: 100%; } .url-cell { font-family: monospace; font-size: 0.875rem; max-width: 300px; display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .events-chips { display: flex; gap: 4px; flex-wrap: wrap; } .mat-column-actions { width: 60px; text-align: right; } `, ], }) export class WebhookListComponent implements OnInit { private readonly webhookService = inject(WebhookService); private readonly notification = inject(NotificationService); private readonly dialog = inject(MatDialog); readonly loading = signal(true); readonly webhooks = signal([]); readonly displayedColumns = ['url', 'events', 'status', 'actions']; ngOnInit(): void { this.loadWebhooks(); } loadWebhooks(): void { this.loading.set(true); this.webhookService.getWebhooks().subscribe({ next: (data) => { this.webhooks.set(data); this.loading.set(false); }, error: () => { this.loading.set(false); }, }); } formatEvent(event: string): string { return event.replace(/_/g, ' ').toLowerCase(); } testWebhook(webhook: WebhookResponseDto): void { this.webhookService.testWebhook(webhook.id).subscribe({ next: (result) => { if (result.success) { this.notification.success(`Webhook test successful (${result.statusCode})`); } else { this.notification.error(`Webhook test failed: ${result.error || result.statusMessage}`); } }, }); } deleteWebhook(webhook: WebhookResponseDto): void { const dialogRef = this.dialog.open(ConfirmDialogComponent, { data: { title: 'Delete Webhook', message: 'Are you sure you want to delete this webhook?', confirmText: 'Delete', confirmColor: 'warn', }, }); dialogRef.afterClosed().subscribe((confirmed) => { if (confirmed) { this.webhookService.deleteWebhook(webhook.id).subscribe({ next: () => { this.notification.success('Webhook deleted'); this.loadWebhooks(); }, }); } }); } }