Skip to content

feat: expand snapshot details with additional info#505

Merged
nicotsx merged 3 commits intomainfrom
feat/expand-snapshot-details
Feb 12, 2026
Merged

feat: expand snapshot details with additional info#505
nicotsx merged 3 commits intomainfrom
feat/expand-snapshot-details

Conversation

@nicotsx
Copy link
Owner

@nicotsx nicotsx commented Feb 12, 2026

Closes #385

image

Summary by CodeRabbit

Release Notes

  • New Features

    • Added detailed backup summary statistics displayed on backup details pages, including backup duration, files processed, data added, and other key metrics.
    • Enhanced API responses with comprehensive backup summary information.
  • Improvements

    • Updated file size formatting consistency across the application.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This PR extends the backup reporting system with summary data, introducing new DTO schemas for Restic and backup events, adding a UI component to display backup summaries, creating a byte formatting utility, and propagating summary information through the backup execution and notification flows.

Changes

Cohort / File(s) Summary
Schema & DTO Definitions
app/schemas/restic-dto.ts, app/schemas/events-dto.ts
New ARK type schemas and TypeScript type exports for Restic snapshot/backup summaries and backup event DTOs (started, progress, completed), enabling structured validation and type-safe payload handling across the backup pipeline.
API Type Generation
app/client/api-client/types.gen.ts
Generated API client types updated to include optional summary field with backup metrics (backup_start/end, files/dirs statistics, data blobs/tree blobs, total bytes/files processed) in snapshot list and detail responses.
Byte Formatting Utility
app/utils/format-bytes.ts
New utility module providing formatBytes function with options for SI/IEC bases, locale-aware formatting, smart rounding, and non-finite value fallbacks, returning structured result with text, unit, unitIndex, and numeric value.
Backup Summary UI Component
app/client/components/backup-summary-card.tsx
New React component displaying backup summary statistics card with top metrics (data added/stored, files/bytes processed, duration) and detailed metrics (new/changed/unmodified files/dirs, data/tree blobs), including duration calculation from backup_start/end timestamps.
ByteSize Component Refactoring
app/client/components/bytes-size.tsx
Removed internal formatBytes implementation and delegated to external utility via import from ~/utils/format-bytes; component behavior preserved with updated comparison against fallback value.
Size Formatting Updates
app/client/components/file-tree.tsx, app/client/modules/backups/components/backup-progress-card.tsx, app/client/modules/backups/components/snapshot-timeline.tsx
Updated ByteSize component usage with explicit base={1024} parameter for consistent IEC-based byte formatting across file tree, backup progress, and snapshot timeline displays.
Event Hook Type Updates
app/client/hooks/use-server-events.ts
Replaced local BackupEvent and BackupProgressEvent interfaces with DTO-based types (BackupStartedEventDto, BackupProgressEventDto, BackupCompletedEventDto) from ~/schemas/events-dto.
Summary Card Integration in Routes
app/client/modules/backups/routes/backup-details.tsx, app/client/modules/repositories/routes/snapshot-details.tsx
Integrated BackupSummaryCard component into backup-details and snapshot-details pages to display selectedSnapshot/data summary information.
Server Event Definitions
app/server/core/events.ts, app/server/modules/events/events.controller.ts
Updated ServerEvents interface and event controller to use ServerBackupStartedEventDto, ServerBackupProgressEventDto, and ServerBackupCompletedEventDto for backup event payloads; removed inline object type definitions.
Backup Execution & Summary Propagation
app/server/modules/backups/backups.execution.ts
Modified backup execution to return full ResticBackupOutputDto from runBackupOperation and extended finalizeSuccessfulBackup to accept result parameter, enabling buildBackupSummary helper to normalize and propagate summary through completion events and notifications.
Notification Summary Formatting
app/server/modules/notifications/notifications.service.ts
Extended backup notifications to include summary-driven formatting with helpers for rendering duration, file counts, byte counts, and snapshot ID from ResticBackupRunSummaryDto, generating human-readable summary lines for success and warning events.
Repository API & DTO Updates
app/server/modules/repositories/repositories.controller.ts, app/server/modules/repositories/repositories.dto.ts
Added optional summary field to snapshot schema (ResticSnapshotSummaryDto) and included summary in GET /:id/snapshots list response for each snapshot.
Restic Utility DTO Alignment
app/server/utils/restic.ts
Migrated from inline backup/restore output schemas to restic-dto imports; updated Snapshot interface summary type to ResticSnapshotSummaryDto; aligned validation against resticBackupOutputSchema, resticBackupProgressSchema, and resticRestoreOutputSchema with fallback behavior for restore validation failures.

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change of the PR: expanding snapshot details with additional information through a new BackupSummaryCard component and supporting DTO structures.
Linked Issues check ✅ Passed The PR implements most key requirements from #385 by adding detailed backup summary metrics (data added, files processed, bytes processed, duration, file/directory counts) through new DTO schemas, UI components, and API responses, though some requested metrics like volume size, compression ratio, and throughput are not explicitly included.
Out of Scope Changes check ✅ Passed The PR maintains scope by focusing on snapshot detail expansion through DTO schemas, components, and API changes; all modifications directly support the BackupSummaryCard feature and schema centralization work.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@app/server/modules/notifications/notifications.service.ts`:
- Around line 487-491: The notification body currently repeats metrics because
derivedDuration, derivedFilesProcessed, derivedBytesProcessed, and
derivedSnapshotId are always appended alongside summaryLines; update the logic
in notifications.service.ts to avoid duplicates by conditionally omitting the
derived* lines when summaryLines is non-empty (or alternatively adjust
buildBackupSummaryLines to exclude overlapping fields), e.g., check if
summaryLines.length > 0 before pushing `Duration: ...`, `Files: ...`, `Size:
...`, `Snapshot: ...` so only one set of metric lines appears; reference the
derivedDuration/derivedFilesProcessed/derivedBytesProcessed/derivedSnapshotId
variables and the summaryLines array or the buildBackupSummaryLines helper to
implement this change.
🧹 Nitpick comments (6)
app/server/modules/repositories/repositories.controller.ts (2)

102-121: Duration calculation is duplicated between listSnapshots and getSnapshotDetails.

Lines 105–109 here and lines 135–139 in the getSnapshotDetails handler compute duration identically. Consider extracting a small helper to keep them in sync.

♻️ Optional extraction
+function getSnapshotDuration(summary?: { backup_start: string; backup_end: string }): number {
+	if (!summary) return 0;
+	return new Date(summary.backup_end).getTime() - new Date(summary.backup_start).getTime();
+}
+

116-117: Prefer ?? 0 over || 0 for numeric fallback.

|| 0 also coerces 0 itself to the fallback (though the result is the same here). Using ?? 0 is more precise and idiomatic for nullish checks. Same applies to Line 147.

♻️ Suggested fix
-			size: summary?.total_bytes_processed || 0,
+			size: summary?.total_bytes_processed ?? 0,
app/client/modules/backups/components/backup-progress-card.tsx (1)

8-8: Inconsistent import path style — use tilde alias for consistency.

Other files in this PR (e.g., notifications.service.ts line 19) import from ~/utils/format-bytes. This relative path traversal is fragile and inconsistent.

♻️ Suggested fix
-import { formatBytes } from "../../../../utils/format-bytes";
+import { formatBytes } from "~/utils/format-bytes";
app/server/utils/restic.ts (1)

366-377: Pre-existing: summaryLine type confusion between string and parsed object.

summaryLine is declared as string but line 370 assigns the parsed JSON object to it. In the success path, resticBackupOutputSchema receives an object (correct), but in the catch path it receives the string "{}" (will fail validation and hit the null fallback). This is a pre-existing pattern, not introduced by this PR, but worth noting for a future cleanup.

The same pattern exists in the restore path (lines 443–454).

app/server/modules/backups/backups.execution.ts (1)

135-138: buildBackupSummary is a no-op identity function.

This helper returns undefined for falsy input or the input itself unchanged — it performs no transformation. Consider inlining result ?? undefined at the call site (line 147), or if the intent is to eventually map/transform the result into a different summary shape, add a TODO comment clarifying the planned logic.

♻️ Proposed inline simplification
-const buildBackupSummary = (result: ResticBackupOutputDto | null | undefined) => {
-	if (!result) return undefined;
-	return result;
-};
-
 const finalizeSuccessfulBackup = async (
 	ctx: BackupContext,
 	scheduleId: number,
 	exitCode: number,
 	result: ResticBackupOutputDto | null,
 ) => {
 	const finalStatus = exitCode === 0 ? "success" : "warning";
-	const summary = buildBackupSummary(result);
+	const summary = result ?? undefined;
app/schemas/events-dto.ts (1)

20-25: Note: summary type is broader than what's actually passed.

The event schema declares summary as resticBackupRunSummarySchema.optional(), but finalizeSuccessfulBackup in backups.execution.ts (line 186) passes a ResticBackupOutputDto (which adds message_type: 'summary'). This is structurally compatible in TypeScript, so it works — but the consumer will receive the extra message_type field that isn't reflected in the event's type. This is fine if intentional; just noting the slight type widening.

@nicotsx nicotsx merged commit 7ebce11 into main Feb 12, 2026
7 checks passed
@nicotsx nicotsx deleted the feat/expand-snapshot-details branch February 12, 2026 17:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature request] Extend backup report with additional details

1 participant