mirror of
https://github.com/dyzulk/trustlab.git
synced 2026-01-26 13:32:06 +07:00
feat: localize all hardcoded strings in Root CA Management and Archive UI
This commit is contained in:
@@ -62,25 +62,21 @@ export default function RootCaManagementClient() {
|
|||||||
setActiveSync(syncKey);
|
setActiveSync(syncKey);
|
||||||
try {
|
try {
|
||||||
let endpoint = "/api/admin/ca-certificates/sync-cdn";
|
let endpoint = "/api/admin/ca-certificates/sync-cdn";
|
||||||
let msg = `Sync successful (Mode: ${mode})`;
|
|
||||||
|
|
||||||
if (type === 'crt') {
|
if (type === 'crt') {
|
||||||
endpoint = "/api/admin/ca-certificates/sync-crt";
|
endpoint = "/api/admin/ca-certificates/sync-crt";
|
||||||
msg = `CRT Files Sync successful (${mode})`;
|
|
||||||
} else if (type === 'installers') {
|
} else if (type === 'installers') {
|
||||||
endpoint = "/api/admin/ca-certificates/sync-installers";
|
endpoint = "/api/admin/ca-certificates/sync-installers";
|
||||||
msg = `Individual Installers Sync successful (${mode})`;
|
|
||||||
} else if (type === 'bundles') {
|
} else if (type === 'bundles') {
|
||||||
endpoint = "/api/admin/ca-certificates/sync-bundles";
|
endpoint = "/api/admin/ca-certificates/sync-bundles";
|
||||||
msg = "Global Bundles Sync successful";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await axios.post(endpoint, { mode });
|
const response = await axios.post(endpoint, { mode });
|
||||||
addToast(response.data.message || msg, "success");
|
addToast(response.data.message || t("toast_sync_success"), "success");
|
||||||
mutate();
|
mutate();
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
addToast(err.response?.data?.message || "Sync failed", "error");
|
addToast(err.response?.data?.message || t("toast_sync_failed"), "error");
|
||||||
} finally {
|
} finally {
|
||||||
setActiveSync(null);
|
setActiveSync(null);
|
||||||
}
|
}
|
||||||
@@ -90,11 +86,11 @@ export default function RootCaManagementClient() {
|
|||||||
setIsPromoting(true);
|
setIsPromoting(true);
|
||||||
try {
|
try {
|
||||||
const response = await axios.post(`/api/admin/ca-certificates/${uuid}/promote`);
|
const response = await axios.post(`/api/admin/ca-certificates/${uuid}/promote`);
|
||||||
addToast(response.data.message || "Promoted successfully", "success");
|
addToast(response.data.message || t("toast_promote_success"), "success");
|
||||||
mutate();
|
mutate();
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
addToast(err.response?.data?.message || "Promotion failed", "error");
|
addToast(err.response?.data?.message || t("toast_promote_failed"), "error");
|
||||||
} finally {
|
} finally {
|
||||||
setIsPromoting(false);
|
setIsPromoting(false);
|
||||||
}
|
}
|
||||||
@@ -192,8 +188,8 @@ export default function RootCaManagementClient() {
|
|||||||
|
|
||||||
{/* Full-width Archive History */}
|
{/* Full-width Archive History */}
|
||||||
<ComponentCard
|
<ComponentCard
|
||||||
title="Version Archives"
|
title={t("archive_management_title")}
|
||||||
desc="Browse historical versions and promote them back to Latest if needed. This table provides full visibility into your CDN audit trail."
|
desc={t("archive_management_desc")}
|
||||||
>
|
>
|
||||||
<ArchiveManagementTable
|
<ArchiveManagementTable
|
||||||
certificates={certificates}
|
certificates={certificates}
|
||||||
|
|||||||
@@ -72,10 +72,10 @@ export default function ArchiveManagementTable({
|
|||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{/* Table Header Controls */}
|
{/* Table Header Controls */}
|
||||||
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between px-1">
|
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between px-1">
|
||||||
<h4 className="text-sm font-bold text-gray-800 dark:text-white/90">CDN Archive History</h4>
|
<h4 className="text-sm font-bold text-gray-800 dark:text-white/90">{t("archive_history_title")}</h4>
|
||||||
<div className="w-full sm:w-64">
|
<div className="w-full sm:w-64">
|
||||||
<InputField
|
<InputField
|
||||||
placeholder="Search version/CN..."
|
placeholder={t("archive_search_placeholder")}
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
className="!py-2"
|
className="!py-2"
|
||||||
@@ -89,10 +89,10 @@ export default function ArchiveManagementTable({
|
|||||||
<TableHeader className="border-b border-gray-100 dark:border-white/[0.05]">
|
<TableHeader className="border-b border-gray-100 dark:border-white/[0.05]">
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell isHeader className="px-5 py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400">
|
<TableCell isHeader className="px-5 py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400">
|
||||||
Version (UUID)
|
{t("th_version_uuid")}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell isHeader className="px-5 py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400">
|
<TableCell isHeader className="px-5 py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400">
|
||||||
Family
|
{t("th_family")}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell isHeader className="px-5 py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400">
|
<TableCell isHeader className="px-5 py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400">
|
||||||
{t("common_name_th")}
|
{t("common_name_th")}
|
||||||
@@ -104,7 +104,7 @@ export default function ArchiveManagementTable({
|
|||||||
{t("validity_th")}
|
{t("validity_th")}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell isHeader className="px-5 py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400">
|
<TableCell isHeader className="px-5 py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400">
|
||||||
Status
|
{t("th_status")}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell isHeader className="px-5 py-3 font-medium text-gray-500 text-center text-theme-xs dark:text-gray-400">
|
<TableCell isHeader className="px-5 py-3 font-medium text-gray-500 text-center text-theme-xs dark:text-gray-400">
|
||||||
{t("actions_th")}
|
{t("actions_th")}
|
||||||
@@ -121,12 +121,12 @@ export default function ArchiveManagementTable({
|
|||||||
{cert.last_synced_at ? (
|
{cert.last_synced_at ? (
|
||||||
<div className="flex items-center gap-1.5">
|
<div className="flex items-center gap-1.5">
|
||||||
<span className="flex h-1.5 w-1.5 rounded-full bg-success-500"></span>
|
<span className="flex h-1.5 w-1.5 rounded-full bg-success-500"></span>
|
||||||
<span className="text-[9px] text-success-600 font-bold uppercase tracking-wider">Synced to CDN</span>
|
<span className="text-[9px] text-success-600 font-bold uppercase tracking-wider">{t("status_synced")}</span>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex items-center gap-1.5 opacity-60">
|
<div className="flex items-center gap-1.5 opacity-60">
|
||||||
<span className="flex h-1.5 w-1.5 rounded-full bg-warning-500"></span>
|
<span className="flex h-1.5 w-1.5 rounded-full bg-warning-500"></span>
|
||||||
<span className="text-[9px] text-warning-600 font-bold uppercase tracking-wider">Local Only</span>
|
<span className="text-[9px] text-warning-600 font-bold uppercase tracking-wider">{t("status_local")}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -181,11 +181,11 @@ export default function ArchiveManagementTable({
|
|||||||
onClick={() => onPromote(cert.uuid)}
|
onClick={() => onPromote(cert.uuid)}
|
||||||
loading={isPromoting}
|
loading={isPromoting}
|
||||||
>
|
>
|
||||||
Set as Latest
|
{t("btn_set_latest")}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{cert.is_latest && (
|
{cert.is_latest && (
|
||||||
<span className="text-[10px] text-gray-400 font-medium">Currently Public</span>
|
<span className="text-[10px] text-gray-400 font-medium">{t("status_currently_public")}</span>
|
||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@@ -193,7 +193,7 @@ export default function ArchiveManagementTable({
|
|||||||
{filteredAndSortedCertificates.length === 0 && (
|
{filteredAndSortedCertificates.length === 0 && (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={7} className="px-5 py-10 text-center text-gray-500 dark:text-gray-400">
|
<TableCell colSpan={7} className="px-5 py-10 text-center text-gray-500 dark:text-gray-400">
|
||||||
No versions found.
|
{t("no_archives_found")}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export default function CdnManagementCard({ onSync, activeSync, disabled }: CdnM
|
|||||||
<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" />
|
<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>
|
</svg>
|
||||||
)}
|
)}
|
||||||
{isLoading ? "Syncing..." : "Sync Now"}
|
{isLoading ? t("syncing_label") : t("sync_now_btn")}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -79,22 +79,22 @@ export default function CdnManagementCard({ onSync, activeSync, disabled }: CdnM
|
|||||||
<SyncButton
|
<SyncButton
|
||||||
type="crt"
|
type="crt"
|
||||||
mode="both"
|
mode="both"
|
||||||
label="Update CRT Only"
|
label={t("label_update_crt")}
|
||||||
desc="Hanya unggah file sertifikat publik (.crt, .der)."
|
desc={t("desc_update_crt")}
|
||||||
variant="blue"
|
variant="blue"
|
||||||
/>
|
/>
|
||||||
<SyncButton
|
<SyncButton
|
||||||
type="installers"
|
type="installers"
|
||||||
mode="both"
|
mode="both"
|
||||||
label="Update Scripts Only"
|
label={t("label_update_scripts")}
|
||||||
desc="Hanya perbarui skrip installer individual (.sh, .bat, .mac)."
|
desc={t("desc_update_scripts")}
|
||||||
variant="purple"
|
variant="purple"
|
||||||
/>
|
/>
|
||||||
<SyncButton
|
<SyncButton
|
||||||
type="bundles"
|
type="bundles"
|
||||||
mode="latest"
|
mode="latest"
|
||||||
label="Update Global Bundles"
|
label={t("label_update_bundles")}
|
||||||
desc="Perbarui paket installer sapujagat (Recommended)."
|
desc={t("desc_update_bundles")}
|
||||||
variant="success"
|
variant="success"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -109,22 +109,22 @@ export default function CdnManagementCard({ onSync, activeSync, disabled }: CdnM
|
|||||||
<SyncButton
|
<SyncButton
|
||||||
type="all"
|
type="all"
|
||||||
mode="both"
|
mode="both"
|
||||||
label="Dual Sync (Latest & Archive)"
|
label={t("label_dual_sync")}
|
||||||
desc="Sinkronisasi massal ke kedua jalur. Paling aman untuk integritas data."
|
desc={t("desc_dual_sync")}
|
||||||
variant="indigo"
|
variant="indigo"
|
||||||
/>
|
/>
|
||||||
<SyncButton
|
<SyncButton
|
||||||
type="all"
|
type="all"
|
||||||
mode="latest"
|
mode="latest"
|
||||||
label="Latest Sync (Clean URLs)"
|
label={t("label_latest_sync")}
|
||||||
desc="Hanya perbarui link publik utama pendukung installer."
|
desc={t("desc_latest_sync")}
|
||||||
variant="blue"
|
variant="blue"
|
||||||
/>
|
/>
|
||||||
<SyncButton
|
<SyncButton
|
||||||
type="all"
|
type="all"
|
||||||
mode="archive"
|
mode="archive"
|
||||||
label="Archive Sync (Versioned)"
|
label={t("label_archive_sync")}
|
||||||
desc="Hanya simpan arsip permanen tanpa mengubah link publik."
|
desc={t("desc_archive_sync")}
|
||||||
variant="gray"
|
variant="gray"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ export default function RootCaTable({
|
|||||||
{t("type_th")}
|
{t("type_th")}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell isHeader className="px-5 py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400">
|
<TableCell isHeader className="px-5 py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400">
|
||||||
Family
|
{t("th_family")}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell isHeader className="px-5 py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400">
|
<TableCell isHeader className="px-5 py-3 font-medium text-gray-500 text-start text-theme-xs dark:text-gray-400">
|
||||||
{t("common_name_th")}
|
{t("common_name_th")}
|
||||||
|
|||||||
@@ -676,7 +676,37 @@
|
|||||||
"self_signed": "Self-Signed",
|
"self_signed": "Self-Signed",
|
||||||
"renew_button": "Renew",
|
"renew_button": "Renew",
|
||||||
"no_ca_search": "No CAs matched \"{term}\"",
|
"no_ca_search": "No CAs matched \"{term}\"",
|
||||||
"no_ca_found": "No Root CA certificates found. Start by initializing the Certification Authority."
|
"no_ca_found": "No Root CA certificates found. Start by initializing the Certification Authority.",
|
||||||
|
"archive_history_title": "CDN Archive History",
|
||||||
|
"archive_search_placeholder": "Search version/CN...",
|
||||||
|
"th_version_uuid": "Version (UUID)",
|
||||||
|
"th_family": "Family",
|
||||||
|
"th_status": "Status",
|
||||||
|
"status_synced": "Synced to CDN",
|
||||||
|
"status_local": "Local Only",
|
||||||
|
"btn_set_latest": "Set as Latest",
|
||||||
|
"status_currently_public": "Currently Public",
|
||||||
|
"no_archives_found": "No versions found.",
|
||||||
|
"archive_management_title": "Version Archives",
|
||||||
|
"archive_management_desc": "Browse historical versions and promote them back to Latest if needed. This table provides full visibility into your CDN audit trail.",
|
||||||
|
"toast_sync_success": "Synchronization successful",
|
||||||
|
"toast_sync_failed": "Synchronization failed",
|
||||||
|
"toast_promote_success": "Promoted to latest successfully",
|
||||||
|
"toast_promote_failed": "Failed to promote version",
|
||||||
|
"syncing_label": "Syncing...",
|
||||||
|
"sync_now_btn": "Sync Now",
|
||||||
|
"label_update_crt": "Update CRT Only",
|
||||||
|
"desc_update_crt": "Only upload public certificate files (.crt, .der).",
|
||||||
|
"label_update_scripts": "Update Scripts Only",
|
||||||
|
"desc_update_scripts": "Only update individual installer scripts (.sh, .bat, .mac).",
|
||||||
|
"label_update_bundles": "Update Global Bundles",
|
||||||
|
"desc_update_bundles": "Update all-in-one installer packages (Recommended).",
|
||||||
|
"label_dual_sync": "Dual Sync (Latest & Archive)",
|
||||||
|
"desc_dual_sync": "Bulk sync to both paths. Safest for data integrity.",
|
||||||
|
"label_latest_sync": "Latest Sync (Clean URLs)",
|
||||||
|
"desc_latest_sync": "Only update the primary public links for installers.",
|
||||||
|
"label_archive_sync": "Archive Sync (Versioned)",
|
||||||
|
"desc_archive_sync": "Only save permanent archives without changing public links."
|
||||||
},
|
},
|
||||||
"SmtpTester": {
|
"SmtpTester": {
|
||||||
"page_title": "SMTP Tester",
|
"page_title": "SMTP Tester",
|
||||||
|
|||||||
@@ -676,7 +676,37 @@
|
|||||||
"self_signed": "Self-Signed",
|
"self_signed": "Self-Signed",
|
||||||
"renew_button": "Perbarui",
|
"renew_button": "Perbarui",
|
||||||
"no_ca_search": "Tidak ada CA yang cocok dengan \"{term}\"",
|
"no_ca_search": "Tidak ada CA yang cocok dengan \"{term}\"",
|
||||||
"no_ca_found": "Sertifikat Root CA tidak ditemukan. Mulailah dengan menginisialisasi Certification Authority."
|
"no_ca_found": "Sertifikat Root CA tidak ditemukan. Mulailah dengan menginisialisasi Certification Authority.",
|
||||||
|
"archive_history_title": "Riwayat Arsip CDN",
|
||||||
|
"archive_search_placeholder": "Cari versi/CN...",
|
||||||
|
"th_version_uuid": "Versi (UUID)",
|
||||||
|
"th_family": "Keluarga",
|
||||||
|
"th_status": "Status",
|
||||||
|
"status_synced": "Tersinkronisasi ke CDN",
|
||||||
|
"status_local": "Hanya Lokal",
|
||||||
|
"btn_set_latest": "Jadikan Terbaru",
|
||||||
|
"status_currently_public": "Publik Saat Ini",
|
||||||
|
"no_archives_found": "Versi tidak ditemukan.",
|
||||||
|
"archive_management_title": "Arsip Versi",
|
||||||
|
"archive_management_desc": "Telusuri versi historis dan jadikan kembali sebagai Versi Terbaru jika diperlukan. Tabel ini memberikan visibilitas penuh terhadap jejak audit CDN Anda.",
|
||||||
|
"toast_sync_success": "Sinkronisasi berhasil",
|
||||||
|
"toast_sync_failed": "Sinkronisasi gagal",
|
||||||
|
"toast_promote_success": "Berhasil dijadikan versi terbaru",
|
||||||
|
"toast_promote_failed": "Gagal menjadikan versi terbaru",
|
||||||
|
"syncing_label": "Menyinkronkan...",
|
||||||
|
"sync_now_btn": "Sinkronisasi",
|
||||||
|
"label_update_crt": "Perbarui CRT Saja",
|
||||||
|
"desc_update_crt": "Hanya unggah file sertifikat publik (.crt, .der).",
|
||||||
|
"label_update_scripts": "Perbarui Skrip Saja",
|
||||||
|
"desc_update_scripts": "Hanya perbarui skrip installer individual (.sh, .bat, .mac).",
|
||||||
|
"label_update_bundles": "Perbarui Paket Global",
|
||||||
|
"desc_update_bundles": "Perbarui paket installer sapujagat (Disarankan).",
|
||||||
|
"label_dual_sync": "Sinkronisasi Ganda (Terbaru & Arsip)",
|
||||||
|
"desc_dual_sync": "Sinkronisasi massal ke kedua jalur. Paling aman untuk integritas data.",
|
||||||
|
"label_latest_sync": "Sinkronisasi Terbaru (URL Bersih)",
|
||||||
|
"desc_latest_sync": "Hanya perbarui link publik utama pendukung installer.",
|
||||||
|
"label_archive_sync": "Sinkronisasi Arsip (Versi)",
|
||||||
|
"desc_archive_sync": "Hanya simpan arsip permanen tanpa mengubah link publik."
|
||||||
},
|
},
|
||||||
"SmtpTester": {
|
"SmtpTester": {
|
||||||
"page_title": "Pengetes SMTP",
|
"page_title": "Pengetes SMTP",
|
||||||
|
|||||||
Reference in New Issue
Block a user