Skip to contentVibraUI
Part of the Engineering dashboardinstalls at /engineering

Engineering dashboard

A delivery page: deploy frequency, lead time, change failure rate and time to restore, production deploys a week, the last releases on a timeline, every environment's recent deployments, and the pull requests still waiting for review.

Open the live page

The page is a server component inside AppShell; only the frequency chart crosses into the client, because a chart formats its own axis labels. db.deployments is the whole pipeline history, and three of the four headline numbers fall straight out of it: how often production ships, how often a production deploy fails, and how long the next green deploy takes after a red one. The two things the entity does not record are derived, not written out — lead time is a rule over the row (main ships within hours, a feature branch within days, jittered per row by seeded("engineering-overview")), and the open pull requests are generated once from the same generator over the branches in db.deployments and the people in db.members. Composes AppShell, PageHeader, StatCardGroup, StatCard, DashboardGrid, ChartCard, BarChart, Widget, Timeline, SimpleTable and StatusBadge.

Preview

Install

npx shadcn@latest add @vibra/engineering-overview

Needs the @vibra registry in your components.json — set it up once.

Source

app/engineering/page.tsx
import { REFERENCE_DATE } from "@/lib/sample-data"
import { AppShell } from "@/components/ui/app-shell"
import { DashboardGrid, DashboardGridItem } from "@/components/ui/dashboard-grid"
import { PageHeader } from "@/components/ui/page-header"

import { signOut } from "./actions"
import { DeployFrequency } from "./components/deploy-frequency"
import { DeploysTimeline } from "./components/deploys-timeline"
import { EngineeringStats } from "./components/engineering-stats"
import { OpenPrs } from "./components/open-prs"
import { RecentDeployments } from "./components/recent-deployments"
import { currentUser, deploysByWeek, shellNotifications, windowLabel, WINDOW_DAYS } from "./data"
import { NAV, ROUTES } from "@/lib/dashboards/engineering/nav"

/**
 * The delivery page. It is a server component: the pipeline history is read
 * from db on the server, and only the frequency chart crosses into the
 * client, because a chart formats its own axis labels — handed its weeks
 * already counted, so the store never follows it into the browser.
 */
export default function EngineeringPage() {
  return (
    <AppShell
      nav={NAV}
      activeHref={ROUTES.overview}
      user={currentUser()}
      notifications={shellNotifications()}
      now={REFERENCE_DATE}
      onSignOut={signOut}
    >
      <PageHeader
        title="Engineering"
        description={`How often the last ${WINDOW_DAYS} days shipped, how long a change waited, and what broke.`}
        meta={windowLabel()}
      />

      <EngineeringStats />

      <DashboardGrid>
        <DashboardGridItem colSpan={{ base: 12, lg: 8 }}>
          <DeployFrequency weeks={deploysByWeek()} />
        </DashboardGridItem>
        <DashboardGridItem colSpan={{ base: 12, lg: 4 }}>
          <DeploysTimeline />
        </DashboardGridItem>

        <DashboardGridItem colSpan={{ base: 12, lg: 7 }}>
          <RecentDeployments />
        </DashboardGridItem>
        <DashboardGridItem colSpan={{ base: 12, lg: 5 }}>
          <OpenPrs />
        </DashboardGridItem>
      </DashboardGrid>
    </AppShell>
  )
}
app/engineering/data.ts
/**
 * What this page reads. `db.deployments` is the whole pipeline history, and
 * three of the four headline numbers fall straight out of it: how often
 * production ships, how often a production deploy fails, and how long the
 * next green one takes to arrive after a red one.
 *
 * Two things the entity does not record are derived, and neither is a literal.
 * Lead time is a *rule* over the row db does have — a deploy off `main` was
 * cut hours after its commit, a feature branch days, with a jitter fixed by
 * `seeded("dashboard-engineering")` so the same deploy always reads the same.
 * The open pull requests have no entity at all, so they are generated once
 * from the same generator over the branches in `db.deployments` and the people
 * in `db.members`. "Now" is `REFERENCE_DATE`; nothing here reads a clock.
 */
import { formatDuration, formatNumber, formatPercent, getInitials } from "@/lib/format"
import {
  db,
  intBetween,
  REFERENCE_DATE,
  seeded,
  type Deployment,
  type Member,
} from "@/lib/sample-data"

export type { Deployment }

const HOUR_MS = 3_600_000
const DAY_MS = 86_400_000

/** The window the four headline numbers are measured over. */
export const WINDOW_DAYS = 30

const WINDOW_START = REFERENCE_DATE.getTime() - WINDOW_DAYS * DAY_MS

// One series for the whole block: one lead time per deployment first, then the
// pull requests.
const SEED = "dashboard-engineering"
const rand = seeded(SEED)

const BY_TIME = db.deployments.all().sort((a, b) => a.startedAt.getTime() - b.startedAt.getTime())
const PRODUCTION = BY_TIME.filter((deployment) => deployment.environment === "production")

// How long a change waits before it ships, in hours: work on main goes out the
// same day, a feature branch takes days. The jitter is drawn once per
// deployment, in time order, so a row's lead time never moves.
const LEAD_HOURS = new Map<string, number>(
  BY_TIME.map((deployment) => [
    deployment.id,
    deployment.branch === "main" ? 2 + rand() * 7 : 14 + rand() * 60,
  ])
)

/** How long this change waited between its first commit and this deploy. */
export function leadTimeHours(deployment: Deployment): number {
  return LEAD_HOURS.get(deployment.id) ?? 0
}

const inWindow = (deployment: Deployment) => deployment.startedAt.getTime() >= WINDOW_START

const median = (values: number[]): number => {
  if (values.length === 0) return 0
  const sorted = [...values].sort((a, b) => a - b)
  return sorted[Math.floor(sorted.length / 2)]
}

/**
 * How long production stayed broken: from a failed production deploy inside
 * the window to the next successful one, in milliseconds. The recovery itself
 * may land outside the window — what is windowed is the failure. A failure
 * with nothing green after it is still open and cannot be measured.
 */
function recoveryTimes(): number[] {
  const times: number[] = []
  PRODUCTION.forEach((deployment, index) => {
    if (deployment.status !== "failed" || !inWindow(deployment)) return
    const fixed = PRODUCTION.slice(index + 1).find((next) => next.status === "success")
    if (!fixed) return
    times.push(fixed.startedAt.getTime() - deployment.startedAt.getTime())
  })
  return times
}

// Below this many incidents a median is one or two readings wearing a
// statistic's clothes, so the card says how many it stands on.
const THIN_SAMPLE = 5

export type EngineeringStat = {
  key: string
  label: string
  value: string
  /** Trails the value in quieter type — the sample a thin median stands on. */
  note?: string
  description: string
}

/** Deploy frequency, lead time, change failure rate and time to restore. */
export function engineeringStats(): EngineeringStat[] {
  const shipped = PRODUCTION.filter(inWindow)
  // A cancelled deploy never reached production, so it is neither a change
  // that shipped nor a change that failed: it leaves the ratio entirely.
  const completed = shipped.filter(
    (deployment) => deployment.status === "success" || deployment.status === "failed"
  )
  const failed = completed.filter((deployment) => deployment.status === "failed")
  const recoveries = recoveryTimes()

  return [
    {
      key: "frequency",
      label: "Deploy frequency",
      value: `${formatNumber(shipped.length / WINDOW_DAYS, { maximumFractionDigits: 1 })}/day`,
      description: `${shipped.length} production deploys in ${WINDOW_DAYS} days`,
    },
    {
      key: "lead-time",
      label: "Lead time",
      value: formatDuration(median(shipped.map(leadTimeHours)) * HOUR_MS),
      description: "median, first commit to production",
    },
    {
      key: "failure-rate",
      label: "Change failure rate",
      value: formatPercent(completed.length === 0 ? 0 : failed.length / completed.length, {
        maximumFractionDigits: 1,
      }),
      description: `${failed.length} of ${completed.length} completed deploys failed`,
    },
    {
      key: "mttr",
      label: "Time to restore",
      value: formatDuration(median(recoveries)),
      ...(recoveries.length < THIN_SAMPLE
        ? { note: `${recoveries.length} incident${recoveries.length === 1 ? "" : "s"}` }
        : {}),
      description: "median, failed deploy to the next green one",
    },
  ]
}

export type WeekPoint = { week: string; succeeded: number; failed: number }

const CHART_WEEKS = 12

const WEEK_LABEL = new Intl.DateTimeFormat("en-US", {
  month: "short",
  day: "numeric",
  timeZone: "UTC",
})

/** Production deploys per week over the last twelve, green against red. */
export function deploysByWeek(): WeekPoint[] {
  const end = REFERENCE_DATE.getTime()
  return Array.from({ length: CHART_WEEKS }, (_, index) => {
    const from = end - (CHART_WEEKS - index) * 7 * DAY_MS
    const to = from + 7 * DAY_MS
    const week = PRODUCTION.filter(
      (deployment) =>
        deployment.startedAt.getTime() >= from && deployment.startedAt.getTime() < to
    )
    return {
      week: WEEK_LABEL.format(new Date(from)),
      succeeded: week.filter((deployment) => deployment.status === "success").length,
      failed: week.filter((deployment) => deployment.status === "failed").length,
    }
  })
}

/** The last production deploys, newest first. */
export function productionTimeline(limit = 6): Deployment[] {
  return [...PRODUCTION].reverse().slice(0, limit)
}

/** The last deploys to any environment, newest first. */
export function recentDeployments(limit = 8): Deployment[] {
  return [...BY_TIME].reverse().slice(0, limit)
}

export type PullRequest = {
  id: string
  number: number
  title: string
  branch: string
  author: Member
  additions: number
  deletions: number
  checks: "passing" | "failing" | "running"
  reviews: number
  openedAt: Date
}

// How a branch name reads as a pull request title: "feat/sso-login" becomes
// "Sso login". The branch is the record; the sentence is derived from it.
function titleFor(branch: string): string {
  const words = branch.split("/").slice(1).join(" ").replace(/-/g, " ")
  return words.charAt(0).toUpperCase() + words.slice(1)
}

const PR_COUNT = 6

function generatePullRequests(): PullRequest[] {
  // The pull requests come after the lead times in the block's series: that
  // part of it is replayed per request, so the authors are the members as they
  // are now, a rename or a deactivation included, and every other figure is
  // the one it always was.
  const rand = seeded(SEED)
  for (let drawn = 0; drawn < BY_TIME.length; drawn++) rand()

  // Every branch the pipeline has seen, except main, newest first.
  const branches = [
    ...new Set(
      [...BY_TIME].reverse().map((deployment) => deployment.branch).filter((branch) => branch !== "main")
    ),
  ].slice(0, PR_COUNT)
  const authors = db.members.all().filter((member) => member.status === "active")

  return branches.map((branch, index) => {
    const checks = rand()
    return {
      id: branch,
      number: 1200 + index * intBetween(rand, 3, 19),
      title: titleFor(branch),
      branch,
      author: authors[intBetween(rand, 0, authors.length - 1)],
      additions: intBetween(rand, 12, 940),
      deletions: intBetween(rand, 4, 420),
      checks: checks < 0.68 ? "passing" : checks < 0.86 ? "failing" : "running",
      reviews: intBetween(rand, 0, 3),
      openedAt: new Date(REFERENCE_DATE.getTime() - intBetween(rand, 2, 260) * HOUR_MS),
    }
  })
}

/** What is waiting for review, oldest first. */
export function openPullRequests(): PullRequest[] {
  return generatePullRequests().sort((a, b) => a.openedAt.getTime() - b.openedAt.getTime())
}

/** How long a deploy took, written out. */
export function deployDuration(deployment: Deployment): string {
  return formatDuration(deployment.durationSec * 1000)
}

/** The moment every "ago" on this page is measured against. */
export const NOW = REFERENCE_DATE

/** How long ago something happened, in whole minutes, hours or days. */
export function since(at: Date): string {
  const ms = REFERENCE_DATE.getTime() - at.getTime()
  if (ms < HOUR_MS) return `${Math.max(1, Math.round(ms / 60_000))}m ago`
  return ms < DAY_MS
    ? `${Math.round(ms / HOUR_MS)}h ago`
    : `${Math.round(ms / DAY_MS)}d ago`
}

/** The bell's contents: the newest notifications, unread first in the panel. */
export function shellNotifications() {
  return db.notifications
    .all()
    .sort((a, b) => b.at.getTime() - a.at.getTime())
    .slice(0, 6)
    .map(({ id, title, description, at, read, href }) => ({ id, title, description, at, read, href }))
}

function ownerRow(): Member {
  return db.members.all().find((member) => member.role === "owner") ?? db.members.all()[0]
}

/** The person looking at the page: whoever owns this workspace. */
export function currentUser() {
  const owner = ownerRow()
  return { name: owner.name, email: owner.email, initials: getInitials(owner.name), avatarUrl: owner.avatarUrl }
}

// Fixed to UTC so the line reads the same wherever the page is rendered.
const WINDOW_LABEL = new Intl.DateTimeFormat("en-US", { dateStyle: "medium", timeZone: "UTC" })

/** The window the headline numbers cover, written out. */
export function windowLabel(): string {
  return `${WINDOW_LABEL.format(new Date(WINDOW_START))} – ${WINDOW_LABEL.format(REFERENCE_DATE)} UTC`
}
app/engineering/actions.ts
"use server"

import { mockAuthAdapter } from "@/lib/auth-adapter"
import { type Result } from "@/lib/sample-data"

/**
 * The one thing this page changes. A server action so the page can stay a
 * server component and still hand the shell something to call, and a `Result`
 * so the caller reads the same success-or-error shape every mutation returns.
 */
export async function signOut(): Promise<Result<{ signedOut: true }>> {
  await mockAuthAdapter.signOut()
  return { ok: true, data: { signedOut: true } }
}
app/engineering/components/deploy-frequency.tsx
"use client"

import { formatNumber } from "@/lib/format"
import { BarChart } from "@/components/ui/bar-chart"
import { ChartCard } from "@/components/ui/chart-card"

import { type WeekPoint } from "../data"

// Green against red, in that order, so the eye reads the week's outcome
// before it reads the week's volume.
const SERIES = [
  { key: "succeeded", label: "Succeeded", color: "chart-2" as const },
  { key: "failed", label: "Failed", color: "chart-4" as const },
]

export type DeployFrequencyProps = { weeks: WeekPoint[] }

/** Production deploys a week, green against red. The weeks arrive counted from the server page. */
export function DeployFrequency({ weeks }: DeployFrequencyProps) {
  const succeeded = weeks.reduce((total, week) => total + week.succeeded, 0)
  const failed = weeks.reduce((total, week) => total + week.failed, 0)

  return (
    <ChartCard
      data-widget="widget-engineering-overview-deploy-frequency"
      title="Deploy frequency"
      description="Production deploys a week over the last twelve"
      height={360}
      className="h-full"
      footer={`${formatNumber(succeeded, { maximumFractionDigits: 0 })} shipped clean, ${formatNumber(failed, { maximumFractionDigits: 0 })} failed on the way out.`}
    >
      <BarChart
        data={weeks}
        index="week"
        series={SERIES}
        height={360}
        showYAxis
        valueFormatter={(value) => formatNumber(value, { maximumFractionDigits: 0 })}
      />
    </ChartCard>
  )
}
app/engineering/components/deploys-timeline.tsx
import { CircleCheckIcon, CircleSlashIcon, CircleXIcon, LoaderIcon } from "lucide-react"

import { Timeline, TimelineItem, type TimelineTone } from "@/components/ui/timeline"
import { Widget } from "@/components/ui/widget"

import { deployDuration, productionTimeline, since, type Deployment } from "../data"

const TONE: Record<Deployment["status"], TimelineTone> = {
  success: "success",
  failed: "danger",
  running: "info",
  cancelled: "neutral",
}

const ICON: Record<Deployment["status"], React.ReactNode> = {
  success: <CircleCheckIcon />,
  failed: <CircleXIcon />,
  running: <LoaderIcon />,
  cancelled: <CircleSlashIcon />,
}

export function DeploysTimeline() {
  const deploys = productionTimeline()

  return (
    <Widget
      data-widget="widget-engineering-overview-deploys-timeline"
      title="Production timeline"
      description="The last six releases, newest first"
      className="h-full"
      footer="A cancelled deploy never reached production, so it counts against nothing; a failed one rolled back."
    >
      <Timeline>
        {deploys.map((deployment) => (
          <TimelineItem
            key={deployment.id}
            tone={TONE[deployment.status]}
            icon={ICON[deployment.status]}
            time={since(deployment.startedAt)}
            title={<span className="font-mono">{deployment.sha}</span>}
            description={
              <span className="flex flex-wrap items-baseline gap-x-2">
                <span className="font-mono text-xs">{deployment.branch}</span>
                <span>
                  {deployment.author} · {deployDuration(deployment)}
                </span>
              </span>
            }
          />
        ))}
      </Timeline>
    </Widget>
  )
}
app/engineering/components/engineering-stats.tsx
import { StatCard } from "@/components/ui/stat-card"
import { StatCardGroup } from "@/components/ui/stat-card-group"

import { engineeringStats } from "../data"

