forked from wrenn/wrenn
Minor UI copy updates across capsules and templates pages
This commit is contained in:
@ -47,7 +47,7 @@
|
||||
Capsules
|
||||
</h1>
|
||||
<p class="mt-2 text-ui text-[var(--color-text-secondary)]">
|
||||
Isolated VMs. Start cold in under a second — pause, snapshot, or destroy at will.
|
||||
All active and recent capsules across your team.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@ -247,6 +247,13 @@
|
||||
return `${Math.floor(seconds / 86400)}d ago`;
|
||||
}
|
||||
|
||||
function fmtTimeout(sec: number): string {
|
||||
if (!sec) return 'None';
|
||||
if (sec < 60) return `${sec}s`;
|
||||
if (sec < 3600) return `${Math.round(sec / 60)}m`;
|
||||
return `${Math.round(sec / 3600)}h`;
|
||||
}
|
||||
|
||||
function handleClickOutside(event: MouseEvent) {
|
||||
if (openMenuId && !(event.target as Element)?.closest('.status-menu-container')) {
|
||||
openMenuId = null;
|
||||
@ -300,7 +307,7 @@
|
||||
class="w-full rounded-[var(--radius-input)] border border-[var(--color-border)] bg-[var(--color-bg-2)] py-2 pl-9 pr-3 font-mono text-ui text-[var(--color-text-bright)] outline-none placeholder:text-[var(--color-text-muted)] transition-colors duration-150 focus:border-[var(--color-accent)]"
|
||||
/>
|
||||
</div>
|
||||
<span class="text-ui text-[var(--color-text-secondary)]">{filteredCapsules.length} total</span>
|
||||
<span class="text-ui text-[var(--color-text-secondary)]">{filteredCapsules.length} capsule{filteredCapsules.length !== 1 ? 's' : ''}</span>
|
||||
|
||||
<div class="flex-1"></div>
|
||||
|
||||
@ -363,8 +370,11 @@
|
||||
</div>
|
||||
|
||||
{#if error}
|
||||
<div class="mb-4 rounded-[var(--radius-card)] border border-[var(--color-red)]/30 bg-[var(--color-red)]/5 px-4 py-3 text-ui text-[var(--color-red)]">
|
||||
{error}
|
||||
<div class="mb-4 flex items-start gap-3 rounded-[var(--radius-card)] border border-[var(--color-red)]/30 bg-[var(--color-red)]/5 px-4 py-3">
|
||||
<svg class="mt-0.5 shrink-0 text-[var(--color-red)]" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="10" /><line x1="12" y1="8" x2="12" y2="12" /><line x1="12" y1="16" x2="12.01" y2="16" />
|
||||
</svg>
|
||||
<span class="text-ui text-[var(--color-red)]">{error}. Try refreshing the page.</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@ -466,14 +476,14 @@
|
||||
|
||||
<!-- Idle Timeout -->
|
||||
<div class="px-5 py-4">
|
||||
<span class="font-mono text-ui text-[var(--color-text-secondary)]">{capsule.timeout_sec ? `${capsule.timeout_sec}s` : '—'}</span>
|
||||
<span class="font-mono text-ui text-[var(--color-text-secondary)]">{fmtTimeout(capsule.timeout_sec)}</span>
|
||||
</div>
|
||||
|
||||
<!-- Started -->
|
||||
<div class="px-5 py-4">
|
||||
<span class="text-ui text-[var(--color-text-secondary)]" title={capsule.started_at ?? ''}>{formatTime(capsule.started_at)}</span>
|
||||
{#if capsule.last_active_at}
|
||||
<span class="ml-1.5 text-label text-[var(--color-text-muted)]">{timeAgo(capsule.last_active_at)}</span>
|
||||
<span class="ml-1.5 text-label text-[var(--color-text-muted)]">active {timeAgo(capsule.last_active_at)}</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@ -612,7 +622,7 @@
|
||||
<line x1="12" y1="9" x2="12" y2="13" />
|
||||
<line x1="12" y1="17" x2="12.01" y2="17" />
|
||||
</svg>
|
||||
<p class="text-meta text-[var(--color-amber)] leading-relaxed">This capsule will be <strong class="font-semibold">paused first</strong> — memory state is captured at rest.</p>
|
||||
<p class="text-meta text-[var(--color-amber)] leading-relaxed">This capsule will be <strong class="font-semibold">paused first</strong>, then its full state (memory + disk) will be captured.</p>
|
||||
</div>
|
||||
{:else}
|
||||
<p class="text-ui text-[var(--color-text-tertiary)]">The capsule's current memory state will be captured and stored as a reusable snapshot.</p>
|
||||
|
||||
@ -512,7 +512,7 @@
|
||||
<svg class="shrink-0 text-[var(--color-red)]" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="10" /><line x1="12" y1="8" x2="12" y2="12" /><line x1="12" y1="16" x2="12.01" y2="16" />
|
||||
</svg>
|
||||
<span class="text-ui text-[var(--color-red)]">Failed to load metrics: {metricsError}</span>
|
||||
<span class="text-ui text-[var(--color-red)]">Could not load metrics: {metricsError}. Will retry automatically.</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
||||
@ -114,15 +114,15 @@
|
||||
}
|
||||
|
||||
function emptyHeading(f: TypeFilter): string {
|
||||
if (f === 'snapshot') return 'No snapshots';
|
||||
if (f === 'base') return 'No images';
|
||||
return 'No templates yet';
|
||||
if (f === 'snapshot') return 'No snapshots yet';
|
||||
if (f === 'base') return 'No base images';
|
||||
return 'No snapshots yet';
|
||||
}
|
||||
|
||||
function emptyDescription(f: TypeFilter): string {
|
||||
if (f === 'snapshot') return 'Pause a capsule from the Capsules page, then snapshot it to capture its state.';
|
||||
if (f === 'base') return 'Base images are added by the Wrenn team. Contact support to request a custom image.';
|
||||
return 'To create a snapshot, go to Capsules, pause a running capsule, then choose Snapshot.';
|
||||
if (f === 'snapshot') return 'Pause a running capsule, then choose Snapshot to save its state.';
|
||||
if (f === 'base') return 'Base images are provided by the Wrenn team. Contact support to request a custom one.';
|
||||
return 'Pause a running capsule, then choose Snapshot to save its state. You can launch new capsules from any snapshot.';
|
||||
}
|
||||
|
||||
onMount(fetchSnapshots);
|
||||
@ -162,7 +162,7 @@
|
||||
Templates
|
||||
</h1>
|
||||
<p class="mt-2 text-ui text-[var(--color-text-secondary)]">
|
||||
Snapshots capture a live capsule state. Base images are the rootfs every capsule starts from. Launch a full VM from any template.
|
||||
Snapshots capture a running capsule's state. Base images are the starting point for every new capsule. Launch from either.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -206,8 +206,11 @@
|
||||
{#if pageTab === 'snapshots'}
|
||||
<div class="p-8" style="animation: fadeUp 0.35s ease both">
|
||||
{#if error}
|
||||
<div class="mb-4 rounded-[var(--radius-card)] border border-[var(--color-red)]/30 bg-[var(--color-red)]/5 px-4 py-3 text-ui text-[var(--color-red)]">
|
||||
{error}
|
||||
<div class="mb-4 flex items-start gap-3 rounded-[var(--radius-card)] border border-[var(--color-red)]/30 bg-[var(--color-red)]/5 px-4 py-3">
|
||||
<svg class="mt-0.5 shrink-0 text-[var(--color-red)]" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="10" /><line x1="12" y1="8" x2="12" y2="12" /><line x1="12" y1="16" x2="12.01" y2="16" />
|
||||
</svg>
|
||||
<span class="text-ui text-[var(--color-red)]">{error}. Try refreshing the page.</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@ -274,11 +277,11 @@
|
||||
</div>
|
||||
<span class="text-meta text-[var(--color-text-muted)]">
|
||||
{filteredSnapshots.length}
|
||||
{typeFilter === 'all'
|
||||
? filteredSnapshots.length === 1 ? 'template' : 'templates'
|
||||
: typeFilter === 'snapshot'
|
||||
? filteredSnapshots.length === 1 ? 'snapshot' : 'snapshots'
|
||||
: filteredSnapshots.length === 1 ? 'image' : 'images'}
|
||||
{typeFilter === 'snapshot'
|
||||
? filteredSnapshots.length === 1 ? 'snapshot' : 'snapshots'
|
||||
: typeFilter === 'base'
|
||||
? filteredSnapshots.length === 1 ? 'image' : 'images'
|
||||
: filteredSnapshots.length === 1 ? 'item' : 'total'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@ -447,11 +450,11 @@
|
||||
|
||||
<p class="mt-3 text-meta text-[var(--color-text-muted)]">
|
||||
{filteredSnapshots.length}
|
||||
{typeFilter === 'all'
|
||||
? filteredSnapshots.length === 1 ? 'template' : 'templates'
|
||||
: typeFilter === 'snapshot'
|
||||
? filteredSnapshots.length === 1 ? 'snapshot' : 'snapshots'
|
||||
: filteredSnapshots.length === 1 ? 'image' : 'images'}
|
||||
{typeFilter === 'snapshot'
|
||||
? filteredSnapshots.length === 1 ? 'snapshot' : 'snapshots'
|
||||
: typeFilter === 'base'
|
||||
? filteredSnapshots.length === 1 ? 'image' : 'images'
|
||||
: filteredSnapshots.length === 1 ? 'item' : 'total'}
|
||||
{typeFilter !== 'all' ? '· filtered' : '· total'}
|
||||
</p>
|
||||
{/if}
|
||||
@ -513,10 +516,10 @@
|
||||
class="relative w-full max-w-[380px] rounded-[var(--radius-card)] border border-[var(--color-border-mid)] bg-[var(--color-bg-2)] p-6"
|
||||
style="animation: fadeUp 0.2s ease both"
|
||||
>
|
||||
<h2 class="font-serif text-heading tracking-[-0.02em] text-[var(--color-text-bright)]">Delete Snapshot</h2>
|
||||
<h2 class="font-serif text-heading tracking-[-0.02em] text-[var(--color-text-bright)]">Delete snapshot</h2>
|
||||
<p class="mt-2 text-ui text-[var(--color-text-tertiary)]">
|
||||
Permanently delete <span class="font-mono font-medium text-[var(--color-text-secondary)]">{deleteTarget.name}</span>.
|
||||
Any capsule using this template will not be affected, but you won't be able to launch from it again.
|
||||
Running capsules won't be affected, but you won't be able to launch new ones from it.
|
||||
</p>
|
||||
|
||||
{#if deleteTarget.type === 'snapshot'}
|
||||
@ -526,7 +529,7 @@
|
||||
<line x1="12" y1="9" x2="12" y2="13" /><line x1="12" y1="17" x2="12.01" y2="17" />
|
||||
</svg>
|
||||
<p class="text-meta leading-relaxed text-[var(--color-amber)]">
|
||||
This live capture includes saved memory state. Any capsule relying on it will be unable to resume.
|
||||
This snapshot includes memory state. Paused capsules that depend on it won't be able to resume.
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
@ -580,7 +583,7 @@
|
||||
>
|
||||
<h2 class="font-serif text-heading tracking-[-0.02em] text-[var(--color-text-bright)]">Launch Capsule</h2>
|
||||
<p class="mt-1 text-ui text-[var(--color-text-tertiary)]">
|
||||
Configure resources and launch. The VM will clone from this template and be ready in seconds.
|
||||
Configure resources and launch a new capsule from this snapshot.
|
||||
</p>
|
||||
|
||||
{#if launchError}
|
||||
@ -655,14 +658,16 @@
|
||||
|
||||
<!-- Timeout -->
|
||||
<div class="mt-4">
|
||||
<label class="mb-1.5 block text-label font-semibold uppercase tracking-[0.05em] text-[var(--color-text-tertiary)]" for="launch-timeout">Auto-pause timeout (seconds, 0 = never)</label>
|
||||
<label class="mb-1.5 block text-label font-semibold uppercase tracking-[0.05em] text-[var(--color-text-tertiary)]" for="launch-timeout">Idle timeout</label>
|
||||
<input
|
||||
id="launch-timeout"
|
||||
type="number"
|
||||
min="0"
|
||||
bind:value={launchTimeoutSec}
|
||||
placeholder="0"
|
||||
class="w-full rounded-[var(--radius-input)] border border-[var(--color-border)] bg-[var(--color-bg-4)] px-3 py-2 font-mono text-ui text-[var(--color-text-bright)] outline-none transition-colors duration-150 focus:border-[var(--color-accent)]"
|
||||
/>
|
||||
<p class="mt-1.5 text-meta text-[var(--color-text-muted)]">Seconds of inactivity before the capsule pauses. Set to 0 to keep it running indefinitely.</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex justify-end gap-3">
|
||||
|
||||
Reference in New Issue
Block a user