import { Component, Input, OnInit } from '@angular/core'; import { CommonModule } from '@angular/common'; import { MatCardModule } from '@angular/material/card'; import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; import { MatExpansionModule } from '@angular/material/expansion'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { Tunnel, Mapping } from '../../../shared/models'; import { ApiService } from '../../../core/services/api.service'; @Component({ selector: 'app-tunnel-list', standalone: true, imports: [ CommonModule, MatCardModule, MatButtonModule, MatIconModule, MatExpansionModule, MatProgressSpinnerModule, ], template: ` dns Tunnels {{ tunnels.length }} tunnel(s) configured @if (isLoading) {
} @if (!isLoading && tunnels.length === 0) {
info

No tunnels configured

} @for (tunnel of tunnels; track tunnel.id) { hub {{ tunnel.name }} {{ tunnel.environment }} @if (expandedTunnelId === tunnel.id) { @if (mappingsLoading) { } @else if (tunnelMappings[tunnel.id]?.length === 0) {

No mappings for this tunnel

} @else { @for (mapping of tunnelMappings[tunnel.id]; track mapping.id) {
{{ mapping.subdomain }}.hithomelabs.com → {{ mapping.protocol }}://192.168.0.100:{{ mapping.port }}
} } } @else { }
}
`, styles: [ ` .tunnels-card { margin-bottom: 1.5rem; } .loading-container { display: flex; justify-content: center; padding: 2rem; } .empty-state { display: flex; flex-direction: column; align-items: center; padding: 2rem; color: #666; } .empty-state mat-icon { font-size: 48px; width: 48px; height: 48px; } .tunnel-icon { margin-right: 0.5rem; } .mapping-item { display: flex; flex-direction: column; padding: 0.75rem; margin: 0.5rem 0; background: #f5f5f5; border-radius: 4px; } .hostname { font-weight: 500; color: #1976d2; } .service { color: #666; font-size: 0.9rem; } .no-mappings { color: #999; font-style: italic; } mat-panel-title { display: flex; align-items: center; } `, ], }) export class TunnelListComponent implements OnInit { @Input() tunnels: Tunnel[] = []; isLoading = false; mappingsLoading = false; expandedTunnelId: string | null = null; tunnelMappings: { [key: string]: Mapping[] } = {}; constructor(private apiService: ApiService) {} ngOnInit(): void {} loadMappings(tunnelId: string): void { this.expandedTunnelId = tunnelId; this.mappingsLoading = true; this.apiService.getTunnelMappings(tunnelId).subscribe({ next: (response) => { this.tunnelMappings[tunnelId] = response.data; this.mappingsLoading = false; }, error: (err) => { console.error('Error loading mappings:', err); this.mappingsLoading = false; }, }); } }