Skip to content

Tracking

Data Display

Compact service history with labeled samples and a full text legend.

Thirty-sample historyCompact healthy workersNo history
Open preview

Responsive viewport — resize the window to explore. Direction and density apply only to this preview. Theme applies to the docs too.

Usage

Provide chronological observations with unique ids, a visible time label, and up, degraded, down, or unknown status. The summary reports operational known samples divided by all known samples; unknown observations are excluded. This is an equally weighted sample ratio, not time-weighted uptime. Supply actual telemetry in your application; the component makes no network requests.

Import
import { Tracking, type TrackingEntry } from "@/components/ui/tracking";

Shipped as editable source in src/components/ui/tracking.tsx in both apps. Copy the implementation below when moving it to another project. Copy the complete example from Source code for all imports and state. Add "use client" when using hooks or event handlers. See installation and theming for project setup.

Component source

The complete implementation is included in both apps. It uses the React, Radix, Lucide, and shared-core dependencies already installed in Apex. Keep your project’s semantic theme tokens when reusing it.

src/components/ui/tracking.tsx
import { cn } from "@dashboardpack/core/lib/utils";
export interface TrackingEntry {
  id: string;
  label: string;
  status: "up" | "degraded" | "down" | "unknown";
}
export interface TrackingProps {
  label: string;
  entries: TrackingEntry[];
  compact?: boolean;
  className?: string;
}
export function Tracking({
  label,
  entries,
  compact = false,
  className,
}: TrackingProps) {
  const labels = {
    up: "Operational",
    degraded: "Degraded",
    down: "Outage",
    unknown: "No data",
  };
  const known = entries.filter((entry) => entry.status !== "unknown");
  const availability = known.length
    ? `${Math.round((known.filter((entry) => entry.status === "up").length / known.length) * 100)}% operational samples`
    : "No known samples";
  return (
    <figure className={cn("min-w-0 space-y-3", className)}>
      <figcaption className="flex flex-wrap items-center justify-between gap-2 text-sm">
        <span className="font-medium">{label}</span>
        <span className="text-xs text-muted-foreground">{availability}</span>
      </figcaption>
      {entries.length ? (
        <ul
          aria-label={`${label} history`}
          className={cn("flex gap-1", compact ? "h-5" : "h-9")}
        >
          {entries.map((entry) => (
            <li
              key={entry.id}
              title={`${entry.label}: ${labels[entry.status]}`}
              className={cn(
                "min-w-0 flex-1 rounded-sm",
                entry.status === "up"
                  ? "bg-success"
                  : entry.status === "degraded"
                    ? "bg-warning"
                    : entry.status === "down"
                      ? "bg-destructive"
                      : "bg-muted",
              )}
            >
              <span className="sr-only">
                {entry.label}: {labels[entry.status]}
              </span>
            </li>
          ))}
        </ul>
      ) : (
        <p className="rounded-md border border-dashed p-4 text-sm text-muted-foreground">
          No history available.
        </p>
      )}
      <ul
        aria-label="History legend"
        className="flex flex-wrap gap-x-4 gap-y-1 text-xs text-muted-foreground"
      >
        {Object.entries(labels).map(([status, text]) => (
          <li key={status} className="flex items-center gap-1.5">
            <span
              aria-hidden
              className={cn(
                "size-2 rounded-sm",
                status === "up"
                  ? "bg-success"
                  : status === "degraded"
                    ? "bg-warning"
                    : status === "down"
                      ? "bg-destructive"
                      : "bg-muted",
              )}
            />
            {text}
          </li>
        ))}
      </ul>
    </figure>
  );
}

API reference

Common props and defaults. Slot-specific props are named below; native elements also accept their standard HTML attributes. The component TypeScript definitions are the complete type reference.

Tracking props
PropType / DefaultDescription
labelstring

Default: required

Visible caption and accessible history name.
entriesTrackingEntry[]

Default: required

Unique id, observation label, and up/degraded/down/unknown state.
compactboolean

Default: false

Use shorter history blocks for dense dashboards.
classNamestring

Default: —

Extend the component container with theme-aware utility classes.

Build with these too