Drop the measure name from a collapsed column's slice
Clicking a bucket subtotal with the month level collapsed produced
{"customer": "...", "pf_bucket": "04 - Forecast", "smon_e": "sales_usd"} --
a month equal to a measure, matching nothing, so the ledger came back empty
and an operation would have had no rows to act on.
Perspective maps split_by positionally over the column name, and a collapsed
axis has fewer segments than there are split_by levels, so the measure lands
on the first hidden dimension. Both slice paths now drop any == filter whose
value is one of the view's measures; the region path additionally takes the
measure off the end of the column name before mapping, which is the same
error made in our own code.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
50a0bb42aa
commit
f94aa4ec99
@ -323,13 +323,23 @@ export default function Forecast({ sources = [], sourceId, versions = [], versio
|
||||
for (let c = c0; c < c1; c++) {
|
||||
const key = userKeys[c]
|
||||
if (!key) continue
|
||||
// A column name is dimension values joined by | with the measure last, and
|
||||
// only as many values as the axis currently shows -- collapse the column
|
||||
// hierarchy and the deeper levels are simply absent. Mapping split_by
|
||||
// positionally over every segment therefore read the measure as a value
|
||||
// for the first collapsed dimension: a bucket subtotal came back as
|
||||
// smon_e = 'sales_usd', which matches no row, so the operation silently
|
||||
// had nothing to act on. Drop the measure, then map over what is left.
|
||||
const segs = key.split('|').slice(0, -1)
|
||||
const colFilters = splitBy
|
||||
.slice(0, segs.length)
|
||||
.map((col, ix) => {
|
||||
const v = key.split('|')[ix]
|
||||
const v = segs[ix]
|
||||
return (v && !META_COL_RE.test(v)) ? [col, '==', v] : null
|
||||
})
|
||||
.filter(Boolean)
|
||||
const slice = sliceFromFilters([...base, ...rowFilters, ...colFilters])
|
||||
const slice = sliceFromFilters([...base, ...rowFilters, ...colFilters],
|
||||
(cfg.columns || []).filter(Boolean))
|
||||
if (!Object.keys(slice).length) continue
|
||||
const y = win.start_row + i
|
||||
out.push({ slice, area: { x0: c, x1: c, y0: y, y1: y } })
|
||||
@ -770,7 +780,8 @@ export default function Forecast({ sources = [], sourceId, versions = [], versio
|
||||
if (!detail.row) return
|
||||
const config = await viewer.save()
|
||||
if (!(config.group_by || []).length) return
|
||||
const s = sliceFromFilters((detail.config || {}).filter || [])
|
||||
const s = sliceFromFilters((detail.config || {}).filter || [],
|
||||
(config.columns || []).filter(Boolean))
|
||||
if (!Object.keys(s).length) return
|
||||
// the CustomEvent carries no modifier flags, so read them off the
|
||||
// mousedown that produced it (captured on window below)
|
||||
@ -1948,12 +1959,22 @@ function LogCell({ entry, field, placeholder, editing, setEditing, onSave, listI
|
||||
const META_COL_RE = /^__(?:ROW_PATH(?:_\d+)?|ID|GROUPING_ID)__$/
|
||||
|
||||
// Perspective encodes a clicked/selected row position as [col, '==', value] triples
|
||||
function sliceFromFilters(filters) {
|
||||
// `measures` is the view's `columns` list. Clicking a cell whose column axis is
|
||||
// collapsed makes Perspective emit the measure name as the value of the first
|
||||
// hidden split_by dimension -- a bucket subtotal arrives as
|
||||
// ["smon_e", "==", "sales_usd"] -- because the engine maps split_by positionally
|
||||
// over a column name that no longer has that many segments. Left in, the slice
|
||||
// asks for a month equal to a measure, matches nothing, and the operation
|
||||
// silently has no rows to act on.
|
||||
function sliceFromFilters(filters, measures = []) {
|
||||
const measureSet = new Set(measures)
|
||||
const s = {}
|
||||
for (const f of filters) {
|
||||
if (!Array.isArray(f)) continue
|
||||
const [col, op, val] = f
|
||||
if (op === '==' && val != null) s[col] = String(val)
|
||||
if (op !== '==' || val == null) continue
|
||||
if (measureSet.has(String(val))) continue
|
||||
s[col] = String(val)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user