87 lines
3.1 KiB
TypeScript
87 lines
3.1 KiB
TypeScript
|
|
import { Component, OnInit, inject, signal } from '@angular/core';
|
||
|
|
import { CommonModule } from '@angular/common';
|
||
|
|
import { ApiService } from '../../core/services/api.service';
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
selector: 'app-ssl',
|
||
|
|
standalone: true,
|
||
|
|
imports: [CommonModule],
|
||
|
|
template: `
|
||
|
|
<div class="px-4 sm:px-0">
|
||
|
|
<h1 class="text-3xl font-bold text-gray-900 mb-8">SSL Certificates</h1>
|
||
|
|
|
||
|
|
@if (certificates().length > 0) {
|
||
|
|
<div class="card overflow-hidden p-0">
|
||
|
|
<table class="min-w-full divide-y divide-gray-200">
|
||
|
|
<thead class="bg-gray-50">
|
||
|
|
<tr>
|
||
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Domain</th>
|
||
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Issuer</th>
|
||
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Expiry</th>
|
||
|
|
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase">Actions</th>
|
||
|
|
</tr>
|
||
|
|
</thead>
|
||
|
|
<tbody class="bg-white divide-y divide-gray-200">
|
||
|
|
@for (cert of certificates(); track cert.domain) {
|
||
|
|
<tr>
|
||
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ cert.domain }}</td>
|
||
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ cert.issuer }}</td>
|
||
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm">
|
||
|
|
<span [ngClass]="isExpiringSoon(cert.expiryDate) ? 'text-red-600' : 'text-gray-500'">
|
||
|
|
{{ formatDate(cert.expiryDate) }}
|
||
|
|
</span>
|
||
|
|
</td>
|
||
|
|
<td class="px-6 py-4 whitespace-nowrap text-right text-sm">
|
||
|
|
<button (click)="renewCertificate(cert)" class="text-primary-600 hover:text-primary-900">Renew</button>
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
}
|
||
|
|
</tbody>
|
||
|
|
</table>
|
||
|
|
</div>
|
||
|
|
} @else {
|
||
|
|
<div class="card text-center py-12">
|
||
|
|
<p class="text-gray-500">No SSL certificates</p>
|
||
|
|
<p class="text-sm text-gray-400 mt-2">Certificates are obtained automatically when deploying services with domains</p>
|
||
|
|
</div>
|
||
|
|
}
|
||
|
|
</div>
|
||
|
|
`,
|
||
|
|
})
|
||
|
|
export class SslComponent implements OnInit {
|
||
|
|
private apiService = inject(ApiService);
|
||
|
|
certificates = signal<any[]>([]);
|
||
|
|
|
||
|
|
ngOnInit(): void {
|
||
|
|
this.loadCertificates();
|
||
|
|
}
|
||
|
|
|
||
|
|
loadCertificates(): void {
|
||
|
|
this.apiService.getSslCertificates().subscribe({
|
||
|
|
next: (response) => {
|
||
|
|
if (response.success && response.data) {
|
||
|
|
this.certificates.set(response.data);
|
||
|
|
}
|
||
|
|
},
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
renewCertificate(cert: any): void {
|
||
|
|
this.apiService.renewSslCertificate(cert.domain).subscribe({
|
||
|
|
next: () => {
|
||
|
|
alert('Certificate renewal initiated');
|
||
|
|
this.loadCertificates();
|
||
|
|
},
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
formatDate(timestamp: number): string {
|
||
|
|
return new Date(timestamp).toLocaleDateString();
|
||
|
|
}
|
||
|
|
|
||
|
|
isExpiringSoon(timestamp: number): boolean {
|
||
|
|
const thirtyDays = 30 * 24 * 60 * 60 * 1000;
|
||
|
|
return timestamp - Date.now() < thirtyDays;
|
||
|
|
}
|
||
|
|
}
|