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