Skip to content

feat: SW-1162 Add self-describing visualization metadata#75

Open
darwinboersma wants to merge 6 commits into
mainfrom
dboersma/glassbox-viz-metadata
Open

feat: SW-1162 Add self-describing visualization metadata#75
darwinboersma wants to merge 6 commits into
mainfrom
dboersma/glassbox-viz-metadata

Conversation

@darwinboersma
Copy link
Copy Markdown
Contributor

@darwinboersma darwinboersma commented Apr 29, 2026

Summary

Introduces a metadata contract so visualization components can carry their own discoverability information, removing the need for a separate registry on the consumer side.

  • New src/lib/visualization.ts exports VisualizationParameter, VisualizationMeta, VisualizationComponent, plus a withVisualization(Component, meta) helper and an isVisualizationComponent type guard.
  • PlateMap is wrapped with the helper, declaring id: "plate-map", inputKind: "plate_map", and the user-tunable subset of its props.
  • Generic toolkit visualizations are now exported with metadata:
    • PlotlyVisualization -> id: "plotly", inputKind: "plot"
    • TableVisualization -> id: "table", inputKind: "table"
    • ScalarVisualization -> id: "scalar", inputKind: "number"
  • Types re-exported from the package root.

Why

The TetraScience GlassBox sandbox maintains a consumer-side visualization registry. Letting toolkit components self-describe means consumers can scan kit exports at runtime and dispatch by inputKind with minimal per-component glue. The kit owns IDs, versioning, metadata, and tested defaults; the consumer owns routing.

How consumers use it

import * as kit from "@tetrascience-npm/tetrascience-react-ui";

const VIZ_BY_KIND = Object.values(kit)
  .filter(kit.isVisualizationComponent)
  .reduce((acc, component) => ({ ...acc, [component.visualization.inputKind]: component }), {});

// Render: <VIZ_BY_KIND[output.type] {...payload} {...userOverrides} />

Test plan

  • yarn typecheck
  • yarn lint
  • yarn test src/components/visualizations/__tests__/visualization.test.ts src/components/charts/PlateMap/__tests__/visualization.test.ts
  • yarn build

Notes

  • yarn format:check still reports broad pre-existing formatting drift in this repo; only the files touched here were formatted.
  • Plotly is mocked in visualization unit tests because importing Plotly-backed components can touch browser APIs at module load in jsdom.

Adds a visualization metadata contract and helper so chart components
can be self-describing. Consumers (e.g. the GlassBox sandbox) can scan
kit exports for components carrying a .visualization static property
and dispatch calculation outputs to compatible visualizations without
maintaining a separate registry.

- src/lib/visualization.ts — VisualizationParameter, VisualizationMeta,
  VisualizationComponent types, plus withVisualization() helper and an
  isVisualizationComponent type guard
- Re-exported from src/index.ts so consumers can import the types
- PlateMap is wrapped with withVisualization, declaring inputKind
  "plate_map" and the user-tunable subset of its props (colorScale,
  precision, showColorBar, showLegend, markerShape, visualizationMode)

Tests cover the helper's metadata attachment, the type guard, and the
attached PlateMap metadata. Plotly is mocked in the PlateMap unit test
because importing the component triggers Plotly's module-load access
to window.URL.createObjectURL, which is unavailable in jsdom.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 29, 2026 19:04
@darwinboersma darwinboersma requested a review from a team as a code owner April 29, 2026 19:04
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ts-lib-ui-kit-storybook Ready Ready Preview, Comment Apr 30, 2026 2:39pm

Request Review

Copy link
Copy Markdown

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

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: 67adb8700d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

name: "colorScale",
type: "select",
description: "Color scale used to render well values in heatmap mode.",
default: "Viridis",
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 Keep metadata default in sync with PlateMap colorScale default

Set the colorScale metadata default to match the component’s real default; right now the metadata says "Viridis", but PlateMap itself defaults colorScale to DEFAULT_COLOR_SCALE (a custom array). Any consumer that applies defaults from .visualization.tunableProps will render a different palette than direct PlateMap usage, which breaks the stated self-describing/defaults contract and can cause inconsistent charts across integration paths.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a first-class “self-describing visualization” contract so chart components can expose discoverability metadata (.visualization) directly on the component export, removing the need for a separate consumer-side registry.

