Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:Risingwavelabs Risingwave Relation Graph Page

From Leeroopedia


Property Value
Component StreamingGraph
File dashboard/pages/relation_graph.tsx
Language TypeScript/TSX
Lines 224
Type Next.js Page Component
Framework React, Chakra UI, nuqs (URL query state)

Overview

relation_graph.tsx is a dashboard page that visualizes the dependency graph between all relations (tables, materialized views, sources, sinks, subscriptions) in the RisingWave catalog, with back-pressure statistics overlaid on edges. It fetches all relations and their dependency maps, builds a DAG of relation edges, periodically polls streaming stats (every 5 seconds) to compute relation-level back-pressure by mapping fragment-level channel stats to relation-level edges. The page supports time-travel controls for viewing historical stats and URL-based relation selection via nuqs. This provides a high-level system topology view showing how data flows between relations and where bottlenecks exist.

Code Reference

Source Location

dashboard/pages/relation_graph.tsx

Signature

// Internal helper function
function buildDependencyAsEdges(
  list: Relation[],
  relation_deps: Map<number, number[]>
): RelationPoint[]

// Main page component
export default function StreamingGraph(): JSX.Element

Import

// This is a Next.js page component, routed automatically
// Key imports:
import RelationGraph, { boxHeight, boxWidth } from "../components/RelationGraph"
import TimeControls from "../components/TimeControls"
import useFetch from "../lib/api/fetch"
import {
  Relation,
  getFragmentToRelationMap,
  getRelationDependencies,
  getRelations,
  relationIsStreamingJob,
} from "../lib/api/streaming"
import {
  TimeParams,
  createStreamingStatsRefresh,
} from "../lib/api/streamingStats"

I/O Contract

Internal State

State Variable Type Description
relationList Relation[] All relations fetched via useFetch(getRelations)
relationDeps Map<number, number[]> Relation dependency map via useFetch(getRelationDependencies)
selectedId null Currently selected relation ID, synced with URL query param ?id=
fragmentToRelationMap FragmentToRelationMap Mapping from fragment IDs to relation IDs
channelStats Map<string, ChannelDeltaStats> Fragment-level channel statistics
relationStats { [key: number]: RelationStats } Relation-level aggregated statistics
timeParams TimeParams Time-travel parameters (timestamp and offset)

buildDependencyAsEdges Function

Parameter Type Description
list Relation[] All relations to include in the graph
relation_deps Map<number, number[]> Dependency map (relation ID -> list of dependency IDs)
Returns RelationPoint[] Array of graph nodes with id, name, parentIds, order, width, height, and relation properties

Only relations that pass relationIsStreamingJob have their dependency edges included. Relations are sorted in reverse order by ID.

Fragment-to-Relation Stats Mapping

The page converts fragment-level channel stats to relation-level stats using useMemo:

const relationChannelStats = useMemo(() => {
  if (!fragmentToRelationMap) return new Map()
  let mapping = fragmentToRelationMap.fragmentToRelationMap

  if (channelStats) {
    let map = new Map<string, ChannelDeltaStats>()
    for (const [key, stats] of channelStats) {
      const [outputFragment, inputFragment] = key.split("_").map(Number)
      let input_relation = mapping[inputFragment]
      let output_relation = mapping[outputFragment]
      if (input_relation && output_relation && input_relation !== output_relation) {
        let key = `${output_relation}_${input_relation}`
        map.set(key, stats)
      }
    }
    return map
  }
}, [channelStats, fragmentToRelationMap])

Data Fetching Strategy

Data Method Frequency
Relations useFetch(getRelations) Once on mount
Relation dependencies useFetch(getRelationDependencies) Once on mount
Fragment-to-relation map useFetch(getFragmentToRelationMap) Once on mount
Streaming stats createStreamingStatsRefresh Every 5 seconds (INTERVAL_MS)

Constants

Constant Value Description
SIDEBAR_WIDTH "200px" Width of the left sidebar
INTERVAL_MS 5000 Polling interval for streaming stats (5 seconds)

Usage Examples

Page Layout Structure

// The page renders a two-panel layout:
// Left sidebar:
//   - TimeControls component for historical time queries
//   - Scrollable list of relation buttons for selection
// Main area:
//   - RelationGraph component with dependency edges and stats overlay

<Flex>
  <Flex width={SIDEBAR_WIDTH}>
    <TimeControls onApply={handleTimeParamsChange} />
    {relationList?.map((r) => (
      <Button
        key={r.id}
        colorScheme={selectedId === r.id ? "blue" : "gray"}
        onClick={() => setSelectedId(r.id)}
      >
        {r.name}
      </Button>
    ))}
  </Flex>
  <Box flex={1}>
    <RelationGraph
      nodes={relationDependency}
      selectedId={selectedId?.toString()}
      setSelectedId={(id) => setSelectedId(parseInt(id))}
      channelStats={relationChannelStats}
      relationStats={relationStats}
    />
  </Box>
</Flex>

Time Controls Integration

const handleTimeParamsChange = (timestamp?: number, offset?: number) => {
  setTimeParams({
    at: timestamp,
    timeOffset: offset,
  })
}

// timeParams change triggers the useEffect to recreate the refresh function
// with updated time parameters, enabling historical stats queries

URL Query State

import { parseAsInteger, useQueryState } from "nuqs"

// Selected relation ID is persisted in the URL as ?id=123
const [selectedId, setSelectedId] = useQueryState("id", parseAsInteger)

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment