100 lines
3.6 KiB
TypeScript
100 lines
3.6 KiB
TypeScript
import { Component, Input } from '@angular/core';
|
|
import { RouterLink } from '@angular/router';
|
|
import {
|
|
CardComponent,
|
|
CardHeaderComponent,
|
|
CardTitleComponent,
|
|
CardDescriptionComponent,
|
|
CardContentComponent,
|
|
} from '../../ui/card/card.component';
|
|
|
|
interface ICertificateHealth {
|
|
valid: number;
|
|
expiringSoon: number;
|
|
expired: number;
|
|
expiringDomains: Array<{ domain: string; daysRemaining: number }>;
|
|
}
|
|
|
|
@Component({
|
|
selector: 'app-certificates-card',
|
|
standalone: true,
|
|
host: { class: 'block h-full' },
|
|
imports: [
|
|
RouterLink,
|
|
CardComponent,
|
|
CardHeaderComponent,
|
|
CardTitleComponent,
|
|
CardDescriptionComponent,
|
|
CardContentComponent,
|
|
],
|
|
template: `
|
|
<ui-card class="h-full">
|
|
<ui-card-header class="flex flex-col space-y-1.5">
|
|
<ui-card-title>Certificates</ui-card-title>
|
|
<ui-card-description>SSL/TLS certificate status</ui-card-description>
|
|
</ui-card-header>
|
|
<ui-card-content class="space-y-3">
|
|
<!-- Status summary -->
|
|
<div class="space-y-2">
|
|
@if (health.valid > 0) {
|
|
<div class="flex items-center gap-2">
|
|
<svg class="h-4 w-4 text-success" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
|
|
</svg>
|
|
<span class="text-sm">{{ health.valid }} valid</span>
|
|
</div>
|
|
}
|
|
|
|
@if (health.expiringSoon > 0) {
|
|
<div class="flex items-center gap-2">
|
|
<svg class="h-4 w-4 text-warning" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
|
</svg>
|
|
<span class="text-sm text-warning">{{ health.expiringSoon }} expiring soon</span>
|
|
</div>
|
|
}
|
|
|
|
@if (health.expired > 0) {
|
|
<div class="flex items-center gap-2">
|
|
<svg class="h-4 w-4 text-destructive" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
<span class="text-sm text-destructive">{{ health.expired }} expired</span>
|
|
</div>
|
|
}
|
|
|
|
@if (health.valid === 0 && health.expiringSoon === 0 && health.expired === 0) {
|
|
<div class="text-sm text-muted-foreground">No certificates</div>
|
|
}
|
|
</div>
|
|
|
|
<!-- Expiring domains list -->
|
|
@if (health.expiringDomains.length > 0) {
|
|
<div class="border-t pt-2 space-y-1">
|
|
@for (item of health.expiringDomains; track item.domain) {
|
|
<a [routerLink]="['/network']"
|
|
class="flex items-center justify-between text-sm py-1 hover:bg-muted/50 rounded px-1 -mx-1 transition-colors">
|
|
<span class="truncate text-muted-foreground">{{ item.domain }}</span>
|
|
<span
|
|
class="ml-2 whitespace-nowrap"
|
|
[class.text-warning]="item.daysRemaining > 7"
|
|
[class.text-destructive]="item.daysRemaining <= 7">
|
|
{{ item.daysRemaining }}d
|
|
</span>
|
|
</a>
|
|
}
|
|
</div>
|
|
}
|
|
</ui-card-content>
|
|
</ui-card>
|
|
`,
|
|
})
|
|
export class CertificatesCardComponent {
|
|
@Input() health: ICertificateHealth = {
|
|
valid: 0,
|
|
expiringSoon: 0,
|
|
expired: 0,
|
|
expiringDomains: [],
|
|
};
|
|
}
|