From a3550eabc3dcc449b675e2d742b761a417e3aa40 Mon Sep 17 00:00:00 2001 From: Paul Trowbridge Date: Thu, 17 Sep 2026 00:31:54 -0400 Subject: [PATCH] Fall back to the source when the member list misses Autofill stopped filling anything as soon as the member endpoint answered, because a hit was treated as the only possible answer: if the key was not in the list, it returned rather than trying the source. An empty list counted as an answer too, which is the state while a refresh is still running -- so wiring up master data broke the behaviour it was meant to improve, for everyone who had not finished building the list yet. A miss is not an answer. Empty list, or a key the list does not know, both fall through to the source lookup as before. It costs one request, on a path that only runs when someone types a value. Co-Authored-By: Claude Opus 5 (1M context) --- ui/src/views/Forecast.jsx | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/ui/src/views/Forecast.jsx b/ui/src/views/Forecast.jsx index 30815c1..6b726e1 100644 --- a/ui/src/views/Forecast.jsx +++ b/ui/src/views/Forecast.jsx @@ -1080,15 +1080,20 @@ export default function Forecast({ sources = [], sourceId, versions = [], versio const meta = colMetaRef.current.find(c => c.cname === col) const group = meta?.dim_group && dimMembers[meta.dim_group] - // With the member list in hand this is a local lookup. It also answers where - // the source query could not: the source holds every attribute set a part ever - // had, so anything with more than one came back ambiguous and filled nothing. - // A member row is a single definition by construction. - let derived = null - if (group) { - derived = group.members.find(m => m.key_value === value.trim())?.attrs || null - if (!derived) return - } else { + // With the member list in hand this is a local lookup, and it answers where the + // source query could not: the source holds every attribute set a part ever had, + // so anything with more than one came back ambiguous and filled nothing. A + // member row is a single definition by construction. + // + // A miss is not an answer though. The list can be empty (never refreshed, or a + // refresh still running) or simply not contain this key, and in either case the + // source still knows. Falling back costs one request on a path that only runs + // when someone types a value. + let derived = group?.members?.length + ? (group.members.find(m => m.key_value === value.trim())?.attrs || null) + : null + + if (!derived) { const res = await fetch(`/api/sources/${sourceId}/lookup?col=${encodeURIComponent(col)}&value=${encodeURIComponent(value)}`) if (!res.ok) return derived = await res.json()