Changes:

  • Added src/lib/visualization.ts with VisualizationMeta / VisualizationComponent types, a withVisualization helper, and an isVisualizationComponent type guard.
  • Wrapped PlateMap with withVisualization(...) and defined its inputKind and tunable prop metadata.
  • Re-exported visualization utilities from the package root and added unit tests for both the helper and PlateMap metadata.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/lib/visualization.ts Introduces the visualization metadata contract + helper/guard APIs.
src/lib/visualization.test.ts Adds unit tests for withVisualization and isVisualizationComponent.
src/index.ts Re-exports visualization APIs from the package root.
src/components/charts/PlateMap/PlateMap.tsx Attaches .visualization metadata to the exported PlateMap component.
src/components/charts/PlateMap/tests/visualization.test.ts Verifies PlateMap exposes expected visualization metadata.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/lib/visualization.ts
Comment on lines +76 to +79
return (
typeof value === "function" &&
"visualization" in value &&
typeof (value as { visualization?: unknown }).visualization === "object"
name: "colorScale",
type: "select",
description: "Color scale used to render well values in heatmap mode.",
default: "Viridis",
});

it("rejects non-component values", () => {
expect(isVisualizationComponent()).toBe(false);
@darwinboersma darwinboersma changed the title feat(visualization): self-describing chart components via .visualization metadata SW-1162: Add self-describing visualization metadata Apr 29, 2026
@darwinboersma darwinboersma changed the title SW-1162: Add self-describing visualization metadata feat: SW-1162 Add self-describing visualization metadata Apr 29, 2026
@github-actions
Copy link
Copy Markdown

Coverage Report

Status Category Percentage Covered / Total
🟢 Lines 88.2% (🎯 83%)
⬇️ -1.42%
14532 / 16475
🟢 Statements 88.2% (🎯 83%)
⬇️ -1.42%
14532 / 16475
🟢 Functions 87.44% (🎯 74%)
⬇️ -1.10%
627 / 717
🟢 Branches 84% (🎯 81%)
⬇️ -0.36%
2032 / 2419
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
src/components/ai/attachments.tsx 89.13% 76.47% 93.75% 89.13% 69-70, 78-79, 142-143, 257-258, 297-298, 330-332, 352-355, 415-427
src/components/ai/chain-of-thought.tsx 99.23% 88.88% 100% 99.23% 127
src/components/ai/code-block.tsx 96.94% 78.94% 100% 96.94% 246-247, 303-304, 406-408, 477-479, 484-485
src/components/ai/confirmation.tsx 95.68% 87.5% 100% 95.68% 27-28, 50-51, 133
src/components/ai/context.tsx 97.63% 73.21% 100% 97.63% 60-61, 271, 277, 304, 344, 384, 424
src/components/ai/conversation.tsx 88.88% 93.33% 100% 88.88% 81, 86-98
src/components/ai/inline-citation.tsx 99.03% 96.29% 100% 99.03% 165-166
src/components/ai/message.tsx 91.25% 86.2% 100% 91.25% 101-111, 133-136, 157-159, 164-166, 170-172
src/components/ai/model-selector.tsx 100% 100% 100% 100%
src/components/ai/prompt-input.tsx 46.47% 64.19% 42.85% 46.47% 84-100, 103-177, 216-223, 230-237, 251-368, 382-385, 404-411, 427-429, 447-484, 554, 559-576, 582-627, 633-639, 646-683, 689-698, 710, 714-715, 723, 730-731, 738-742, 744-751, 766-767, 770-771, 779, 786-789, 797-802, 821-826, 829-830, 838-893, 966-967, 970-988, 993-994, 996-1001, 1008-1029, 1037-1043, 1154, 1178, 1211-1214, 1240, 1244-1245, 1249-1255, 1330-1334, 1342-1343, 1350-1353, 1403-1405, 1410-1412, 1417-1429, 1435-1438, 1444-1453, 1459-1461, 1466-1469, 1475-1478, 1484-1487, 1493-1496, 1502-1505, 1513-1516
src/components/ai/queue.tsx 100% 100% 100% 100%
src/components/ai/reasoning.tsx 89.69% 75.86% 100% 89.69% 42-43, 95-97, 103-104, 112-113, 115-121, 126-127
src/components/ai/shimmer.tsx 100% 85.71% 100% 100%
src/components/ai/sources.tsx 100% 100% 100% 100%
src/components/ai/speech-input.tsx 46.22% 34.78% 33.33% 46.22% 77-78, 85-89, 119-120, 131-132, 135-136, 139-156, 159-160, 185-186, 188-191, 198-256, 261-264, 268-280, 294-303, 311
src/components/ai/stream-status.tsx 95.2% 75.75% 100% 95.2% 134, 151-154, 216
src/components/ai/suggestion.tsx 100% 100% 100% 100%
src/components/ai/task.tsx 100% 100% 100% 100%
src/components/ai/tool.tsx 97.47% 62.5% 100% 97.47% 145-146, 167
src/components/ai-elements/snippet.tsx 95% 69.23% 100% 95% 108-110, 115-116
src/components/charts/AreaGraph/AreaGraph.tsx 100%
🟰 ±0%
81.25%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/components/charts/BarGraph/BarGraph.tsx 99.57%
⬆️ +0.08%
83.33%
🟰 ±0%
100%
🟰 ±0%
99.57%
⬆️ +0.08%
102
src/components/charts/Boxplot/Boxplot.tsx 100%
🟰 ±0%
83.33%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/components/charts/Chromatogram/Chromatogram.tsx 99.13%
⬆️ +0.03%
92.85%
🟰 ±0%
100%
🟰 ±0%
99.13%
⬆️ +0.03%
184-185
src/components/charts/ChromatogramChart/ChromatogramChart.tsx 97.86%
⬆️ +0.40%
76.66%
🟰 ±0%
100%
🟰 ±0%
97.86%
⬆️ +0.40%
130-134, 182
src/components/charts/DotPlot/DotPlot.tsx 100%
🟰 ±0%
76.19%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/components/charts/Heatmap/Heatmap.tsx 100%
🟰 ±0%
85.71%
⬆️ +1.10%
100%
🟰 ±0%
100%
🟰 ±0%
src/components/charts/Histogram/Histogram.tsx 100%
⬆️ +0.37%
90.24%
🟰 ±0%
100%
🟰 ±0%
100%
⬆️ +0.37%
src/components/charts/InteractiveScatter/InteractiveScatter.tsx 100%
⬆️ +23.68%
95.69%
⬆️ +27.84%
100%
🟰 ±0%
100%
⬆️ +23.68%
src/components/charts/LineGraph/LineGraph.tsx 97.13%
⬆️ +0.44%
82.75%
🟰 ±0%
100%
🟰 ±0%
97.13%
⬆️ +0.44%
298-304
src/components/charts/PieChart/PieChart.tsx 100%
🟰 ±0%
76.47%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/components/charts/PlateMap/PlateMap.tsx 98.2%
⬆️ +0.08%
89.47%
🟰 ±0%
100%
🟰 ±0%
98.2%
⬆️ +0.08%
215-216, 287-288, 293-294, 304-305, 321-323
src/components/charts/ScatterGraph/ScatterGraph.tsx 100%
🟰 ±0%
82.6%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/components/composed/Chat/Chat.tsx 85.99% 89.65% 28.57% 85.99% 105-107, 133-155, 164, 168-172, 250-256
src/components/ui/badge.tsx 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/components/ui/progress.tsx 100% 100% 100% 100%
src/components/ui/data-table/data-table.tsx 100%
🟰 ±0%
90.59%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/lib/visualization.ts 100% 100% 100% 100%
Generated in workflow #496 for commit 2c8941f by the Vitest Coverage Report Action

Copy link
Copy Markdown
Contributor

@54321jenn-ts 54321jenn-ts left a comment

Choose a reason for hiding this comment

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

I don't think this needs a UX review, but just in case LGTM

Copy link
Copy Markdown
Collaborator

@blee-tetrascience blee-tetrascience left a comment

Choose a reason for hiding this comment

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

Requesting changes because CI is failing and the diff includes large unrelated AI component work. CI is failing because overall coverage dropped and several new AI files miss the coverage gate.

Comment thread src/index.ts
export * from "@/components/ui/code-editor";
export * from "@/components/ui/tetrascience-icon";

// AI
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

These exports add a broad AI component surface to a PR whose stated scope is visualization metadata. That also brings many new runtime dependencies. Please split the AI components into their own Jira scoped PR or remove them here.

@blee-tetrascience
Copy link
Copy Markdown
Collaborator

Actually this PR isn't needed anymore, right @darwinboersma ? This was just for our onsite prototyping

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants