dataflow-rs 2.1.5

A lightweight rules engine for building IFTTT-style automation and data processing pipelines in Rust. Define rules with JSONLogic conditions, execute actions, and chain workflows.
Documentation
import { useEffect, useCallback } from 'react';
import {
  Play,
  Pause,
  Square,
  SkipBack,
  SkipForward,
  RotateCcw,
  Gauge,
} from 'lucide-react';
import { useDebugger } from '../context';

interface DebuggerControlsProps {
  /** Show compact version */
  compact?: boolean;
  /** Additional CSS class */
  className?: string;
}

/**
 * Playback controls for the debugger
 */
export function DebuggerControls({ compact = false, className = '' }: DebuggerControlsProps) {
  const {
    state,
    play,
    pause,
    stop,
    reset,
    stepForward,
    stepBackward,
    setSpeed,
    isAtStart,
    isAtEnd,
    hasTrace,
    progress,
    totalSteps,
  } = useDebugger();

  const { playbackState, playbackSpeed, currentStepIndex, isExecuting } = state;

  // Keyboard shortcuts
  const handleKeyDown = useCallback(
    (e: KeyboardEvent) => {
      // Don't handle if in an input/textarea
      if (
        e.target instanceof HTMLInputElement ||
        e.target instanceof HTMLTextAreaElement
      ) {
        return;
      }

      switch (e.key) {
        case ' ':
          e.preventDefault();
          if (playbackState === 'playing') {
            pause();
          } else if (hasTrace) {
            play();
          }
          break;
        case 'ArrowRight':
          e.preventDefault();
          if (hasTrace && !isAtEnd) {
            stepForward();
          }
          break;
        case 'ArrowLeft':
          e.preventDefault();
          if (hasTrace && !isAtStart) {
            stepBackward();
          }
          break;
        case 'Escape':
          e.preventDefault();
          stop();
          break;
        case 'r':
          if (e.metaKey || e.ctrlKey) {
            e.preventDefault();
            reset();
          }
          break;
      }
    },
    [playbackState, hasTrace, isAtEnd, isAtStart, play, pause, stop, stepForward, stepBackward, reset]
  );

  useEffect(() => {
    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [handleKeyDown]);

  const handleSpeedChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setSpeed(Number(e.target.value));
  };


  if (compact) {
    return (
      <div className={`df-debug-controls df-debug-controls-compact ${className}`}>
        <button
          className="df-debug-btn"
          onClick={stepBackward}
          disabled={!hasTrace || isAtStart || isExecuting}
          title="Previous step (Left Arrow)"
        >
          <SkipBack size={16} />
        </button>

        {playbackState === 'playing' ? (
          <button
            className="df-debug-btn df-debug-btn-primary"
            onClick={pause}
            disabled={!hasTrace || isExecuting}
            title="Pause (Space)"
          >
            <Pause size={18} />
          </button>
        ) : (
          <button
            className="df-debug-btn df-debug-btn-primary"
            onClick={play}
            disabled={!hasTrace || isAtEnd || isExecuting}
            title="Play (Space)"
          >
            <Play size={18} />
          </button>
        )}

        <button
          className="df-debug-btn"
          onClick={stepForward}
          disabled={!hasTrace || isAtEnd || isExecuting}
          title="Next step (Right Arrow)"
        >
          <SkipForward size={16} />
        </button>

        <span className="df-debug-step-counter">
          {currentStepIndex + 1} / {totalSteps}
        </span>
      </div>
    );
  }

  return (
    <div className={`df-debug-controls ${className}`}>
      {/* Main controls */}
      <div className="df-debug-controls-main">
        <button
          className="df-debug-btn"
          onClick={stop}
          disabled={!hasTrace || isExecuting}
          title="Stop (Escape)"
        >
          <Square size={20} />
        </button>

        <button
          className="df-debug-btn"
          onClick={stepBackward}
          disabled={!hasTrace || isAtStart || isExecuting}
          title="Previous step (Left Arrow)"
        >
          <SkipBack size={20} />
        </button>

        {playbackState === 'playing' ? (
          <button
            className="df-debug-btn df-debug-btn-primary"
            onClick={pause}
            disabled={!hasTrace || isExecuting}
            title="Pause (Space)"
          >
            <Pause size={24} />
          </button>
        ) : (
          <button
            className="df-debug-btn df-debug-btn-primary"
            onClick={play}
            disabled={!hasTrace || isAtEnd || isExecuting}
            title="Play (Space)"
          >
            <Play size={24} />
          </button>
        )}

        <button
          className="df-debug-btn"
          onClick={stepForward}
          disabled={!hasTrace || isAtEnd || isExecuting}
          title="Next step (Right Arrow)"
        >
          <SkipForward size={20} />
        </button>

        <button
          className="df-debug-btn"
          onClick={reset}
          disabled={!hasTrace || isExecuting}
          title="Reset (Ctrl+R)"
        >
          <RotateCcw size={20} />
        </button>
      </div>

      {/* Progress indicator */}
      <div className="df-debug-progress">
        <div className="df-debug-progress-bar">
          <div
            className="df-debug-progress-fill"
            style={{ width: `${progress * 100}%` }}
          />
        </div>
        <span className="df-debug-step-counter">
          Step {currentStepIndex + 1} of {totalSteps}
        </span>
      </div>

      {/* Speed control */}
      <div className="df-debug-speed">
        <Gauge size={14} />
        <input
          type="range"
          min="100"
          max="2000"
          step="100"
          value={playbackSpeed}
          onChange={handleSpeedChange}
          className="df-debug-speed-slider"
          title={`Playback speed: ${playbackSpeed}ms`}
        />
        <span className="df-debug-speed-label">{playbackSpeed}ms</span>
      </div>
    </div>
  );
}