diff --git a/backend/app/api/common.py b/backend/app/api/common.py index 5282f3e..af0ebb6 100644 --- a/backend/app/api/common.py +++ b/backend/app/api/common.py @@ -159,6 +159,13 @@ class DashboardStatsSchema(BaseModel): redundancy_ratio: float +class StagingInfoSchema(BaseModel): + path: str + total_bytes: int + used_bytes: int + free_bytes: int + + class JobSchema(BaseModel): model_config = ConfigDict(from_attributes=True) diff --git a/backend/app/api/system/dashboard.py b/backend/app/api/system/dashboard.py index d29efc3..8f8c506 100644 --- a/backend/app/api/system/dashboard.py +++ b/backend/app/api/system/dashboard.py @@ -1,7 +1,10 @@ +import shutil + from fastapi import APIRouter, Depends from sqlalchemy.orm import Session from app.db.database import get_db -from app.api.common import DashboardStatsSchema +from app.api.common import DashboardStatsSchema, StagingInfoSchema +from app.core.config import settings from sqlalchemy import func, text from app.db import models @@ -113,3 +116,37 @@ def get_dashboard_stats(db_session: Session = Depends(get_db)): last_scan_time=last_scan.completed_at if last_scan else None, redundancy_ratio=round(redundancy_percentage, 1), ) + + +@router.get( + "/staging/info", response_model=StagingInfoSchema, operation_id="get_staging_info" +) +def get_staging_info(): + """Returns disk usage information for the backup staging directory.""" + path = settings.staging_directory + try: + usage = shutil.disk_usage(path) + return StagingInfoSchema( + path=path, + total_bytes=usage.total, + used_bytes=usage.used, + free_bytes=usage.free, + ) + except OSError: + # Fallback: if the configured path doesn't exist yet, check its parent + parent = path if path == "/" else path.rsplit("/", 1)[0] or "/" + try: + usage = shutil.disk_usage(parent) + return StagingInfoSchema( + path=path, + total_bytes=usage.total, + used_bytes=usage.used, + free_bytes=usage.free, + ) + except OSError: + return StagingInfoSchema( + path=path, + total_bytes=0, + used_bytes=0, + free_bytes=0, + ) diff --git a/backend/app/services/archiver.py b/backend/app/services/archiver.py index 27be8b3..8ad1741 100644 --- a/backend/app/services/archiver.py +++ b/backend/app/services/archiver.py @@ -374,6 +374,31 @@ class ArchiverService: if current_chunk: chunks.append(current_chunk) + # --- Staging Space Validation --- + # Sequential media (tape) requires staging the full tarfile before writing. + # Ensure the staging directory has enough free space for the largest chunk. + if not storage_provider.capabilities.get("supports_random_access"): + largest_chunk_size = max( + sum(i["offset_end"] - i["offset_start"] for i in chunk) + for chunk in chunks + ) + try: + usage = shutil.disk_usage(self.staging_directory) + # Require 110% of chunk size to leave headroom for tar overhead + required = int(largest_chunk_size * 1.1) + if usage.free < required: + free_gb = usage.free / (1024**3) + req_gb = required / (1024**3) + JobManager.fail_job( + job_id, + f"Staging area at {self.staging_directory} has only {free_gb:.1f} GB free, " + f"but the largest archive chunk requires {req_gb:.1f} GB. " + f"Free up space or reduce the backup set.", + ) + return + except OSError as e: + logger.warning(f"Could not check staging disk usage: {e}") + JobManager.add_job_log(job_id, f"Packed into {len(chunks)} archive(s)") for chunk_index, chunk_items in enumerate(chunks): diff --git a/frontend/src/lib/api/index.ts b/frontend/src/lib/api/index.ts index 9570603..f10597d 100644 --- a/frontend/src/lib/api/index.ts +++ b/frontend/src/lib/api/index.ts @@ -1,4 +1,4 @@ // This file is auto-generated by @hey-api/openapi-ts -export { addDirectoryToRestoreQueue, addFileToRestoreQueue, archiveBrowse, archiveMetadata, archiveSearch, archiveTree, batchAddToRestoreQueue, batchConfirmDiscrepancies, batchDeleteDiscrepancies, batchDismissDiscrepancies, batchResolveDiscrepancies, batchTrack, browseDiscrepancies, browseRestoreQueue, cancelJob, checkHealth, clearRestoreQueue, confirmDiscrepancy, createMedia, createSecret, deleteDiscrepancy, deleteMedia, deleteSecret, detectMedia, discoverHardware, dismissDiscrepancy, downloadExclusionReport, exportDatabase, filesystemBrowse, filesystemSearch, filesystemTree, getAnalytics, getDashboardStats, getDiscrepancyTree, getJob, getJobCount, getJobLogs, getJobStats, getRestoreManifest, getRestoreQueue, getRestoreQueueTree, getScanStatus, getSecret, getSettings, getTreemap, ignoreHardware, importDatabase, initializeMedia, listBackups, listDirectories, listDiscrepancies, listJobs, listMedia, listProviders, listSecrets, type Options, removeFromRestoreQueue, reorderMedia, resetTestEnvironment, retryJob, streamJobs, testExclusions, testNotification, triggerAutoBackup, triggerBackup, triggerIndexing, triggerRestore, triggerScan, undoDismissDiscrepancy, updateMedia, updateSettings } from './sdk.gen'; -export type { AddDirectoryToRestoreQueueData, AddDirectoryToRestoreQueueError, AddDirectoryToRestoreQueueErrors, AddDirectoryToRestoreQueueResponses, AddFileToRestoreQueueData, AddFileToRestoreQueueError, AddFileToRestoreQueueErrors, AddFileToRestoreQueueResponses, AppApiBackupsJobSchema, AppApiCommonJobSchema, ArchiveBrowseData, ArchiveBrowseError, ArchiveBrowseErrors, ArchiveBrowseResponses, ArchiveMetadataData, ArchiveMetadataError, ArchiveMetadataErrors, ArchiveMetadataResponse, ArchiveMetadataResponses, ArchiveSearchData, ArchiveSearchError, ArchiveSearchErrors, ArchiveSearchResponses, ArchiveTreeData, ArchiveTreeError, ArchiveTreeErrors, ArchiveTreeResponse, ArchiveTreeResponses, BatchAddToRestoreQueueData, BatchAddToRestoreQueueError, BatchAddToRestoreQueueErrors, BatchAddToRestoreQueueResponses, BatchCartRequest, BatchConfirmDiscrepanciesData, BatchConfirmDiscrepanciesError, BatchConfirmDiscrepanciesErrors, BatchConfirmDiscrepanciesResponses, BatchDeleteDiscrepanciesData, BatchDeleteDiscrepanciesError, BatchDeleteDiscrepanciesErrors, BatchDeleteDiscrepanciesResponses, BatchDiscrepancyAction, BatchDismissDiscrepanciesData, BatchDismissDiscrepanciesError, BatchDismissDiscrepanciesErrors, BatchDismissDiscrepanciesResponses, BatchResolveDiscrepanciesData, BatchResolveDiscrepanciesError, BatchResolveDiscrepanciesErrors, BatchResolveDiscrepanciesResponse, BatchResolveDiscrepanciesResponses, BatchResolveReport, BatchTrackData, BatchTrackError, BatchTrackErrors, BatchTrackRequest, BatchTrackResponses, BrowseDiscrepanciesData, BrowseDiscrepanciesError, BrowseDiscrepanciesErrors, BrowseDiscrepanciesResponse, BrowseDiscrepanciesResponses, BrowseResponseSchema, BrowseRestoreQueueData, BrowseRestoreQueueError, BrowseRestoreQueueErrors, BrowseRestoreQueueResponse, BrowseRestoreQueueResponses, CancelJobData, CancelJobError, CancelJobErrors, CancelJobResponses, CartFileItemSchema, CartItemSchema, CartTreeNodeSchema, CheckHealthData, CheckHealthResponses, ClearRestoreQueueData, ClearRestoreQueueResponses, ClientOptions, CloudCreateSchema, ConfirmDiscrepancyData, ConfirmDiscrepancyError, ConfirmDiscrepancyErrors, ConfirmDiscrepancyResponses, CreateMediaData, CreateMediaError, CreateMediaErrors, CreateMediaResponse, CreateMediaResponses, CreateSecretData, CreateSecretError, CreateSecretErrors, CreateSecretResponses, DashboardStatsSchema, DeleteDiscrepancyData, DeleteDiscrepancyError, DeleteDiscrepancyErrors, DeleteDiscrepancyResponses, DeleteMediaData, DeleteMediaError, DeleteMediaErrors, DeleteMediaResponses, DeleteSecretData, DeleteSecretError, DeleteSecretErrors, DeleteSecretResponses, DetectMediaData, DetectMediaResponses, DirectoryCartRequest, DiscoverHardwareData, DiscoverHardwareResponses, DiscrepancySchema, DismissDiscrepancyData, DismissDiscrepancyError, DismissDiscrepancyErrors, DismissDiscrepancyResponses, DownloadExclusionReportData, DownloadExclusionReportError, DownloadExclusionReportErrors, DownloadExclusionReportResponses, ExportDatabaseData, ExportDatabaseResponses, FileItemSchema, FilesystemBrowseData, FilesystemBrowseError, FilesystemBrowseErrors, FilesystemBrowseResponse, FilesystemBrowseResponses, FilesystemSearchData, FilesystemSearchError, FilesystemSearchErrors, FilesystemSearchResponse, FilesystemSearchResponses, FilesystemTreeData, FilesystemTreeError, FilesystemTreeErrors, FilesystemTreeResponse, FilesystemTreeResponses, GetAnalyticsData, GetAnalyticsResponses, GetDashboardStatsData, GetDashboardStatsResponse, GetDashboardStatsResponses, GetDiscrepancyTreeData, GetDiscrepancyTreeError, GetDiscrepancyTreeErrors, GetDiscrepancyTreeResponse, GetDiscrepancyTreeResponses, GetJobCountData, GetJobCountResponses, GetJobData, GetJobError, GetJobErrors, GetJobLogsData, GetJobLogsError, GetJobLogsErrors, GetJobLogsResponse, GetJobLogsResponses, GetJobResponse, GetJobResponses, GetJobStatsData, GetJobStatsResponses, GetRestoreManifestData, GetRestoreManifestResponse, GetRestoreManifestResponses, GetRestoreQueueData, GetRestoreQueueResponse, GetRestoreQueueResponses, GetRestoreQueueTreeData, GetRestoreQueueTreeError, GetRestoreQueueTreeErrors, GetRestoreQueueTreeResponse, GetRestoreQueueTreeResponses, GetScanStatusData, GetScanStatusResponse, GetScanStatusResponses, GetSecretData, GetSecretError, GetSecretErrors, GetSecretResponses, GetSettingsData, GetSettingsResponse, GetSettingsResponses, GetTreemapData, GetTreemapResponses, HttpValidationError, IgnoreHardwareData, IgnoreHardwareError, IgnoreHardwareErrors, IgnoreHardwareRequest, IgnoreHardwareResponses, ImportDatabaseData, ImportDatabaseError, ImportDatabaseErrors, ImportDatabaseResponses, InitializeMediaData, InitializeMediaError, InitializeMediaErrors, InitializeMediaResponses, ItemMetadataSchema, JobLogSchema, ListBackupsData, ListBackupsResponse, ListBackupsResponses, ListDirectoriesData, ListDirectoriesError, ListDirectoriesErrors, ListDirectoriesResponses, ListDiscrepanciesData, ListDiscrepanciesResponse, ListDiscrepanciesResponses, ListJobsData, ListJobsError, ListJobsErrors, ListJobsResponse, ListJobsResponses, ListMediaData, ListMediaError, ListMediaErrors, ListMediaResponse, ListMediaResponses, ListProvidersData, ListProvidersResponse, ListProvidersResponses, ListSecretsData, ListSecretsResponse, ListSecretsResponses, LtoTapeCreateSchema, ManifestMediaSchema, MediaSchema, MediaUpdateSchema, OfflineHddCreateSchema, RemoveFromRestoreQueueData, RemoveFromRestoreQueueError, RemoveFromRestoreQueueErrors, RemoveFromRestoreQueueResponses, ReorderMediaData, ReorderMediaError, ReorderMediaErrors, ReorderMediaRequest, ReorderMediaResponses, ResetTestEnvironmentData, ResetTestEnvironmentResponses, RestoreManifestSchema, RestoreTriggerRequest, RetryJobData, RetryJobError, RetryJobErrors, RetryJobResponses, ScanStatusSchema, SecretCreateRequest, SecretDeleteRequest, SettingSchema, StorageProviderSchema, StreamJobsData, StreamJobsResponses, TestExclusionsData, TestExclusionsError, TestExclusionsErrors, TestExclusionsRequest, TestExclusionsResponse, TestExclusionsResponse2, TestExclusionsResponses, TestNotificationData, TestNotificationError, TestNotificationErrors, TestNotificationRequest, TestNotificationResponses, TreeNodeSchema, TriggerAutoBackupData, TriggerAutoBackupResponses, TriggerBackupData, TriggerBackupError, TriggerBackupErrors, TriggerBackupResponses, TriggerIndexingData, TriggerIndexingResponses, TriggerRestoreData, TriggerRestoreError, TriggerRestoreErrors, TriggerRestoreResponses, TriggerScanData, TriggerScanResponses, UndoDismissDiscrepancyData, UndoDismissDiscrepancyError, UndoDismissDiscrepancyErrors, UndoDismissDiscrepancyResponses, UpdateMediaData, UpdateMediaError, UpdateMediaErrors, UpdateMediaResponse, UpdateMediaResponses, UpdateSettingsData, UpdateSettingsError, UpdateSettingsErrors, UpdateSettingsResponses, ValidationError } from './types.gen'; +export { addDirectoryToRestoreQueue, addFileToRestoreQueue, archiveBrowse, archiveMetadata, archiveSearch, archiveTree, batchAddToRestoreQueue, batchConfirmDiscrepancies, batchDeleteDiscrepancies, batchDismissDiscrepancies, batchResolveDiscrepancies, batchTrack, browseDiscrepancies, browseRestoreQueue, cancelJob, checkHealth, clearRestoreQueue, confirmDiscrepancy, createMedia, createSecret, deleteDiscrepancy, deleteMedia, deleteSecret, detectMedia, discoverHardware, dismissDiscrepancy, downloadExclusionReport, exportDatabase, filesystemBrowse, filesystemSearch, filesystemTree, getAnalytics, getDashboardStats, getDiscrepancyTree, getJob, getJobCount, getJobLogs, getJobStats, getRestoreManifest, getRestoreQueue, getRestoreQueueTree, getScanStatus, getSecret, getSettings, getStagingInfo, getTreemap, ignoreHardware, importDatabase, initializeMedia, listBackups, listDirectories, listDiscrepancies, listJobs, listMedia, listProviders, listSecrets, type Options, removeFromRestoreQueue, reorderMedia, resetTestEnvironment, retryJob, streamJobs, testExclusions, testNotification, triggerAutoBackup, triggerBackup, triggerIndexing, triggerRestore, triggerScan, undoDismissDiscrepancy, updateMedia, updateSettings } from './sdk.gen'; +export type { AddDirectoryToRestoreQueueData, AddDirectoryToRestoreQueueError, AddDirectoryToRestoreQueueErrors, AddDirectoryToRestoreQueueResponses, AddFileToRestoreQueueData, AddFileToRestoreQueueError, AddFileToRestoreQueueErrors, AddFileToRestoreQueueResponses, AppApiBackupsJobSchema, AppApiCommonJobSchema, ArchiveBrowseData, ArchiveBrowseError, ArchiveBrowseErrors, ArchiveBrowseResponses, ArchiveMetadataData, ArchiveMetadataError, ArchiveMetadataErrors, ArchiveMetadataResponse, ArchiveMetadataResponses, ArchiveSearchData, ArchiveSearchError, ArchiveSearchErrors, ArchiveSearchResponses, ArchiveTreeData, ArchiveTreeError, ArchiveTreeErrors, ArchiveTreeResponse, ArchiveTreeResponses, BatchAddToRestoreQueueData, BatchAddToRestoreQueueError, BatchAddToRestoreQueueErrors, BatchAddToRestoreQueueResponses, BatchCartRequest, BatchConfirmDiscrepanciesData, BatchConfirmDiscrepanciesError, BatchConfirmDiscrepanciesErrors, BatchConfirmDiscrepanciesResponses, BatchDeleteDiscrepanciesData, BatchDeleteDiscrepanciesError, BatchDeleteDiscrepanciesErrors, BatchDeleteDiscrepanciesResponses, BatchDiscrepancyAction, BatchDismissDiscrepanciesData, BatchDismissDiscrepanciesError, BatchDismissDiscrepanciesErrors, BatchDismissDiscrepanciesResponses, BatchResolveDiscrepanciesData, BatchResolveDiscrepanciesError, BatchResolveDiscrepanciesErrors, BatchResolveDiscrepanciesResponse, BatchResolveDiscrepanciesResponses, BatchResolveReport, BatchTrackData, BatchTrackError, BatchTrackErrors, BatchTrackRequest, BatchTrackResponses, BrowseDiscrepanciesData, BrowseDiscrepanciesError, BrowseDiscrepanciesErrors, BrowseDiscrepanciesResponse, BrowseDiscrepanciesResponses, BrowseResponseSchema, BrowseRestoreQueueData, BrowseRestoreQueueError, BrowseRestoreQueueErrors, BrowseRestoreQueueResponse, BrowseRestoreQueueResponses, CancelJobData, CancelJobError, CancelJobErrors, CancelJobResponses, CartFileItemSchema, CartItemSchema, CartTreeNodeSchema, CheckHealthData, CheckHealthResponses, ClearRestoreQueueData, ClearRestoreQueueResponses, ClientOptions, CloudCreateSchema, ConfirmDiscrepancyData, ConfirmDiscrepancyError, ConfirmDiscrepancyErrors, ConfirmDiscrepancyResponses, CreateMediaData, CreateMediaError, CreateMediaErrors, CreateMediaResponse, CreateMediaResponses, CreateSecretData, CreateSecretError, CreateSecretErrors, CreateSecretResponses, DashboardStatsSchema, DeleteDiscrepancyData, DeleteDiscrepancyError, DeleteDiscrepancyErrors, DeleteDiscrepancyResponses, DeleteMediaData, DeleteMediaError, DeleteMediaErrors, DeleteMediaResponses, DeleteSecretData, DeleteSecretError, DeleteSecretErrors, DeleteSecretResponses, DetectMediaData, DetectMediaResponses, DirectoryCartRequest, DiscoverHardwareData, DiscoverHardwareResponses, DiscrepancySchema, DismissDiscrepancyData, DismissDiscrepancyError, DismissDiscrepancyErrors, DismissDiscrepancyResponses, DownloadExclusionReportData, DownloadExclusionReportError, DownloadExclusionReportErrors, DownloadExclusionReportResponses, ExportDatabaseData, ExportDatabaseResponses, FileItemSchema, FilesystemBrowseData, FilesystemBrowseError, FilesystemBrowseErrors, FilesystemBrowseResponse, FilesystemBrowseResponses, FilesystemSearchData, FilesystemSearchError, FilesystemSearchErrors, FilesystemSearchResponse, FilesystemSearchResponses, FilesystemTreeData, FilesystemTreeError, FilesystemTreeErrors, FilesystemTreeResponse, FilesystemTreeResponses, GetAnalyticsData, GetAnalyticsResponses, GetDashboardStatsData, GetDashboardStatsResponse, GetDashboardStatsResponses, GetDiscrepancyTreeData, GetDiscrepancyTreeError, GetDiscrepancyTreeErrors, GetDiscrepancyTreeResponse, GetDiscrepancyTreeResponses, GetJobCountData, GetJobCountResponses, GetJobData, GetJobError, GetJobErrors, GetJobLogsData, GetJobLogsError, GetJobLogsErrors, GetJobLogsResponse, GetJobLogsResponses, GetJobResponse, GetJobResponses, GetJobStatsData, GetJobStatsResponses, GetRestoreManifestData, GetRestoreManifestResponse, GetRestoreManifestResponses, GetRestoreQueueData, GetRestoreQueueResponse, GetRestoreQueueResponses, GetRestoreQueueTreeData, GetRestoreQueueTreeError, GetRestoreQueueTreeErrors, GetRestoreQueueTreeResponse, GetRestoreQueueTreeResponses, GetScanStatusData, GetScanStatusResponse, GetScanStatusResponses, GetSecretData, GetSecretError, GetSecretErrors, GetSecretResponses, GetSettingsData, GetSettingsResponse, GetSettingsResponses, GetStagingInfoData, GetStagingInfoResponse, GetStagingInfoResponses, GetTreemapData, GetTreemapResponses, HttpValidationError, IgnoreHardwareData, IgnoreHardwareError, IgnoreHardwareErrors, IgnoreHardwareRequest, IgnoreHardwareResponses, ImportDatabaseData, ImportDatabaseError, ImportDatabaseErrors, ImportDatabaseResponses, InitializeMediaData, InitializeMediaError, InitializeMediaErrors, InitializeMediaResponses, ItemMetadataSchema, JobLogSchema, ListBackupsData, ListBackupsResponse, ListBackupsResponses, ListDirectoriesData, ListDirectoriesError, ListDirectoriesErrors, ListDirectoriesResponses, ListDiscrepanciesData, ListDiscrepanciesResponse, ListDiscrepanciesResponses, ListJobsData, ListJobsError, ListJobsErrors, ListJobsResponse, ListJobsResponses, ListMediaData, ListMediaError, ListMediaErrors, ListMediaResponse, ListMediaResponses, ListProvidersData, ListProvidersResponse, ListProvidersResponses, ListSecretsData, ListSecretsResponse, ListSecretsResponses, LtoTapeCreateSchema, ManifestMediaSchema, MediaSchema, MediaUpdateSchema, OfflineHddCreateSchema, RemoveFromRestoreQueueData, RemoveFromRestoreQueueError, RemoveFromRestoreQueueErrors, RemoveFromRestoreQueueResponses, ReorderMediaData, ReorderMediaError, ReorderMediaErrors, ReorderMediaRequest, ReorderMediaResponses, ResetTestEnvironmentData, ResetTestEnvironmentResponses, RestoreManifestSchema, RestoreTriggerRequest, RetryJobData, RetryJobError, RetryJobErrors, RetryJobResponses, ScanStatusSchema, SecretCreateRequest, SecretDeleteRequest, SettingSchema, StagingInfoSchema, StorageProviderSchema, StreamJobsData, StreamJobsResponses, TestExclusionsData, TestExclusionsError, TestExclusionsErrors, TestExclusionsRequest, TestExclusionsResponse, TestExclusionsResponse2, TestExclusionsResponses, TestNotificationData, TestNotificationError, TestNotificationErrors, TestNotificationRequest, TestNotificationResponses, TreeNodeSchema, TriggerAutoBackupData, TriggerAutoBackupResponses, TriggerBackupData, TriggerBackupError, TriggerBackupErrors, TriggerBackupResponses, TriggerIndexingData, TriggerIndexingResponses, TriggerRestoreData, TriggerRestoreError, TriggerRestoreErrors, TriggerRestoreResponses, TriggerScanData, TriggerScanResponses, UndoDismissDiscrepancyData, UndoDismissDiscrepancyError, UndoDismissDiscrepancyErrors, UndoDismissDiscrepancyResponses, UpdateMediaData, UpdateMediaError, UpdateMediaErrors, UpdateMediaResponse, UpdateMediaResponses, UpdateSettingsData, UpdateSettingsError, UpdateSettingsErrors, UpdateSettingsResponses, ValidationError } from './types.gen'; diff --git a/frontend/src/lib/api/sdk.gen.ts b/frontend/src/lib/api/sdk.gen.ts index c137da9..c61cb45 100644 --- a/frontend/src/lib/api/sdk.gen.ts +++ b/frontend/src/lib/api/sdk.gen.ts @@ -2,7 +2,7 @@ import type { Client, Options as Options2, TDataShape } from './client'; import { client } from './client.gen'; -import type { AddDirectoryToRestoreQueueData, AddDirectoryToRestoreQueueErrors, AddDirectoryToRestoreQueueResponses, AddFileToRestoreQueueData, AddFileToRestoreQueueErrors, AddFileToRestoreQueueResponses, ArchiveBrowseData, ArchiveBrowseErrors, ArchiveBrowseResponses, ArchiveMetadataData, ArchiveMetadataErrors, ArchiveMetadataResponses, ArchiveSearchData, ArchiveSearchErrors, ArchiveSearchResponses, ArchiveTreeData, ArchiveTreeErrors, ArchiveTreeResponses, BatchAddToRestoreQueueData, BatchAddToRestoreQueueErrors, BatchAddToRestoreQueueResponses, BatchConfirmDiscrepanciesData, BatchConfirmDiscrepanciesErrors, BatchConfirmDiscrepanciesResponses, BatchDeleteDiscrepanciesData, BatchDeleteDiscrepanciesErrors, BatchDeleteDiscrepanciesResponses, BatchDismissDiscrepanciesData, BatchDismissDiscrepanciesErrors, BatchDismissDiscrepanciesResponses, BatchResolveDiscrepanciesData, BatchResolveDiscrepanciesErrors, BatchResolveDiscrepanciesResponses, BatchTrackData, BatchTrackErrors, BatchTrackResponses, BrowseDiscrepanciesData, BrowseDiscrepanciesErrors, BrowseDiscrepanciesResponses, BrowseRestoreQueueData, BrowseRestoreQueueErrors, BrowseRestoreQueueResponses, CancelJobData, CancelJobErrors, CancelJobResponses, CheckHealthData, CheckHealthResponses, ClearRestoreQueueData, ClearRestoreQueueResponses, ConfirmDiscrepancyData, ConfirmDiscrepancyErrors, ConfirmDiscrepancyResponses, CreateMediaData, CreateMediaErrors, CreateMediaResponses, CreateSecretData, CreateSecretErrors, CreateSecretResponses, DeleteDiscrepancyData, DeleteDiscrepancyErrors, DeleteDiscrepancyResponses, DeleteMediaData, DeleteMediaErrors, DeleteMediaResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponses, DetectMediaData, DetectMediaResponses, DiscoverHardwareData, DiscoverHardwareResponses, DismissDiscrepancyData, DismissDiscrepancyErrors, DismissDiscrepancyResponses, DownloadExclusionReportData, DownloadExclusionReportErrors, DownloadExclusionReportResponses, ExportDatabaseData, ExportDatabaseResponses, FilesystemBrowseData, FilesystemBrowseErrors, FilesystemBrowseResponses, FilesystemSearchData, FilesystemSearchErrors, FilesystemSearchResponses, FilesystemTreeData, FilesystemTreeErrors, FilesystemTreeResponses, GetAnalyticsData, GetAnalyticsResponses, GetDashboardStatsData, GetDashboardStatsResponses, GetDiscrepancyTreeData, GetDiscrepancyTreeErrors, GetDiscrepancyTreeResponses, GetJobCountData, GetJobCountResponses, GetJobData, GetJobErrors, GetJobLogsData, GetJobLogsErrors, GetJobLogsResponses, GetJobResponses, GetJobStatsData, GetJobStatsResponses, GetRestoreManifestData, GetRestoreManifestResponses, GetRestoreQueueData, GetRestoreQueueResponses, GetRestoreQueueTreeData, GetRestoreQueueTreeErrors, GetRestoreQueueTreeResponses, GetScanStatusData, GetScanStatusResponses, GetSecretData, GetSecretErrors, GetSecretResponses, GetSettingsData, GetSettingsResponses, GetTreemapData, GetTreemapResponses, IgnoreHardwareData, IgnoreHardwareErrors, IgnoreHardwareResponses, ImportDatabaseData, ImportDatabaseErrors, ImportDatabaseResponses, InitializeMediaData, InitializeMediaErrors, InitializeMediaResponses, ListBackupsData, ListBackupsResponses, ListDirectoriesData, ListDirectoriesErrors, ListDirectoriesResponses, ListDiscrepanciesData, ListDiscrepanciesResponses, ListJobsData, ListJobsErrors, ListJobsResponses, ListMediaData, ListMediaErrors, ListMediaResponses, ListProvidersData, ListProvidersResponses, ListSecretsData, ListSecretsResponses, RemoveFromRestoreQueueData, RemoveFromRestoreQueueErrors, RemoveFromRestoreQueueResponses, ReorderMediaData, ReorderMediaErrors, ReorderMediaResponses, ResetTestEnvironmentData, ResetTestEnvironmentResponses, RetryJobData, RetryJobErrors, RetryJobResponses, StreamJobsData, StreamJobsResponses, TestExclusionsData, TestExclusionsErrors, TestExclusionsResponses, TestNotificationData, TestNotificationErrors, TestNotificationResponses, TriggerAutoBackupData, TriggerAutoBackupResponses, TriggerBackupData, TriggerBackupErrors, TriggerBackupResponses, TriggerIndexingData, TriggerIndexingResponses, TriggerRestoreData, TriggerRestoreErrors, TriggerRestoreResponses, TriggerScanData, TriggerScanResponses, UndoDismissDiscrepancyData, UndoDismissDiscrepancyErrors, UndoDismissDiscrepancyResponses, UpdateMediaData, UpdateMediaErrors, UpdateMediaResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponses } from './types.gen'; +import type { AddDirectoryToRestoreQueueData, AddDirectoryToRestoreQueueErrors, AddDirectoryToRestoreQueueResponses, AddFileToRestoreQueueData, AddFileToRestoreQueueErrors, AddFileToRestoreQueueResponses, ArchiveBrowseData, ArchiveBrowseErrors, ArchiveBrowseResponses, ArchiveMetadataData, ArchiveMetadataErrors, ArchiveMetadataResponses, ArchiveSearchData, ArchiveSearchErrors, ArchiveSearchResponses, ArchiveTreeData, ArchiveTreeErrors, ArchiveTreeResponses, BatchAddToRestoreQueueData, BatchAddToRestoreQueueErrors, BatchAddToRestoreQueueResponses, BatchConfirmDiscrepanciesData, BatchConfirmDiscrepanciesErrors, BatchConfirmDiscrepanciesResponses, BatchDeleteDiscrepanciesData, BatchDeleteDiscrepanciesErrors, BatchDeleteDiscrepanciesResponses, BatchDismissDiscrepanciesData, BatchDismissDiscrepanciesErrors, BatchDismissDiscrepanciesResponses, BatchResolveDiscrepanciesData, BatchResolveDiscrepanciesErrors, BatchResolveDiscrepanciesResponses, BatchTrackData, BatchTrackErrors, BatchTrackResponses, BrowseDiscrepanciesData, BrowseDiscrepanciesErrors, BrowseDiscrepanciesResponses, BrowseRestoreQueueData, BrowseRestoreQueueErrors, BrowseRestoreQueueResponses, CancelJobData, CancelJobErrors, CancelJobResponses, CheckHealthData, CheckHealthResponses, ClearRestoreQueueData, ClearRestoreQueueResponses, ConfirmDiscrepancyData, ConfirmDiscrepancyErrors, ConfirmDiscrepancyResponses, CreateMediaData, CreateMediaErrors, CreateMediaResponses, CreateSecretData, CreateSecretErrors, CreateSecretResponses, DeleteDiscrepancyData, DeleteDiscrepancyErrors, DeleteDiscrepancyResponses, DeleteMediaData, DeleteMediaErrors, DeleteMediaResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponses, DetectMediaData, DetectMediaResponses, DiscoverHardwareData, DiscoverHardwareResponses, DismissDiscrepancyData, DismissDiscrepancyErrors, DismissDiscrepancyResponses, DownloadExclusionReportData, DownloadExclusionReportErrors, DownloadExclusionReportResponses, ExportDatabaseData, ExportDatabaseResponses, FilesystemBrowseData, FilesystemBrowseErrors, FilesystemBrowseResponses, FilesystemSearchData, FilesystemSearchErrors, FilesystemSearchResponses, FilesystemTreeData, FilesystemTreeErrors, FilesystemTreeResponses, GetAnalyticsData, GetAnalyticsResponses, GetDashboardStatsData, GetDashboardStatsResponses, GetDiscrepancyTreeData, GetDiscrepancyTreeErrors, GetDiscrepancyTreeResponses, GetJobCountData, GetJobCountResponses, GetJobData, GetJobErrors, GetJobLogsData, GetJobLogsErrors, GetJobLogsResponses, GetJobResponses, GetJobStatsData, GetJobStatsResponses, GetRestoreManifestData, GetRestoreManifestResponses, GetRestoreQueueData, GetRestoreQueueResponses, GetRestoreQueueTreeData, GetRestoreQueueTreeErrors, GetRestoreQueueTreeResponses, GetScanStatusData, GetScanStatusResponses, GetSecretData, GetSecretErrors, GetSecretResponses, GetSettingsData, GetSettingsResponses, GetStagingInfoData, GetStagingInfoResponses, GetTreemapData, GetTreemapResponses, IgnoreHardwareData, IgnoreHardwareErrors, IgnoreHardwareResponses, ImportDatabaseData, ImportDatabaseErrors, ImportDatabaseResponses, InitializeMediaData, InitializeMediaErrors, InitializeMediaResponses, ListBackupsData, ListBackupsResponses, ListDirectoriesData, ListDirectoriesErrors, ListDirectoriesResponses, ListDiscrepanciesData, ListDiscrepanciesResponses, ListJobsData, ListJobsErrors, ListJobsResponses, ListMediaData, ListMediaErrors, ListMediaResponses, ListProvidersData, ListProvidersResponses, ListSecretsData, ListSecretsResponses, RemoveFromRestoreQueueData, RemoveFromRestoreQueueErrors, RemoveFromRestoreQueueResponses, ReorderMediaData, ReorderMediaErrors, ReorderMediaResponses, ResetTestEnvironmentData, ResetTestEnvironmentResponses, RetryJobData, RetryJobErrors, RetryJobResponses, StreamJobsData, StreamJobsResponses, TestExclusionsData, TestExclusionsErrors, TestExclusionsResponses, TestNotificationData, TestNotificationErrors, TestNotificationResponses, TriggerAutoBackupData, TriggerAutoBackupResponses, TriggerBackupData, TriggerBackupErrors, TriggerBackupResponses, TriggerIndexingData, TriggerIndexingResponses, TriggerRestoreData, TriggerRestoreErrors, TriggerRestoreResponses, TriggerScanData, TriggerScanResponses, UndoDismissDiscrepancyData, UndoDismissDiscrepancyErrors, UndoDismissDiscrepancyResponses, UpdateMediaData, UpdateMediaErrors, UpdateMediaResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponses } from './types.gen'; export type Options = Options2 & { /** @@ -32,6 +32,13 @@ export const resetTestEnvironment = (optio */ export const getDashboardStats = (options?: Options) => (options?.client ?? client).get({ url: '/system/dashboard/stats', ...options }); +/** + * Get Staging Info + * + * Returns disk usage information for the backup staging directory. + */ +export const getStagingInfo = (options?: Options) => (options?.client ?? client).get({ url: '/system/staging/info', ...options }); + /** * List Jobs * @@ -53,6 +60,13 @@ export const getJobCount = (options?: Opti */ export const getJobStats = (options?: Options) => (options?.client ?? client).get({ url: '/system/jobs/stats', ...options }); +/** + * Stream Jobs + * + * Server-Sent Events (SSE) endpoint for real-time job status updates. + */ +export const streamJobs = (options?: Options) => (options?.client ?? client).get({ url: '/system/jobs/stream', ...options }); + /** * Get Job * @@ -81,13 +95,6 @@ export const cancelJob = (options: Options */ export const retryJob = (options: Options) => (options.client ?? client).post({ url: '/system/jobs/{job_id}/retry', ...options }); -/** - * Stream Jobs - * - * Server-Sent Events (SSE) endpoint for real-time job status updates. - */ -export const streamJobs = (options?: Options) => (options?.client ?? client).get({ url: '/system/jobs/stream', ...options }); - /** * Trigger Scan * diff --git a/frontend/src/lib/api/types.gen.ts b/frontend/src/lib/api/types.gen.ts index 25872e3..30515b8 100644 --- a/frontend/src/lib/api/types.gen.ts +++ b/frontend/src/lib/api/types.gen.ts @@ -1106,6 +1106,28 @@ export type SettingSchema = { value: string; }; +/** + * StagingInfoSchema + */ +export type StagingInfoSchema = { + /** + * Path + */ + path: string; + /** + * Total Bytes + */ + total_bytes: number; + /** + * Used Bytes + */ + used_bytes: number; + /** + * Free Bytes + */ + free_bytes: number; +}; + /** * StorageProviderSchema */ @@ -1338,6 +1360,22 @@ export type GetDashboardStatsResponses = { export type GetDashboardStatsResponse = GetDashboardStatsResponses[keyof GetDashboardStatsResponses]; +export type GetStagingInfoData = { + body?: never; + path?: never; + query?: never; + url: '/system/staging/info'; +}; + +export type GetStagingInfoResponses = { + /** + * Successful Response + */ + 200: StagingInfoSchema; +}; + +export type GetStagingInfoResponse = GetStagingInfoResponses[keyof GetStagingInfoResponses]; + export type ListJobsData = { body?: never; path?: never; @@ -1402,6 +1440,20 @@ export type GetJobStatsResponses = { 200: unknown; }; +export type StreamJobsData = { + body?: never; + path?: never; + query?: never; + url: '/system/jobs/stream'; +}; + +export type StreamJobsResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + export type GetJobData = { body?: never; path: { @@ -1520,20 +1572,6 @@ export type RetryJobResponses = { 200: unknown; }; -export type StreamJobsData = { - body?: never; - path?: never; - query?: never; - url: '/system/jobs/stream'; -}; - -export type StreamJobsResponses = { - /** - * Successful Response - */ - 200: unknown; -}; - export type TriggerScanData = { body?: never; path?: never; diff --git a/frontend/src/routes/inventory/+page.svelte b/frontend/src/routes/inventory/+page.svelte index 7587f94..7bcc726 100644 --- a/frontend/src/routes/inventory/+page.svelte +++ b/frontend/src/routes/inventory/+page.svelte @@ -52,8 +52,10 @@ ignoreHardware, listProviders, listSecrets, + getStagingInfo, type MediaSchema, - type StorageProviderSchema + type StorageProviderSchema, + type StagingInfoSchema } from '$lib/api'; import { LTO_CAPACITY, PROVIDER_TEMPLATES, type LtoTapeCreateData, type OfflineHddCreateData, type CloudCreateData } from '$lib/types'; import { dndzone } from 'svelte-dnd-action'; @@ -67,6 +69,7 @@ let loading = $state(true); let showRegisterDialog = $state(false); let editingMedia = $state(null); + let stagingInfo = $state(null); let activeMedia = $derived(mediaList.filter(m => m.status === 'active')); let fullMedia = $derived(mediaList.filter(m => m.status === 'full')); @@ -295,10 +298,20 @@ } } + async function loadStagingInfo() { + try { + const res = await getStagingInfo(); + if (res.data) stagingInfo = res.data; + } catch (error) { + console.error("Failed to load staging info:", error); + } + } + onMount(async () => { // Initial load (non-silent and forced refresh to show live hardware status immediately) loadMedia(false, true); loadSecrets(); + loadStagingInfo(); try { const res = await listProviders(); @@ -307,7 +320,10 @@ console.error("Failed to load storage providers:", error); } - pollInterval = setInterval(pollHardware, POLL_SLOW); + pollInterval = setInterval(() => { + pollHardware(); + loadStagingInfo(); + }, POLL_SLOW); }); onDestroy(() => {