Retention Change

Says exactly what a shorter data-retention period will delete and when, and suggests an export before it purges.

StopsShorter retention purged months of data

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/retention-change.json

The files land in your project. They're yours to edit.

Usage

retention-change-usage.tsx
import { RetentionChange, type RetentionDay } from "@/components/ui/retention-change"

<RetentionChange
  current={current}
  defaultValue={30}
  noun="events"
  history={setup.history}
  purgeAt={setup.purgeAt}
  onExport={() => new Promise((resolve) => setTimeout(resolve, 900))}
  onConfirm={(days) => new Promise<void>((resolve) => setTimeout(() => {
    setCurrent(days)
    setSaved(`Retention set to ${days} days.`)
    resolve()
  }, 600))}
/>

What it catches

  • Record count and cutoff date a shorter period would delete
  • When the next purge runs
  • Roughly how many more records go each night after
  • Window in which raising it back still loses nothing
  • Confirming without an export, named on the button

Props

RetentionChange props
PropTypeDefault
current* (required)

Retention in force today, in days.

number—
value

New retention in days. Controlled.

number—
defaultValue

Starting retention in days when uncontrolled.

numbercurrent
onValueChange

Called with the chosen retention in days.

(days: number) => void—
options

Periods to offer, in days.

number[][7, 30, 90, 365]
history* (required)

Records per day, oldest first.

RetentionDay[]—
purgeAt* (required)

When the next purge job runs.

When—
noun

Plural noun for the data, e.g. "events".

string"records"
onExport

Exports everything older than the cutoff. Shows "Export first" when given.

(olderThan: Date) => void | Promise<void>—
onConfirm* (required)

Saves the new period. A returned promise shows a pending state; a rejection is caught.

(days: number) => void | Promise<void>—
locale

BCP 47 locale for numbers and dates.

string"en-GB"
timeZone

IANA zone for the purge time and dates, e.g. the workspace's zone. Defaults to the viewer's.

string—
messages

Every visible string (see `RETENTION_CHANGE_MESSAGES`). The single-string props below still work and win.

Partial<RetentionChangeMessages>—
optionLabel(days: number) => string—
undoText(left: string) => string—
raiseText(days: string) => string—

* required. Also accepts the native props of <section> (className, aria-*, data-*…), passed through to it.

Accessibility

  • Options are native radios in a group labelled by the title
  • Deletion summary in a polite live region
  • Chart is aria-hidden; the same facts are in text
  • Export and save buttons set aria-busy while pending; icons are aria-hidden

Only what the source does. Test with your own screen reader and content before shipping.

Limitations

This is a UX guard rail. Enforce on the server: Apply the new retention server-side with its own grace period, and make the purge job re-check the setting before deleting.

  • Counts come from the daily history you pass; days are UTC calendar days
  • The chart is a summary (bars group days) and is hidden from screen readers; the text states the numbers
  • Does not delete or export anything itself

What it stops

Shorter retention purged months of data

Also known as

data retention · retention period · logs · purge · analytics events · compliance · export · ttl

Field type

Dependencies

Pairs well with