380 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			380 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<!DOCTYPE html>
 | 
						|
<html lang="en">
 | 
						|
<head>
 | 
						|
    <meta charset="UTF-8">
 | 
						|
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
						|
    <title>Test Modal 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>Test Modal Flow</h3>
 | 
						|
        
 | 
						|
        <!-- Test Slice -->
 | 
						|
        <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>test-slice</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>
 | 
						|
        
 | 
						|
        <!-- Debug Info -->
 | 
						|
        <div class="mt-4 p-3 bg-info bg-opacity-10 border border-info rounded">
 | 
						|
            <h6>Debug Info:</h6>
 | 
						|
            <div id="debugInfo">Ready to test...</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 debug(message) {
 | 
						|
            document.getElementById('debugInfo').innerHTML += '<br>' + message;
 | 
						|
            console.log(message);
 | 
						|
        }
 | 
						|
        
 | 
						|
        function openAssignmentModal(sliceElement) {
 | 
						|
            debug('Opening modal for slice: ' + sliceElement.dataset.sliceId);
 | 
						|
            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;
 | 
						|
            
 | 
						|
            debug('Current state - Assignment: ' + currentAssignment + ', Cluster: ' + currentCluster + ', Role: ' + currentRole);
 | 
						|
            
 | 
						|
            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';
 | 
						|
                
 | 
						|
                // Set cluster dropdown
 | 
						|
                document.getElementById('clusterSelect').value = currentCluster;
 | 
						|
                
 | 
						|
                // Set role radio button
 | 
						|
                document.querySelector(`input[name="nodeRole"][value="${currentRole}"]`).checked = true;
 | 
						|
                
 | 
						|
                // Don't show new cluster name field since we're editing existing assignment
 | 
						|
                document.getElementById('newClusterName').style.display = 'none';
 | 
						|
            }
 | 
						|
            
 | 
						|
            // Show modal
 | 
						|
            new bootstrap.Modal(document.getElementById('assignmentModal')).show();
 | 
						|
        }
 | 
						|
        
 | 
						|
        function populateClusterDropdown() {
 | 
						|
            const select = document.getElementById('clusterSelect');
 | 
						|
            select.innerHTML = '';
 | 
						|
            
 | 
						|
            // Add existing clusters
 | 
						|
            Object.keys(clusters).forEach(clusterId => {
 | 
						|
                const cluster = clusters[clusterId];
 | 
						|
                const displayName = cluster.customName || cluster.name;
 | 
						|
                const option = document.createElement('option');
 | 
						|
                option.value = clusterId;
 | 
						|
                option.textContent = displayName;
 | 
						|
                select.appendChild(option);
 | 
						|
            });
 | 
						|
            
 | 
						|
            // Add "Create New Cluster" option
 | 
						|
            const newOption = document.createElement('option');
 | 
						|
            newOption.value = 'new';
 | 
						|
            newOption.textContent = '+ Create New Cluster';
 | 
						|
            select.appendChild(newOption);
 | 
						|
        }
 | 
						|
        
 | 
						|
        function selectAssignment(optionElement) {
 | 
						|
            debug('Selected assignment: ' + optionElement.dataset.assignment);
 | 
						|
            
 | 
						|
            // Clear previous selections
 | 
						|
            document.querySelectorAll('.assignment-option').forEach(opt => opt.classList.remove('selected'));
 | 
						|
            
 | 
						|
            // Select current option
 | 
						|
            optionElement.classList.add('selected');
 | 
						|
            
 | 
						|
            // Show/hide cluster options
 | 
						|
            const isCluster = optionElement.dataset.assignment === 'cluster';
 | 
						|
            document.getElementById('clusterRoleSelector').style.display = isCluster ? 'block' : 'none';
 | 
						|
            
 | 
						|
            if (isCluster) {
 | 
						|
                debug('Showing cluster options');
 | 
						|
                
 | 
						|
                // Check if we should show new cluster name field
 | 
						|
                const clusterSelect = document.getElementById('clusterSelect');
 | 
						|
                const newClusterDiv = document.getElementById('newClusterName');
 | 
						|
                if (clusterSelect.value === 'new') {
 | 
						|
                    newClusterDiv.style.display = 'block';
 | 
						|
                    // Generate default name
 | 
						|
                    const nextNumber = clusterCounter + 1;
 | 
						|
                    document.getElementById('newClusterNameInput').value = `Cluster #${nextNumber}`;
 | 
						|
                } else {
 | 
						|
                    newClusterDiv.style.display = 'none';
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        
 | 
						|
        // Add event listener for cluster select change
 | 
						|
        document.addEventListener('DOMContentLoaded', function() {
 | 
						|
            document.getElementById('clusterSelect').addEventListener('change', function() {
 | 
						|
                const newClusterDiv = document.getElementById('newClusterName');
 | 
						|
                if (this.value === 'new') {
 | 
						|
                    newClusterDiv.style.display = 'block';
 | 
						|
                    // Generate default name
 | 
						|
                    const nextNumber = clusterCounter + 1;
 | 
						|
                    document.getElementById('newClusterNameInput').value = `Cluster #${nextNumber}`;
 | 
						|
                } else {
 | 
						|
                    newClusterDiv.style.display = 'none';
 | 
						|
                }
 | 
						|
            });
 | 
						|
        });
 | 
						|
        
 | 
						|
        function assignSlice() {
 | 
						|
            const selectedOption = document.querySelector('.assignment-option.selected');
 | 
						|
            if (!selectedOption) {
 | 
						|
                debug('ERROR: No assignment option selected');
 | 
						|
                alert('Please select an assignment option');
 | 
						|
                return;
 | 
						|
            }
 | 
						|
            
 | 
						|
            debug('Assigning slice with option: ' + selectedOption.dataset.assignment);
 | 
						|
            
 | 
						|
            if (selectedOption.dataset.assignment === 'individual') {
 | 
						|
                debug('Assigning as Individual VM');
 | 
						|
                updateSliceAssignment(currentSliceElement, 'individual', 'Individual VM', '', '');
 | 
						|
            } else if (selectedOption.dataset.assignment === 'cluster') {
 | 
						|
                const roleRadio = document.querySelector('input[name="nodeRole"]:checked');
 | 
						|
                
 | 
						|
                if (!roleRadio) {
 | 
						|
                    debug('ERROR: No role selected');
 | 
						|
                    alert('Please select a node role (Master or Worker)');
 | 
						|
                    return;
 | 
						|
                }
 | 
						|
                
 | 
						|
                const role = roleRadio.value;
 | 
						|
                debug('Creating new cluster with role: ' + role);
 | 
						|
                
 | 
						|
                // Create new cluster
 | 
						|
                clusterCounter++;
 | 
						|
                const clusterId = 'cluster' + clusterCounter;
 | 
						|
                const clusterName = document.getElementById('newClusterNameInput').value.trim() || `Cluster #${clusterCounter}`;
 | 
						|
                
 | 
						|
                clusters[clusterId] = {
 | 
						|
                    name: `Cluster #${clusterCounter}`,
 | 
						|
                    customName: clusterName !== `Cluster #${clusterCounter}` ? clusterName : '',
 | 
						|
                    masters: [],
 | 
						|
                    workers: []
 | 
						|
                };
 | 
						|
                
 | 
						|
                // Add slice to cluster
 | 
						|
                clusters[clusterId][role + 's'].push(currentSliceElement.dataset.sliceId);
 | 
						|
                
 | 
						|
                debug('Created cluster: ' + clusterId + ' with name: ' + clusterName);
 | 
						|
                
 | 
						|
                const displayName = clusters[clusterId].customName || clusters[clusterId].name;
 | 
						|
                const roleText = role === 'master' ? 'Master' : 'Worker';
 | 
						|
                updateSliceAssignment(currentSliceElement, role, `${displayName} ${roleText}`, clusterId, role);
 | 
						|
                
 | 
						|
                createClusterDisplay(clusterId);
 | 
						|
            }
 | 
						|
            
 | 
						|
            // Close modal
 | 
						|
            debug('Closing modal');
 | 
						|
            const modal = bootstrap.Modal.getInstance(document.getElementById('assignmentModal'));
 | 
						|
            if (modal) {
 | 
						|
                modal.hide();
 | 
						|
            }
 | 
						|
        }
 | 
						|
        
 | 
						|
        function updateSliceAssignment(sliceElement, type, badgeText, clusterId, role) {
 | 
						|
            debug('Updating slice assignment: ' + type + ' - ' + badgeText);
 | 
						|
            
 | 
						|
            // Remove old classes
 | 
						|
            sliceElement.classList.remove('assigned-individual', 'assigned-master', 'assigned-worker');
 | 
						|
            
 | 
						|
            // Add new class
 | 
						|
            sliceElement.classList.add(`assigned-${type}`);
 | 
						|
            
 | 
						|
            // Update badge
 | 
						|
            const badge = sliceElement.querySelector('.assignment-badge');
 | 
						|
            badge.className = `assignment-badge badge-${type}`;
 | 
						|
            badge.textContent = badgeText;
 | 
						|
            
 | 
						|
            // Update data attributes
 | 
						|
            sliceElement.dataset.assignment = type === 'individual' ? 'individual' : 'cluster';
 | 
						|
            sliceElement.dataset.cluster = clusterId;
 | 
						|
            sliceElement.dataset.role = role;
 | 
						|
        }
 | 
						|
        
 | 
						|
        function createClusterDisplay(clusterId) {
 | 
						|
            const cluster = clusters[clusterId];
 | 
						|
            const clustersContainer = document.getElementById('clustersContainer');
 | 
						|
            
 | 
						|
            debug('Creating cluster display for: ' + clusterId);
 | 
						|
            
 | 
						|
            const clusterDiv = document.createElement('div');
 | 
						|
            clusterDiv.className = 'mt-3 p-3 bg-success bg-opacity-10 border border-success rounded';
 | 
						|
            clusterDiv.id = `cluster-display-${clusterId}`;
 | 
						|
            
 | 
						|
            clusterDiv.innerHTML = `
 | 
						|
                <h6>Cluster: ${cluster.customName || cluster.name}</h6>
 | 
						|
                <p>Masters: ${cluster.masters.length}, Workers: ${cluster.workers.length}</p>
 | 
						|
            `;
 | 
						|
            
 | 
						|
            clustersContainer.appendChild(clusterDiv);
 | 
						|
        }
 | 
						|
    </script>
 | 
						|
</body>
 | 
						|
</html> |