Offering match options in a review step

Write a script that tells a review step which values a reviewer may choose from for a cell, so they pick from real candidates instead of typing a value by hand.

A review step exists because a value could not be resolved automatically. Filtering on every key you have still leaves more than one possibility, so a person has to decide which one is right.

The Match options script is how you tell the review step what those possibilities are. It runs once when a run pauses for review, and every cell it narrows becomes a dropdown of exactly those values. Cells the script says nothing about stay ordinary text fields.

Writing the script

Open the review step's settings and find the Match options section. Your script receives two things — the rows of the data under review, and the step's reference file — and calls setOptions for each cell it can narrow:

import { Reference, Row } from "oneschema/reviewoptions"

export default function (rows: Row[], reference: Reference) {
  rows.forEach((row) => {
    // Already resolved upstream — leave it alone.
    if (row.values["Tax Code"]) return

    const candidates = reference.findRows("Locality", row.values["Locality"])

    row.setOptions(
      "Tax Code",
      candidates.map((match) => ({
        value: match.values["Code"],
        label: match.values["Name"],
        description: match.values["County"],
        referenceRowId: match.id,
      })),
    )
  })
}

A reviewer working the Tax Code column now sees the two Pocono codes on the POCONO T row, and nothing at all on the row that was already resolved. Because each option says which reference row it came from, they can also jump to that row in the reference pane before accepting it.

The Row object

PropertyDescription
row.idIdentifier for the row. Stable while the run is paused.
row.valuesThe row's cells, keyed by column name.
row.setOptions(column, opts)Offer opts to the reviewer for this row's column.

Say nothing about a cell and it stays a text field, so a script only has to speak up where it can genuinely narrow things down. Calling setOptions twice for the same cell replaces the earlier list.

The Option object

FieldRequiredDescription
valueYesWritten into the cell when the reviewer picks it, so it must be the value your later steps expect. A number is accepted and stored as its string form.
labelNoShown beside the value. When omitted, the value is shown on its own.
descriptionNoSecondary text, for telling near-identical candidates apart.
referenceRowIdNoThe id of the reference row you read this option out of. Lets the reviewer jump to that row.

label and description exist for the situation this feature is for: when two candidates differ by something a bare code does not show. A reviewer recognizes "Pocono Twp SD" long before they recognize 340603.

referenceRowId must be the id of a row of this step's reference file. An id that names no such row is reported as an error rather than stored, so a "show me where this came from" never quietly goes nowhere.

Reading the reference file

The reference file configured on the step is handed to your script as its second argument, so you can compare the data under review against it instead of copying it into the script.

PropertyDescription
reference.rowsEvery row of the reference file. Read-only — only the review data is editable.
reference.columnsIts columns, in the order they appear in the file.
reference.findColumn(key)One reference column by key, or undefined.
reference.findRows(column, value)Every reference row whose column holds exactly value.

findRows matches exactly and is case-sensitive, and it indexes the column the first time you ask for it — so looking a value up once per review row costs one pass over the file, not one per row. For anything looser, filter reference.rows yourself.

The reference is read-only, and typed that way: findRows answers from an index built once from these rows, so reordering or editing them in place would change what later lookups return. Copy first if you need to sort — [...reference.rows].sort(…).

A reference row has an id and a values object keyed by the reference file's own column names, the same shape as a review row:

import { getReference, Row } from "oneschema/reviewoptions"

function codesFor(locality: string) {
  // The same reference the default export is given, for a helper that isn't it.
  return getReference().findRows("Locality", locality)
}

With no reference file configured on the step, reference is present but empty — a script that consults it offers nothing rather than failing.

Fetching data from elsewhere

For a lookup that lives outside both the review data and the reference file, your script can make a request:

import { fetch } from "oneschema"
import { Row } from "oneschema/reviewoptions"

export default async function (rows: Row[]) {
  const response = await fetch("https://example.com/tax-codes")
  const codes = await response.json()
  // …
}

Network access is off unless outbound requests are enabled for your organization — the same setting that enables validation webhooks. Contact support if your script needs it.

Working with the columns

findColumn and getColumns describe the data under review, which is useful when column names vary between files:

import { Row, getColumns } from "oneschema/reviewoptions"

export default function (rows: Row[]) {
  const codeColumns = getColumns().filter((c) => c.key.endsWith(" Code"))
  // …
}
FunctionReturns
getColumns()Every column, in the order the reviewer sees them.
findColumn(key)One column by key, or undefined when the data has no such column.

A column's key here is its name in the data under review — the same string you use to read a cell from row.values and to name a column in setOptions. That differs from a validation code hook, where the key is the template's target attribute: a review step need not have a template at all, so it works from the column names the data actually carries.

What a reviewer sees

  • Cells you narrowed open a dropdown of your candidates, searchable by value or label.
  • Cells you said nothing about stay ordinary text fields.
  • Candidates that name a reference row point at it: hovering one scrolls the reference pane to that row and tints it, Show row pins it without accepting the value, and picking the value leaves its row marked.
  • A reviewer can always type a value you did not offer. The review step exists because the decision needed a person, so when your narrowing is wrong they are never boxed in by it.

When options do not appear

The script is a convenience, so a failure never blocks a review — the run still pauses and the affected cells stay text fields. Options are missing when:

  • No script is configured on the step.
  • The script ran without narrowing any cell.
  • The script raised an error. The failure is recorded on the step for support to look into; there is no self-serve view of it yet.
  • The script offered options for an implausible number of cells. A review is human-scale; a script narrowing thousands of cells is usually doing something other than helping a person decide.

Limits

LimitValue
Options per cell1,000
Cells with options per file5,000
Script run timeShares the code-hook timeout for your organization

Exceeding either count is reported as an error rather than silently truncated.


Did this page help you?