mirror of
https://github.com/dyzulk/trustlab.git
synced 2026-01-26 13:32:06 +07:00
feat: implement global bundle UI, granular sync buttons, and integration with new API endpoints
This commit is contained in:
@@ -15,6 +15,35 @@ import { useTranslations } from "next-intl";
|
||||
|
||||
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 (
|
||||
<button
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
className={`flex items-center justify-center gap-2 px-3 py-1.5 ${variantClasses[variant]} text-white text-xs font-medium rounded-lg transition-all shadow-sm active:scale-95`}
|
||||
>
|
||||
{isLoading ? (
|
||||
<svg className="animate-spin h-3.5 w-3.5 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-3.5 w-3.5" 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>
|
||||
)}
|
||||
{isLoading ? "Syncing..." : label}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export default function RootCaManagementClient() {
|
||||
const t = useTranslations("RootCA");
|
||||
const { user } = useAuth();
|
||||
@@ -50,15 +79,29 @@ export default function RootCaManagementClient() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleSyncCdn = async () => {
|
||||
const handleSyncCdn = async (type: 'all' | 'crt' | 'installers' | 'bundles') => {
|
||||
setIsSyncing(true);
|
||||
try {
|
||||
const response = await axios.post("/api/admin/ca-certificates/sync-cdn");
|
||||
addToast(response.data.message || "Sync to CDN successful", "success");
|
||||
let endpoint = "/api/admin/ca-certificates/sync-cdn";
|
||||
let msg = "Full Sync successful";
|
||||
|
||||
if (type === 'crt') {
|
||||
endpoint = "/api/admin/ca-certificates/sync-crt";
|
||||
msg = "CRT Files Sync successful";
|
||||
} else if (type === 'installers') {
|
||||
endpoint = "/api/admin/ca-certificates/sync-installers";
|
||||
msg = "Individual Installers Sync successful";
|
||||
} else if (type === 'bundles') {
|
||||
endpoint = "/api/admin/ca-certificates/sync-bundles";
|
||||
msg = "Global Bundles Sync successful";
|
||||
}
|
||||
|
||||
const response = await axios.post(endpoint);
|
||||
addToast(response.data.message || msg, "success");
|
||||
mutate();
|
||||
} catch (err: any) {
|
||||
console.error(err);
|
||||
addToast(err.response?.data?.message || "Sync to CDN failed", "error");
|
||||
addToast(err.response?.data?.message || "Sync failed", "error");
|
||||
} finally {
|
||||
setIsSyncing(false);
|
||||
}
|
||||
@@ -73,23 +116,36 @@ export default function RootCaManagementClient() {
|
||||
<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 className="flex flex-wrap items-center gap-2">
|
||||
<SyncButton
|
||||
onClick={() => handleSyncCdn('crt')}
|
||||
disabled={isSyncing || isLoading}
|
||||
isLoading={isSyncing}
|
||||
label="Sync CRT Only"
|
||||
variant="gray"
|
||||
/>
|
||||
<SyncButton
|
||||
onClick={() => handleSyncCdn('installers')}
|
||||
disabled={isSyncing || isLoading}
|
||||
isLoading={isSyncing}
|
||||
label="Sync Installers Only"
|
||||
variant="blue"
|
||||
/>
|
||||
<SyncButton
|
||||
onClick={() => handleSyncCdn('bundles')}
|
||||
disabled={isSyncing || isLoading}
|
||||
isLoading={isSyncing}
|
||||
label="Sync Full Bundles"
|
||||
variant="purple"
|
||||
/>
|
||||
<SyncButton
|
||||
onClick={() => handleSyncCdn('all')}
|
||||
disabled={isSyncing || isLoading}
|
||||
isLoading={isSyncing}
|
||||
label="Sync All to CDN"
|
||||
variant="indigo"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6">
|
||||
|
||||
Reference in New Issue
Block a user