feat(events): a searchable source's chosen note is found when the page lacks it
A searchable source answers the editor a bounded first page, so the value an author picked (or a template filled in) may not be on it, and its note with it. useChosenNote asks the source for that value as a search term, once per value, and shows the exact match's note. Found building the Rust kit warning (PLAN_REDESIGNS §2.6), whose source - rust.options.grouppermissions - is searchable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -220,6 +220,46 @@ function SearchableOptions({ sourceId, label, disabled, onPick }) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* The chosen option's note (MODULE_API 1.13.0), found even when the list the
|
||||
* form holds does not reach it.
|
||||
*
|
||||
* A searchable source answers the form a bounded first page, so the value an
|
||||
* author picked — or a template filled in — may not be in it, and its note with
|
||||
* it. Then the source is asked for that value as a search term, once per value,
|
||||
* and the row whose value matches exactly is the one whose note is shown. A
|
||||
* failure is no note: advice never breaks the field it advises.
|
||||
*/
|
||||
function useChosenNote(sourceId, value, entry) {
|
||||
const [asked, setAsked] = useState({ key: null, note: null })
|
||||
const text = value === undefined || value === null ? '' : String(value)
|
||||
const known = noteFor(entry, value)
|
||||
const needAsk = Boolean(sourceId && entry?.state === 'ok' && entry.searchable && text && !known &&
|
||||
!entry.options.some((o) => o.value === text))
|
||||
const key = needAsk ? `${sourceId}\u0000${text}` : null
|
||||
|
||||
useEffect(() => {
|
||||
if (!key || asked.key === key) return undefined
|
||||
let alive = true
|
||||
const timer = setTimeout(async () => {
|
||||
try {
|
||||
const answer = await api.admin.eventOptions(sourceId, text)
|
||||
const row = answer?.ok ? (answer.options || []).find((o) => o.value === text) : null
|
||||
if (alive) setAsked({ key, note: row?.note || null })
|
||||
} catch {
|
||||
if (alive) setAsked({ key, note: null })
|
||||
}
|
||||
}, 300)
|
||||
return () => {
|
||||
alive = false
|
||||
clearTimeout(timer)
|
||||
}
|
||||
}, [key, asked.key, sourceId, text])
|
||||
|
||||
if (known) return known
|
||||
return key && asked.key === key ? asked.note : null
|
||||
}
|
||||
|
||||
/**
|
||||
* A row of buttons for a choice of two or three (Rust PLAN_REDESIGNS §2.4).
|
||||
*
|
||||
@@ -366,7 +406,7 @@ function ParamField({ param, value, sourceEntry, disabled, onChange, missing, la
|
||||
// editable rather than look unset.
|
||||
const segmented = param.source && param.type !== 'boolean' && !values && isSegmentable(sourceEntry)
|
||||
const offList = segmented && asText !== '' && !sourceEntry.options.some((o) => o.value === asText)
|
||||
const note = param.source ? noteFor(sourceEntry, value) : null
|
||||
const note = useChosenNote(param.source, value, sourceEntry)
|
||||
|
||||
return (
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
|
||||
Reference in New Issue
Block a user