From 9e931ad4392765a78ed86495829c2bedfe1ae0d8 Mon Sep 17 00:00:00 2001 From: Tola Leng Date: Fri, 16 May 2025 22:14:05 +0800 Subject: [PATCH] Updated the SSL detail dialog in `SSLCertificatesTable.tsx` --- .../ssl-domain/SSLCertificatesTable.tsx | 397 +++++++++++++++--- 1 file changed, 328 insertions(+), 69 deletions(-) diff --git a/application/src/components/ssl-domain/SSLCertificatesTable.tsx b/application/src/components/ssl-domain/SSLCertificatesTable.tsx index 141b93f..06e16f0 100644 --- a/application/src/components/ssl-domain/SSLCertificatesTable.tsx +++ b/application/src/components/ssl-domain/SSLCertificatesTable.tsx @@ -1,5 +1,5 @@ -import React from "react"; +import React, { useState } from "react"; import { format } from "date-fns"; import { Table, @@ -10,93 +10,352 @@ import { TableCell } from "@/components/ui/table"; import { Button } from "@/components/ui/button"; -import { RefreshCw } from "lucide-react"; +import { RefreshCw, Eye, Edit, Trash2, MoreHorizontal } from "lucide-react"; import { SSLCertificate } from "@/types/ssl.types"; import { SSLStatusBadge } from "./SSLStatusBadge"; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { toast } from "sonner"; interface SSLCertificatesTableProps { certificates: SSLCertificate[]; onRefresh: (id: string) => void; refreshingId: string | null; + onEdit?: (certificate: SSLCertificate) => void; + onDelete?: (certificate: SSLCertificate) => void; } -export const SSLCertificatesTable = ({ certificates, onRefresh, refreshingId }: SSLCertificatesTableProps) => { - const calculateDaysLeft = (expirationDate: string) => { +export const SSLCertificatesTable = ({ + certificates, + onRefresh, + refreshingId, + onEdit, + onDelete +}: SSLCertificatesTableProps) => { + const [selectedCert, setSelectedCert] = useState(null); + const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false); + const [certToDelete, setCertToDelete] = useState(null); + + const formatDate = (dateString: string | undefined) => { + if (!dateString) return 'Unknown'; + try { - const expDate = new Date(expirationDate); - const today = new Date(); - const diffTime = expDate.getTime() - today.getTime(); - const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); - return diffDays > 0 ? diffDays : 0; + const date = new Date(dateString); + if (isNaN(date.getTime())) { + console.warn("Invalid date for formatting:", dateString); + return 'Unknown'; + } + return format(date, "MMM dd, yyyy"); } catch (error) { - console.error("Error calculating days left:", error); - return 0; + console.error("Error formatting date:", error); + return 'Unknown'; + } + }; + + const handleViewCertificate = (certificate: SSLCertificate) => { + setSelectedCert(certificate); + }; + + const handleEditCertificate = (certificate: SSLCertificate) => { + if (onEdit) { + onEdit(certificate); + } else { + toast.error("Edit functionality not implemented yet"); + } + }; + + const handleDeleteCertificate = (certificate: SSLCertificate) => { + setCertToDelete(certificate); + setDeleteConfirmOpen(true); + }; + + const confirmDelete = () => { + if (certToDelete && onDelete) { + onDelete(certToDelete); + setDeleteConfirmOpen(false); + setCertToDelete(null); } }; return ( -
- - - - Domain - Issuer - Expiration Date - Days Left - Status - Last Notified - Actions - - - - {certificates.length === 0 ? ( + <> +
+ {refreshingId && ( +
+
+ + Checking SSL certificate... +
+
+ )} +
+ - - No SSL certificates found - + Domain + Issuer + Expiration Date + Days Left + Status + Last Notified + Actions - ) : ( - certificates.map((certificate) => ( - - {certificate.domain} - {certificate.issuer || 'Unknown'} - - {certificate.expiration_date ? - format(new Date(certificate.expiration_date), "MMM dd, yyyy") : - 'Unknown'} - - - {certificate.expiration_date ? - calculateDaysLeft(certificate.expiration_date) : - 'Unknown'} - - - - - - {certificate.last_notified - ? format(new Date(certificate.last_notified), "MMM dd, yyyy") - : "Never"} - - -
- - -
+
+ + {certificates.length === 0 ? ( + + + No SSL certificates found - )) + ) : ( + certificates.map((certificate) => ( + + {certificate.domain} + {certificate.issuer_o || 'Unknown'} + + {formatDate(certificate.valid_till)} + + + {typeof certificate.days_left === 'number' ? certificate.days_left : 'Unknown'} + + + + + + {certificate.last_notified + ? formatDate(certificate.last_notified) + : "Never"} + + + + + + + + handleViewCertificate(certificate)} + className="cursor-pointer" + > + View + + { + if (refreshingId === null) { + onRefresh(certificate.id); + } + }} + disabled={refreshingId !== null} + className="cursor-pointer" + > + + Check + + handleEditCertificate(certificate)} + className="cursor-pointer" + > + Edit + + handleDeleteCertificate(certificate)} + className="cursor-pointer text-destructive focus:text-destructive" + > + Delete + + + + + + )) + )} + +
+
+ + {/* SSL Certificate Details Dialog */} + !open && setSelectedCert(null)}> + + + + SSL Certificate Details + +

+ Detailed information about the SSL certificate for {selectedCert?.domain} +

+
+ + {selectedCert && ( +
+
+ {/* Basic Information */} +
+

Basic Information

+
+
+ Domain: + {selectedCert.domain} +
+
+ Status: + +
+
+ Issued To: + {selectedCert.issued_to || 'Unknown'} +
+
+ Resolved IP: + {selectedCert.resolved_ip || 'Unknown'} +
+
+
+ + {/* Validity */} +
+

Validity

+
+
+ Valid From: + {selectedCert.valid_from ? formatDate(selectedCert.valid_from) : 'Unknown'} +
+
+ Valid Until: + {formatDate(selectedCert.valid_till)} +
+
+ Days Left: + {selectedCert.days_left} +
+
+ Validity Days: + {selectedCert.validity_days || 'Unknown'} +
+
+
+ + {/* Issuer */} +
+

Issuer

+
+
+ Organization: + {selectedCert.issuer_o || 'Unknown'} +
+
+ Common Name: + {selectedCert.issuer_cn || 'Unknown'} +
+
+
+ + {/* Technical Details */} +
+

Technical Details

+
+
+ Serial Number: + {selectedCert.serial_number || 'Unknown'} +
+
+ Algorithm: + {selectedCert.cert_alg || 'Unknown'} +
+
+
+
+ + {/* Subject Alternative Names */} +
+

Subject Alternative Names (SANs)

+
+ {selectedCert.cert_sans ? ( +

{selectedCert.cert_sans}

+ ) : ( +

None

+ )} +
+
+ + {/* Monitoring Configuration */} +
+

Monitoring Configuration

+
+
+
Warning Threshold:
+
{selectedCert.warning_threshold} days
+
+
+
Expiry Threshold:
+
{selectedCert.expiry_threshold} days
+
+
+
Notification Channel:
+
{selectedCert.notification_channel}
+
+
+
+ + {/* Timestamps */} +
+

Record Information

+
+
+
Created:
+
{selectedCert.created ? formatDate(selectedCert.created) : 'Unknown'}
+
+
+
Last Updated:
+
{selectedCert.updated ? formatDate(selectedCert.updated) : 'Unknown'}
+
+
+
Last Notification:
+
{selectedCert.last_notified ? formatDate(selectedCert.last_notified) : 'Never'}
+
+
+
Collection ID:
+
{selectedCert.collectionId || 'Unknown'}
+
+
+
+
)} - - - + + + + +
+
+ + {/* Delete Confirmation Dialog */} + + + + Delete SSL Certificate + +
+

Are you sure you want to delete the SSL certificate for {certToDelete?.domain}?

+

This action cannot be undone.

+
+ + + + +
+
+ ); }; \ No newline at end of file