Workflow Monitor Component Library π
Real-time workflow execution monitoring with WebSocket streaming and animated status indicators.
Installationβ
npm install react-toastify @stomp/stompjs
Quick Startβ
import { WorkflowMonitor } from '@/components/WorkflowMonitor';
import { useGetWorkflowQuery } from '@thor/redux/services/WorkflowService';
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
function MyWorkflowPage({ workflowId }: { workflowId: string }) {
const { data: workflow } = useGetWorkflowQuery(workflowId);
if (!workflow) return <div>Loading...</div>;
return (
<>
<WorkflowMonitor
workflow={workflow}
onStart={() => fetch(`/api/workflows/${workflowId}/start`, { method: 'POST' })}
onPause={() => fetch(`/api/workflows/${workflowId}/pause`, { method: 'POST' })}
onStop={() => fetch(`/api/workflows/${workflowId}/stop`, { method: 'POST' })}
/>
<ToastContainer position="bottom-right" />
</>
);
}
Componentsβ
WorkflowMonitorβ
Main container component that orchestrates all workflow monitoring features.
Propsβ
| Prop | Type | Required | Description |
|---|---|---|---|
workflow | Workflow | β | ThorAPI Workflow model |
onStart | () => Promise<void> | β | Start workflow handler |
onPause | () => Promise<void> | β | Pause workflow handler |
onStop | () => Promise<void> | β | Stop workflow handler |
onServerChange | (url: string) => void | β | Server URL change handler |
Exampleβ
<WorkflowMonitor
workflow={workflow}
onStart={async () => {
const response = await startWorkflowMutation(workflowId);
console.log('Started:', response);
}}
onPause={async () => {
await pauseWorkflowMutation(workflowId);
}}
onStop={async () => {
await stopWorkflowMutation(workflowId);
}}
onServerChange={(url) => {
console.log('Server changed to:', url);
}}
/>
ExecModuleCardβ
Animated card displaying individual module execution status.
Propsβ
| Prop | Type | Required | Description |
|---|---|---|---|
module | ExecModule | β | ThorAPI ExecModule model |
status | ModuleStatus | β | Current status (default: 'PENDING') |
eventLogs | EventLog[] | β | Recent event logs |
duration | number | β | Execution duration in ms |
onExpand | (id: string) => void | β | Expand handler |
Status Valuesβ
PENDING- π΅ Blue, no animationRUNNING- π‘ Yellow, pulsing animationSUCCESS- π’ Green, glow animationERROR- π΄ Red, shake animationPAUSED- βΈοΈ Gray, staticSKIPPED- βοΈ Light gray
Exampleβ
<ExecModuleCard
module={execModule}
status="RUNNING"
eventLogs={recentLogs}
duration={1500}
onExpand={(id) => console.log('Expanded:', id)}
/>
WorkflowControlsβ
Play/Pause/Stop buttons with smart enable/disable logic.
Propsβ
| Prop | Type | Required | Description |
|---|---|---|---|
workflow | Workflow | β | ThorAPI Workflow model |
onStart | () => Promise<void> | β | Start handler |
onPause | () => Promise<void> | β | Pause handler |
onStop | () => Promise<void> | β | Stop handler |
onRefresh | () => void | β | Refresh handler |
disabled | boolean | β | Disable all buttons |
Button Statesβ
| Workflow Status | Play | Pause | Stop |
|---|---|---|---|
| READY | β | β | β |
| RUNNING | β | β | β |
| STOPPED | β | β | β |
| ERROR | β | β | β |
Exampleβ
<WorkflowControls
workflow={workflow}
onStart={handleStart}
onPause={handlePause}
onStop={handleStop}
onRefresh={() => refetch()}
/>
WorkflowStatePanelβ
Collapsible panel for viewing live workflow state.
Propsβ
| Prop | Type | Required | Description |
|---|---|---|---|
state | Record<string, any> | β | State key-value pairs |
collapsed | boolean | β | Collapsed state |
onToggle | () => void | β | Toggle handler |
Featuresβ
- β Namespace grouping (e.g., "build.*")
- β Search/filter by key or value
- β Click to copy individual values
- β Export all state as JSON
- β Type badges (string, number, boolean, object)
Exampleβ
const [collapsed, setCollapsed] = useState(true);
<WorkflowStatePanel
state={{
'build.version': '1.0.0',
'deploy.target': 'production',
'ig.publish.status': 'pending'
}}
collapsed={collapsed}
onToggle={() => setCollapsed(!collapsed)}
/>
OasServerPickerβ
Dropdown for selecting API server endpoint.
Propsβ
| Prop | Type | Required | Description |
|---|---|---|---|
currentServer | string | β | Current server URL |
onChange | (url: string) => void | β | Change handler |
disabled | boolean | β | Disable picker |
Built-in Serversβ
- Development -
http://localhost:8080 - Staging -
https://staging.valkyr.ai - Production -
https://api.valkyr.ai - Custom - User-defined URL
Exampleβ
<OasServerPicker
currentServer="http://localhost:8080"
onChange={(url) => {
console.log('Server changed to:', url);
updateWorkflowServer(workflowId, url);
}}
disabled={workflow.status === 'running'}
/>
Hooksβ
useWorkflowWebSocketβ
Custom hook for WebSocket connection and real-time updates.
Parametersβ
| Param | Type | Description |
|---|---|---|
workflowId | string | undefined | Workflow UUID |
Returnsβ
| Property | Type | Description |
|---|---|---|
liveStatus | Record<string, ModuleStatus> | Module statuses by ID |
liveEvents | Record<string, EventLog[]> | Event logs by module ID |
workflowState | Record<string, any> | Current workflow state |
durations | Record<string, number> | Execution durations (ms) |
connected | boolean | WebSocket connection status |
error | Error | null | Connection error |
reconnect | () => void | Manual reconnect function |
Exampleβ
const {
liveStatus,
liveEvents,
workflowState,
durations,
connected,
error,
reconnect
} = useWorkflowWebSocket(workflowId);
if (!connected) {
return <div>Connecting... <button onClick={reconnect}>Retry</button></div>;
}
if (error) {
return <div>Error: {error.message}</div>;
}
// Use live data...
Stylingβ
Custom Animationsβ
The component library includes GPU-accelerated CSS animations:
.module-status-running {
animation: pulse 2s ease-in-out infinite;
}
.module-status-success {
animation: glow 1s ease-in-out;
}
.module-status-error {
animation: shake 0.5s ease-in-out;
}
Themingβ
Override default styles:
.workflow-monitor {
--status-pending: #6c757d;
--status-running: #ffc107;
--status-success: #28a745;
--status-error: #dc3545;
--status-paused: #6c757d;
}
Accessibilityβ
All components follow WCAG 2.1 AA guidelines:
- β Keyboard navigation (Tab, Enter, Space, Esc)
- β ARIA labels on interactive elements
- β Screen reader announcements
- β High contrast mode support
- β Focus indicators
- β Reduced motion support
Performanceβ
- π 60fps animations via CSS GPU acceleration
- π Debounced WebSocket updates (max 10/sec)
- π Memoized components with React.memo()
- π Lazy loading for module details
- π Virtual scrolling for 20+ modules
Browser Supportβ
- β Chrome 90+
- β Firefox 88+
- β Safari 14+
- β Edge 90+
Troubleshootingβ
WebSocket Connection Failsβ
// Check WebSocket URL
const wsUrl = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}/ws`;
console.log('WebSocket URL:', wsUrl);
TypeScript Errorsβ
Enable skipLibCheck in tsconfig.json:
{
"compilerOptions": {
"skipLibCheck": true
}
}
Missing Toast Notificationsβ
Import ToastContainer:
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
<ToastContainer position="bottom-right" />
Examplesβ
With Redux Toolkit Queryβ
import { useGetWorkflowQuery, useStartWorkflowMutation } from '@thor/redux/services/WorkflowService';
function WorkflowPage({ id }: { id: string }) {
const { data: workflow, refetch } = useGetWorkflowQuery(id);
const [start] = useStartWorkflowMutation();
const [pause] = usePauseWorkflowMutation();
const [stop] = useStopWorkflowMutation();
return (
<WorkflowMonitor
workflow={workflow!}
onStart={() => start(id).unwrap()}
onPause={() => pause(id).unwrap()}
onStop={() => stop(id).unwrap()}
/>
);
}
With Custom WebSocket Endpointβ
// Modify useWorkflowWebSocket hook
const wsUrl = process.env.REACT_APP_WS_URL || `ws://${window.location.host}/ws`;
const client = new Client({
brokerURL: wsUrl,
// ...
});
API Referenceβ
For complete API documentation, see: