diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 6a2c0909..56c44a07 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -10,6 +10,7 @@ import RemoteServers from './pages/RemoteServers' import ImportCaddy from './pages/ImportCaddy' import Certificates from './pages/Certificates' import SettingsLayout from './pages/SettingsLayout' +import SystemSettings from './pages/SystemSettings' import Security from './pages/Security' import Backups from './pages/Backups' import Logs from './pages/Logs' @@ -40,7 +41,8 @@ export default function App() { {/* Settings Routes */} }> - } /> {/* Default to Security */} + } /> {/* Default to System */} + } /> } /> } /> diff --git a/frontend/src/api/backups.ts b/frontend/src/api/backups.ts index 032e2146..672f4a49 100644 --- a/frontend/src/api/backups.ts +++ b/frontend/src/api/backups.ts @@ -1,9 +1,9 @@ import client from './client'; export interface BackupFile { - name: string; + filename: string; size: number; - mod_time: string; + time: string; } export const getBackups = async (): Promise => { @@ -20,10 +20,6 @@ export const restoreBackup = async (filename: string): Promise => { await client.post(`/backups/${filename}/restore`); }; -export const deleteBackup = async (_filename: string): Promise => { - // Note: Delete endpoint wasn't explicitly asked for in the backend implementation plan, - // but it's good practice. I'll skip implementing the API call for now if the backend doesn't support it yet - // to avoid 404s, but I should probably add it to the backend later. - // For now, let's stick to what we built. - throw new Error("Not implemented"); +export const deleteBackup = async (filename: string): Promise => { + await client.delete(`/backups/${filename}`); }; diff --git a/frontend/src/pages/Backups.tsx b/frontend/src/pages/Backups.tsx index 4ec7495c..fd4f609a 100644 --- a/frontend/src/pages/Backups.tsx +++ b/frontend/src/pages/Backups.tsx @@ -8,6 +8,12 @@ import { getBackups, createBackup, restoreBackup, deleteBackup } from '../api/ba import { getSettings, updateSetting } from '../api/settings' import { Loader2, Download, RotateCcw, Plus, Archive, Trash2, Save } from 'lucide-react' +const formatSize = (bytes: number): string => { + if (bytes < 1024) return `${bytes} B` + if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB` + return `${(bytes / 1024 / 1024).toFixed(2)} MB` +} + export default function Backups() { const queryClient = useQueryClient() const [interval, setInterval] = useState('7') @@ -165,10 +171,10 @@ export default function Backups() { {backup.filename} - {(backup.size / 1024 / 1024).toFixed(2)} MB + {formatSize(backup.size)} - {new Date(backup.created_at).toLocaleString()} + {new Date(backup.time).toLocaleString()} + + + + + {/* System Status */} + +

+ + System Status +

+ {isLoadingHealth ? ( +
+ +
+ ) : health ? ( +
+
+

Service

+

{health.service}

+
+
+

Status

+

+ {health.status} +

+
+
+

Version

+

{health.version}

+
+
+

Build Time

+

+ {health.build_time || 'N/A'} +

+
+
+

Git Commit

+

+ {health.git_commit || 'N/A'} +

+
+
+ ) : ( +

Unable to fetch system status

+ )} +
+ + {/* Update Check */} + +

Software Updates

+
+ {updateInfo && ( +
+
+

Current Version

+

+ {updateInfo.current_version} +

+
+
+

Latest Version

+

+ {updateInfo.latest_version} +

+
+ {updateInfo.update_available && ( +
+
+

+ A new version is available! +

+ {updateInfo.release_url && ( + + View Release Notes + + )} +
+
+ )} + {!updateInfo.update_available && ( +
+

+ ✓ You are running the latest version +

+
+ )} +
+ )} + +
+
+ + ) +}