{ if (e.key === 'Escape') openMenuId = null; }} />
{filteredCapsules.length} capsule{filteredCapsules.length !== 1 ? 's' : ''}
{#if error}
{error}. Try refreshing the page.
{/if}
ID
Template
{@render sortableHeader('CPU', 'vcpus')} {@render sortableHeader('Memory', 'memory_mb')} {@render sortableHeader('Idle Timeout', 'timeout_sec')} {@render sortableHeader('Started', 'started_at')} {@render sortableHeader('Status', 'status', 'right')}
{#if loading && capsules.length === 0}
Loading capsules...
{:else if filteredCapsules.length === 0 && searchQuery}

No matching capsules

No capsules match "{searchQuery}". Try a different ID.

{:else if filteredCapsules.length === 0}

No capsules yet

Each capsule is an isolated VM. Launch one to get started.

{:else} {#each filteredCapsules as capsule, i (capsule.id)} {@const stripeColor = capsule.status === 'running' ? 'bg-[var(--color-accent)]' : capsule.status === 'paused' ? 'bg-[var(--color-amber)]' : 'bg-[var(--color-text-muted)]'}
{#if capsule.status === 'running'} {:else if capsule.status === 'paused'} {:else} {/if} {#if searchQuery && capsule.id.toLowerCase().includes(searchQuery.toLowerCase())} {@const matchIdx = capsule.id.toLowerCase().indexOf(searchQuery.toLowerCase())} {capsule.id.slice(0, matchIdx)}{capsule.id.slice(matchIdx, matchIdx + searchQuery.length)}{capsule.id.slice(matchIdx + searchQuery.length)} {:else} {capsule.id} {/if}
{capsule.template}
{capsule.vcpus}
{capsule.memory_mb}MB
{fmtTimeout(capsule.timeout_sec)}
{formatTime(capsule.started_at)} {#if capsule.last_active_at} active {timeAgo(capsule.last_active_at)} {/if}
{#if actionLoading === capsule.id} {:else} {/if}
{/each} {/if}
{#if openMenuId} {@const openCapsule = capsules.find((c) => c.id === openMenuId)} {#if openCapsule}
{#if openCapsule.status === 'running'} {:else if openCapsule.status === 'paused'} {/if}
{/if} {/if} {#if snapshotTarget} { snapshotTarget = null; }} onsnapshot={handleSnapshotDone} /> {/if} {#if destroyTarget} { destroyTarget = null; }} ondestroyed={handleDestroyed} /> {/if} { showCreateDialog = false; }} oncreated={handleCapsuleCreated} /> {#snippet sortableHeader(label: string, key: SortKey, align: 'left' | 'right' = 'left')} {/snippet}