init tools repo
This commit is contained in:
208
asf-cloud-server/TBM_devbench/views/dashboard.ejs
Normal file
208
asf-cloud-server/TBM_devbench/views/dashboard.ejs
Normal file
@@ -0,0 +1,208 @@
|
||||
<%- include('layout', { body: `
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2><i class="fas fa-tachometer-alt"></i> My DevBenches</h2>
|
||||
<button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#createDevbenchModal">
|
||||
<i class="fas fa-plus"></i> Create DevBench
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
${devbenches.map(db => `
|
||||
<div class="col-md-6 col-lg-4 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h6 class="mb-0">${db.name}</h6>
|
||||
<span id="status-${db.id}" class="badge bg-${db.status === 'active' ? 'success' : db.status === 'creating' ? 'warning' : 'danger'}">
|
||||
${db.status}
|
||||
</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
${db.actual_name ? `
|
||||
<p><strong>VM Name:</strong> ${db.actual_name}</p>
|
||||
|
||||
${db.ssh_info || db.vnc_info ? `
|
||||
<div class="connection-info">
|
||||
<h6><i class="fas fa-plug"></i> Connection Info:</h6>
|
||||
${db.ssh_info ? `
|
||||
<div class="mb-3">
|
||||
<strong><i class="fas fa-terminal"></i> SSH Port:</strong><br>
|
||||
<code class="fs-5">${db.ssh_info}</code>
|
||||
<button class="btn btn-sm btn-outline-primary ms-2" onclick="copyToClipboard('${db.ssh_info}')">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
` : ''}
|
||||
${db.vnc_info ? `
|
||||
<div class="mb-3">
|
||||
<strong><i class="fas fa-desktop"></i> VNC Port:</strong><br>
|
||||
<code class="fs-5">${db.vnc_info}</code>
|
||||
<button class="btn btn-sm btn-outline-primary ms-2" onclick="copyToClipboard('${db.vnc_info}')">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
` : ''}
|
||||
<div class="alert alert-info mt-3">
|
||||
<i class="fas fa-info-circle"></i> Need help connecting?
|
||||
<a href="/help" class="alert-link">View setup guide</a>
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
` : `
|
||||
<p class="text-muted">DevBench is being created...</p>
|
||||
<div class="log-output" id="log-${db.id}"></div>
|
||||
`}
|
||||
|
||||
<p class="text-muted mt-2">
|
||||
<small>Created: ${new Date(db.created_at).toLocaleString()}</small>
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="btn-group w-100" role="group">
|
||||
${db.status !== 'creating' ? `
|
||||
<button class="btn btn-sm btn-primary" onclick="activateDevbench(${db.id})"
|
||||
${db.status === 'active' ? 'disabled' : ''}>
|
||||
<i class="fas fa-play"></i> Activate
|
||||
</button>
|
||||
<button class="btn btn-sm btn-info" onclick="checkStatus(${db.id})">
|
||||
<i class="fas fa-sync"></i> Check Status
|
||||
</button>
|
||||
` : ''}
|
||||
<button class="btn btn-sm btn-danger" onclick="deleteDevbench(${db.id})">
|
||||
<i class="fas fa-trash"></i> Delete
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
|
||||
${devbenches.length === 0 ? `
|
||||
<div class="col-12">
|
||||
<div class="text-center py-5">
|
||||
<i class="fas fa-server fa-3x text-muted mb-3"></i>
|
||||
<h4 class="text-muted">No DevBenches Yet</h4>
|
||||
<p class="text-muted">Create your first DevBench to get started!</p>
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
|
||||
<!-- Create DevBench Modal -->
|
||||
<div class="modal fade" id="createDevbenchModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Create New DevBench</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<form id="createDevbenchForm">
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label for="devbenchName" class="form-label">DevBench Name</label>
|
||||
<input type="text" class="form-control" id="devbenchName" name="name" required
|
||||
pattern="[a-zA-Z0-9_-]+" title="Only letters, numbers, hyphens, and underscores allowed">
|
||||
<div class="form-text">
|
||||
Only letters, numbers, hyphens (-), and underscores (_) are allowed.<br>
|
||||
Full name will be: <strong>${username}_[your-name]</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" class="btn btn-success">Create DevBench</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('createDevbenchForm').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(e.target);
|
||||
|
||||
try {
|
||||
const response = await fetch('/create-devbench', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(Object.fromEntries(formData))
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert(result.error);
|
||||
}
|
||||
} catch (error) {
|
||||
alert('Error creating DevBench');
|
||||
}
|
||||
});
|
||||
|
||||
async function deleteDevbench(devbenchId) {
|
||||
if (confirm('Are you sure you want to delete this DevBench?')) {
|
||||
try {
|
||||
const response = await fetch(\`/delete-devbench/\${devbenchId}\`, { method: 'POST' });
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert(result.error);
|
||||
}
|
||||
} catch (error) {
|
||||
alert('Error deleting DevBench');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function activateDevbench(devbenchId) {
|
||||
try {
|
||||
const response = await fetch(\`/activate-devbench/\${devbenchId}\`, { method: 'POST' });
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
alert('DevBench activation started');
|
||||
} else {
|
||||
alert(result.error);
|
||||
}
|
||||
} catch (error) {
|
||||
alert('Error activating DevBench');
|
||||
}
|
||||
}
|
||||
|
||||
async function checkStatus(devbenchId) {
|
||||
try {
|
||||
const response = await fetch(\`/check-status/\${devbenchId}\`);
|
||||
const result = await response.json();
|
||||
|
||||
const statusElement = document.getElementById(\`status-\${devbenchId}\`);
|
||||
if (statusElement) {
|
||||
statusElement.className = \`badge bg-\${result.status === 'active' ? 'success' : 'danger'}\`;
|
||||
statusElement.textContent = result.status;
|
||||
}
|
||||
} catch (error) {
|
||||
alert('Error checking status');
|
||||
}
|
||||
}
|
||||
|
||||
function copyToClipboard(text) {
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
// Show a temporary success message
|
||||
const toast = document.createElement('div');
|
||||
toast.className = 'alert alert-success position-fixed';
|
||||
toast.style.cssText = 'top: 20px; right: 20px; z-index: 9999; opacity: 0.9;';
|
||||
toast.innerHTML = '<i class="fas fa-check"></i> Copied to clipboard!';
|
||||
document.body.appendChild(toast);
|
||||
|
||||
setTimeout(() => {
|
||||
document.body.removeChild(toast);
|
||||
}, 2000);
|
||||
}).catch(err => {
|
||||
console.error('Failed to copy: ', err);
|
||||
alert('Failed to copy to clipboard');
|
||||
});
|
||||
}
|
||||
</script>
|
||||
`, username }) %>
|
||||
Reference in New Issue
Block a user