import { Component, inject, signal, OnInit, effect } from '@angular/core'; import { ActivatedRoute, Router, RouterLink } from '@angular/router'; import { ApiService } from '../../core/services/api.service'; import { ToastService } from '../../core/services/toast.service'; import { WebSocketService } from '../../core/services/websocket.service'; import { IPlatformService, IContainerStats, TPlatformServiceType } from '../../core/types/api.types'; import { ContainerStatsComponent } from '../../shared/components/container-stats/container-stats.component'; import { CardComponent, CardHeaderComponent, CardTitleComponent, CardDescriptionComponent, CardContentComponent, } from '../../ui/card/card.component'; import { ButtonComponent } from '../../ui/button/button.component'; import { BadgeComponent } from '../../ui/badge/badge.component'; import { SkeletonComponent } from '../../ui/skeleton/skeleton.component'; @Component({ selector: 'app-platform-service-detail', standalone: true, imports: [ RouterLink, CardComponent, CardHeaderComponent, CardTitleComponent, CardDescriptionComponent, CardContentComponent, ButtonComponent, BadgeComponent, SkeletonComponent, ContainerStatsComponent, ], template: `
Back to Services @if (loading() && !service()) { } @else if (service()) {

{{ service()!.displayName }}

{{ service()!.status }} @if (service()!.isCore) { Core Service }
}
@if (loading() && !service()) {
@for (_ of [1,2,3]; track $index) { }
} @else if (service()) {
Service Details Platform service information
Type
{{ service()!.type }}
Resource Types
@for (type of service()!.resourceTypes; track type) { {{ type }} }
@if (service()!.containerId) {
Container ID
{{ service()!.containerId?.slice(0, 12) }}
} @if (service()!.createdAt) {
Created
{{ formatDate(service()!.createdAt!) }}
}
Actions Manage platform service state @if (service()!.isCore) {

This is a core service managed by Onebox. It cannot be stopped manually.

} @else {
@if (service()!.status === 'stopped' || service()!.status === 'not-deployed' || service()!.status === 'failed') { } @if (service()!.status === 'running') { }
}
@if (service()!.status === 'running') { } About {{ service()!.displayName }}

{{ getServiceDescription(service()!.type) }}

}
`, }) export class PlatformServiceDetailComponent implements OnInit { private route = inject(ActivatedRoute); private router = inject(Router); private api = inject(ApiService); private toast = inject(ToastService); private ws = inject(WebSocketService); service = signal(null); stats = signal(null); loading = signal(false); actionLoading = signal(false); private statsInterval: any; constructor() { // Listen for WebSocket stats updates for platform services effect(() => { const update = this.ws.statsUpdate(); const currentService = this.service(); // Platform services use "onebox-{type}" as service name in WebSocket if (update && currentService && update.serviceName === `onebox-${currentService.type}`) { this.stats.set(update.stats); } }); } ngOnInit(): void { const type = this.route.snapshot.paramMap.get('type') as TPlatformServiceType; if (type) { this.loadService(type); } } async loadService(type: TPlatformServiceType): Promise { this.loading.set(true); try { const response = await this.api.getPlatformService(type); if (response.success && response.data) { this.service.set(response.data); // Load stats if service is running if (response.data.status === 'running') { this.loadStats(type); // Start polling stats every 5 seconds this.startStatsPolling(type); } } else { this.toast.error(response.error || 'Platform service not found'); this.router.navigate(['/services']); } } catch { this.toast.error('Failed to load platform service'); } finally { this.loading.set(false); } } async loadStats(type: TPlatformServiceType): Promise { try { const response = await this.api.getPlatformServiceStats(type); if (response.success && response.data) { this.stats.set(response.data); } } catch { // Silent fail - stats are optional } } startStatsPolling(type: TPlatformServiceType): void { // Clear existing interval if any if (this.statsInterval) { clearInterval(this.statsInterval); } // Poll every 5 seconds this.statsInterval = setInterval(() => { if (this.service()?.status === 'running') { this.loadStats(type); } }, 5000); } getStatusVariant(status: string): 'success' | 'destructive' | 'warning' | 'secondary' { switch (status) { case 'running': return 'success'; case 'stopped': case 'not-deployed': return 'secondary'; case 'failed': return 'destructive'; case 'starting': case 'stopping': return 'warning'; default: return 'secondary'; } } formatDate(timestamp: number): string { return new Date(timestamp).toLocaleString(); } getServiceDescription(type: TPlatformServiceType): string { const descriptions: Record = { mongodb: 'MongoDB is a document-oriented NoSQL database used for high volume data storage. It stores data in flexible, JSON-like documents.', minio: 'MinIO is a high-performance, S3-compatible object storage service. Use it to store unstructured data like photos, videos, log files, and backups.', redis: 'Redis is an in-memory data structure store, used as a distributed cache, message broker, and key-value database.', postgresql: 'PostgreSQL is a powerful, open-source object-relational database system with over 35 years of active development.', rabbitmq: 'RabbitMQ is a message broker that enables applications to communicate with each other using messages through queues.', caddy: 'Caddy is a powerful, enterprise-ready, open-source web server with automatic HTTPS. It serves as the reverse proxy for Onebox.', }; return descriptions[type] || 'A platform service managed by Onebox.'; } async startService(): Promise { const type = this.service()?.type; if (!type) return; this.actionLoading.set(true); try { const response = await this.api.startPlatformService(type); if (response.success) { this.toast.success('Platform service started'); this.loadService(type); } else { this.toast.error(response.error || 'Failed to start platform service'); } } catch { this.toast.error('Failed to start platform service'); } finally { this.actionLoading.set(false); } } async stopService(): Promise { const type = this.service()?.type; if (!type) return; this.actionLoading.set(true); try { const response = await this.api.stopPlatformService(type); if (response.success) { this.toast.success('Platform service stopped'); // Clear stats and stop polling this.stats.set(null); if (this.statsInterval) { clearInterval(this.statsInterval); this.statsInterval = null; } this.loadService(type); } else { this.toast.error(response.error || 'Failed to stop platform service'); } } catch { this.toast.error('Failed to stop platform service'); } finally { this.actionLoading.set(false); } } }