Preserve originating views through detail navigation
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { contextHref } from '$lib/navigation-context.js';
|
||||
import { timeFormat } from '$ui/stores/time-zone.js';
|
||||
import { onMount } from 'svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
@@ -52,7 +54,19 @@
|
||||
const waiting=beta.servers.find(server=>server.stage!=='ready');
|
||||
return waiting?`${serverTitle(waiting.server)}: ${statusPresentation(waiting.stage).label.toLowerCase()}.`:'Waiting for test evaluation.';
|
||||
}
|
||||
$effect(() => { search; tab; limit = 25; });
|
||||
$effect(() => {
|
||||
const params = $page.url.searchParams;
|
||||
tab = params.get('view') === 'history' ? 'history' : 'active';
|
||||
search = params.get('q') ?? '';
|
||||
limit = Math.min(10000, Math.max(25, Number(params.get('limit')) || 25));
|
||||
});
|
||||
function saveContext() {
|
||||
const url = new URL($page.url);
|
||||
if (tab === 'history') url.searchParams.set('view', tab); else url.searchParams.delete('view');
|
||||
if (search) url.searchParams.set('q', search); else url.searchParams.delete('q');
|
||||
if (limit > 25) url.searchParams.set('limit', String(limit)); else url.searchParams.delete('limit');
|
||||
void goto(url, { replaceState: true, noScroll: true, keepFocus: true });
|
||||
}
|
||||
async function load() {
|
||||
try { const res = await fetch('/api/betas'); if (!res.ok) throw new Error('Could not refresh betas.'); betas = (await res.json()).betas; now=Date.now(); error = ''; }
|
||||
catch (e) { error = (e as Error).message; } finally { loading = false; }
|
||||
@@ -63,22 +77,23 @@
|
||||
return pollVisible(load, 5000);
|
||||
});
|
||||
</script>
|
||||
<svelte:head><title>Betas · Electric Cherry</title></svelte:head>
|
||||
<div class="page">
|
||||
<SectionHeader title="Betas" subtitle="Test selected versions before promoting them to the fleet.">
|
||||
{#snippet actions()}<Button variant="primary" href="/betas/new">New beta</Button>{/snippet}
|
||||
</SectionHeader>
|
||||
<Tabs {tabs} bind:value={tab} idPrefix="beta-tabs" panelId="beta-list" ariaLabel="Beta views" />
|
||||
<div class="ui-toolbar"><input type="search" bind:value={search} aria-label="Search betas" placeholder="Search betas or files…" /></div>
|
||||
<Tabs {tabs} bind:value={tab} onchange={() => { limit = 25; saveContext(); }} idPrefix="beta-tabs" panelId="beta-list" ariaLabel="Beta views" />
|
||||
<div class="ui-toolbar"><input type="search" bind:value={search} oninput={event => { search = event.currentTarget.value; limit = 25; saveContext(); }} aria-label="Search betas" placeholder="Search betas or files…" /></div>
|
||||
{#if error}<div class="ui-error" role="alert">{error} {betas.length ? 'Showing the last loaded results.' : ''}<Button size="sm" onclick={load}>Retry</Button></div>{/if}
|
||||
<div id="beta-list" role="tabpanel" aria-labelledby={'beta-tabs-' + tab}>
|
||||
{#if loading}<EmptyState title="Loading betas…" />
|
||||
{:else if !filtered.length && !error}<EmptyState title={search ? 'No matching betas' : tab === 'active' ? 'No active betas' : 'No beta history'} description={tab === 'active' && !search ? 'Start a beta when you have a version ready to test.' : undefined} />
|
||||
{:else}<div class="rows">{#each filtered.slice(0,limit) as beta (beta.id)}
|
||||
<a href={'/betas/' + beta.id} class="row">
|
||||
<a href={contextHref('/betas/' + beta.id, $page.url)} class="row">
|
||||
<div class="identity"><strong>{beta.notes || `Beta #${beta.id}`}</strong>{#if beta.notes}<span class="beta-id"> · #{beta.id}</span>{/if}<span class="files">{beta.scripts.map(s => s.name + ' · ' + artifactVersionLabel(s.version)).join(', ')}</span><span class="blocker">{blocker(beta)}</span><span class="timing"><time datetime={beta.opened_at} title={$timeFormat.dateTime(beta.opened_at)}>Opened {age(beta.opened_at)}</time>{#if beta.deadlineAt && active(beta)} · Ends {$timeFormat.dateTime(beta.deadlineAt)}{:else if beta.closed_at} · Finished {$timeFormat.dateTime(beta.closed_at)}{/if}</span></div>
|
||||
<div class="meta"><StatusBadge state={beta.state} />{#if beta.testOutcome && beta.testOutcome !== 'active'}<StatusBadge state={beta.testOutcome} />{/if}<span>{beta.servers.filter(server=>server.stage==='ready').length} / {beta.servers.length} servers passed</span></div>
|
||||
</a>
|
||||
{/each}</div><ListFooter total={filtered.length} bind:limit label="betas" />{/if}
|
||||
{/each}</div><ListFooter total={filtered.length} bind:limit onchange={saveContext} label="betas" />{/if}
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
|
||||
Reference in New Issue
Block a user