Skip to content

feat: standalone parameterized custom viz components#9685

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

feat: standalone parameterized custom viz components#9685
nishantmonu51 wants to merge 6 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 thread runtime/canvas/component.go Outdated
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 👍 / 👎.

# Conflicts:
#	proto/gen/rill/runtime/v1/queries.pb.go
#	proto/gen/rill/runtime/v1/resources.pb.go
#	runtime/parser/parser_test.go
…ct time_dimension picker

- Renderer validators now run structural checks (required keys, types, enums)
  on parameterized components with templated properties; only field-membership
  checks against the metrics view are skipped for unresolvable values.
- The time_dimension param picker now only offers time fields (the primary
  time dimension and time-typed dimensions) and supports search, instead of
  listing every dimension and returning no results for any search term.
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