feat(ext/setup): vault-presence probe + mode-mismatch banners on Step 2
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1256,3 +1256,23 @@ textarea {
|
||||
.mode-card.active { border-color: #58a6ff; background: rgba(88,166,255,0.08); }
|
||||
.mode-card-title { font-weight: 600; margin-bottom: 4px; font-size: 14px; }
|
||||
.mode-card-blurb { color: #8b949e; font-size: 12px; margin: 0; line-height: 1.5; }
|
||||
|
||||
/* --- Setup wizard probe banners (Step 2) --- */
|
||||
.banner { padding: 12px; border-radius: 6px; margin: 12px 0; font-size: 13px; }
|
||||
.banner-ok {
|
||||
background: rgba(46,160,67,0.10);
|
||||
border: 1px solid rgba(46,160,67,0.4);
|
||||
}
|
||||
.banner-warn {
|
||||
background: rgba(218,54,51,0.08);
|
||||
border: 1px solid rgba(218,54,51,0.4);
|
||||
}
|
||||
.banner strong { display: block; margin-bottom: 4px; }
|
||||
.banner p { margin: 6px 0; line-height: 1.5; color: #c9d1d9; }
|
||||
.banner code {
|
||||
font-family: ui-monospace, SFMono-Regular, monospace;
|
||||
font-size: 12px;
|
||||
background: #21262d;
|
||||
padding: 1px 5px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
/// Step 5: Finish (download reference image, push config to extension or copy JSON)
|
||||
|
||||
import { createGitHost, uint8ArrayToBase64 } from '../service-worker/git-host';
|
||||
import { probeVault } from './probe';
|
||||
import type { VaultConfig } from '../shared/types';
|
||||
|
||||
// --- WASM module (loaded dynamically) ---
|
||||
@@ -400,7 +401,55 @@ function attachStep1(): void {
|
||||
|
||||
// --- Step 2: Configure Connection ---
|
||||
|
||||
function renderProbeBanner(): string {
|
||||
const probe = state.vaultProbe;
|
||||
if (!state.connectionTested || !probe) return '';
|
||||
const meta = probe.lastCommit
|
||||
? `Last commit: <code>${escapeHtml(probe.lastCommit.sha)}</code> by ${escapeHtml(probe.lastCommit.author)} on ${escapeHtml(probe.lastCommit.date.slice(0, 10))}.`
|
||||
: '';
|
||||
if (state.mode === 'new' && probe.exists) {
|
||||
return `
|
||||
<div class="banner banner-warn">
|
||||
<strong>⚠ This repository already contains a relicario vault.</strong>
|
||||
<p>${meta}</p>
|
||||
<p>Creating a new vault here would overwrite the existing one and <strong>destroy all data inside</strong>.
|
||||
To use this vault on this device, switch to <em>attach</em> mode instead.
|
||||
If you really mean to start over, delete the repository via your git host's web UI and come back here.</p>
|
||||
<div class="form-actions">
|
||||
<button class="btn" id="switch-mode-btn" data-target="attach">switch to attach mode</button>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
if (state.mode === 'attach' && !probe.exists) {
|
||||
return `
|
||||
<div class="banner banner-warn">
|
||||
<strong>No vault found in this repo.</strong>
|
||||
<p>Did you mean to create a new vault?</p>
|
||||
<div class="form-actions">
|
||||
<button class="btn" id="switch-mode-btn" data-target="new">switch to new-vault mode</button>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
if (state.mode === 'attach' && probe.exists) {
|
||||
return `
|
||||
<div class="banner banner-ok">
|
||||
<strong>✓ Existing vault found.</strong>
|
||||
<p>${meta}</p>
|
||||
<p>Continue to attach this device.</p>
|
||||
</div>`;
|
||||
}
|
||||
// mode = new, !exists
|
||||
return `
|
||||
<div class="banner banner-ok">
|
||||
<strong>✓ Repo is empty — ready to create a new vault.</strong>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function renderStep2(): string {
|
||||
const probe = state.vaultProbe;
|
||||
const modeMismatch =
|
||||
!!probe && ((state.mode === 'new' && probe.exists) || (state.mode === 'attach' && !probe.exists));
|
||||
const nextDisabled = !state.connectionTested || !probe || modeMismatch;
|
||||
return `
|
||||
<div class="wizard-step">
|
||||
<h3>configure connection</h3>
|
||||
@@ -420,9 +469,10 @@ function renderStep2(): string {
|
||||
<button class="btn" id="test-btn">test connection</button>
|
||||
${state.connectionTested ? '<span class="test-result pass">connected</span>' : ''}
|
||||
</div>
|
||||
${renderProbeBanner()}
|
||||
<div class="form-actions" style="margin-top:12px;">
|
||||
<button class="btn" id="back-btn">back</button>
|
||||
<button class="btn btn-primary" id="next-btn" ${!state.connectionTested ? 'disabled' : ''}>next</button>
|
||||
<button class="btn btn-primary" id="next-btn" ${nextDisabled ? 'disabled' : ''}>next</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -430,6 +480,8 @@ function renderStep2(): string {
|
||||
|
||||
function attachStep2(): void {
|
||||
document.getElementById('test-btn')?.addEventListener('click', async () => {
|
||||
state.connectionTested = false;
|
||||
state.vaultProbe = null;
|
||||
const hostUrl = state.hostType === 'github'
|
||||
? 'https://api.github.com'
|
||||
: (document.getElementById('host-url') as HTMLInputElement).value.trim();
|
||||
@@ -456,8 +508,15 @@ function attachStep2(): void {
|
||||
await host.listDir('');
|
||||
state.connectionTested = true;
|
||||
state.error = null;
|
||||
try {
|
||||
state.vaultProbe = await probeVault(host);
|
||||
} catch (probeErr) {
|
||||
state.vaultProbe = null;
|
||||
state.error = `Could not check repo state: ${probeErr instanceof Error ? probeErr.message : String(probeErr)}`;
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
state.connectionTested = false;
|
||||
state.vaultProbe = null;
|
||||
state.error = `Connection failed: ${err instanceof Error ? err.message : String(err)}`;
|
||||
}
|
||||
render();
|
||||
@@ -475,6 +534,13 @@ function attachStep2(): void {
|
||||
state.error = null;
|
||||
render();
|
||||
});
|
||||
|
||||
document.getElementById('switch-mode-btn')?.addEventListener('click', (e) => {
|
||||
const target = (e.currentTarget as HTMLElement).dataset.target as 'new' | 'attach';
|
||||
state.mode = target;
|
||||
state.error = null;
|
||||
render();
|
||||
});
|
||||
}
|
||||
|
||||
// --- Step 3 (new-vault variant): Create Vault ---
|
||||
|
||||
Reference in New Issue
Block a user