diff --git a/frontend-modern/src/api/notifications.ts b/frontend-modern/src/api/notifications.ts index a943bd685..559584f50 100644 --- a/frontend-modern/src/api/notifications.ts +++ b/frontend-modern/src/api/notifications.ts @@ -1,4 +1,3 @@ -import type { AlertConfig } from '@/types/alerts'; export interface EmailProvider { id: string; diff --git a/frontend-modern/src/api/settings.ts b/frontend-modern/src/api/settings.ts index 3b252df4a..6ac9c15a7 100644 --- a/frontend-modern/src/api/settings.ts +++ b/frontend-modern/src/api/settings.ts @@ -1,8 +1,6 @@ import type { - Settings, SettingsResponse, - SettingsUpdateRequest, - MonitoringSettings + SettingsUpdateRequest } from '@/types/settings'; // System settings type matching Go backend diff --git a/frontend-modern/src/components/Backups/UnifiedBackups.tsx b/frontend-modern/src/components/Backups/UnifiedBackups.tsx index 473cab4cc..b411e4107 100644 --- a/frontend-modern/src/components/Backups/UnifiedBackups.tsx +++ b/frontend-modern/src/components/Backups/UnifiedBackups.tsx @@ -88,7 +88,7 @@ const UnifiedBackups: Component = () => { const debugMode = false; // Normalize snapshots - state.pveBackups?.guestSnapshots?.forEach((snapshot: any) => { + state.pveBackups?.guestSnapshots?.forEach((snapshot) => { unified.push({ backupType: 'snapshot', vmid: snapshot.vmid, @@ -110,7 +110,7 @@ const UnifiedBackups: Component = () => { // Process PBS backups FIRST from the new Go backend (state.pbsBackups) // This ensures we have the complete PBS data with namespaces - state.pbsBackups?.forEach((backup: any) => { + state.pbsBackups?.forEach((backup) => { const backupDate = new Date(backup.backupTime); const dateStr = backupDate.toISOString().split('T')[0]; const timeStr = backupDate.toISOString().split('T')[1].split('.')[0].replace(/:/g, ''); @@ -146,7 +146,7 @@ const UnifiedBackups: Component = () => { }); // Normalize local backups (including PBS through PVE storage) - state.pveBackups?.storageBackups?.forEach((backup: any) => { + state.pveBackups?.storageBackups?.forEach((backup) => { // Determine if this is actually a PBS backup based on storage const backupType = backup.isPBS ? 'remote' : 'local'; @@ -211,7 +211,7 @@ const UnifiedBackups: Component = () => { // Also check datastores for snapshots (original JS structure) if (pbsInstance.datastores && Array.isArray(pbsInstance.datastores)) { - pbsInstance.datastores.forEach((datastore: any) => { + pbsInstance.datastores?.forEach((datastore: any) => { if (datastore.snapshots && Array.isArray(datastore.snapshots)) { datastore.snapshots.forEach((backup: any) => { let totalSize = 0; diff --git a/frontend-modern/src/components/Settings/Settings.tsx b/frontend-modern/src/components/Settings/Settings.tsx index 46d5bfd8d..b2310894a 100644 --- a/frontend-modern/src/components/Settings/Settings.tsx +++ b/frontend-modern/src/components/Settings/Settings.tsx @@ -226,12 +226,12 @@ const Settings: Component = () => {

{node.host}

- {node.user ? `User: ${node.user}` : `Token: ${node.tokenName}`} + {node.username ? `User: ${node.username}` : `Token: ${node.tokenName}`} - {node.monitorVMs && VMs} - {node.monitorContainers && Containers} - {node.monitorStorage && Storage} - {node.monitorBackups && Backups} + {node.type === 'pve' && 'monitorVMs' in node && node.monitorVMs && VMs} + {node.type === 'pve' && 'monitorContainers' in node && node.monitorContainers && Containers} + {node.type === 'pve' && 'monitorStorage' in node && node.monitorStorage && Storage} + {node.type === 'pve' && 'monitorBackups' in node && node.monitorBackups && Backups}
@@ -317,12 +317,12 @@ const Settings: Component = () => {

{node.host}

- {node.user ? `User: ${node.user}` : `Token: ${node.tokenName}`} + {node.username ? `User: ${node.username}` : `Token: ${node.tokenName}`} - {node.monitorDatastores && Datastores} - {node.monitorSyncJobs && Sync Jobs} - {node.monitorVerifyJobs && Verify Jobs} - {node.monitorPruneJobs && Prune Jobs} + {node.type === 'pbs' && 'monitorDatastores' in node && node.monitorDatastores && Datastores} + {node.type === 'pbs' && 'monitorSyncJobs' in node && node.monitorSyncJobs && Sync Jobs} + {node.type === 'pbs' && 'monitorVerifyJobs' in node && node.monitorVerifyJobs && Verify Jobs} + {node.type === 'pbs' && 'monitorPruneJobs' in node && node.monitorPruneJobs && Prune Jobs}
diff --git a/frontend-modern/src/pages/Alerts.tsx b/frontend-modern/src/pages/Alerts.tsx index 83b3cb788..ba95353cc 100644 --- a/frontend-modern/src/pages/Alerts.tsx +++ b/frontend-modern/src/pages/Alerts.tsx @@ -5,6 +5,8 @@ import { WebhookConfig } from '@/components/Alerts/WebhookConfig'; import { CustomRulesTab } from '@/components/Alerts/CustomRulesTab'; import { useWebSocket } from '@/App'; import { showSuccess, showError } from '@/utils/toast'; +import { AlertsAPI } from '@/api/alerts'; +import { NotificationsAPI } from '@/api/notifications'; type AlertTab = 'overview' | 'thresholds' | 'destinations' | 'schedule' | 'history' | 'custom-rules'; @@ -555,7 +557,7 @@ function OverviewTab(props: { overrides: any[]; activeAlerts: Record { // API call to acknowledge alert AlertsAPI.acknowledge(alert.id) - .catch(err => console.error('Failed to acknowledge alert:', err)); + .catch((err: unknown) => console.error('Failed to acknowledge alert:', err)); }} > Acknowledge @@ -566,7 +568,7 @@ function OverviewTab(props: { overrides: any[]; activeAlerts: Record { // API call to clear alert AlertsAPI.clearAlert(alert.id) - .catch(err => console.error('Failed to clear alert:', err)); + .catch((err: unknown) => console.error('Failed to clear alert:', err)); }} > Clear @@ -1192,7 +1194,23 @@ function DestinationsTab(props: any) { onMount(async () => { try { const config = await NotificationsAPI.getEmailConfig(); - setEmailConfig(config); + // Map API config to local format + setEmailConfig({ + enabled: config.enabled, + provider: config.provider, + smtpHost: config.server, + smtpPort: config.port, + username: config.username, + password: config.password || '', + from: config.from, + to: config.to, + tls: config.tls, + startTLS: config.starttls, + replyTo: '', + maxRetries: 3, + retryDelay: 5, + rateLimit: 60 + }); } catch (err) { console.error('Failed to load email config:', err); } diff --git a/frontend-modern/src/types/backups.ts b/frontend-modern/src/types/backups.ts new file mode 100644 index 000000000..3d9742377 --- /dev/null +++ b/frontend-modern/src/types/backups.ts @@ -0,0 +1,94 @@ +// Unified backup types for the backup view + +export interface UnifiedBackup { + // Common fields + backupType: 'backup' | 'snapshot' | 'pbs'; + vmid: number; + name: string; + type: 'VM' | 'LXC' | 'CT'; + node: string; + backupTime: number; // Unix timestamp in seconds + backupName: string; + description: string; + status: string; + size: number | null; + storage: string | null; + + // PBS specific + datastore: string | null; + namespace: string | null; + verified: boolean | null; + + // Common flags + protected: boolean; + + // UI specific + instance?: string; + isPBS?: boolean; +} + +// PBS-specific backup file info +export interface PBSBackupFile { + filename: string; + size: number; + crypt?: string; +} + +// Extended PBS backup with file details +export interface PBSBackupWithFiles { + id: string; + instance: string; + datastore: string; + namespace?: string; + backupType: string; + vmid: number; + backupTime: string; + size: number; + protected: boolean; + verified: boolean; + comment?: string; + files: PBSBackupFile[]; +} + +// PBS datastore with snapshots +export interface PBSDatastoreSnapshot { + id: string; + backupTime: string; + size: number; + owner?: string; + verified?: boolean; + protected?: boolean; + files?: PBSBackupFile[]; +} + +export interface PBSDatastore { + name: string; + total: number; + used: number; + free: number; + snapshots: PBSDatastoreSnapshot[]; +} + +export interface PBSInstanceData { + id: string; + name: string; + host: string; + backups: PBSBackupWithFiles[]; + datastores: PBSDatastore[]; +} + +// Filter options for the backup view +export interface BackupFilters { + instance: string; + type: 'all' | 'VM' | 'LXC'; + node: string; + storage: string; + protected: 'all' | 'protected' | 'unprotected'; + verified: 'all' | 'verified' | 'unverified'; +} + +// Sorting options +export interface BackupSort { + key: keyof UnifiedBackup; + order: 'asc' | 'desc'; +} \ No newline at end of file