Improve operational UX, recovery flows, and action safety
Implement the approved UX review across Fleet, Betas, Library, deployments, and Settings. Add reviewed promotion and reconciliation plans, atomic queued-removal cancellation, recoverable beta drafts and launch inputs, accessible controls, and mobile improvements. Validated with 473 tests, a clean typecheck, production build, and isolated desktop/mobile browser walkthroughs. Include the review and implementation coverage notes.
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
import ConfigTextEditor from './ConfigTextEditor.svelte';
|
||||
import ConfigInspector from './ConfigInspector.svelte';
|
||||
import Button from './primitives/Button.svelte';
|
||||
import { configWarnings } from '$lib/config-workbench.js';
|
||||
interface Version { id: number; version: number; notes: string | null; }
|
||||
let { id, kind, versions, currentVersionId, runningBetaId, scopeType, scopeValue, onsaved }: {
|
||||
id: number; kind: 'baseline' | 'config'; versions: Version[]; currentVersionId: number | null;
|
||||
@@ -23,6 +24,7 @@
|
||||
let loadedVersion = $state('');
|
||||
let recovered = $state<{ version: string; text: string; notes: string } | null>(null);
|
||||
const dirty = $derived(text !== original || notes.trim().length > 0);
|
||||
const ignoredWarnings = $derived(configWarnings(text, kind === 'config').filter(warning => warning.includes('ignored') || warning.includes('no value')));
|
||||
const storageKey = $derived(`electric-cherry.config-draft.${id}`);
|
||||
onMount(() => {
|
||||
selected = String(versions[0]?.id ?? ''); ready = true;
|
||||
@@ -117,7 +119,7 @@
|
||||
{:else if loadedVersion}
|
||||
<ConfigTextEditor bind:text overlay={kind === 'config'} disabled={saving || runningBetaId !== null} />
|
||||
<label class="notes-label">Version notes<input bind:value={notes} placeholder="What changed, and why?" disabled={saving || runningBetaId !== null} /></label>
|
||||
<div class="actions ui-sticky-actions"><span class="muted">{runningBetaId !== null ? 'Finish the active beta to save another version.' : 'A new version must pass through a beta before promotion.'}</span>
|
||||
<div class="actions ui-sticky-actions"><span class="muted">{runningBetaId !== null ? 'Finish the active beta to save another version.' : 'A new version must pass through a beta before promotion.'}{#if ignoredWarnings.length}<strong class="save-warning">{ignoredWarnings.length} ignored or incomplete lines — review the open configuration notes before saving.</strong>{/if}</span>
|
||||
<Button variant="ghost" size="sm" onclick={discard} disabled={!dirty || saving}>Discard</Button>
|
||||
<Button variant="primary" onclick={save} loading={saving} disabled={!dirty || !text.trim() || runningBetaId !== null}>Save new version</Button>
|
||||
</div>
|
||||
@@ -144,8 +146,10 @@
|
||||
.actions { margin-top: 16px; }
|
||||
.actions > span { flex: 1 1 200px; }
|
||||
.muted { color: var(--text-secondary); font-size: var(--text-xs); }
|
||||
.save-warning { display: block; color: var(--state-warning); font-weight: 500; margin-top: 6px; }
|
||||
.recovery, .success, .error { font-size: var(--text-sm); padding: 12px; border-radius: var(--radius-sm); background: var(--surface-raised); margin-bottom: 16px; }
|
||||
.recovery { color: var(--state-warning); } .success { color: var(--state-online); } .error { color: var(--state-danger); }
|
||||
@media (max-width: 1100px) { .workbench { grid-template-columns: 1fr; } }
|
||||
@media (max-width: 600px) { .editor-panel { padding: 16px; } }
|
||||
input:not([type='checkbox']):not([type='file']), select { border-color: var(--border-control); }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user