Skip to content

feat: standalone parameterized custom viz components#9685

Draft
nishantmonu51 wants to merge 4 commits into
mainfrom
nishant/custom-viz
Draft

feat: standalone parameterized custom viz components#9685
nishantmonu51 wants to merge 4 commits into
mainfrom
nishant/custom-viz

Conversation

@nishantmonu51

Copy link
Copy Markdown
Collaborator
  • Adds a standalone type: component authoring surface ("custom viz"): components declare typed params (metrics_view, measure, dimension, time_dimension, scalars) and canvases reference them via component: + params: bindings, validated end to end and covered by transitive-access security.
  • New component workspace with live preview, test bindings, used-by panel, and breaking-change warnings; Save as custom viz extraction from inline charts and Detach copy inverse.
  • Vega-Lite examples gallery (vendored offline snapshot with pre-rendered SVG thumbnails) with AI-first import: the example spec is embedded in the dev-agent prompt and a self-healing loop feeds parse/reconcile/static-structure errors back until the component reconciles cleanly.
  • Generated components include customizable order_by and limit params with density-based defaults; the editor offers bound fields as order_by choices and keeps the binding in step when fields are re-bound.
  • Dev-agent instructions for authoring components (restricted metrics_sql dialect, encoding/param type matching, preserving row-local calculate transforms for diverging charts).
  • Gated behind the customComponents frontend flag and custom_components runtime flag.

Checklist:

  • Covered by tests
  • Ran it and it works as intended
  • Reviewed the diff before requesting a review
  • Checked for unhandled edge cases
  • Linked the issues it closes
  • Checked if the docs need to be updated. If so, create a separate Linear DOCS issue
  • Intend to cherry-pick into the release branch
  • I'm proud of this work!

Extract inline canvas custom charts into reusable component resources:

- Components declare typed params (metrics_view, measure, dimension,
  time_dimension, scalars) validated at parse and reconcile time
- Canvas items reference components via 'component:' + 'params:' bindings;
  param-bound metrics views flow through transitive access security
- ResolveComponent merges defaults, validates bindings, resolves templates,
  and injects scalar params as native Vega-Lite params
- Component workspace with live preview, test bindings, used-by panel, and
  breaking-change warnings
- 'Save as custom viz' extraction from inline charts and 'Detach copy' inverse
- Vega-Lite examples gallery (vendored snapshot with static SVG thumbnails)
  with AI-first import: spec-in-prompt generation, placeholder file, and a
  self-healing validation loop with static structure/consistency checks
- Generated components include customizable order_by and limit params with
  density-based defaults; order_by follows re-bound fields in the editor
- Dev-agent instructions for authoring components (metrics_sql dialect rules,
  encoding/param type matching, row-local calculate preservation for
  diverging charts)

Gated behind the customComponents frontend flag and custom_components
runtime flag.
@nishantmonu51
nishantmonu51 requested a review from djbarnwal July 14, 2026 20:57
- Format touched files with prettier
- Fix svelte-check errors: Extract string keys in AllKeys so ComponentRefSpec's
  index signature doesn't widen keys to string | number; narrow the index
  signature values to scalars (matching the parser's scalar-only bindings);
  type initializeRow over AddableItem; pass the required editor binding in
  ComponentWorkspace; remove unused imports and cast union field accesses
- Add customComponents to the expected maps in Test_ResolveFeatureFlags
- Add the component_extract_title message key (en/es)
- Bind the required viewVL prop on the preview's inline VegaLiteRenderer
- Cast metrics_view access in FiltersMapper to string | null
- ResolveCanvas: skip templated metrics_view renderer properties instead of
  looking them up as literal resource names (param-bound metrics views are
  collected from the canvas items)
- Frontend: give canvas items referencing an external component their
  positional instance id as component.id, so two references to the same
  component get distinct DOM ids and consistent selection/cleanup; make the
  drag-move reselect path instance-aware and use getElementById for ids
  containing '::'
- Transitive access: scan metrics_sql lists (multi-query custom charts) for
  metrics view refs, not just single query strings
- Parser: components declaring a metrics_view param with a default now get a
  ref to the default metrics view for DAG ordering and invalidation
@nishantmonu51 nishantmonu51 added Type:Feature New feature request Area:Dashboard Custom Dashboards Size:XL Very large change: 2,000+ lines labels Jul 15, 2026
@nishantmonu51

Copy link
Copy Markdown
Collaborator Author

@codex: review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 573137c8c0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +27 to +35
if allowTemplated && hasTemplatedString(props) {
if renderer == "custom_chart" {
return validateCustomChart(props)
}
// Skip field-membership validation, but still reject unknown renderers.
if !knownRenderers[renderer] {
return fmt.Errorf("unsupported renderer %q", renderer)
}
return nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not skip validation for templated renderers

When a parameterized non-custom_chart renderer has any template in its properties, this branch returns before the renderer-specific checks run. For example, a kpi component with metrics_view: "{{ .params.metrics_view }}" but no required measure now reconciles as valid, and ResolveComponent only resolves templates rather than re-running ValidateRendererProperties, so canvases can serve broken renderer props instead of surfacing the validation error.

Useful? React with 👍 / 👎.

Comment on lines +122 to +128
case "time_dimension":
// A dimension picker restricted to the metrics view's time dimension.
return {
type: "dimension",
...common,
meta: { includeTime: true, searchableItems: [] },
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict time-dimension params to time fields

For time_dimension params this returns a generic dimension selector with searchableItems: [], but useMetricFieldData only applies searchableItems when the user has typed a search term; with an empty search the dropdown still lists every dimension, while includeTime only adds the primary time dimension. This lets users bind non-time dimensions that later fail reconcile and prevents searching for secondary time-typed dimensions that the backend accepts.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area:Dashboard Custom Dashboards Size:XL Very large change: 2,000+ lines Type:Feature New feature request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant