Import review

Pro

Check rows before they land: how many are ready, which need fixing and why, grouped by kind of problem. A suggested fix can be accepted per row or for the whole group. Loading stays locked while problems remain, unless the person chooses to leave those rows out — and it says how many that is.

Markdown

Preview

Install

With the Candor CLI

First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/import-review

Brings in: button, collapsible, data, locale, locked, utils · npm: lucide-react@^1.67.0

Usage

TSX · The example above
"use client"

import * as React from "react"
import { ImportReview } from "@/components/import-review"
import type { ImportIssue } from "@/lib/data"

const found: ImportIssue[] = [
  { row: 14, field: "Repository", kind: "unknown-value", message: "Not one of acme/api, acme/web, acme/workers", value: "acme/website", suggestion: "acme/web" },
  { row: 22, field: "Repository", kind: "unknown-value", message: "Not one of acme/api, acme/web, acme/workers", value: "API", suggestion: "acme/api" },
  { row: 3, field: "Owner", kind: "invalid", message: "No active user with this email", value: "jonas@acme", suggestion: "jonas@acme.example" },
  { row: 3, field: "Rollout", kind: "invalid", message: "Not a number", value: "n/a" },
  { row: 88, field: "Flag key", kind: "duplicate", message: "Same key as an existing flag", value: "dark-mode" },
  { row: 140, field: "Flag key", kind: "missing", message: "Required", value: "" },
]

export default function Example() {
  const [issues, setIssues] = React.useState(found)
  const [loading, setLoading] = React.useState(false)
  return (
    <ImportReview
      className="max-w-2xl"
      total={214}
      issues={issues}
      target="flags in Staging"
      loading={loading}
      onFix={(fixes) => setIssues((all) => all.filter((i) => !fixes.includes(i)))}
      onLoad={() => setLoading(true)}
    />
  )
}

<ImportReview>

PropTypeDefaultDescription
totalrequirednumber—How many rows the file has.
issuesrequiredImportIssue[]—Problems found, one per row and field, with a suggested fix where there is one.
targetrequiredstring—Where rows go, e.g. "Customers in Shop staging".
onFixrequired(fixes: ImportIssue[]) => void—Called with the issues whose suggested fixes a person accepted, one row or a whole group.
onLoadrequired(skipRows: number[]) => void—Called on Load with the row numbers to leave out; empty unless the person chose to skip rows with problems.
loadingboolean | undefinedfalseRows are being loaded; the Load button is disabled.
classNamestring | undefined—Extra classes for the outer element.

Strings

The fixed words, in English by default. Change any of them under importReview in <LocaleProvider strings={{ … }}>; the table is exported as importReviewStrings.

KeyEnglish
reviewRowsReview rows
readyReady
needFixingNeed fixing
totalTotal
allGoodEvery row checks out.
kindInvalidNot valid
kindMissingMissing a required value
kindDuplicateDuplicates
kindTooLongToo long
kindUnknownValueNot an allowed value
applyFixes{ one: "Apply {count} fix", other: "Apply {count} fixes" }
rowrow {row}
blank(blank)
applyApply
moreand {count} more
locked{ one: "{count} row needs fixing, or choose to leave them out.", other: "{count} rows need fixing, or choose to leave them out." }
leaveOut{ one: "Leave out the {count} row with problems", other: "Leave out the {count} rows with problems" }
load{ one: "Load {count} row into {target}", other: "Load {count} rows into {target}" }