Connection Dashboard
Rendered bySystemDashboard.tsx. Accepts a connectionId prop. Fetches stats via the useDashboardStats hook, which calls the get_dashboard_stats RPC with p_connection_id.
Layout
The dashboard is organized top-to-bottom into four zones:- Summary cards — Custom objects count, relationships count, modules count
- Analysis section — Clean Core score (S/4) or Conversion Readiness score (ECC), findings table, action items, executive summary. Collapsible. Only appears when analysis data exists.
- Charts — Module breakdown, type distribution, delivery class, risk tiers
- Tables — Hub tables (top 10 by connections), object inventory
Chart components
| Component | File | Data source | Click behavior |
|---|---|---|---|
SummaryCards | SummaryCards.tsx | stats top-level counts | Clicks scroll to inventory with reset filters |
ModuleBreakdownChart | ModuleBreakdownChart.tsx | stats.module_breakdown | Module name opens side detail panel; count filters inventory by module; “+X more” switches to module view |
TypeDistributionChart | TypeDistributionChart.tsx | stats.type_distribution | Clicks filter inventory by type |
DeliveryClassChart | DeliveryClassChart.tsx | stats.delivery_class_distribution | Clicks filter inventory by delivery class |
RiskTiersChart | RiskTiersChart.tsx | stats.risk_tiers | Clicks filter inventory by risk level |
HubTablesTable | HubTablesTable.tsx | stats.hub_tables | Clicks open object detail panel |
ObjectInventoryTable | ObjectInventoryTable.tsx | useDashboardEntries hook | Paginated table with filters for search, type, module, delivery class, and risk |
Clickable numbers pattern
All charts route clicks to the inventory section at the bottom. TheSystemDashboard component lifts inventory filter state and exposes a scrollToInventory callback:
ObjectInventoryTable and smooth-scrolls to it. Each chart passes its own filter dimension:
- Type distribution → sets
typefilter (e.g.,'table') - Delivery class → sets
deliveryClassfilter (e.g.,'A') - Risk tiers → sets
riskfilter (e.g.,'High') - Module breakdown count → sets
modulefilter (e.g.,'FI') - Summary cards → resets all filters, switches to objects view
Module breakdown split click
TheModuleBreakdownChart has two distinct click targets per row:
- Module name (left) — calls
openObjectDetail('module:FI', connectionId)to open the side detail panel for that module - Object count (right) — calls
onModuleClick('FI')which filters inventory to that module
onTotalClick, which switches inventory to the modules view.
Inventory filters
ObjectInventoryTable supports these filter dimensions:
| Filter | Query param | UI element |
|---|---|---|
| Search text | q | Text input |
| Object type | type | Dropdown (table, program, class, bapi, tcode, etc.) |
| Module | module | Dropdown (populated from stats.module_breakdown) |
| Delivery class | delivery_class | Dropdown (A-Application, C-Customizing, L-Temporary, G-Protected, E-System, S-SAP Internal, W-Transfer) |
| Risk level | — | Dropdown (populated from stats.risk_tiers) |
external*Filter props so charts can set them. Each external prop syncs to local state via useEffect.
The inventory also has a view switcher: Objects (paginated table), Modules (module list), and Business Processes (inferred processes).
Diff Dashboard
Rendered byDiffDashboard.tsx. Compares two indexed connections side-by-side. Fetches diff data via useDiffData, which calls the compute_system_diff RPC with source_connection_id and target_connection_id.
Layout
- Summary cards — Source system stats, target system stats
- Coverage bar — Matched, partial, source-only, target-only counts
- Module comparison chart — Dumbbell chart comparing module counts across systems
- Gap analysis — Source-only and target-only objects
- Matched objects table — Objects present in both systems with diff status
Module comparison chart
ModuleComparisonChart.tsx uses a dumbbell chart to visualize module-level differences between source and target systems. Each row shows:
- Module name on the left
- A horizontal track with two color-coded dots (source and target) positioned proportionally to their object count
- A connecting line between the dots — shorter line = more similar coverage
- Color-coded counts on the right matching the dot colors
API Endpoints
All dashboard routes are under/api/workspaces/:id/dashboard and require org membership.
| Method | Path | Purpose |
|---|---|---|
GET | /connections | Indexed connections (returns connection_id, name, system_type, status, last_indexed_at) |
GET | /:connectionId/stats | Aggregated stats via get_dashboard_stats RPC |
GET | /:connectionId/entries | Paginated object inventory with filters (q, type, module, delivery_class, risk, page, page_size) |
GET | /:connectionId/entry/:entryKey | Single entry with resolved related entries |
POST | /:connectionId/resolve-keys | Batch resolve bare names to entry_key values |
GET | /diffs | List saved diffs |
POST | /diffs | Create a new diff (name, source_connection_id, target_connection_id) |
GET | /diff/:diffId | Computed diff data via compute_system_diff RPC |
Pagination
The entries endpoint clampspage_size to a maximum of 200. Default is 50.
Filtering
The entries endpoint accepts these query parameters:q— text search acrossnameanddescription(sanitized for PostgREST)type— exact match onentry_typemodule— exact match onmoduledelivery_class— exact match ondelivery_class
Data hooks
| Hook | File | Returns |
|---|---|---|
useIndexedConnections(workspaceId) | useDashboardData.ts | { connections: IndexedConnection[] } |
useDashboardStats(workspaceId, connectionId) | useDashboardData.ts | { stats: DashboardStats } |
useDashboardEntries(workspaceId, connectionId, filters) | useDashboardData.ts | { entries, total, page, page_size } |
useSavedDiffs(workspaceId) | useDashboardData.ts | { diffs: SavedDiff[] } |
useDiffData(workspaceId, diffId) | useDashboardData.ts | { diff: SavedDiff & { data: DiffData } } |
useCreateDiff(workspaceId) | useDashboardData.ts | SWR mutation for POST /diffs |
useAuthSWR which attaches the Supabase JWT and handles revalidation.