init projectmycelium
This commit is contained in:
		
							
								
								
									
										646
									
								
								html_template_tests/checkout_flow_modal_v2.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										646
									
								
								html_template_tests/checkout_flow_modal_v2.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,646 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="UTF-8">
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
			
		||||
    <title>Project Mycelium - Checkout Flow</title>
 | 
			
		||||
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
 | 
			
		||||
    <style>
 | 
			
		||||
        .slice-card {
 | 
			
		||||
            background: white;
 | 
			
		||||
            border: 1px solid #dee2e6;
 | 
			
		||||
            border-radius: 8px;
 | 
			
		||||
            padding: 15px;
 | 
			
		||||
            margin: 10px;
 | 
			
		||||
            cursor: pointer;
 | 
			
		||||
            transition: all 0.2s ease;
 | 
			
		||||
            position: relative;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .slice-card:hover {
 | 
			
		||||
            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
 | 
			
		||||
            transform: translateY(-2px);
 | 
			
		||||
            border-color: #0d6efd;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .slice-card.assigned-individual {
 | 
			
		||||
            border-left: 4px solid #6c757d;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .slice-card.assigned-master {
 | 
			
		||||
            border-left: 4px solid #dc3545;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .slice-card.assigned-worker {
 | 
			
		||||
            border-left: 4px solid #28a745;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .assignment-badge {
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            top: 10px;
 | 
			
		||||
            right: 10px;
 | 
			
		||||
            font-size: 0.75rem;
 | 
			
		||||
            padding: 4px 8px;
 | 
			
		||||
            border-radius: 12px;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .badge-individual {
 | 
			
		||||
            background: #6c757d;
 | 
			
		||||
            color: white;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .badge-master {
 | 
			
		||||
            background: #dc3545;
 | 
			
		||||
            color: white;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .badge-worker {
 | 
			
		||||
            background: #28a745;
 | 
			
		||||
            color: white;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .assignment-option {
 | 
			
		||||
            border: 1px solid #dee2e6;
 | 
			
		||||
            border-radius: 6px;
 | 
			
		||||
            padding: 15px;
 | 
			
		||||
            margin-bottom: 10px;
 | 
			
		||||
            cursor: pointer;
 | 
			
		||||
            transition: all 0.2s ease;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .assignment-option:hover {
 | 
			
		||||
            border-color: #0d6efd;
 | 
			
		||||
            background: #f8f9fa;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .assignment-option.selected {
 | 
			
		||||
            border-color: #0d6efd;
 | 
			
		||||
            background: #e7f3ff;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
</head>
 | 
			
		||||
<body class="bg-light">
 | 
			
		||||
    <div class="container py-4">
 | 
			
		||||
        <h3>Project Mycelium - Checkout Flow</h3>
 | 
			
		||||
        
 | 
			
		||||
        <!-- Compute Slices -->
 | 
			
		||||
        <div class="row">
 | 
			
		||||
            <div class="col-md-6">
 | 
			
		||||
                <div class="slice-card assigned-individual" data-slice-id="1" data-assignment="individual" data-cluster="" data-role="" onclick="openAssignmentModal(this)">
 | 
			
		||||
                    <div class="assignment-badge badge-individual">Individual VM</div>
 | 
			
		||||
                    <div>
 | 
			
		||||
                        <strong>slice-1</strong> <span class="text-muted">4x Base Unit</span><br>
 | 
			
		||||
                        <small>4 cores, 16GB, 800GB</small>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="text-end mt-2">
 | 
			
		||||
                        <strong>4.00 TFP</strong><br>
 | 
			
		||||
                        <small class="text-muted">per hour</small>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            
 | 
			
		||||
            <div class="col-md-6">
 | 
			
		||||
                <div class="slice-card assigned-individual" data-slice-id="2" data-assignment="individual" data-cluster="" data-role="" onclick="openAssignmentModal(this)">
 | 
			
		||||
                    <div class="assignment-badge badge-individual">Individual VM</div>
 | 
			
		||||
                    <div>
 | 
			
		||||
                        <strong>slice-2</strong> <span class="text-muted">2x Base Unit</span><br>
 | 
			
		||||
                        <small>2 cores, 8GB, 400GB</small>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="text-end mt-2">
 | 
			
		||||
                        <strong>2.00 TFP</strong><br>
 | 
			
		||||
                        <small class="text-muted">per hour</small>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            
 | 
			
		||||
            <div class="col-md-6">
 | 
			
		||||
                <div class="slice-card assigned-individual" data-slice-id="3" data-assignment="individual" data-cluster="" data-role="" onclick="openAssignmentModal(this)">
 | 
			
		||||
                    <div class="assignment-badge badge-individual">Individual VM</div>
 | 
			
		||||
                    <div>
 | 
			
		||||
                        <strong>slice-3</strong> <span class="text-muted">8x Base Unit</span><br>
 | 
			
		||||
                        <small>8 cores, 32GB, 1600GB</small>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="text-end mt-2">
 | 
			
		||||
                        <strong>8.00 TFP</strong><br>
 | 
			
		||||
                        <small class="text-muted">per hour</small>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            
 | 
			
		||||
            <div class="col-md-6">
 | 
			
		||||
                <div class="slice-card assigned-individual" data-slice-id="4" data-assignment="individual" data-cluster="" data-role="" onclick="openAssignmentModal(this)">
 | 
			
		||||
                    <div class="assignment-badge badge-individual">Individual VM</div>
 | 
			
		||||
                    <div>
 | 
			
		||||
                        <strong>slice-4</strong> <span class="text-muted">1x Base Unit</span><br>
 | 
			
		||||
                        <small>1 core, 4GB, 200GB</small>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="text-end mt-2">
 | 
			
		||||
                        <strong>1.00 TFP</strong><br>
 | 
			
		||||
                        <small class="text-muted">per hour</small>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            
 | 
			
		||||
            <div class="col-md-6">
 | 
			
		||||
                <div class="slice-card assigned-individual" data-slice-id="5" data-assignment="individual" data-cluster="" data-role="" onclick="openAssignmentModal(this)">
 | 
			
		||||
                    <div class="assignment-badge badge-individual">Individual VM</div>
 | 
			
		||||
                    <div>
 | 
			
		||||
                        <strong>slice-5</strong> <span class="text-muted">4x Base Unit</span><br>
 | 
			
		||||
                        <small>4 cores, 16GB, 800GB</small>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="text-end mt-2">
 | 
			
		||||
                        <strong>4.00 TFP</strong><br>
 | 
			
		||||
                        <small class="text-muted">per hour</small>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            
 | 
			
		||||
            <div class="col-md-6">
 | 
			
		||||
                <div class="slice-card assigned-individual" data-slice-id="6" data-assignment="individual" data-cluster="" data-role="" onclick="openAssignmentModal(this)">
 | 
			
		||||
                    <div class="assignment-badge badge-individual">Individual VM</div>
 | 
			
		||||
                    <div>
 | 
			
		||||
                        <strong>slice-6</strong> <span class="text-muted">2x Base Unit</span><br>
 | 
			
		||||
                        <small>2 cores, 8GB, 400GB</small>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="text-end mt-2">
 | 
			
		||||
                        <strong>2.00 TFP</strong><br>
 | 
			
		||||
                        <small class="text-muted">per hour</small>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            
 | 
			
		||||
            <div class="col-md-6">
 | 
			
		||||
                <div class="slice-card assigned-individual" data-slice-id="7" data-assignment="individual" data-cluster="" data-role="" onclick="openAssignmentModal(this)">
 | 
			
		||||
                    <div class="assignment-badge badge-individual">Individual VM</div>
 | 
			
		||||
                    <div>
 | 
			
		||||
                        <strong>slice-7</strong> <span class="text-muted">4x Base Unit</span><br>
 | 
			
		||||
                        <small>4 cores, 16GB, 800GB</small>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="text-end mt-2">
 | 
			
		||||
                        <strong>4.00 TFP</strong><br>
 | 
			
		||||
                        <small class="text-muted">per hour</small>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            
 | 
			
		||||
            <div class="col-md-6">
 | 
			
		||||
                <div class="slice-card assigned-individual" data-slice-id="8" data-assignment="individual" data-cluster="" data-role="" onclick="openAssignmentModal(this)">
 | 
			
		||||
                    <div class="assignment-badge badge-individual">Individual VM</div>
 | 
			
		||||
                    <div>
 | 
			
		||||
                        <strong>slice-8</strong> <span class="text-muted">8x Base Unit</span><br>
 | 
			
		||||
                        <small>8 cores, 32GB, 1600GB</small>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="text-end mt-2">
 | 
			
		||||
                        <strong>8.00 TFP</strong><br>
 | 
			
		||||
                        <small class="text-muted">per hour</small>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        
 | 
			
		||||
        <!-- Deployment Overview -->
 | 
			
		||||
        <div class="mt-5">
 | 
			
		||||
            <div class="card">
 | 
			
		||||
                <div class="card-header">
 | 
			
		||||
                    <h5 class="mb-0">
 | 
			
		||||
                        <i class="bi bi-graph-up me-2"></i>Deployment Overview
 | 
			
		||||
                    </h5>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    <div class="row">
 | 
			
		||||
                        <div class="col-md-3">
 | 
			
		||||
                            <div class="text-center p-3 bg-light rounded">
 | 
			
		||||
                                <div class="h4 mb-1" id="totalSlices">8</div>
 | 
			
		||||
                                <small class="text-muted">Total Slices</small>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="col-md-3">
 | 
			
		||||
                            <div class="text-center p-3 bg-light rounded">
 | 
			
		||||
                                <div class="h4 mb-1" id="individualCount">8</div>
 | 
			
		||||
                                <small class="text-muted">Individual VMs</small>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="col-md-3">
 | 
			
		||||
                            <div class="text-center p-3 bg-light rounded">
 | 
			
		||||
                                <div class="h4 mb-1" id="clusterCount">0</div>
 | 
			
		||||
                                <small class="text-muted">Clusters</small>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="col-md-3">
 | 
			
		||||
                            <div class="text-center p-3 bg-primary text-white rounded">
 | 
			
		||||
                                <div class="h4 mb-1" id="totalCost">25.00 TFP</div>
 | 
			
		||||
                                <small>Total Cost/Hour</small>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        
 | 
			
		||||
        <!-- Clusters Container -->
 | 
			
		||||
        <div id="clustersContainer" class="mt-4"></div>
 | 
			
		||||
    </div>
 | 
			
		||||
    
 | 
			
		||||
    <!-- Assignment Modal -->
 | 
			
		||||
    <div class="modal fade" id="assignmentModal" tabindex="-1">
 | 
			
		||||
        <div class="modal-dialog">
 | 
			
		||||
            <div class="modal-content">
 | 
			
		||||
                <div class="modal-header">
 | 
			
		||||
                    <h5 class="modal-title">Assign Slice</h5>
 | 
			
		||||
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="modal-body">
 | 
			
		||||
                    <h6>Choose Assignment:</h6>
 | 
			
		||||
                    
 | 
			
		||||
                    <!-- Individual VM Option -->
 | 
			
		||||
                    <div class="assignment-option" data-assignment="individual" onclick="selectAssignment(this)">
 | 
			
		||||
                        <strong>Individual VM</strong>
 | 
			
		||||
                        <div class="text-muted">Deploy as a standalone virtual machine</div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    
 | 
			
		||||
                    <!-- Cluster Assignment Option -->
 | 
			
		||||
                    <div class="assignment-option" data-assignment="cluster" onclick="selectAssignment(this)">
 | 
			
		||||
                        <strong>Assign to Cluster</strong>
 | 
			
		||||
                        <div class="text-muted">Add to a Kubernetes cluster</div>
 | 
			
		||||
                        
 | 
			
		||||
                        <!-- Cluster Role Selector -->
 | 
			
		||||
                        <div class="mt-3" id="clusterRoleSelector" style="display: none;">
 | 
			
		||||
                            <div class="row">
 | 
			
		||||
                                <div class="col-md-6">
 | 
			
		||||
                                    <label class="form-label">Select Cluster:</label>
 | 
			
		||||
                                    <select class="form-select" id="clusterSelect">
 | 
			
		||||
                                        <option value="new">+ Create New Cluster</option>
 | 
			
		||||
                                    </select>
 | 
			
		||||
                                </div>
 | 
			
		||||
                                <div class="col-md-6">
 | 
			
		||||
                                    <label class="form-label">Node Role:</label>
 | 
			
		||||
                                    <div class="btn-group w-100" role="group">
 | 
			
		||||
                                        <input type="radio" class="btn-check" name="nodeRole" id="masterRole" value="master">
 | 
			
		||||
                                        <label class="btn btn-outline-danger" for="masterRole">Master</label>
 | 
			
		||||
                                        
 | 
			
		||||
                                        <input type="radio" class="btn-check" name="nodeRole" id="workerRole" value="worker" checked>
 | 
			
		||||
                                        <label class="btn btn-outline-success" for="workerRole">Worker</label>
 | 
			
		||||
                                    </div>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </div>
 | 
			
		||||
                            
 | 
			
		||||
                            <!-- New Cluster Name -->
 | 
			
		||||
                            <div class="mt-3" id="newClusterName" style="display: block;">
 | 
			
		||||
                                <label class="form-label">Cluster Name:</label>
 | 
			
		||||
                                <input type="text" class="form-control" id="newClusterNameInput" value="Cluster #1">
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="modal-footer">
 | 
			
		||||
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
 | 
			
		||||
                    <button type="button" class="btn btn-primary" onclick="assignSlice()">Assign Slice</button>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    
 | 
			
		||||
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
 | 
			
		||||
    <script>
 | 
			
		||||
        let currentSliceElement = null;
 | 
			
		||||
        let clusters = {};
 | 
			
		||||
        let clusterCounter = 0;
 | 
			
		||||
        
 | 
			
		||||
        function openAssignmentModal(sliceElement) {
 | 
			
		||||
            currentSliceElement = sliceElement;
 | 
			
		||||
            
 | 
			
		||||
            // Reset selections
 | 
			
		||||
            document.querySelectorAll('.assignment-option').forEach(opt => opt.classList.remove('selected'));
 | 
			
		||||
            document.getElementById('clusterRoleSelector').style.display = 'none';
 | 
			
		||||
            document.getElementById('newClusterName').style.display = 'none';
 | 
			
		||||
            
 | 
			
		||||
            // Populate cluster dropdown
 | 
			
		||||
            populateClusterDropdown();
 | 
			
		||||
            
 | 
			
		||||
            // Set current state
 | 
			
		||||
            const currentAssignment = sliceElement.dataset.assignment;
 | 
			
		||||
            const currentCluster = sliceElement.dataset.cluster;
 | 
			
		||||
            const currentRole = sliceElement.dataset.role;
 | 
			
		||||
            
 | 
			
		||||
            if (currentAssignment === 'individual') {
 | 
			
		||||
                document.querySelector('[data-assignment="individual"]').classList.add('selected');
 | 
			
		||||
            } else if (currentAssignment === 'cluster') {
 | 
			
		||||
                document.querySelector('[data-assignment="cluster"]').classList.add('selected');
 | 
			
		||||
                document.getElementById('clusterRoleSelector').style.display = 'block';
 | 
			
		||||
                
 | 
			
		||||
                if (currentCluster) {
 | 
			
		||||
                    document.getElementById('clusterSelect').value = currentCluster;
 | 
			
		||||
                    document.getElementById('newClusterName').style.display = 'none';
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                if (currentRole === 'master') {
 | 
			
		||||
                    document.getElementById('masterRole').checked = true;
 | 
			
		||||
                } else {
 | 
			
		||||
                    document.getElementById('workerRole').checked = true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            new bootstrap.Modal(document.getElementById('assignmentModal')).show();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function selectAssignment(optionElement) {
 | 
			
		||||
            document.querySelectorAll('.assignment-option').forEach(opt => opt.classList.remove('selected'));
 | 
			
		||||
            optionElement.classList.add('selected');
 | 
			
		||||
            
 | 
			
		||||
            if (optionElement.dataset.assignment === 'cluster') {
 | 
			
		||||
                document.getElementById('clusterRoleSelector').style.display = 'block';
 | 
			
		||||
                updateClusterNameVisibility();
 | 
			
		||||
            } else {
 | 
			
		||||
                document.getElementById('clusterRoleSelector').style.display = 'none';
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function populateClusterDropdown() {
 | 
			
		||||
            const select = document.getElementById('clusterSelect');
 | 
			
		||||
            select.innerHTML = '<option value="new">+ Create New Cluster</option>';
 | 
			
		||||
            
 | 
			
		||||
            Object.keys(clusters).forEach(clusterId => {
 | 
			
		||||
                const option = document.createElement('option');
 | 
			
		||||
                option.value = clusterId;
 | 
			
		||||
                option.textContent = clusters[clusterId].name;
 | 
			
		||||
                select.appendChild(option);
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            select.addEventListener('change', updateClusterNameVisibility);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function updateClusterNameVisibility() {
 | 
			
		||||
            const select = document.getElementById('clusterSelect');
 | 
			
		||||
            const newClusterDiv = document.getElementById('newClusterName');
 | 
			
		||||
            
 | 
			
		||||
            if (select.value === 'new') {
 | 
			
		||||
                newClusterDiv.style.display = 'block';
 | 
			
		||||
                clusterCounter++;
 | 
			
		||||
                document.getElementById('newClusterNameInput').value = `Cluster #${clusterCounter}`;
 | 
			
		||||
            } else {
 | 
			
		||||
                newClusterDiv.style.display = 'none';
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function assignSlice() {
 | 
			
		||||
            const selectedOption = document.querySelector('.assignment-option.selected');
 | 
			
		||||
            if (!selectedOption) return;
 | 
			
		||||
            
 | 
			
		||||
            const assignment = selectedOption.dataset.assignment;
 | 
			
		||||
            
 | 
			
		||||
            if (assignment === 'individual') {
 | 
			
		||||
                updateSliceAssignment(currentSliceElement, 'individual', '', '');
 | 
			
		||||
            } else if (assignment === 'cluster') {
 | 
			
		||||
                const clusterSelect = document.getElementById('clusterSelect');
 | 
			
		||||
                const roleInputs = document.querySelectorAll('input[name="nodeRole"]');
 | 
			
		||||
                let selectedRole = '';
 | 
			
		||||
                
 | 
			
		||||
                roleInputs.forEach(input => {
 | 
			
		||||
                    if (input.checked) selectedRole = input.value;
 | 
			
		||||
                });
 | 
			
		||||
                
 | 
			
		||||
                let clusterId = clusterSelect.value;
 | 
			
		||||
                let clusterName = '';
 | 
			
		||||
                
 | 
			
		||||
                if (clusterId === 'new') {
 | 
			
		||||
                    clusterName = document.getElementById('newClusterNameInput').value || `Cluster #${clusterCounter}`;
 | 
			
		||||
                    clusterId = 'cluster_' + Date.now();
 | 
			
		||||
                    
 | 
			
		||||
                    clusters[clusterId] = {
 | 
			
		||||
                        name: clusterName,
 | 
			
		||||
                        slices: []
 | 
			
		||||
                    };
 | 
			
		||||
                    
 | 
			
		||||
                    createClusterDisplay(clusterId, clusterName);
 | 
			
		||||
                } else {
 | 
			
		||||
                    clusterName = clusters[clusterId].name;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                updateSliceAssignment(currentSliceElement, 'cluster', clusterId, selectedRole);
 | 
			
		||||
                clusters[clusterId].slices.push(currentSliceElement.dataset.sliceId);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            updateDeploymentOverview();
 | 
			
		||||
            bootstrap.Modal.getInstance(document.getElementById('assignmentModal')).hide();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function updateSliceAssignment(sliceElement, assignment, clusterId, role) {
 | 
			
		||||
            sliceElement.dataset.assignment = assignment;
 | 
			
		||||
            sliceElement.dataset.cluster = clusterId;
 | 
			
		||||
            sliceElement.dataset.role = role;
 | 
			
		||||
            
 | 
			
		||||
            const badge = sliceElement.querySelector('.assignment-badge');
 | 
			
		||||
            
 | 
			
		||||
            sliceElement.className = 'slice-card';
 | 
			
		||||
            
 | 
			
		||||
            if (assignment === 'individual') {
 | 
			
		||||
                sliceElement.classList.add('assigned-individual');
 | 
			
		||||
                badge.className = 'assignment-badge badge-individual';
 | 
			
		||||
                badge.textContent = 'Individual VM';
 | 
			
		||||
            } else if (assignment === 'cluster') {
 | 
			
		||||
                if (role === 'master') {
 | 
			
		||||
                    sliceElement.classList.add('assigned-master');
 | 
			
		||||
                    badge.className = 'assignment-badge badge-master';
 | 
			
		||||
                    badge.textContent = `${clusters[clusterId].name} (Master)`;
 | 
			
		||||
                } else {
 | 
			
		||||
                    sliceElement.classList.add('assigned-worker');
 | 
			
		||||
                    badge.className = 'assignment-badge badge-worker';
 | 
			
		||||
                    badge.textContent = `${clusters[clusterId].name} (Worker)`;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function createClusterDisplay(clusterId, clusterName) {
 | 
			
		||||
            const container = document.getElementById('clustersContainer');
 | 
			
		||||
            
 | 
			
		||||
            const clusterDiv = document.createElement('div');
 | 
			
		||||
            clusterDiv.className = 'card mt-3';
 | 
			
		||||
            clusterDiv.id = `cluster_${clusterId}`;
 | 
			
		||||
            clusterDiv.innerHTML = `
 | 
			
		||||
                <div class="card-header d-flex justify-content-between align-items-center">
 | 
			
		||||
                    <h6 class="mb-0">${clusterName}</h6>
 | 
			
		||||
                    <button class="btn btn-sm btn-outline-danger" onclick="deleteCluster('${clusterId}')">Delete</button>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    <small class="text-muted">Cluster created</small>
 | 
			
		||||
                </div>
 | 
			
		||||
            `;
 | 
			
		||||
            
 | 
			
		||||
            container.appendChild(clusterDiv);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function deleteCluster(clusterId) {
 | 
			
		||||
            // Reassign all slices in this cluster to individual
 | 
			
		||||
            clusters[clusterId].slices.forEach(sliceId => {
 | 
			
		||||
                const sliceElement = document.querySelector(`[data-slice-id="${sliceId}"]`);
 | 
			
		||||
                if (sliceElement) {
 | 
			
		||||
                    updateSliceAssignment(sliceElement, 'individual', '', '');
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            // Remove cluster
 | 
			
		||||
            delete clusters[clusterId];
 | 
			
		||||
            document.getElementById(`cluster_${clusterId}`).remove();
 | 
			
		||||
            updateDeploymentOverview();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function updateDeploymentOverview() {
 | 
			
		||||
            const allSlices = document.querySelectorAll('.slice-card');
 | 
			
		||||
            let individualCount = 0;
 | 
			
		||||
            let clusterCount = Object.keys(clusters).length;
 | 
			
		||||
            let totalCost = 0;
 | 
			
		||||
            
 | 
			
		||||
            allSlices.forEach(slice => {
 | 
			
		||||
                if (slice.dataset.assignment === 'individual') {
 | 
			
		||||
                    individualCount++;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                // Calculate cost from slice text
 | 
			
		||||
                const priceText = slice.querySelector('strong:last-child').textContent;
 | 
			
		||||
                const price = parseFloat(priceText.replace(' TFP', ''));
 | 
			
		||||
                totalCost += price;
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            document.getElementById('individualCount').textContent = individualCount;
 | 
			
		||||
            document.getElementById('clusterCount').textContent = clusterCount;
 | 
			
		||||
            document.getElementById('totalCost').textContent = totalCost.toFixed(2) + ' TFP';
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function updateClusterNameVisibility() {
 | 
			
		||||
            const select = document.getElementById('clusterSelect');
 | 
			
		||||
            const newClusterDiv = document.getElementById('newClusterName');
 | 
			
		||||
            
 | 
			
		||||
            if (select.value === 'new') {
 | 
			
		||||
                newClusterDiv.style.display = 'block';
 | 
			
		||||
                clusterCounter++;
 | 
			
		||||
                document.getElementById('newClusterNameInput').value = `Cluster #${clusterCounter}`;
 | 
			
		||||
            } else {
 | 
			
		||||
                newClusterDiv.style.display = 'none';
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function assignSlice() {
 | 
			
		||||
            const selectedOption = document.querySelector('.assignment-option.selected');
 | 
			
		||||
            if (!selectedOption) return;
 | 
			
		||||
            
 | 
			
		||||
            const assignment = selectedOption.dataset.assignment;
 | 
			
		||||
            
 | 
			
		||||
            if (assignment === 'individual') {
 | 
			
		||||
                updateSliceAssignment(currentSliceElement, 'individual', '', '');
 | 
			
		||||
            } else if (assignment === 'cluster') {
 | 
			
		||||
                const clusterSelect = document.getElementById('clusterSelect');
 | 
			
		||||
                const roleInputs = document.querySelectorAll('input[name="nodeRole"]');
 | 
			
		||||
                let selectedRole = '';
 | 
			
		||||
                
 | 
			
		||||
                roleInputs.forEach(input => {
 | 
			
		||||
                    if (input.checked) selectedRole = input.value;
 | 
			
		||||
                });
 | 
			
		||||
                
 | 
			
		||||
                let clusterId = clusterSelect.value;
 | 
			
		||||
                let clusterName = '';
 | 
			
		||||
                
 | 
			
		||||
                if (clusterId === 'new') {
 | 
			
		||||
                    clusterName = document.getElementById('newClusterNameInput').value || `Cluster #${clusterCounter}`;
 | 
			
		||||
                    clusterId = 'cluster_' + Date.now();
 | 
			
		||||
                    
 | 
			
		||||
                    clusters[clusterId] = {
 | 
			
		||||
                        name: clusterName,
 | 
			
		||||
                        slices: []
 | 
			
		||||
                    };
 | 
			
		||||
                    
 | 
			
		||||
                    createClusterDisplay(clusterId, clusterName);
 | 
			
		||||
                } else {
 | 
			
		||||
                    clusterName = clusters[clusterId].name;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                updateSliceAssignment(currentSliceElement, 'cluster', clusterId, selectedRole);
 | 
			
		||||
                clusters[clusterId].slices.push(currentSliceElement.dataset.sliceId);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            bootstrap.Modal.getInstance(document.getElementById('assignmentModal')).hide();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function updateSliceAssignment(sliceElement, assignment, clusterId, role) {
 | 
			
		||||
            sliceElement.dataset.assignment = assignment;
 | 
			
		||||
            sliceElement.dataset.cluster = clusterId;
 | 
			
		||||
            sliceElement.dataset.role = role;
 | 
			
		||||
            
 | 
			
		||||
            const badge = sliceElement.querySelector('.assignment-badge');
 | 
			
		||||
            
 | 
			
		||||
            sliceElement.className = 'slice-card';
 | 
			
		||||
            
 | 
			
		||||
            if (assignment === 'individual') {
 | 
			
		||||
                sliceElement.classList.add('assigned-individual');
 | 
			
		||||
                badge.className = 'assignment-badge badge-individual';
 | 
			
		||||
                badge.textContent = 'Individual VM';
 | 
			
		||||
            } else if (assignment === 'cluster') {
 | 
			
		||||
                if (role === 'master') {
 | 
			
		||||
                    sliceElement.classList.add('assigned-master');
 | 
			
		||||
                    badge.className = 'assignment-badge badge-master';
 | 
			
		||||
                    badge.textContent = `${clusters[clusterId].name} (Master)`;
 | 
			
		||||
                } else {
 | 
			
		||||
                    sliceElement.classList.add('assigned-worker');
 | 
			
		||||
                    badge.className = 'assignment-badge badge-worker';
 | 
			
		||||
                    badge.textContent = `${clusters[clusterId].name} (Worker)`;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function createClusterDisplay(clusterId, clusterName) {
 | 
			
		||||
            const container = document.getElementById('clustersContainer');
 | 
			
		||||
            
 | 
			
		||||
            const clusterDiv = document.createElement('div');
 | 
			
		||||
            clusterDiv.className = 'card mt-3';
 | 
			
		||||
            clusterDiv.id = `cluster_${clusterId}`;
 | 
			
		||||
            clusterDiv.innerHTML = `
 | 
			
		||||
                <div class="card-header d-flex justify-content-between align-items-center">
 | 
			
		||||
                    <h6 class="mb-0">${clusterName}</h6>
 | 
			
		||||
                    <button class="btn btn-sm btn-outline-danger" onclick="deleteCluster('${clusterId}')">Delete</button>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="card-body">
 | 
			
		||||
                    <small class="text-muted">Cluster created</small>
 | 
			
		||||
                </div>
 | 
			
		||||
            `;
 | 
			
		||||
            
 | 
			
		||||
            container.appendChild(clusterDiv);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function deleteCluster(clusterId) {
 | 
			
		||||
            // Reassign all slices in this cluster to individual
 | 
			
		||||
            clusters[clusterId].slices.forEach(sliceId => {
 | 
			
		||||
                const sliceElement = document.querySelector(`[data-slice-id="${sliceId}"]`);
 | 
			
		||||
                if (sliceElement) {
 | 
			
		||||
                    updateSliceAssignment(sliceElement, 'individual', '', '');
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            // Remove cluster
 | 
			
		||||
            delete clusters[clusterId];
 | 
			
		||||
            document.getElementById(`cluster_${clusterId}`).remove();
 | 
			
		||||
            updateDeploymentOverview();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        function updateDeploymentOverview() {
 | 
			
		||||
            const allSlices = document.querySelectorAll('.slice-card');
 | 
			
		||||
            let individualCount = 0;
 | 
			
		||||
            let clusterCount = Object.keys(clusters).length;
 | 
			
		||||
            let totalCost = 0;
 | 
			
		||||
            
 | 
			
		||||
            allSlices.forEach(slice => {
 | 
			
		||||
                if (slice.dataset.assignment === 'individual') {
 | 
			
		||||
                    individualCount++;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                // Calculate cost from slice text
 | 
			
		||||
                const priceText = slice.querySelector('strong:last-child').textContent;
 | 
			
		||||
                const price = parseFloat(priceText.replace(' TFP', ''));
 | 
			
		||||
                totalCost += price;
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            document.getElementById('individualCount').textContent = individualCount;
 | 
			
		||||
            document.getElementById('clusterCount').textContent = clusterCount;
 | 
			
		||||
            document.getElementById('totalCost').textContent = totalCost.toFixed(2) + ' TFP';
 | 
			
		||||
        }
 | 
			
		||||
    </script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
		Reference in New Issue
	
	Block a user