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:
@@ -28,13 +28,16 @@ async function loadWasm(): Promise<WasmModule> {
|
|||||||
// --- State ---
|
// --- State ---
|
||||||
|
|
||||||
interface WizardState {
|
interface WizardState {
|
||||||
step: number;
|
step: number; // now 0..5; was 1..5
|
||||||
|
mode: 'new' | 'attach' | null; // null until Step 0 picks
|
||||||
hostType: 'gitea' | 'github';
|
hostType: 'gitea' | 'github';
|
||||||
hostUrl: string;
|
hostUrl: string;
|
||||||
repoPath: string;
|
repoPath: string;
|
||||||
apiToken: string;
|
apiToken: string;
|
||||||
connectionTested: boolean;
|
connectionTested: boolean;
|
||||||
|
vaultProbe: import('./probe').VaultProbe | null;
|
||||||
carrierImageBytes: Uint8Array | null;
|
carrierImageBytes: Uint8Array | null;
|
||||||
|
referenceImageBytesAttach: Uint8Array | null;
|
||||||
passphrase: string;
|
passphrase: string;
|
||||||
passphraseConfirm: string;
|
passphraseConfirm: string;
|
||||||
// zxcvbn meter state — -1 means "not yet scored" (empty passphrase).
|
// zxcvbn meter state — -1 means "not yet scored" (empty passphrase).
|
||||||
@@ -43,7 +46,9 @@ interface WizardState {
|
|||||||
passphraseVisible: boolean;
|
passphraseVisible: boolean;
|
||||||
confirmVisible: boolean;
|
confirmVisible: boolean;
|
||||||
referenceImageBytes: Uint8Array | null;
|
referenceImageBytes: Uint8Array | null;
|
||||||
|
verifiedHandle: number | null;
|
||||||
creating: boolean;
|
creating: boolean;
|
||||||
|
attaching: boolean;
|
||||||
error: string | null;
|
error: string | null;
|
||||||
extensionDetected: boolean;
|
extensionDetected: boolean;
|
||||||
configPushed: boolean;
|
configPushed: boolean;
|
||||||
@@ -51,13 +56,16 @@ interface WizardState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const state: WizardState = {
|
const state: WizardState = {
|
||||||
step: 1,
|
step: 0,
|
||||||
|
mode: null,
|
||||||
hostType: 'gitea',
|
hostType: 'gitea',
|
||||||
hostUrl: '',
|
hostUrl: '',
|
||||||
repoPath: '',
|
repoPath: '',
|
||||||
apiToken: '',
|
apiToken: '',
|
||||||
connectionTested: false,
|
connectionTested: false,
|
||||||
|
vaultProbe: null,
|
||||||
carrierImageBytes: null,
|
carrierImageBytes: null,
|
||||||
|
referenceImageBytesAttach: null,
|
||||||
passphrase: '',
|
passphrase: '',
|
||||||
passphraseConfirm: '',
|
passphraseConfirm: '',
|
||||||
passphraseScore: -1,
|
passphraseScore: -1,
|
||||||
@@ -65,7 +73,9 @@ const state: WizardState = {
|
|||||||
passphraseVisible: false,
|
passphraseVisible: false,
|
||||||
confirmVisible: false,
|
confirmVisible: false,
|
||||||
referenceImageBytes: null,
|
referenceImageBytes: null,
|
||||||
|
verifiedHandle: null,
|
||||||
creating: false,
|
creating: false,
|
||||||
|
attaching: false,
|
||||||
error: null,
|
error: null,
|
||||||
extensionDetected: false,
|
extensionDetected: false,
|
||||||
configPushed: false,
|
configPushed: false,
|
||||||
@@ -224,6 +234,7 @@ function render(): void {
|
|||||||
|
|
||||||
const progressHtml = `
|
const progressHtml = `
|
||||||
<div class="progress-bar">
|
<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 > 1 ? 'done' : state.step === 1 ? 'current' : ''}"></div>
|
||||||
<div class="step ${state.step > 2 ? 'done' : state.step === 2 ? '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>
|
<div class="step ${state.step > 3 ? 'done' : state.step === 3 ? 'current' : ''}"></div>
|
||||||
@@ -234,9 +245,10 @@ function render(): void {
|
|||||||
|
|
||||||
let stepHtml = '';
|
let stepHtml = '';
|
||||||
switch (state.step) {
|
switch (state.step) {
|
||||||
|
case 0: stepHtml = renderStep0(); break;
|
||||||
case 1: stepHtml = renderStep1(); break;
|
case 1: stepHtml = renderStep1(); break;
|
||||||
case 2: stepHtml = renderStep2(); 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 4: stepHtml = renderStep4(); break;
|
||||||
case 5: stepHtml = renderStep5(); break;
|
case 5: stepHtml = renderStep5(); break;
|
||||||
}
|
}
|
||||||
@@ -252,14 +264,43 @@ function render(): void {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
switch (state.step) {
|
switch (state.step) {
|
||||||
|
case 0: attachStep0(); break;
|
||||||
case 1: attachStep1(); break;
|
case 1: attachStep1(); break;
|
||||||
case 2: attachStep2(); break;
|
case 2: attachStep2(); break;
|
||||||
case 3: attachStep3(); break;
|
case 3: state.mode === 'attach' ? attachStep3Attach() : attachStep3New(); break;
|
||||||
case 4: attachStep4(); break;
|
case 4: attachStep4(); break;
|
||||||
case 5: attachStep5(); 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 ---
|
// --- Step 1: Choose Host ---
|
||||||
|
|
||||||
function renderStep1(): string {
|
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 score = state.passphraseScore;
|
||||||
const guessesLog10 = state.passphraseGuessesLog10;
|
const guessesLog10 = state.passphraseGuessesLog10;
|
||||||
const hasScore = score >= 0;
|
const hasScore = score >= 0;
|
||||||
@@ -485,7 +526,7 @@ function renderStep3(): string {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function attachStep3(): void {
|
function attachStep3New(): void {
|
||||||
const fileDrop = document.getElementById('file-drop')!;
|
const fileDrop = document.getElementById('file-drop')!;
|
||||||
const fileInput = document.getElementById('file-input') as HTMLInputElement;
|
const fileInput = document.getElementById('file-input') as HTMLInputElement;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user