mirror of
https://github.com/dyzulk/trustlab.git
synced 2026-01-26 05:25:36 +07:00
feat: add sync to CDN button in Root CA management
This commit is contained in:
12
.agent/workflows/ai-instructions.md
Normal file
12
.agent/workflows/ai-instructions.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
description: Referensi Aturan AI TrustLab-Web
|
||||||
|
---
|
||||||
|
|
||||||
|
# ⚠️ BACA ATURAN UTAMA SEBELUM BEKERJA
|
||||||
|
|
||||||
|
Semua aturan untuk proyek ini telah dipusatkan di root folder untuk menghindari miskomunikasi.
|
||||||
|
|
||||||
|
**WAJIB BACA:**
|
||||||
|
[Master AI Instructions (Root)](file:///D:/Lab/HomeLab/Github/dyzulk/trustlab/.agent/workflows/ai-instructions.md)
|
||||||
|
|
||||||
|
Pahami bagian **PART 5: FRONTEND (TRUSTLAB-WEB)** secara mendalam sebelum melakukan perubahan.
|
||||||
@@ -22,6 +22,7 @@ export default function RootCaManagementClient() {
|
|||||||
const { addToast } = useToast();
|
const { addToast } = useToast();
|
||||||
const { data, error, mutate, isLoading } = useSWR("/api/admin/ca-certificates", fetcher);
|
const { data, error, mutate, isLoading } = useSWR("/api/admin/ca-certificates", fetcher);
|
||||||
const [isRenewing, setIsRenewing] = useState(false);
|
const [isRenewing, setIsRenewing] = useState(false);
|
||||||
|
const [isSyncing, setIsSyncing] = useState(false);
|
||||||
const [confirmRenewUuid, setConfirmRenewUuid] = useState<string | null>(null);
|
const [confirmRenewUuid, setConfirmRenewUuid] = useState<string | null>(null);
|
||||||
|
|
||||||
// Redirect if not admin or owner (double security, backend also checks)
|
// Redirect if not admin or owner (double security, backend also checks)
|
||||||
@@ -49,13 +50,47 @@ export default function RootCaManagementClient() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSyncCdn = async () => {
|
||||||
|
setIsSyncing(true);
|
||||||
|
try {
|
||||||
|
const response = await axios.post("/api/admin/ca-certificates/sync-cdn");
|
||||||
|
addToast(response.data.message || "Sync to CDN successful", "success");
|
||||||
|
mutate();
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error(err);
|
||||||
|
addToast(err.response?.data?.message || "Sync to CDN failed", "error");
|
||||||
|
} finally {
|
||||||
|
setIsSyncing(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (error) return <div className="p-10 text-center text-error-500">{t("load_failed")}</div>;
|
if (error) return <div className="p-10 text-center text-error-500">{t("load_failed")}</div>;
|
||||||
|
|
||||||
const certificates = data?.data || [];
|
const certificates = data?.data || [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PageBreadcrumb pageTitle={t("management_title")} />
|
<div className="flex flex-col md:flex-row md:items-center justify-between mb-4 gap-4">
|
||||||
|
<PageBreadcrumb pageTitle={t("management_title")} />
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={handleSyncCdn}
|
||||||
|
disabled={isSyncing || isLoading}
|
||||||
|
className="flex items-center justify-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 disabled:bg-blue-400 text-white text-sm font-medium rounded-lg transition-colors shadow-sm"
|
||||||
|
>
|
||||||
|
{isSyncing ? (
|
||||||
|
<svg className="animate-spin h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||||
|
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
|
||||||
|
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||||
|
</svg>
|
||||||
|
) : (
|
||||||
|
<svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
{isSyncing ? "Syncing..." : "Sync All to CDN"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<ComponentCard
|
<ComponentCard
|
||||||
|
|||||||
Reference in New Issue
Block a user