From 0fdb08291d62c196243388e2b1886a80b63aed1d Mon Sep 17 00:00:00 2001 From: Paul Trowbridge Date: Thu, 17 Sep 2026 15:38:03 -0400 Subject: [PATCH] Carry the pivot's expressions into the bridge's own view MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bridge builds its own view from the pivot's filters, and those filters can name pf_bucket_ord or pf_segment_ord — columns that exist only as expressions. A view created without them cannot resolve the column, so the bridge failed outright as soon as anyone filtered on an ordering column. The per-slice path is left alone: its filters are built from col_meta names, so they only ever reference real columns. Said so in place, since the asymmetry otherwise reads as an oversight. Co-Authored-By: Claude Opus 5 (1M context) --- ui/src/components/BridgeView.jsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ui/src/components/BridgeView.jsx b/ui/src/components/BridgeView.jsx index ae6f1b8..7802673 100644 --- a/ui/src/components/BridgeView.jsx +++ b/ui/src/components/BridgeView.jsx @@ -228,6 +228,8 @@ export default function BridgeView({ ...Object.entries(sl).filter(([c]) => dateNames.has(c)).map(([c, v]) => [c, '==', Number(v)]), ] if (!f.length) continue + // No expressions needed here: these filters are built from col_meta + // names, so they only ever reference real columns. const view = await tableRef.current.view({ filter: f }) const part = await view.to_json() await view.delete() @@ -239,11 +241,20 @@ export default function BridgeView({ } } else { let filter = [] + // Expression columns have to come with the filter that uses them. The + // pivot's filter can name pf_bucket_ord or pf_segment_ord, which exist + // only as expressions — a view built without them cannot resolve the + // column and fails outright. + let expressions = {} if (scope === 'filtered' && viewerRef?.current) { const cfg = await viewerRef.current.save() filter = (cfg.filter || []).filter(f => Array.isArray(f) && f.length >= 2) + expressions = cfg.expressions || {} } - const view = await tableRef.current.view(filter.length ? { filter } : {}) + const viewCfg = {} + if (filter.length) viewCfg.filter = filter + if (Object.keys(expressions).length) viewCfg.expressions = expressions + const view = await tableRef.current.view(viewCfg) rows = await view.to_json() await view.delete() }