Skip to content

Dashboard UI

The DevAll dashboard provides a web-based interface for managing development services. This guide explains how the UI components work and interact with your services.

The dashboard operates as a Vue 3 single-page application that maintains a persistent WebSocket connection to the DevAll backend server. This architecture enables real-time bidirectional communication between your services and the browser.

The WebSocket connection on /ws handles several message types:

  • init - Initial payload containing all service configurations and buffered logs
  • status - Service state transitions (stopped → starting → running → error)
  • log - Stdout/stderr output from running processes
  • config-update - Configuration changes that need UI refresh
  • resource-update - CPU and memory metrics

The frontend maintains reactive state that automatically updates the UI when these messages arrive. If the connection drops, the client attempts reconnection every 3 seconds with exponential backoff.

The header provides global controls through dropdown menus. The project switcher allows switching between different DevAll configurations without restarting the server. Each project maintains its own service definitions and state.

The commands dropdown dynamically populates with your most frequently used npm scripts and custom commands. These are tracked based on execution frequency and stored in local preferences.

Batch operations like “Start All” or “Stop All” send commands to all registered services simultaneously. The backend processes these requests in parallel but respects any configured startup delays.

Each service renders as an independent card component that maintains its own state while staying synchronized with the backend through the WebSocket connection.

The backend determines service status by parsing stdout for specific patterns:

  • Running state - Detected via patterns like “Server running”, “Listening on”, localhost URLs
  • Crashed state - Patterns include “app crashed”, “waiting for file changes”
  • Starting state - Nodemon restart messages or initial spawn events
  • Error state - Non-zero exit codes or specific error patterns

Status changes trigger visual updates: gray (stopped), orange with pulse animation (starting), green with glow (running), or red (error). The pulse animation uses CSS keyframes to indicate transitional states.

Service controls communicate with the backend via REST API endpoints. Starting a service spawns a child process with the configured command and arguments. The backend sets the PORT environment variable if specified and manages the process lifecycle.

For services with stealPort: true, the backend first kills any process occupying the configured port using platform-specific commands (lsof on Unix, netstat on Windows).

Each service card embeds an xterm.js terminal instance that receives log data through the WebSocket connection. The terminal maintains a 10,000 line scrollback buffer and processes ANSI escape codes for color output.

Log messages are batched with a 16ms debounce to prevent UI thrashing during rapid output. The terminal automatically scrolls to bottom on new content unless the user has scrolled up.

For terminal-type services (those with type: "terminal"), the backend spawns a PTY (pseudo-terminal) process using node-pty instead of a standard child process. This enables full bidirectional communication, allowing users to type commands and see interactive output.

The resource monitoring system polls system metrics every 2 seconds and broadcasts updates to all connected clients.

CPU usage calculation differs by platform:

  • macOS/Linux - Parses /proc/stat or uses ps command
  • Windows - Uses WMI queries via wmic command

Memory metrics come from Node.js process.memoryUsage() for individual services and os.totalmem()/os.freemem() for system-wide statistics.

The frontend maintains a rolling buffer of CPU measurements to render trend sparklines using SVG paths.

When the dashboard loads, services marked with autostart: true spawn automatically. The backend maintains a process registry that tracks PIDs, status, and resource usage for each service.

Service startup follows this sequence:

  1. Backend receives start command via HTTP POST
  2. Kills any existing process on the configured port (if stealPort is enabled)
  3. Spawns child process with environment variables
  4. Monitors stdout/stderr for status patterns
  5. Broadcasts status changes via WebSocket

The system handles both standard processes and interactive terminals differently. Standard services use Node’s child_process.spawn() while terminal services use node-pty to create proper PTY sessions.

Services with file watching enabled use chokidar to monitor their working directory. The watcher looks for changes in common development files (.js, .ts, .json, etc.) and triggers automatic restarts.

The restart mechanism preserves the process environment and arguments while creating a fresh child process. A cooldown period prevents restart loops if a service crashes repeatedly.

The dashboard implements cross-platform port management. Before starting a service with a configured port:

  1. The backend checks if the port is occupied
  2. If stealPort is true, it identifies the process using the port
  3. Sends termination signal to that process
  4. Waits for port to be freed (with timeout)
  5. Starts the new service

This prevents “port already in use” errors common in development environments.

The tunnel feature integrates with ngrok or LocalTunnel to expose local services publicly. When activated:

  1. The backend spawns a tunnel process pointing to the service’s port
  2. Parses the tunnel output for the public URL
  3. Broadcasts the URL to all connected clients
  4. Maintains the tunnel as long as the service runs

Tunnel credentials can be configured per-service or globally through environment variables.

Freestyle terminals are full PTY sessions that run independently of services. The backend creates these using node-pty with the user’s default shell. Input from the frontend gets sent through the WebSocket connection directly to the PTY process.

The terminal maintains complete shell state including environment variables, working directory, and command history. Users can run any command as if using a native terminal, including interactive programs like vim or top.

The commands feature tracks npm scripts and custom commands in a local SQLite database. Each execution increments a usage counter, and the UI displays the most frequently used commands.

When executing a command, the system:

  • Creates a temporary service configuration
  • Spawns the process in the specified working directory
  • Streams output to a dynamically created service card
  • Removes the card when the process completes

The IDE launcher uses platform-specific URL schemes or command-line interfaces:

  • VS Code - Uses code command or vscode:// URL scheme
  • Cursor - Launches via cursor command
  • WebStorm - Uses JetBrains Toolbox URL scheme
  • GitHub Desktop - Uses x-github-client:// URL scheme

The integration detects installed IDEs during startup and only shows available options in the UI.

Each service configuration supports multiple display and behavior options:

  • Visual properties - Custom colors (hex values) and icons affect the card appearance
  • Behavioral flags - autostart, watchFiles, stealPort, secondary, background
  • Runtime settings - Command, arguments, working directory, environment variables

Configuration changes made through the UI are persisted back to the config file (YAML, JSON, or JSONC) using the /api/services/:id endpoint.

The dashboard maintains state in several layers:

  1. Backend state - Process registry, service configurations, log buffers
  2. Frontend state - UI preferences, collapsed sections, search history
  3. Browser storage - Project selection, theme preferences, font sizes

Local storage keys follow the pattern devall::{feature}::{value} for easy identification and cleanup.

Terminal appearance is controlled through xterm.js themes. The system provides default themes for light and dark modes, but users can override colors through CSS custom properties:

--terminal-foreground: #ffffff;
--terminal-background: #1e1e1e;
--terminal-cursor: #ffffff;
--terminal-selection: #3e3e3e;

Font size adjustments persist in local storage and apply to all terminal instances.

The backend maintains a circular buffer of 10,000 lines per service. When a client connects, it receives the buffer contents as part of the init message. This ensures users see historical output even when connecting after services have started.

Logs are stored with metadata including timestamp, level (if detected), and source (stdout/stderr).

Status detection uses a priority-based pattern matching system:

  1. Check for explicit error patterns (highest priority)
  2. Look for running indicators
  3. Check for crash patterns
  4. Fall back to process exit codes

The system includes a 2-second timeout for the “starting” state. If no definitive pattern is found within this window but the process is producing output, it transitions to “running”.

Resource metrics update on a 2-second interval:

CPU Usage:

  • Calculated as the delta between process CPU time measurements
  • Normalized against the number of CPU cores
  • Smoothed using a moving average to reduce noise

Memory Usage:

  • RSS (Resident Set Size) from process statistics
  • Converted to human-readable format (KB, MB, GB)
  • Percentage calculated against total system memory

The WebSocket connection handles bidirectional communication between the dashboard and backend:

Message Flow:

  1. Client connects to /ws endpoint
  2. Server sends init message with complete state snapshot
  3. Server broadcasts updates as events occur
  4. Client can send commands (for terminal input)

Reconnection Logic:

  • Exponential backoff starting at 3 seconds
  • Maximum retry interval of 30 seconds
  • Displays connection status after first successful connection
  • Queues actions during disconnection

The dashboard implements several optimizations for smooth operation:

Log Batching: Rapid log output is batched using a 16ms debounce. This prevents the UI from updating hundreds of times per second during verbose output.

Virtual Scrolling: Terminal components only render visible portions of the log buffer. This keeps memory usage constant regardless of log size.

Lazy Loading: Service cards that are outside the viewport don’t update their terminals until scrolled into view.

CSS Containment: Each service card uses CSS containment to isolate layout calculations and prevent reflows from affecting other cards.

While the UI remains consistent, the underlying implementation varies by platform:

  • Runs as standard web application
  • Uses browser storage APIs for preferences
  • Network accessible from any device
  • Subject to browser security policies
  • WebView renders the same Vue application
  • Native file system access through Tauri APIs
  • System tray integration for background operation
  • Can launch external applications directly

Both platforms share the same backend server, allowing seamless switching between desktop and web interfaces.

Services show as “starting” indefinitely: The status detection patterns may not match your service’s output. Check the stdout for patterns like “Server running” or configure custom patterns.

High CPU usage in browser: Terminal output may be overwhelming the renderer. Try clearing logs or reducing the terminal buffer size.

WebSocket disconnections: Check for proxy configurations or firewall rules that might interfere with WebSocket connections. The dashboard requires a persistent connection to function.

Port conflicts: Enable stealPort: true in your service configuration to automatically kill conflicting processes.