Files
projectmycelium/html_template_tests/test_modal_flow.html
2025-09-01 21:37:01 -04:00

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>