refactor(ext/setup): wizard state shape for mode-aware flow

Expand WizardState with mode/vaultProbe/referenceImageBytesAttach/
verifiedHandle/attaching fields; start wizard at step 0; grow progress
bar to 6 segments; rename renderStep3/attachStep3 to *New variants;
add placeholder renderStep0/attachStep0/renderStep3Attach/attachStep3Attach.
No behaviour change for the existing new-vault flow.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
adlee-was-taken
2026-04-27 18:14:42 -04:00
parent 8e72ed8714
commit 7fa1f2990f

View File

@@ -28,13 +28,16 @@ async function loadWasm(): Promise<WasmModule> {
// --- State ---
interface WizardState {
step: number;
step: number; // now 0..5; was 1..5
mode: 'new' | 'attach' | null; // null until Step 0 picks
hostType: 'gitea' | 'github';
hostUrl: string;
repoPath: string;
apiToken: string;
connectionTested: boolean;
vaultProbe: import('./probe').VaultProbe | null;
carrierImageBytes: Uint8Array | null;
referenceImageBytesAttach: Uint8Array | null;
passphrase: string;
passphraseConfirm: string;
// zxcvbn meter state — -1 means "not yet scored" (empty passphrase).
@@ -43,7 +46,9 @@ interface WizardState {
passphraseVisible: boolean;
confirmVisible: boolean;
referenceImageBytes: Uint8Array | null;
verifiedHandle: number | null;
creating: boolean;
attaching: boolean;
error: string | null;
extensionDetected: boolean;
configPushed: boolean;
@@ -51,13 +56,16 @@ interface WizardState {
}
const state: WizardState = {
step: 1,
step: 0,
mode: null,
hostType: 'gitea',
hostUrl: '',
repoPath: '',
apiToken: '',
connectionTested: false,
vaultProbe: null,
carrierImageBytes: null,
referenceImageBytesAttach: null,
passphrase: '',
passphraseConfirm: '',
passphraseScore: -1,
@@ -65,7 +73,9 @@ const state: WizardState = {
passphraseVisible: false,
confirmVisible: false,
referenceImageBytes: null,
verifiedHandle: null,
creating: false,
attaching: false,
error: null,
extensionDetected: false,
configPushed: false,
@@ -224,6 +234,7 @@ function render(): void {
const progressHtml = `
<div class="progress-bar">
<div class="step ${state.step > 0 ? 'done' : state.step === 0 ? 'current' : ''}"></div>
<div class="step ${state.step > 1 ? 'done' : state.step === 1 ? 'current' : ''}"></div>
<div class="step ${state.step > 2 ? 'done' : state.step === 2 ? 'current' : ''}"></div>
<div class="step ${state.step > 3 ? 'done' : state.step === 3 ? 'current' : ''}"></div>
@@ -234,9 +245,10 @@ function render(): void {
let stepHtml = '';
switch (state.step) {
case 0: stepHtml = renderStep0(); break;
case 1: stepHtml = renderStep1(); break;
case 2: stepHtml = renderStep2(); break;
case 3: stepHtml = renderStep3(); break;
case 3: stepHtml = state.mode === 'attach' ? renderStep3Attach() : renderStep3New(); break;
case 4: stepHtml = renderStep4(); break;
case 5: stepHtml = renderStep5(); break;
}
@@ -252,14 +264,43 @@ function render(): void {
`;
switch (state.step) {
case 0: attachStep0(); break;
case 1: attachStep1(); break;
case 2: attachStep2(); break;
case 3: attachStep3(); break;
case 3: state.mode === 'attach' ? attachStep3Attach() : attachStep3New(); break;
case 4: attachStep4(); break;
case 5: attachStep5(); break;
}
}
// --- Step 0: Mode picker (placeholder; filled in Task 5) ---
function renderStep0(): string {
return '<div class="wizard-step"><p>Step 0 (placeholder)</p><button class="btn btn-primary" id="next-btn">next</button></div>';
}
function attachStep0(): void {
// Temporary: jump straight to Step 1 so the wizard remains operable
// for users who already have it open during the refactor. Real Step 0
// is filled in by Task 5.
document.getElementById('next-btn')?.addEventListener('click', () => {
state.step = 1;
state.mode = 'new'; // safe default while picker is stubbed
state.error = null;
render();
});
}
// --- Step 3 (attach variant) — placeholder; filled in Task 8 ---
function renderStep3Attach(): string {
return '<div class="wizard-step"><p>Step 3b (placeholder)</p></div>';
}
function attachStep3Attach(): void {
/* filled in Task 8 */
}
// --- Step 1: Choose Host ---
function renderStep1(): string {
@@ -398,9 +439,9 @@ function attachStep2(): void {
});
}
// --- Step 3: Create Vault ---
// --- Step 3 (new-vault variant): Create Vault ---
function renderStep3(): string {
function renderStep3New(): string {
const score = state.passphraseScore;
const guessesLog10 = state.passphraseGuessesLog10;
const hasScore = score >= 0;
@@ -485,7 +526,7 @@ function renderStep3(): string {
`;
}
function attachStep3(): void {
function attachStep3New(): void {
const fileDrop = document.getElementById('file-drop')!;
const fileInput = document.getElementById('file-input') as HTMLInputElement;