feat: landing page with Download, SCP Pull, and Resume cards
- Hero header at top describing the app - Two side-by-side cards: Download (URL) and SCP Pull - Resume sessions section appears above cards when sessions exist - Download card expands to inline form - Resume asks for VM Name/ID only, skips URL field - Clean separation of entry points
This commit is contained in:
parent
162110b4b1
commit
df6b8085ca
2 changed files with 125 additions and 41 deletions
|
|
@ -293,3 +293,50 @@ body {
|
|||
.pve-divider { border: none; border-top: 1px solid var(--pve-border); margin: 1rem 0; }
|
||||
.pve-code { background: #f5f5f5; padding: 0.1rem 0.4rem; border-radius: 2px; font-size: 0.78rem; }
|
||||
.pve-center { text-align: center; }
|
||||
|
||||
/* ── Landing page ─────────────────────────────────────────────── */
|
||||
.pve-hero {
|
||||
text-align: center;
|
||||
padding: 1.8rem 1rem 1.2rem;
|
||||
}
|
||||
.pve-hero h1 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: var(--pve-text);
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
.pve-hero p {
|
||||
font-size: 0.82rem;
|
||||
color: var(--pve-muted);
|
||||
}
|
||||
|
||||
.landing-cards {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
@media (max-width: 520px) { .landing-cards { grid-template-columns: 1fr; } }
|
||||
|
||||
.landing-card {
|
||||
background: var(--pve-panel-bg);
|
||||
border: 1px solid var(--pve-border);
|
||||
border-radius: var(--pve-radius);
|
||||
padding: 1.2rem 1rem;
|
||||
text-align: center;
|
||||
cursor: default;
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.04);
|
||||
}
|
||||
.landing-card:hover { border-color: var(--pve-accent); }
|
||||
.landing-card-icon { font-size: 1.6rem; margin-bottom: 0.4rem; }
|
||||
.landing-card h3 {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
.landing-card p {
|
||||
font-size: 0.75rem;
|
||||
color: var(--pve-muted);
|
||||
margin-bottom: 0.75rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,52 +1,62 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<div class="pve-hero">
|
||||
<h1>VM Bench</h1>
|
||||
<p>Convert VMware images to Proxmox VMs — automatic OS detection, disk shrink, EFI probing.</p>
|
||||
</div>
|
||||
|
||||
<div id="resume-sessions" class="pve-panel pve-hidden">
|
||||
<div class="pve-panel-header">
|
||||
<span class="pve-panel-title">Resume Previous Session</span>
|
||||
<span class="pve-panel-title">Resume Previous Sessions</span>
|
||||
</div>
|
||||
<div class="pve-panel-body" id="resume-sessions-list">
|
||||
<div class="pve-panel-body" id="resume-sessions-list"></div>
|
||||
</div>
|
||||
|
||||
<div class="landing-cards">
|
||||
<div class="landing-card" id="card-download">
|
||||
<div class="landing-card-icon">📥</div>
|
||||
<h3>Download</h3>
|
||||
<p>Pull a disk image or archive from a URL via high-speed download.</p>
|
||||
<button class="pve-btn pve-btn-primary" onclick="showDownload()">Start</button>
|
||||
</div>
|
||||
<div class="landing-card" id="card-scp">
|
||||
<div class="landing-card-icon">📡</div>
|
||||
<h3>SCP Pull</h3>
|
||||
<p>Transfer files directly from a remote server via SCP — no middle hop.</p>
|
||||
<a href="/scp" class="pve-btn pve-btn-primary">Start</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pve-panel" id="step1">
|
||||
<div id="download-section" class="pve-panel pve-hidden">
|
||||
<div class="pve-panel-header">
|
||||
<span class="pve-panel-title">New Conversion Session</span>
|
||||
<span class="pve-panel-title" id="download-title">New Download Session</span>
|
||||
</div>
|
||||
<div class="pve-panel-body">
|
||||
|
||||
<form id="session-form" onsubmit="startSession(event)">
|
||||
<div class="pve-form-group">
|
||||
<label for="vm-name">VM Name *</label>
|
||||
<input type="text" id="vm-name" name="vm_name" required class="pve-input"
|
||||
placeholder="e.g. debian-test" value="{{ prefill_vmname or '' }}">
|
||||
<span class="pve-hint">Display name for the VM on the Proxmox host.</span>
|
||||
<div class="pve-row">
|
||||
<div class="pve-form-group">
|
||||
<label>VM Name *</label>
|
||||
<input type="text" id="vm-name" name="vm_name" required class="pve-input"
|
||||
placeholder="e.g. debian-test" value="{{ prefill_vmname or '' }}">
|
||||
</div>
|
||||
<div class="pve-form-group">
|
||||
<label>VM ID *</label>
|
||||
<input type="number" id="vmid" name="vmid" required class="pve-input"
|
||||
placeholder="e.g. 21050" min="21000" max="21100">
|
||||
<span class="pve-hint">Range 21000–21100. Must be unique on host.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pve-form-group">
|
||||
<label for="vmid">VM ID *</label>
|
||||
<input type="number" id="vmid" name="vmid" required class="pve-input"
|
||||
placeholder="e.g. 21050" min="21000" max="21100">
|
||||
<span class="pve-hint">Range 21000–21100. Must be unique on the Proxmox host.</span>
|
||||
</div>
|
||||
|
||||
<div class="pve-form-group">
|
||||
<label for="source-url">Download URL *</label>
|
||||
<div class="pve-form-group" id="url-group">
|
||||
<label>Download URL *</label>
|
||||
<input type="url" id="source-url" name="source_url" required class="pve-input"
|
||||
placeholder="https://example.com/image.7z">
|
||||
<span class="pve-hint">Direct URL to a disk image or archive (.vmdk, .7z, .zip, etc.)</span>
|
||||
</div>
|
||||
|
||||
<button type="submit" id="start-btn" class="pve-btn pve-btn-primary">Download & Analyse</button>
|
||||
<button type="button" class="pve-btn" onclick="hideDownload()" style="margin-left:0.5rem;">Cancel</button>
|
||||
</form>
|
||||
|
||||
<hr class="pve-divider">
|
||||
<p class="pve-dim" style="font-size:0.78rem; margin-bottom:0.5rem;">
|
||||
Files on a remote server? Pull directly via SCP:
|
||||
</p>
|
||||
<a href="/scp" class="pve-btn">SCP Pull</a>
|
||||
|
||||
<!-- Progress area -->
|
||||
<div id="session-status" class="pve-hidden" style="margin-top:1rem;">
|
||||
<div id="phase-label" style="margin-bottom:0.5rem;"></div>
|
||||
<div class="pve-progress">
|
||||
|
|
@ -63,6 +73,24 @@
|
|||
<script>
|
||||
loadSessions();
|
||||
|
||||
function showDownload() {
|
||||
document.getElementById('card-download').style.display = 'none';
|
||||
document.getElementById('card-scp').style.display = 'none';
|
||||
document.getElementById('download-section').classList.remove('pve-hidden');
|
||||
document.getElementById('download-title').textContent = 'New Download Session';
|
||||
document.getElementById('url-group').classList.remove('pve-hidden');
|
||||
document.getElementById('start-btn').textContent = 'Download & Analyse';
|
||||
document.getElementById('start-btn').onclick = null; // restore form submit
|
||||
document.getElementById('source-url').required = true;
|
||||
}
|
||||
|
||||
function hideDownload() {
|
||||
document.getElementById('card-download').style.display = '';
|
||||
document.getElementById('card-scp').style.display = '';
|
||||
document.getElementById('download-section').classList.add('pve-hidden');
|
||||
window.RESUMED_SID = null;
|
||||
}
|
||||
|
||||
async function loadSessions() {
|
||||
try {
|
||||
var resp = await fetch('/session/sessions');
|
||||
|
|
@ -89,17 +117,26 @@ async function loadSessions() {
|
|||
}
|
||||
|
||||
function resumeSession(sessionId, firstFile) {
|
||||
var vmid = document.getElementById('vmid').value;
|
||||
var vmName = document.getElementById('vm-name').value.trim();
|
||||
if (!vmid) { alert('Please enter a VM ID first.'); return; }
|
||||
window.RESUMED_SID = sessionId;
|
||||
var ses = document.getElementById('resume-sessions');
|
||||
ses.classList.add('pve-hidden');
|
||||
document.getElementById('step1').style.display = 'none';
|
||||
var status = document.getElementById('session-status');
|
||||
status.classList.remove('pve-hidden');
|
||||
setPhase('Analysing source image...', 0, true);
|
||||
runAnalysis(vmid, firstFile, vmName, sessionId);
|
||||
document.getElementById('card-download').style.display = 'none';
|
||||
document.getElementById('card-scp').style.display = 'none';
|
||||
document.getElementById('download-section').classList.remove('pve-hidden');
|
||||
document.getElementById('download-title').textContent = 'Resume Session';
|
||||
document.getElementById('url-group').classList.add('pve-hidden');
|
||||
var btn = document.getElementById('start-btn');
|
||||
btn.textContent = 'Resume Analysis';
|
||||
btn.onclick = function(e) {
|
||||
e.preventDefault();
|
||||
var vmid = document.getElementById('vmid').value;
|
||||
var vmName = document.getElementById('vm-name').value.trim();
|
||||
if (!vmid) { alert('Please enter a VM ID.'); return; }
|
||||
window.RESUMED_SID = sessionId;
|
||||
document.getElementById('resume-sessions').classList.add('pve-hidden');
|
||||
var status = document.getElementById('session-status');
|
||||
status.classList.remove('pve-hidden');
|
||||
setPhase('Analysing source image...', 0, true);
|
||||
runAnalysis(vmid, firstFile, vmName, sessionId);
|
||||
};
|
||||
document.getElementById('source-url').required = false;
|
||||
}
|
||||
|
||||
function setPhase(label, pct, isSpinner) {
|
||||
|
|
@ -278,7 +315,7 @@ async function submitJob(e) {
|
|||
try {
|
||||
const resp = await fetch('/session/confirm', { method: 'POST', body: formData });
|
||||
const html = await resp.text();
|
||||
document.getElementById('step1').style.display = 'none';
|
||||
document.getElementById('download-section').style.display = 'none';
|
||||
document.getElementById('analysis-section').innerHTML = '';
|
||||
document.getElementById('polling-section').innerHTML = html;
|
||||
initPolling();
|
||||
|
|
|
|||
Loading…
Reference in a new issue