Skip to content

Attribute filter option columns per filter, not globally by name (duplicate-provider errors once sources are copied) #450

Description

@BorisTyshkevich

Found while manually testing #427. #428 will hit this, so it needs deciding before copy-on-drag ships.

The shape

mergeDashboardFilterHelpers (src/core/dashboard-filters.ts) attributes helper columns to parameters globally by name: it collects every provider's helpers, groups by column name, and reports filter-duplicate-provider when one name has more than one provider. That was correct when a source was shared — #359 made N filters on one source resolve to ONE provider, so each name had exactly one.

#427 changed the topology. A filter source is now cloned per Dashboard, and #428 will clone one per drop. As soon as a workspace holds two copies of one option source in the same Dashboard, every column they both emit has two providers.

#427 added a partial mitigation: content-identical providers collapse to one instead of erroring (helperKey). That covers a stable option list, but not a volatile one. Reproduced live against examples/clickhouse-operations.json after an intermediate build wrote one copy per filter:

Multiple Filter queries provide "query_hash": Grafana port filters.

Six copies of gco-filter each ran separately against system.query_log; five columns matched, but query_hash genuinely differed between executions, so it is not deduplicable. Every such column takes its filter out of service.

The robust fix

Attribute per filter, not globally. A curated filter declares its own parameter and owns its own sourceQueryId, so the option list for parameter P should come from the source of the filter that declares P — never from "whichever provider happened to emit a column named P". Under #427's ownership that mapping is unambiguous by construction.

Sketch: pass the filter→source relation into the merge (the viewer session already has it — dashboard-viewer-session.ts builds FilterRuntime with both def.parameter and state.sourceId), and resolve fields[P] from that filter's own provider. filter-duplicate-provider then only fires for a genuinely unattributable column, and the helperKey dedup becomes belt-and-braces.

Deliberately NOT done in #427: it is a change to the #189/#359/#360 filter machinery, the most intricate code in the app, and #427 does not need it — a correctly migrated workspace has one source per Dashboard and therefore one provider per column.

Also worth deciding here

Should #428 reuse a Dashboard's existing copy when the user drops the same Library filter query onto a second filter of that Dashboard, rather than minting a second copy? That matches what #427's migration does and would avoid creating this state at all. The ownership invariant already allows it (ownersAreValid accepts several curated-filter owners within one Dashboard).

Metadata

Metadata

Assignees

No one assigned

    Labels

    inboxFiled mid-task; not yet triaged into the roadmap

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions