Documents
Real-Time Mirror Synchronization Progress, In-Progress Status Display, and Breadcrumb Navigation
Real-Time Mirror Synchronization Progress, In-Progress Status Display, and Breadcrumb Navigation
Type
Document
Status
Published
Created
Feb 16, 2026
Updated
Mar 22, 2026
Updated by
Dosu Bot

Real-Time Mirror Synchronization Progress, In-Progress Status Display, Download Functionality, Minimum Loading Duration, and Breadcrumb Navigation#

This document details UI/UX features in the zerobyte application: real-time mirror synchronization progress indicators with animated visual feedback, the 'in progress' status display during various copy operations, snapshot download functionality, minimum loading duration pattern, and breadcrumb navigation in the repository details page.

Real-Time Mirror Synchronization Progress Indicators#

Event-Driven Architecture#

Mirror synchronization uses a real-time event-driven system based on Server-Sent Events (SSE) to provide live status updates. Two key events drive the UI:

  • mirror:started: Emitted when a mirror sync operation begins
  • mirror:completed: Emitted when sync completes with success or error status

This event-driven approach ensures the UI stays synchronized with backend operations without polling.

Technical Implementation - Server-Sent Events (SSE)#

The useServerEvents hook provides the foundation for real-time updates throughout the application.

Hook Signature:

useServerEvents({ enabled?: boolean })

Configuration:

  • enabled (optional, default: true): Controls whether the SSE connection is established
    • When set to false, the hook will not establish an SSE connection
    • Useful for conditionally disabling real-time updates on certain pages (e.g., authentication pages where SSE connections are not needed)

Example Usage:

// Enable SSE conditionally
const { addEventListener } = useServerEvents({ enabled: !isAuthPage });

Functionality:

  • Establishes and maintains a persistent connection to /api/v1/events
  • Automatically handles cache invalidation for backup and volume events
  • Returns an addEventListener function for subscribing to specific server events
  • Manages connection lifecycle (connect, disconnect, reconnect) automatically

Visual Feedback Components#

StatusDot Component#

The StatusDot component provides the primary visual indicator for mirror sync status. The component implements an animated pulsing effect using Tailwind's animate-ping class:

{statusMapping?.animated && (
  <span
    className={cn(
      "absolute inline-flex h-full w-full animate-ping rounded-full opacity-75",
      `${statusMapping.colorLight}`,
    )}
  />
)}

Component Features:

  • Accepts an animated prop to enable/disable pulsing animation
  • Uses blue "info" variant for in-progress operations
  • Displays color-coded status using theme-aware semantic colors across five variants:
    • success: Green indicator (bg-success, text-success) for successful operations
    • error: Red indicator (destructive colors) for failed operations
    • warning: Yellow/amber indicator for operations that complete with warnings
    • info: Blue indicator for in-progress or informational states
    • neutral: Gray indicator for inactive or pending states
  • Colors adapt to both light and dark themes while maintaining semantic meaning
  • Includes accessible tooltip for status label with aria-label attribute

ScheduleMirrorsConfig Component#

The ScheduleMirrorsConfig component orchestrates real-time mirror status display.

Event Listeners:

The component subscribes to SSE events and updates local state:

Visual Display:

Status Tracking System#

Mirror assignments track synchronization state through the MirrorAssignment type:

  • lastCopyStatus: "success" | "error" | "in_progress" | null
  • lastCopyAt: Timestamp of last sync
  • lastCopyError: Error message if sync failed

The backend execution service updates database status and emits events at key lifecycle points: when sync starts, succeeds, or fails.

Progress Display Limitations#

Unlike backup operations with detailed progress tracking (percentage, files processed, data transferred, speed via BackupProgressCard component), mirror synchronization displays only binary status information:

  • Syncing vs. completed states
  • Animated visual feedback during sync
  • Success/error outcome
  • Timestamp of last completion

The Progress component exists for backup/restore operations but is not used for mirror operations, which do not emit granular progress events during execution.


'In Progress' Status Display During Copy Operations#

The zerobyte application provides consistent 'in progress' status display across three operation types: backups, restores, and mirror copies.

Backup Operations#

