Implementation:TobikoData Sqlmesh Story ModelNode
| Knowledge Sources | |
|---|---|
| Domains | Data_Lineage, Web_UI, Graph_Visualization, Model_Management |
| Last Updated | 2026-02-07 20:00 GMT |
Overview
React component for rendering individual model nodes in lineage graphs.
Description
ModelNode is a React component that visualizes a single SQLMesh model as a node in a lineage graph. It displays comprehensive model metadata including name, type, kind, cron schedule, owner, and columns, with support for adaptive rendering based on zoom level and interaction state.
The component implements sophisticated UX features:
- Dynamic height calculation based on visible columns and zoom level
- Column-level visualization with collapsible/expandable columns list
- Hover state handling with opacity transitions for visual clarity
- Cron schedule tooltips using the cronstrue library for human-readable schedules
- Selection state management with visual indicators (current, selected, active)
Columns are rendered with virtual scrolling (via NodePorts component) when the count exceeds MAX_COLUMNS_TO_DISPLAY, ensuring performance with models containing hundreds of columns.
Usage
This component is registered as a ReactFlow node type and rendered automatically by the ModelLineage component. It should not be used directly outside the lineage context.
Code Reference
Source Location
- Repository: TobikoData_Sqlmesh
- File: web/common/src/components/Lineage/stories/ModelNode.tsx
Signature
export const ModelNode = React.memo(function ModelNode({
id,
data,
...props
}: NodeProps<NodeData>)
Import
import { ModelNode } from '@sqlmesh-common/components/Lineage/stories/ModelNode'
// Registered as ReactFlow node type
const nodeTypes = {
node: ModelNode,
}
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| id | ModelNodeId | Yes | Unique node identifier (branded string) |
| data | NodeData | Yes | Node data (name, type, kind, columns, metadata) |
| ...props | NodeProps | Yes | Additional ReactFlow node properties (position, etc.) |
Outputs
| Name | Type | Description |
|---|---|---|
| Node Element | JSX.Element | Rendered node with handles, header, columns, and badges |
| State Updates | void | Updates selected node ID via context on click |
Implementation Details
Node Structure
Header Section
- Model Name: Displays model's display name with copy-to-clipboard functionality
- Schema Visibility: Hides schema when zoom <= ZOOM_THRESHOLD for cleaner view
- Connection Handles: Left (incoming) and right (outgoing) handles for edges
- Click Handler: Toggles node selection on click
Top Appendix
- Current Badge: Highlights if this is the currently selected model (isCurrent)
- Kind Badge: Shows model kind (INCREMENTAL_BY_TIME_RANGE, FULL, SCD_TYPE_2, etc.)
- Cron Badge: Displays cron schedule with human-readable tooltip (uses cronstrue)
Column Section
- Selected Columns: Always visible when any column is selected (modelSelectedColumns)
- All Columns: Shown when showColumns is true, node is selected, or user hovers
- Virtual Scrolling: Uses NodePorts component with Fuse.js filtering for large lists
- Filter: Appears when columns > MAX_COLUMNS_TO_DISPLAY
Bottom Appendix
- Type Badge: Shows model type (sql, seed, python, external) with color coding
Adaptive Rendering
Zoom-Based Behavior
- High Zoom (> ZOOM_THRESHOLD): Shows all details (badges, columns, metadata)
- Low Zoom (<= ZOOM_THRESHOLD): Simplified view (larger text, minimal details)
- Node Height: Doubles at low zoom for visibility (nodeBaseHeight * 2)
Visibility Conditions
- Show Columns When:
* showColumns is true (global toggle) * isSelected is true (node is selected) * hasSelectedColumns is true (any column selected) * hasFetchingColumns is true (column lineage loading) * isHovered is true (user hovering)
Opacity States
- Full Opacity (100%): isActive, isSelected, or hasSelectedColumns
- Reduced Opacity (10%): Default state (becomes 100% on hover via group-hover)
Dynamic Height Calculation
nodeHeight =
(zoom > ZOOM_THRESHOLD ? nodeBaseHeight : nodeBaseHeight * 2) +
nodeDetailsHeight +
selectedColumnsHeight +
columnsHeight
// Where:
// - nodeBaseHeight: Fixed height for header/footer (excludes footer in calculation)
// - nodeDetailsHeight: 0 if zoom <= ZOOM_THRESHOLD
// - selectedColumnsHeight: 6px per selected column
// - columnsHeight: Based on visible column count + filter (if applicable)
Node Metadata Hook
Uses `useNodeMetadata` to compute derived state:
- leftId/rightId: Handle IDs for ReactFlow edges
- isCurrent: True if this node is the originally selected model
- isSelected: True if this node is the selected node
- isActive: True if this node is in the path of the selected node
Color Coding
Node colors are determined by model type:
- SQL Models: Specific color (via getNodeTypeColor)
- Seed Models: Specific color
- Python Models: Specific color
- External Models: Specific color
Border and text colors match via getNodeTypeBorderColor and getNodeTypeTextColor.
Performance Optimizations
- React.memo: Prevents unnecessary re-renders when props unchanged
- Virtual Scrolling: NodePorts uses react-window for large column lists
- Fuse.js Filtering: Fuzzy search with threshold 0.3 for column filtering
- Conditional Rendering: Only renders column section when shouldShowColumns is true
Usage Examples
// Registered as ReactFlow node type
const nodeTypes = {
node: ModelNode,
}
// Used within ModelLineage
<ReactFlow
nodes={nodes}
edges={edges}
nodeTypes={nodeTypes}
/>
// Node data structure
const nodeData: NodeData = {
name: 'my_model' as ModelName,
displayName: 'schema.my_model' as ModelDisplayName,
identifier: 'catalog.schema.my_model',
model_type: 'sql' as NodeType,
kind: 'incremental_by_time_range',
cron: '0 0 * * *', // Daily at midnight UTC
owner: 'data_team',
dialect: 'snowflake',
version: 'abc123def',
tags: ['production', 'critical'],
columns: {
id: { name: 'id', data_type: 'INT' },
created_at: { name: 'created_at', data_type: 'TIMESTAMP' },
// ... more columns
},
}
Related Pages
- Environment:TobikoData_Sqlmesh_Web_UI_Stack
- Implementation:TobikoData_Sqlmesh_ModelLineage
- Implementation:TobikoData_Sqlmesh_ColumnLevelLineageContext
- Implementation:TobikoData_Sqlmesh_ModelNode
- Implementation:TobikoData_Sqlmesh_NodePorts
- Tool:ReactFlow_Library
- Tool:Cronstrue_Library
- Tool:Fuse_JS
- Concept:Virtual_Scrolling
- Concept:Column_Level_Lineage