 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>
		
			
				
	
	
		
			113 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			113 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import { addUniqueItem, removeItem } from '../../utils/array.mjs';
 | |
| 
 | |
| class NodeStack {
 | |
|     constructor() {
 | |
|         this.members = [];
 | |
|     }
 | |
|     add(node) {
 | |
|         addUniqueItem(this.members, node);
 | |
|         node.scheduleRender();
 | |
|     }
 | |
|     remove(node) {
 | |
|         removeItem(this.members, node);
 | |
|         if (node === this.prevLead) {
 | |
|             this.prevLead = undefined;
 | |
|         }
 | |
|         if (node === this.lead) {
 | |
|             const prevLead = this.members[this.members.length - 1];
 | |
|             if (prevLead) {
 | |
|                 this.promote(prevLead);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     relegate(node) {
 | |
|         const indexOfNode = this.members.findIndex((member) => node === member);
 | |
|         if (indexOfNode === 0)
 | |
|             return false;
 | |
|         /**
 | |
|          * Find the next projection node that is present
 | |
|          */
 | |
|         let prevLead;
 | |
|         for (let i = indexOfNode; i >= 0; i--) {
 | |
|             const member = this.members[i];
 | |
|             if (member.isPresent !== false) {
 | |
|                 prevLead = member;
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|         if (prevLead) {
 | |
|             this.promote(prevLead);
 | |
|             return true;
 | |
|         }
 | |
|         else {
 | |
|             return false;
 | |
|         }
 | |
|     }
 | |
|     promote(node, preserveFollowOpacity) {
 | |
|         const prevLead = this.lead;
 | |
|         if (node === prevLead)
 | |
|             return;
 | |
|         this.prevLead = prevLead;
 | |
|         this.lead = node;
 | |
|         node.show();
 | |
|         if (prevLead) {
 | |
|             prevLead.instance && prevLead.scheduleRender();
 | |
|             node.scheduleRender();
 | |
|             node.resumeFrom = prevLead;
 | |
|             if (preserveFollowOpacity) {
 | |
|                 node.resumeFrom.preserveOpacity = true;
 | |
|             }
 | |
|             if (prevLead.snapshot) {
 | |
|                 node.snapshot = prevLead.snapshot;
 | |
|                 node.snapshot.latestValues =
 | |
|                     prevLead.animationValues || prevLead.latestValues;
 | |
|             }
 | |
|             if (node.root && node.root.isUpdating) {
 | |
|                 node.isLayoutDirty = true;
 | |
|             }
 | |
|             const { crossfade } = node.options;
 | |
|             if (crossfade === false) {
 | |
|                 prevLead.hide();
 | |
|             }
 | |
|             /**
 | |
|              * TODO:
 | |
|              *   - Test border radius when previous node was deleted
 | |
|              *   - boxShadow mixing
 | |
|              *   - Shared between element A in scrolled container and element B (scroll stays the same or changes)
 | |
|              *   - Shared between element A in transformed container and element B (transform stays the same or changes)
 | |
|              *   - Shared between element A in scrolled page and element B (scroll stays the same or changes)
 | |
|              * ---
 | |
|              *   - Crossfade opacity of root nodes
 | |
|              *   - layoutId changes after animation
 | |
|              *   - layoutId changes mid animation
 | |
|              */
 | |
|         }
 | |
|     }
 | |
|     exitAnimationComplete() {
 | |
|         this.members.forEach((node) => {
 | |
|             const { options, resumingFrom } = node;
 | |
|             options.onExitComplete && options.onExitComplete();
 | |
|             if (resumingFrom) {
 | |
|                 resumingFrom.options.onExitComplete &&
 | |
|                     resumingFrom.options.onExitComplete();
 | |
|             }
 | |
|         });
 | |
|     }
 | |
|     scheduleRender() {
 | |
|         this.members.forEach((node) => {
 | |
|             node.instance && node.scheduleRender(false);
 | |
|         });
 | |
|     }
 | |
|     /**
 | |
|      * Clear any leads that have been removed this render to prevent them from being
 | |
|      * used in future animations and to prevent memory leaks
 | |
|      */
 | |
|     removeLeadSnapshot() {
 | |
|         if (this.lead && this.lead.snapshot) {
 | |
|             this.lead.snapshot = undefined;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| export { NodeStack };
 |