Flow Studio
Tab System
Every panel in the Observer is a TabDescriptor registered with the FlowObserverPanelEngine. The built-in tabs ship with the package; custom tabs can be registered at startup or dynamically at runtime.
TabDescriptor Interface
// flow-observer-core/src/types/panel.types.ts
export interface TabDescriptor {
id: string; // unique key, e.g. 'execution-status'
label: string; // display name in tab bar
icon?: string; // Font Awesome class, e.g. 'fa-solid fa-circle-check'
component: React.ComponentType; // the tab's React component
badge?: number | null; // numeric badge shown on the tab (e.g. pending HIL count)
order?: number; // display order (lower = leftmost)
isVisible?: boolean; // hide without unregistering (default: true)
onActivate?: () => void; // called when user switches to this tab
onDeactivate?: () => void; // called when user switches away
}
Built-In Tab IDs
| ID | Label | Order | Badge |
|---|---|---|---|
execution-status | Execution Status | 10 | None |
node-list | Node List | 20 | None |
logs | Logs | 30 | Unread error count |
node-inspector | Node Inspector | 40 | None |
log-detail | Log Detail | 50 | None (hidden by default) |
TabBar Component
The TabBar component renders the horizontal list of tabs from the current registered tab list. It reads from flowObserverPanelStore.tabs and calls engine.activateTab(id) on click:
// TabBar.tsx (simplified)
export function TabBar() {
const { tabs, activeTabId } = useFlowObserverPanelStore();
const engine = useFlowObserverPanelEngine();
return (
<div className="tab-bar">
{tabs
.filter(t => t.isVisible !== false)
.sort((a, b) => (a.order ?? 99) - (b.order ?? 99))
.map(tab => (
<button
key={tab.id}
className={tab.id === activeTabId ? 'active' : ''}
onClick={() => engine.activateTab(tab.id)}
>
{tab.icon && <i className={tab.icon} />}
{tab.label}
{tab.badge != null && <span className="badge">{tab.badge}</span>}
</button>
))}
</div>
);
}
Programmatic Tab Switching
Any component can switch the active tab by calling the engine directly:
// Clicking a node in the Node List tab opens the Node Inspector
const engine = useFlowObserverPanelEngine();
engine.activateTab('node-inspector');
// Or via the store directly
flowObserverPanelStore.getState().setActiveTabId('node-inspector');
Log Detail Tab Auto-Navigate
The Log Detail tab is hidden by default (isVisible: false). It becomes visible when the user clicks "Expand" on a log entry in the Logs tab. The engine calls
engine.activateTab('log-detail') and sets the selected log entry in the store before switching.