4.0 KiB
Design System Update Instructions
These changes are needed in @cameleer/design-system to replace workarounds in cameleer3-server's UI.
1. Sidebar: Add onNavigate callback prop (HIGH PRIORITY)
Problem
The Sidebar component navigates internally using React Router <Link> components with hardcoded paths (/apps/:appId, /apps/:appId/:routeId, /agents/:appId/:instanceId). The consuming app (cameleer3-server) now uses a different URL structure (/exchanges/:appId, /runtime/:appId/:instanceId) and needs to intercept and re-route sidebar navigation.
The current workaround wraps Sidebar in a <div onClick={...} style={{ display: 'contents' }}> that intercepts anchor clicks via event delegation and prevents default navigation. This is fragile — it depends on the Sidebar rendering <a> elements and breaks if the internal markup changes.
Required Change
Add an optional onNavigate callback to SidebarProps:
interface SidebarProps {
apps: SidebarApp[];
className?: string;
onNavigate?: (path: string) => void; // NEW
}
Behavior:
- When
onNavigateis NOT provided: Sidebar works exactly as today (internal<Link>navigation). No breaking change. - When
onNavigateIS provided: Instead of using<Link>ornavigate(), callonNavigate(path)with the path that would have been navigated to. The consuming app decides where to actually navigate.
Example paths passed to onNavigate:
- App click:
onNavigate('/apps/order-svc') - Route click:
onNavigate('/apps/order-svc/process-order') - Agent click:
onNavigate('/agents/order-svc/agent-1')
The consuming app can then translate these paths to its own URL structure.
Implementation hint: In the Sidebar component, wherever you have <Link to={path}> or navigate(path), check if onNavigate is defined. If yes, render a <button> or <div> with onClick={() => onNavigate(path)} instead of a <Link>. If no, keep the existing <Link> behavior.
How the consumer will use it
<Sidebar
apps={sidebarApps}
onNavigate={(path) => {
// Translate /apps/x/y to /exchanges/x/y (current tab)
// Translate /agents/x/y to /runtime/x/y
const translated = translatePath(path);
navigate(translated);
}}
/>
2. DataTable: Add fillHeight prop (MEDIUM PRIORITY)
Problem
When DataTable is used in a flex layout and needs to fill the remaining vertical space (with the table body scrolling and the pagination footer pinned at the bottom), the consuming app must wrap DataTable in manual flex containers:
.tableSection {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
}
.tableScroll {
flex: 1;
min-height: 0;
overflow-y: auto;
}
<div className={styles.tableSection}>
<div className={styles.tableHeader}>...</div>
<div className={styles.tableScroll}>
<DataTable ... />
</div>
</div>
This pattern is repeated in 3 pages (Dashboard, RoutesMetrics, RouteDetail).
Required Change
Add an optional fillHeight prop to DataTableProps:
interface DataTableProps<T> {
// ... existing props
fillHeight?: boolean; // NEW
}
Behavior when fillHeight is true:
- The DataTable wrapper gets:
display: flex; flex-direction: column; flex: 1; min-height: 0 - The scroll area (containing the
<table>) gets:flex: 1; min-height: 0; overflow-y: auto - The footer (pagination) gets:
flex-shrink: 0(stays pinned at the bottom) - The table header row should remain visible (sticky or outside the scroll area)
When fillHeight is false/undefined: No change to current behavior.
How the consumer will use it
<DataTable
columns={columns}
data={rows}
fillHeight
// ... other props
/>
No wrapper divs needed — DataTable manages its own height filling internally.
Version
After applying these changes, bump the package version (patch or minor) and publish. The cameleer3-server UI will then update its dependency and remove the workarounds.