The BackupProgressCard component provides comprehensive progress tracking with detailed metrics.

Visual Elements:

  • Animated spinning border with text "Backup in progress"
  • CSS animation using border-2 border-primary border-t-transparent and animate-spin classes
  • Progress bar showing percentage completion

Backup Status Indicators:

The BackupStatusDot component provides visual status feedback for backup schedules with support for multiple states:

  • In Progress: Blue "info" variant with animated pulsing when a backup is running
  • Success: Green indicator when backup completes successfully (exit code 0)
  • Warning: Yellow/amber indicator when backup completes with warnings (non-zero exit code but not a complete failure, such as exit code 3 from restic indicating some files could not be read)
  • Error: Red indicator when backup fails completely
  • Neutral: Gray indicator when schedule is disabled

The component accepts hasWarning and hasError props to distinguish between warning and error states, displaying appropriate labels and colors for each condition. Warning status is used when backups complete with issues that don't constitute total failure.

Real-Time Metrics:

  • Files processed
  • Data transferred
  • Elapsed time
  • Transfer speed (MB/s)
  • Estimated time remaining (ETA)
  • Current file being backed up

The ETA is calculated from the seconds_remaining field in the backup progress API response and displayed using the formatDuration() function. When the value is not yet available or is 0, the UI displays "Calculating..." instead.

Progress Field Handling:

The component is designed to handle incomplete or missing progress data gracefully:

  • Progress fields (percent_done, bytes_done, total_bytes, seconds_elapsed, files_done, total_files) are optional in the API response type
  • The component destructures these fields with default values of 0 when they are not present in the progress object
  • This defensive approach ensures the component remains stable during early stages of backup operations or when progress data is temporarily unavailable
  • Example: const { percent_done = 0, bytes_done = 0, total_bytes = 0, ... } = progress ?? {};

Initial Progress Loading:

The component accepts an initialProgress prop of type GetBackupProgressResponse that allows it to display cached progress information immediately upon page load. This enables users to see progress data right away rather than waiting for the first polling request. The component then continues to poll for updates every second during the backup operation.

Progress Data Source:

Progress information is retrieved through polling-based architecture:

  • The component uses useQuery from @tanstack/react-query with getBackupProgressOptions
  • Polling occurs every second via refetchInterval: 1000
  • The GET /api/v1/backups/{shortId}/progress endpoint returns the last known progress for a running backup (or null if no progress has been reported yet)
  • Server-side rendered data is provided via the initialData prop

The backend maintains progress using the centralized cache utility with key backup:${scheduleId}:progress and a 1-hour TTL. This cache is populated as progress events occur, deleted when a backup completes, and automatically cleared when checking progress for non-in-progress backups.

Status Detection:

The component is conditionally rendered when schedule.lastBackupStatus === "in_progress". The ScheduleSummary component uses useSuspenseQuery with getBackupProgressOptions to pre-fetch backup progress data before rendering, then passes this data as the initialProgress prop to BackupProgressCard. The component also displays text "⟳ in progress..." and includes a Stop Backup button when a backup is running.

Warning and Error Display:

When a backup completes with warnings or errors, the ScheduleSummary component displays detailed information in a collapsible section:

  • Warning State (lastBackupStatus === "warning"): Shows a yellow-themed collapsible panel with warning details. Warning status is set when a backup completes with a non-zero exit code but not a complete failure (e.g., exit code 3 from restic when some files could not be read). The lastBackupError field stores stderr output containing specific warning details captured during the backup operation.
  • Error State (lastBackupStatus === "error"): Shows a red-themed collapsible panel with error details for complete backup failures.

Both states display the content of schedule.lastBackupError in a monospace font with appropriate color coding. The collapsible UI provides a clean way to surface diagnostic information without cluttering the main interface.

Restore Operations#

The RestoreProgress component shows progress during restore operations.

Visual Elements:

  • Spinning animation with "Restore in progress" text
  • Identical CSS animation pattern as backup operations

Progress Details:

When progress data is available, the component displays detailed metrics:

  • Percentage complete
  • Files restored
  • Data restored
  • Elapsed time
  • Transfer speed (MB/s)

Event Listener Pattern:

The component uses AbortController/AbortSignal for event listener cleanup:

  • Creates an AbortController and passes its signal to addEventListener calls
  • Listens for restore:started, restore:progress, and restore:completed events
  • Cleanup is simplified to abortController.abort() in the useEffect cleanup function
  • This pattern replaces the manual unsubscribe approach, providing automatic cleanup when the component unmounts or dependencies change

Mirror Copy Operations#

The ScheduleMirrorsConfig component displays copy status for mirror repositories.

Status Tracking:

Uses lastCopyStatus: "in_progress" to track mirror copy operations.

Visual Indicator:

Real-Time Updates:

Listens to server events mirror:started and mirror:completed to update status in real-time.

RestoreForm Component#

The RestoreForm component provides snapshot restore and download capabilities.

Download Functionality:

  • Download button with Download icon in the header alongside Cancel and Restore buttons
  • Button text is dynamic based on selection: "Download All", "Download 1 item", or "Download X items"
  • Download is enabled only when 0 or 1 items are selected (disabled for multiple selections with tooltip explanation)
  • Downloads use the /api/v1/repositories/{shortId}/snapshots/{snapshotId}/dump endpoint
  • Query parameters include path and kind for single item downloads
  • Download is triggered via programmatic link creation and click

Dynamic Button Labels:

  • Restore button text changes based on state: "Restoring...", "Restore All", "Restore 1 item", or "Restore X items"
  • Uses getDownloadButtonText() and getRestoreButtonText() helper functions for dynamic labels

State Management:

  • New state selectedPathKind tracks whether selected item is "file" or "dir"
  • Uses repository.shortId instead of repository.id for consistency with API endpoints
  • AbortController/AbortSignal pattern for event listener cleanup (matching RestoreProgress component)

Responsive Layout:

  • Header buttons use responsive flex layout: flex-col on mobile, flex-row on desktop
  • Tooltip component wraps the download button to explain the single-selection limitation

Common UI Patterns#

All progress displays share consistent design patterns:

  1. Animated Spinners: CSS animations using border-2 border-primary border-t-transparent with animate-spin class for continuous rotation
  2. StatusDot Component: The StatusDot supports five status variants with theme-aware colors:
    • info: Blue dot with pulsing animation for in-progress operations
    • success: Green dot for successful completions
    • warning: Yellow/amber dot for operations completing with warnings
    • error: Red dot for failures
    • neutral: Gray dot for inactive states
  3. Progress Updates: Backup operations use React Query polling every second (refetchInterval: 1000); restore and mirror operations use Server-Sent Events for real-time updates
  4. Consistent Status Values: in_progress, success, warning, and error strings used uniformly across all operation types
  5. Theme Support: Color indicators use semantic tokens (text-success, bg-success, text-warning, text-destructive, text-foreground) that adapt to both light and dark themes

Minimum Loading Duration Pattern#

The zerobyte application implements a minimum loading duration pattern to prevent flashing UI states for very fast operations.

useMinimumDuration Hook#

The useMinimumDuration hook ensures loading states display for a minimum duration for better UX.

Implementation:

  • Accepts isActive boolean and minimumDuration number (in milliseconds)
  • Returns a displayActive boolean that remains true for at least the minimum duration
  • Uses useRef to track start time and timeout reference
  • When isActive becomes false, calculates elapsed time and ensures the loading state persists for the remaining duration

Usage in Button Component:

The Button component implements minimum loading duration logic:

  • Sets MINIMUM_LOADING_DURATION to 300ms
  • Uses useMinimumDuration hook to extend the loading state
  • Displays spinner and hides button content while isLoading is true
  • Prevents very fast operations from causing UI flicker

Benefits:

  • Smoother user experience by avoiding rapid state changes
  • Consistent loading feedback across the application
  • Reduces visual noise from operations that complete quickly

The zerobyte application implements a comprehensive breadcrumb navigation system for repository details pages using TanStack Router and Radix UI.

Route-Level Configuration#

The repository details page at app/routes/(dashboard)/repositories/$repositoryId/index.tsx defines breadcrumb navigation using the staticData property:

staticData: {
  breadcrumb: (match) => [
    { label: "Repositories", href: "/repositories" },
    { label: match.loaderData?.name || "Repository Details" },
  ],
},

This configuration creates a two-level breadcrumb trail:

  • "Repositories" - Clickable link returning to the repositories list page
  • "Repository Name" - Current page (non-clickable text)

The repository name is dynamically loaded from route data, with "Repository Details" as a fallback when data is unavailable.

UI Component Architecture#

The breadcrumb system uses a two-layer component structure.

Base UI Components#

app/client/components/ui/breadcrumb.tsx provides primitive components built on Radix UI:

  • Breadcrumb - Root container element
  • BreadcrumbList - Ordered list wrapper
  • BreadcrumbItem - Individual breadcrumb item wrapper
  • BreadcrumbLink - Clickable navigation link
  • BreadcrumbPage - Current page component (non-clickable)
  • BreadcrumbSeparator - Visual separator between items (typically a chevron or slash)

These primitives provide consistent styling and accessibility features across the application.

App-Level Breadcrumb Component#

app/client/components/app-breadcrumb.tsx dynamically renders breadcrumbs through:

  1. Route Discovery: Uses useMatches() to find the last matched route with breadcrumb data
  2. Function Execution: Executes the breadcrumb function with route match data
  3. Dynamic Rendering: Renders clickable links for intermediate items and plain text for the current page
  4. Reverse Search Pattern: Searches routes in reverse order to find the last route with breadcrumb data, enabling proper nested route breadcrumbs

This approach allows breadcrumbs to be defined declaratively at the route level while maintaining flexibility for dynamic content.

Layout Integration#

The breadcrumb is rendered in the page header within app/client/components/layout.tsx:

<header className="z-50 bg-card-header border-b border-border/50 shrink-0">
  <div className="flex items-center justify-between py-3 sm:py-4 px-2 sm:px-8 mx-auto container gap-4">
    <div className="flex items-center gap-4 min-w-0">
      <SidebarTrigger />
      <AppBreadcrumb />
    </div>

Layout Properties:

  • Position: Top-left section of the header, next to the sidebar trigger
  • Responsive Design: Padding adjusts from py-3 px-2 on small screens to py-4 px-8 on larger viewports
  • Text Truncation: Uses min-w-0 to enable proper text truncation on narrow screens
  • Consistent Context: Provides navigation context across all pages that define breadcrumb data

The breadcrumb's placement in the header ensures it remains visible and accessible throughout the application, providing clear navigational context for users.


Summary#

The zerobyte application implements four cohesive UI/UX features with support for both light and dark themes:

Mirror Synchronization: Real-time status updates via Server-Sent Events with animated visual feedback using the StatusDot component. Mirror sync displays binary status (syncing/completed) without granular progress metrics, distinguishing it from backup and restore operations. Status indicators use theme-aware semantic colors that maintain meaning across themes.

In-Progress Status Display: Consistent status indicators across backup, restore, and mirror operations using animated spinners, color-coded status dots with semantic color tokens, and progress updates. The StatusDot component supports five variants: success (green), error (red), warning (yellow/amber), info (blue), and neutral (gray). Backup operations use React Query with 1-second polling intervals to retrieve progress from the /api/v1/backups/{shortId}/progress endpoint, displaying cached information immediately on page load via the initialData prop. The BackupStatusDot component displays warning status when backups complete with non-zero exit codes but not complete failures (e.g., exit code 3 from restic), with detailed warning messages shown in a collapsible panel. Restore operations provide detailed progress metrics via Server-Sent Events, while mirror operations show simplified status information. RestoreForm component adds download functionality with dynamic button labels and responsive layout. All color indicators adapt to light and dark themes while maintaining their semantic meaning.

Minimum Loading Duration: A pattern that ensures loading states persist for at least 300ms to prevent flashing UI states, implemented through the useMinimumDuration hook and applied to the Button component for consistent user experience.

Breadcrumb Navigation: Dynamic, route-based breadcrumb system using TanStack Router's staticData property with Radix UI components. The system provides consistent navigation context through a two-layer architecture of primitive UI components and an app-level orchestrator that dynamically renders breadcrumbs based on route configuration.