export function EngineeringStats() {
  return (
    <StatCardGroup data-widget="widget-engineering-overview-engineering-stats" columns={4}>
      {engineeringStats().map((stat) => (
        <StatCard
          key={stat.key}
          label={stat.label}
          value={
            stat.note ? (
              <span className="flex items-baseline gap-1.5">
                {stat.value}
                <span className="text-sm font-normal text-muted-foreground">· {stat.note}</span>
              </span>
            ) : (
              stat.value
            )
          }
          description={stat.description}
        />
      ))}
    </StatCardGroup>
  )
}
app/engineering/components/open-prs.tsx
import { formatNumber, getInitials } from "@/lib/format"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { StatusBadge } from "@/components/ui/status-badge"
import { Widget } from "@/components/ui/widget"

import { openPullRequests, since } from "../data"

export function OpenPrs() {
  const requests = openPullRequests()

  return (
    <Widget
      data-widget="widget-engineering-overview-open-prs"
      title="Open pull requests"
      description="Waiting for review, oldest first"
      className="h-full"
      footer="A pull request with no approvals has been waiting for its first reviewer."
    >
      <ul className="flex flex-col divide-y">
        {requests.map((request) => (
          <li key={request.id} className="flex flex-col gap-1 py-3 first:pt-0 last:pb-0">
            <div className="flex items-baseline justify-between gap-3">
              <span className="flex min-w-0 items-baseline gap-2">
                <span className="font-mono text-xs text-muted-foreground">#{request.number}</span>
                <span className="truncate text-sm font-medium">{request.title}</span>
              </span>
              <StatusBadge
                status={request.checks}
                size="sm"
                pulse={request.checks === "running"}
                map={{ passing: "success", failing: "danger", running: "info" }}
              />
            </div>

            <div className="flex flex-wrap items-baseline gap-x-2 text-xs text-muted-foreground">
              <span className="font-mono">{request.branch}</span>
              <span>·</span>
              <span className="inline-flex items-center gap-1.5">
                <Avatar className="size-4">
                  {request.author.avatarUrl ? <AvatarImage src={request.author.avatarUrl} alt="" /> : null}
                  <AvatarFallback className="text-avatar">{getInitials(request.author.name)}</AvatarFallback>
                </Avatar>
                {request.author.name}
              </span>
              <span>·</span>
              <span className="tabular-nums">
                <span className="text-success">
                  +{formatNumber(request.additions, { maximumFractionDigits: 0 })}
                </span>{" "}
                <span className="text-danger">
                  −{formatNumber(request.deletions, { maximumFractionDigits: 0 })}
                </span>
              </span>
              <span>·</span>
              <span className="tabular-nums">
                {request.reviews === 0
                  ? "no approvals"
                  : `${request.reviews} approval${request.reviews === 1 ? "" : "s"}`}
              </span>
              <span>·</span>
              <span className="tabular-nums">{since(request.openedAt)}</span>
            </div>
          </li>
        ))}
      </ul>
    </Widget>
  )
}
app/engineering/components/recent-deployments.tsx
import { SimpleTable, type SimpleTableColumn } from "@/components/ui/simple-table"
import { StatusBadge } from "@/components/ui/status-badge"
import { Widget } from "@/components/ui/widget"

import { deployDuration, recentDeployments, since, type Deployment } from "../data"

const COLUMNS: SimpleTableColumn<Deployment>[] = [
  {
    key: "sha",
    header: "Commit",
    cell: (row) => <span className="font-mono text-xs">{row.sha}</span>,
  },
  {
    key: "branch",
    header: "Branch",
    cell: (row) => <span className="font-mono text-xs">{row.branch}</span>,
  },
  { key: "environment", header: "Environment" },
  {
    key: "status",
    header: "Status",
    cell: (row) => (
      <StatusBadge
        status={row.status}
        pulse={row.status === "running"}
        map={{ success: "success", failed: "danger", running: "info", cancelled: "neutral" }}
      />
    ),
  },
  { key: "author", header: "Author" },
  { key: "duration", header: "Duration", align: "right", cell: (row) => deployDuration(row) },
  { key: "started", header: "Started", align: "right", cell: (row) => since(row.startedAt) },
]

export function RecentDeployments() {
  return (
    <Widget
      data-widget="widget-engineering-overview-recent-deployments"
      title="Recent deployments"
      description="Every environment, newest first"
      className="h-full"
      contentClassName="px-0"
      footer="Duration is the pipeline run, not the time the change waited to ship."
    >
      <SimpleTable
        columns={COLUMNS}
        rows={recentDeployments()}
        rowKey="id"
        size="sm"
        caption="Deployments across every environment"
      />
    </Widget>
  )
}