 85bf1341f3
			
		
	
	85bf1341f3
	
	
	
		
			
			Frontend Enhancements: - Complete React TypeScript frontend with modern UI components - Distributed workflows management interface with real-time updates - Socket.IO integration for live agent status monitoring - Agent management dashboard with cluster visualization - Project management interface with metrics and task tracking - Responsive design with proper error handling and loading states Backend Infrastructure: - Distributed coordinator for multi-agent workflow orchestration - Cluster management API with comprehensive agent operations - Enhanced database models for agents and projects - Project service for filesystem-based project discovery - Performance monitoring and metrics collection - Comprehensive API documentation and error handling Documentation: - Complete distributed development guide (README_DISTRIBUTED.md) - Comprehensive development report with architecture insights - System configuration templates and deployment guides The platform now provides a complete web interface for managing the distributed AI cluster with real-time monitoring, workflow orchestration, and agent coordination capabilities. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			122 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			122 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import { extractEventInfo } from '../events/event-info.mjs';
 | |
| import { addDomEvent } from '../events/add-dom-event.mjs';
 | |
| import { addPointerEvent } from '../events/add-pointer-event.mjs';
 | |
| import { Feature } from '../motion/features/Feature.mjs';
 | |
| import { pipe } from '../utils/pipe.mjs';
 | |
| import { isDragActive } from './drag/utils/lock.mjs';
 | |
| import { isNodeOrChild } from './utils/is-node-or-child.mjs';
 | |
| import { noop } from '../utils/noop.mjs';
 | |
| import { frame } from '../frameloop/frame.mjs';
 | |
| 
 | |
| function fireSyntheticPointerEvent(name, handler) {
 | |
|     if (!handler)
 | |
|         return;
 | |
|     const syntheticPointerEvent = new PointerEvent("pointer" + name);
 | |
|     handler(syntheticPointerEvent, extractEventInfo(syntheticPointerEvent));
 | |
| }
 | |
| class PressGesture extends Feature {
 | |
|     constructor() {
 | |
|         super(...arguments);
 | |
|         this.removeStartListeners = noop;
 | |
|         this.removeEndListeners = noop;
 | |
|         this.removeAccessibleListeners = noop;
 | |
|         this.startPointerPress = (startEvent, startInfo) => {
 | |
|             if (this.isPressing)
 | |
|                 return;
 | |
|             this.removeEndListeners();
 | |
|             const props = this.node.getProps();
 | |
|             const endPointerPress = (endEvent, endInfo) => {
 | |
|                 if (!this.checkPressEnd())
 | |
|                     return;
 | |
|                 const { onTap, onTapCancel, globalTapTarget } = this.node.getProps();
 | |
|                 frame.update(() => {
 | |
|                     /**
 | |
|                      * We only count this as a tap gesture if the event.target is the same
 | |
|                      * as, or a child of, this component's element
 | |
|                      */
 | |
|                     !globalTapTarget &&
 | |
|                         !isNodeOrChild(this.node.current, endEvent.target)
 | |
|                         ? onTapCancel && onTapCancel(endEvent, endInfo)
 | |
|                         : onTap && onTap(endEvent, endInfo);
 | |
|                 });
 | |
|             };
 | |
|             const removePointerUpListener = addPointerEvent(window, "pointerup", endPointerPress, { passive: !(props.onTap || props["onPointerUp"]) });
 | |
|             const removePointerCancelListener = addPointerEvent(window, "pointercancel", (cancelEvent, cancelInfo) => this.cancelPress(cancelEvent, cancelInfo), { passive: !(props.onTapCancel || props["onPointerCancel"]) });
 | |
|             this.removeEndListeners = pipe(removePointerUpListener, removePointerCancelListener);
 | |
|             this.startPress(startEvent, startInfo);
 | |
|         };
 | |
|         this.startAccessiblePress = () => {
 | |
|             const handleKeydown = (keydownEvent) => {
 | |
|                 if (keydownEvent.key !== "Enter" || this.isPressing)
 | |
|                     return;
 | |
|                 const handleKeyup = (keyupEvent) => {
 | |
|                     if (keyupEvent.key !== "Enter" || !this.checkPressEnd())
 | |
|                         return;
 | |
|                     fireSyntheticPointerEvent("up", (event, info) => {
 | |
|                         const { onTap } = this.node.getProps();
 | |
|                         if (onTap) {
 | |
|                             frame.update(() => onTap(event, info));
 | |
|                         }
 | |
|                     });
 | |
|                 };
 | |
|                 this.removeEndListeners();
 | |
|                 this.removeEndListeners = addDomEvent(this.node.current, "keyup", handleKeyup);
 | |
|                 fireSyntheticPointerEvent("down", (event, info) => {
 | |
|                     this.startPress(event, info);
 | |
|                 });
 | |
|             };
 | |
|             const removeKeydownListener = addDomEvent(this.node.current, "keydown", handleKeydown);
 | |
|             const handleBlur = () => {
 | |
|                 if (!this.isPressing)
 | |
|                     return;
 | |
|                 fireSyntheticPointerEvent("cancel", (cancelEvent, cancelInfo) => this.cancelPress(cancelEvent, cancelInfo));
 | |
|             };
 | |
|             const removeBlurListener = addDomEvent(this.node.current, "blur", handleBlur);
 | |
|             this.removeAccessibleListeners = pipe(removeKeydownListener, removeBlurListener);
 | |
|         };
 | |
|     }
 | |
|     startPress(event, info) {
 | |
|         this.isPressing = true;
 | |
|         const { onTapStart, whileTap } = this.node.getProps();
 | |
|         /**
 | |
|          * Ensure we trigger animations before firing event callback
 | |
|          */
 | |
|         if (whileTap && this.node.animationState) {
 | |
|             this.node.animationState.setActive("whileTap", true);
 | |
|         }
 | |
|         if (onTapStart) {
 | |
|             frame.update(() => onTapStart(event, info));
 | |
|         }
 | |
|     }
 | |
|     checkPressEnd() {
 | |
|         this.removeEndListeners();
 | |
|         this.isPressing = false;
 | |
|         const props = this.node.getProps();
 | |
|         if (props.whileTap && this.node.animationState) {
 | |
|             this.node.animationState.setActive("whileTap", false);
 | |
|         }
 | |
|         return !isDragActive();
 | |
|     }
 | |
|     cancelPress(event, info) {
 | |
|         if (!this.checkPressEnd())
 | |
|             return;
 | |
|         const { onTapCancel } = this.node.getProps();
 | |
|         if (onTapCancel) {
 | |
|             frame.update(() => onTapCancel(event, info));
 | |
|         }
 | |
|     }
 | |
|     mount() {
 | |
|         const props = this.node.getProps();
 | |
|         const removePointerListener = addPointerEvent(props.globalTapTarget ? window : this.node.current, "pointerdown", this.startPointerPress, { passive: !(props.onTapStart || props["onPointerStart"]) });
 | |
|         const removeFocusListener = addDomEvent(this.node.current, "focus", this.startAccessiblePress);
 | |
|         this.removeStartListeners = pipe(removePointerListener, removeFocusListener);
 | |
|     }
 | |
|     unmount() {
 | |
|         this.removeStartListeners();
 | |
|         this.removeEndListeners();
 | |
|         this.removeAccessibleListeners();
 | |
|     }
 | |
| }
 | |
| 
 | |
| export { PressGesture };
 |