diff --git a/src/app/dashboard/admin/root-ca/RootCaManagementClient.tsx b/src/app/dashboard/admin/root-ca/RootCaManagementClient.tsx index 64fa618..52c205f 100644 --- a/src/app/dashboard/admin/root-ca/RootCaManagementClient.tsx +++ b/src/app/dashboard/admin/root-ca/RootCaManagementClient.tsx @@ -14,38 +14,10 @@ import PageLoader from "@/components/ui/PageLoader"; import { useTranslations } from "next-intl"; import CdnManagementCard from "@/components/admin/CdnManagementCard"; import ArchiveManagementTable from "@/components/admin/ArchiveManagementTable"; +import Button from "@/components/ui/button/Button"; const fetcher = (url: string) => axios.get(url).then((res) => res.data); -function SyncButton({ onClick, disabled, isLoading, label, variant = 'blue' }: { onClick: () => void, disabled: boolean, isLoading: boolean, label: string, variant?: 'blue' | 'gray' | 'purple' | 'indigo' }) { - const variantClasses = { - blue: 'bg-blue-600 hover:bg-blue-700 disabled:bg-blue-400', - gray: 'bg-gray-600 hover:bg-gray-700 disabled:bg-gray-400', - purple: 'bg-purple-600 hover:bg-purple-700 disabled:bg-purple-400', - indigo: 'bg-indigo-600 hover:bg-indigo-700 disabled:bg-indigo-400', - }; - - return ( - - ); -} - export default function RootCaManagementClient() { const t = useTranslations("RootCA"); const { user } = useAuth(); @@ -53,9 +25,11 @@ export default function RootCaManagementClient() { const { addToast } = useToast(); const { data, error, mutate, isLoading } = useSWR("/api/admin/ca-certificates", fetcher); const [isRenewing, setIsRenewing] = useState(false); + const [isBulkRenewing, setIsBulkRenewing] = useState(false); const [activeSync, setActiveSync] = useState(null); const [isPromoting, setIsPromoting] = useState(false); const [confirmRenewUuid, setConfirmRenewUuid] = useState(null); + const [showBulkRenewConfirm, setShowBulkRenewConfirm] = useState(false); // Redirect if not admin or owner (double security, backend also checks) const { isAdminOrOwner } = useAuth(); @@ -125,6 +99,23 @@ export default function RootCaManagementClient() { } }; + const handleRenewAll = async () => { + setIsBulkRenewing(true); + try { + const response = await axios.post("/api/admin/ca-certificates/renew-all", { days: 3650 }); + if (response.data.status === "success") { + addToast(t("toast_bulk_renew_success"), "success"); + mutate(); + setShowBulkRenewConfirm(false); + } + } catch (err: any) { + console.error(err); + addToast(err.response?.data?.message || t("toast_bulk_renew_failed"), "error"); + } finally { + setIsBulkRenewing(false); + } + }; + if (error) return
{t("load_failed")}
; const certificates = data?.data || []; @@ -133,6 +124,15 @@ export default function RootCaManagementClient() {
+
@@ -196,6 +196,18 @@ export default function RootCaManagementClient() { variant="warning" requiredInput="RENEW" /> + + setShowBulkRenewConfirm(false)} + onConfirm={handleRenewAll} + title={t("bulk_renew_modal_title")} + message={t("bulk_renew_modal_msg")} + isLoading={isBulkRenewing} + confirmLabel={t("bulk_renew_confirm_label")} + variant="warning" + requiredInput="RENEW-ALL" + />
); } diff --git a/src/components/ui/button/Button.tsx b/src/components/ui/button/Button.tsx index 54c9faf..0e22d5b 100644 --- a/src/components/ui/button/Button.tsx +++ b/src/components/ui/button/Button.tsx @@ -3,7 +3,7 @@ import React, { ReactNode } from "react"; interface ButtonProps { children: ReactNode; // Button text or content size?: "sm" | "md"; // Button size - variant?: "primary" | "outline" | "danger" | "success"; // Button variant + variant?: "primary" | "outline" | "danger" | "success" | "warning"; // Button variant startIcon?: ReactNode; // Icon before the text endIcon?: ReactNode; // Icon after the text onClick?: () => void; // Click handler @@ -41,6 +41,8 @@ const Button: React.FC = ({ "bg-red-600 text-white shadow-theme-xs hover:bg-red-700 disabled:bg-red-300 dark:bg-red-600 dark:hover:bg-red-700", success: "bg-green-600 text-white shadow-theme-xs hover:bg-green-700 disabled:bg-green-300 dark:bg-green-600 dark:hover:bg-green-700", + warning: + "bg-warning-500 text-white shadow-theme-xs hover:bg-warning-600 disabled:bg-warning-300 dark:bg-warning-600 dark:hover:bg-warning-700", }; return ( diff --git a/src/messages/en.json b/src/messages/en.json index 1a5f4b9..a0e9f7b 100644 --- a/src/messages/en.json +++ b/src/messages/en.json @@ -643,6 +643,12 @@ "cdn_group_assets_desc": "Update specific file types to the CDN (Uses 'Both' mode by default).", "cdn_group_modes": "Dual CDN Strategy", "cdn_group_modes_desc": "Control asset distribution paths (Clean URLs vs Global Archives).", + "renew_all_button": "Renew All (Chain-Refresh)", + "bulk_renew_modal_title": "Renew Entire CA Chain?", + "bulk_renew_modal_msg": "This will regenerate the Root CA and all Intermediate CAs sequentially. This is a significant action that will refresh the entire Chain of Trust. Type 'RENEW-ALL' to proceed.", + "bulk_renew_confirm_label": "Renew Everything", + "toast_bulk_renew_success": "Entire CA chain renewed successfully!", + "toast_bulk_renew_failed": "Bulk renewal failed", "toast_renew_success": "CA Certificate renewed successfully.", "toast_renew_failed": "Failed to renew CA certificate", "load_failed": "Failed to load CA certificates. Admin access required.", diff --git a/src/messages/id.json b/src/messages/id.json index 7ae63d1..c0511ac 100644 --- a/src/messages/id.json +++ b/src/messages/id.json @@ -643,6 +643,12 @@ "cdn_group_assets_desc": "Perbarui file spesifik ke CDN (Menggunakan mode 'Both' secara default).", "cdn_group_modes": "Strategi Dual CDN (Mode-specific)", "cdn_group_modes_desc": "Kontrol jalur distribusi aset (Clean URLs vs Global Archives).", + "renew_all_button": "Pembaruan Massal (Renew All)", + "bulk_renew_modal_title": "Perbarui Seluruh Rantai CA?", + "bulk_renew_modal_msg": "Ini akan meregenerasi Root CA dan semua Intermediate CA secara berurutan. Ini adalah tindakan besar yang akan menyegarkan seluruh Rantai Kepercayaan (Chain of Trust). Ketik 'RENEW-ALL' untuk melanjutkan.", + "bulk_renew_confirm_label": "Perbarui Semuanya", + "toast_bulk_renew_success": "Seluruh rantai CA berhasil diperbarui!", + "toast_bulk_renew_failed": "Pembaruan massal gagal", "toast_renew_success": "Sertifikat CA berhasil diperbarui.", "toast_renew_failed": "Gagal memperbarui sertifikat CA", "load_failed": "Gagal memuat sertifikat CA. Diperlukan akses admin.",