check staging area has enough capacity
This commit is contained in:
@@ -159,6 +159,13 @@ class DashboardStatsSchema(BaseModel):
|
|||||||
redundancy_ratio: float
|
redundancy_ratio: float
|
||||||
|
|
||||||
|
|
||||||
|
class StagingInfoSchema(BaseModel):
|
||||||
|
path: str
|
||||||
|
total_bytes: int
|
||||||
|
used_bytes: int
|
||||||
|
free_bytes: int
|
||||||
|
|
||||||
|
|
||||||
class JobSchema(BaseModel):
|
class JobSchema(BaseModel):
|
||||||
model_config = ConfigDict(from_attributes=True)
|
model_config = ConfigDict(from_attributes=True)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
import shutil
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from app.db.database import get_db
|
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 sqlalchemy import func, text
|
||||||
from app.db import models
|
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,
|
last_scan_time=last_scan.completed_at if last_scan else None,
|
||||||
redundancy_ratio=round(redundancy_percentage, 1),
|
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,
|
||||||
|
)
|
||||||
|
|||||||
@@ -374,6 +374,31 @@ class ArchiverService:
|
|||||||
if current_chunk:
|
if current_chunk:
|
||||||
chunks.append(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)")
|
JobManager.add_job_log(job_id, f"Packed into {len(chunks)} archive(s)")
|
||||||
|
|
||||||
for chunk_index, chunk_items in enumerate(chunks):
|
for chunk_index, chunk_items in enumerate(chunks):
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import type { Client, Options as Options2, TDataShape } from './client';
|
import type { Client, Options as Options2, TDataShape } from './client';
|
||||||
import { client } from './client.gen';
|
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<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean, TResponse = unknown> = Options2<TData, ThrowOnError, TResponse> & {
|
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean, TResponse = unknown> = Options2<TData, ThrowOnError, TResponse> & {
|
||||||
/**
|
/**
|
||||||
@@ -32,6 +32,13 @@ export const resetTestEnvironment = <ThrowOnError extends boolean = false>(optio
|
|||||||
*/
|
*/
|
||||||
export const getDashboardStats = <ThrowOnError extends boolean = false>(options?: Options<GetDashboardStatsData, ThrowOnError>) => (options?.client ?? client).get<GetDashboardStatsResponses, unknown, ThrowOnError>({ url: '/system/dashboard/stats', ...options });
|
export const getDashboardStats = <ThrowOnError extends boolean = false>(options?: Options<GetDashboardStatsData, ThrowOnError>) => (options?.client ?? client).get<GetDashboardStatsResponses, unknown, ThrowOnError>({ url: '/system/dashboard/stats', ...options });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Staging Info
|
||||||
|
*
|
||||||
|
* Returns disk usage information for the backup staging directory.
|
||||||
|
*/
|
||||||
|
export const getStagingInfo = <ThrowOnError extends boolean = false>(options?: Options<GetStagingInfoData, ThrowOnError>) => (options?.client ?? client).get<GetStagingInfoResponses, unknown, ThrowOnError>({ url: '/system/staging/info', ...options });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List Jobs
|
* List Jobs
|
||||||
*
|
*
|
||||||
@@ -53,6 +60,13 @@ export const getJobCount = <ThrowOnError extends boolean = false>(options?: Opti
|
|||||||
*/
|
*/
|
||||||
export const getJobStats = <ThrowOnError extends boolean = false>(options?: Options<GetJobStatsData, ThrowOnError>) => (options?.client ?? client).get<GetJobStatsResponses, unknown, ThrowOnError>({ url: '/system/jobs/stats', ...options });
|
export const getJobStats = <ThrowOnError extends boolean = false>(options?: Options<GetJobStatsData, ThrowOnError>) => (options?.client ?? client).get<GetJobStatsResponses, unknown, ThrowOnError>({ url: '/system/jobs/stats', ...options });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stream Jobs
|
||||||
|
*
|
||||||
|
* Server-Sent Events (SSE) endpoint for real-time job status updates.
|
||||||
|
*/
|
||||||
|
export const streamJobs = <ThrowOnError extends boolean = false>(options?: Options<StreamJobsData, ThrowOnError>) => (options?.client ?? client).get<StreamJobsResponses, unknown, ThrowOnError>({ url: '/system/jobs/stream', ...options });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Job
|
* Get Job
|
||||||
*
|
*
|
||||||
@@ -81,13 +95,6 @@ export const cancelJob = <ThrowOnError extends boolean = false>(options: Options
|
|||||||
*/
|
*/
|
||||||
export const retryJob = <ThrowOnError extends boolean = false>(options: Options<RetryJobData, ThrowOnError>) => (options.client ?? client).post<RetryJobResponses, RetryJobErrors, ThrowOnError>({ url: '/system/jobs/{job_id}/retry', ...options });
|
export const retryJob = <ThrowOnError extends boolean = false>(options: Options<RetryJobData, ThrowOnError>) => (options.client ?? client).post<RetryJobResponses, RetryJobErrors, ThrowOnError>({ url: '/system/jobs/{job_id}/retry', ...options });
|
||||||
|
|
||||||
/**
|
|
||||||
* Stream Jobs
|
|
||||||
*
|
|
||||||
* Server-Sent Events (SSE) endpoint for real-time job status updates.
|
|
||||||
*/
|
|
||||||
export const streamJobs = <ThrowOnError extends boolean = false>(options?: Options<StreamJobsData, ThrowOnError>) => (options?.client ?? client).get<StreamJobsResponses, unknown, ThrowOnError>({ url: '/system/jobs/stream', ...options });
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger Scan
|
* Trigger Scan
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1106,6 +1106,28 @@ export type SettingSchema = {
|
|||||||
value: string;
|
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
|
* StorageProviderSchema
|
||||||
*/
|
*/
|
||||||
@@ -1338,6 +1360,22 @@ export type GetDashboardStatsResponses = {
|
|||||||
|
|
||||||
export type GetDashboardStatsResponse = GetDashboardStatsResponses[keyof 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 = {
|
export type ListJobsData = {
|
||||||
body?: never;
|
body?: never;
|
||||||
path?: never;
|
path?: never;
|
||||||
@@ -1402,6 +1440,20 @@ export type GetJobStatsResponses = {
|
|||||||
200: unknown;
|
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 = {
|
export type GetJobData = {
|
||||||
body?: never;
|
body?: never;
|
||||||
path: {
|
path: {
|
||||||
@@ -1520,20 +1572,6 @@ export type RetryJobResponses = {
|
|||||||
200: unknown;
|
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 = {
|
export type TriggerScanData = {
|
||||||
body?: never;
|
body?: never;
|
||||||
path?: never;
|
path?: never;
|
||||||
|
|||||||
@@ -52,8 +52,10 @@
|
|||||||
ignoreHardware,
|
ignoreHardware,
|
||||||
listProviders,
|
listProviders,
|
||||||
listSecrets,
|
listSecrets,
|
||||||
|
getStagingInfo,
|
||||||
type MediaSchema,
|
type MediaSchema,
|
||||||
type StorageProviderSchema
|
type StorageProviderSchema,
|
||||||
|
type StagingInfoSchema
|
||||||
} from '$lib/api';
|
} from '$lib/api';
|
||||||
import { LTO_CAPACITY, PROVIDER_TEMPLATES, type LtoTapeCreateData, type OfflineHddCreateData, type CloudCreateData } from '$lib/types';
|
import { LTO_CAPACITY, PROVIDER_TEMPLATES, type LtoTapeCreateData, type OfflineHddCreateData, type CloudCreateData } from '$lib/types';
|
||||||
import { dndzone } from 'svelte-dnd-action';
|
import { dndzone } from 'svelte-dnd-action';
|
||||||
@@ -67,6 +69,7 @@
|
|||||||
let loading = $state(true);
|
let loading = $state(true);
|
||||||
let showRegisterDialog = $state(false);
|
let showRegisterDialog = $state(false);
|
||||||
let editingMedia = $state<MediaSchema | null>(null);
|
let editingMedia = $state<MediaSchema | null>(null);
|
||||||
|
let stagingInfo = $state<StagingInfoSchema | null>(null);
|
||||||
|
|
||||||
let activeMedia = $derived(mediaList.filter(m => m.status === 'active'));
|
let activeMedia = $derived(mediaList.filter(m => m.status === 'active'));
|
||||||
let fullMedia = $derived(mediaList.filter(m => m.status === 'full'));
|
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 () => {
|
onMount(async () => {
|
||||||
// Initial load (non-silent and forced refresh to show live hardware status immediately)
|
// Initial load (non-silent and forced refresh to show live hardware status immediately)
|
||||||
loadMedia(false, true);
|
loadMedia(false, true);
|
||||||
loadSecrets();
|
loadSecrets();
|
||||||
|
loadStagingInfo();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await listProviders();
|
const res = await listProviders();
|
||||||
@@ -307,7 +320,10 @@
|
|||||||
console.error("Failed to load storage providers:", error);
|
console.error("Failed to load storage providers:", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
pollInterval = setInterval(pollHardware, POLL_SLOW);
|
pollInterval = setInterval(() => {
|
||||||
|
pollHardware();
|
||||||
|
loadStagingInfo();
|
||||||
|
}, POLL_SLOW);
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user