portal: tighten onboarding confirmation flow
This commit is contained in:
parent
87c3cb35ab
commit
8677efaa94
@ -187,75 +187,6 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="step.action === 'auto' || step.action === 'confirm'" class="step-actions">
|
|
||||||
<button
|
|
||||||
class="secondary"
|
|
||||||
type="button"
|
|
||||||
@click="confirmStep(step)"
|
|
||||||
:disabled="loading || isStepDone(step.id) || isStepBlocked(step.id)"
|
|
||||||
>
|
|
||||||
Confirm
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="step.action === 'keycloak_rotate'" class="step-actions">
|
|
||||||
<button
|
|
||||||
class="secondary"
|
|
||||||
type="button"
|
|
||||||
@click="requestKeycloakPasswordRotation"
|
|
||||||
:disabled="
|
|
||||||
!auth.authenticated ||
|
|
||||||
loading ||
|
|
||||||
isStepDone('keycloak_password_rotated') ||
|
|
||||||
isStepBlocked('keycloak_password_rotated') ||
|
|
||||||
keycloakPasswordRotationRequested
|
|
||||||
"
|
|
||||||
>
|
|
||||||
Start Keycloak update
|
|
||||||
</button>
|
|
||||||
<a class="mono" href="https://live.bstein.dev" target="_blank" rel="noreferrer">Open Element</a>
|
|
||||||
<button
|
|
||||||
class="secondary"
|
|
||||||
type="button"
|
|
||||||
@click="confirmStep(step)"
|
|
||||||
:disabled="loading || isStepDone(step.id) || isStepBlocked(step.id)"
|
|
||||||
>
|
|
||||||
Confirm
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="step.action === 'element_recovery'" class="recovery-verify">
|
|
||||||
<input
|
|
||||||
v-model="elementRecoveryKey"
|
|
||||||
class="input mono"
|
|
||||||
type="text"
|
|
||||||
placeholder="Paste recovery key (hashed locally)"
|
|
||||||
:disabled="!auth.authenticated || loading || isStepDone(step.id) || isStepBlocked(step.id)"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
class="primary verify"
|
|
||||||
type="button"
|
|
||||||
@click="verifyElementRecoveryKey"
|
|
||||||
:disabled="
|
|
||||||
!auth.authenticated ||
|
|
||||||
loading ||
|
|
||||||
isStepDone(step.id) ||
|
|
||||||
isStepBlocked(step.id) ||
|
|
||||||
!elementRecoveryKey.trim()
|
|
||||||
"
|
|
||||||
>
|
|
||||||
Verify
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="secondary"
|
|
||||||
type="button"
|
|
||||||
@click="confirmStep(step)"
|
|
||||||
:disabled="loading || isStepDone(step.id) || isStepBlocked(step.id) || !elementRecoveryKey.trim()"
|
|
||||||
>
|
|
||||||
Confirm
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<details v-if="step.guide" class="guide-details">
|
<details v-if="step.guide" class="guide-details">
|
||||||
<summary class="mono">Photo guide</summary>
|
<summary class="mono">Photo guide</summary>
|
||||||
<div v-if="guideGroups(step).length" class="guide-groups">
|
<div v-if="guideGroups(step).length" class="guide-groups">
|
||||||
@ -302,14 +233,63 @@
|
|||||||
<p v-else class="muted">Guide coming soon.</p>
|
<p v-else class="muted">Guide coming soon.</p>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<div v-if="step.action === 'checkbox'" class="step-actions">
|
<div v-if="step.action === 'element_recovery'" class="recovery-verify">
|
||||||
|
<input
|
||||||
|
v-model="elementRecoveryKey"
|
||||||
|
class="input mono"
|
||||||
|
type="text"
|
||||||
|
placeholder="Paste recovery key (hashed locally)"
|
||||||
|
:disabled="!auth.authenticated || loading || isStepDone(step.id) || isStepBlocked(step.id)"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
class="primary verify"
|
||||||
|
type="button"
|
||||||
|
@click="verifyElementRecoveryKey"
|
||||||
|
:disabled="
|
||||||
|
!auth.authenticated ||
|
||||||
|
loading ||
|
||||||
|
isStepDone(step.id) ||
|
||||||
|
isStepBlocked(step.id) ||
|
||||||
|
!elementRecoveryKey.trim()
|
||||||
|
"
|
||||||
|
>
|
||||||
|
Verify
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
class="secondary"
|
class="secondary"
|
||||||
type="button"
|
type="button"
|
||||||
@click="confirmStep(step)"
|
@click="confirmStep(step)"
|
||||||
:disabled="loading || isStepDone(step.id) || isStepBlocked(step.id)"
|
:disabled="loading || isStepDone(step.id) || isStepBlocked(step.id) || !elementRecoveryKey.trim()"
|
||||||
>
|
>
|
||||||
Confirm
|
{{ confirmLabel(step) }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else class="step-actions">
|
||||||
|
<template v-if="step.action === 'keycloak_rotate'">
|
||||||
|
<button
|
||||||
|
class="secondary"
|
||||||
|
type="button"
|
||||||
|
@click="requestKeycloakPasswordRotation"
|
||||||
|
:disabled="
|
||||||
|
!auth.authenticated ||
|
||||||
|
loading ||
|
||||||
|
isStepDone('keycloak_password_rotated') ||
|
||||||
|
isStepBlocked('keycloak_password_rotated') ||
|
||||||
|
keycloakPasswordRotationRequested
|
||||||
|
"
|
||||||
|
>
|
||||||
|
Start Keycloak update
|
||||||
|
</button>
|
||||||
|
<a class="mono" href="https://live.bstein.dev" target="_blank" rel="noreferrer">Open Element</a>
|
||||||
|
</template>
|
||||||
|
<button
|
||||||
|
class="secondary"
|
||||||
|
type="button"
|
||||||
|
@click="confirmStep(step)"
|
||||||
|
:disabled="loading || isConfirming(step) || isStepDone(step.id) || isStepBlocked(step.id)"
|
||||||
|
>
|
||||||
|
{{ confirmLabel(step) }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
@ -387,6 +367,7 @@ const activeSectionId = ref("vaultwarden");
|
|||||||
const guideShots = ref({});
|
const guideShots = ref({});
|
||||||
const guidePage = ref({});
|
const guidePage = ref({});
|
||||||
const lightboxShot = ref(null);
|
const lightboxShot = ref(null);
|
||||||
|
const confirmingStepId = ref("");
|
||||||
|
|
||||||
const showPasswordCard = computed(() => Boolean(initialPassword.value || initialPasswordRevealedAt.value));
|
const showPasswordCard = computed(() => Boolean(initialPassword.value || initialPasswordRevealedAt.value));
|
||||||
const passwordRevealLocked = computed(() => Boolean(!initialPassword.value && initialPasswordRevealedAt.value));
|
const passwordRevealLocked = computed(() => Boolean(!initialPassword.value && initialPasswordRevealedAt.value));
|
||||||
@ -759,6 +740,14 @@ function stepPillClass(step) {
|
|||||||
return "pill-warn";
|
return "pill-warn";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isConfirming(step) {
|
||||||
|
return confirmingStepId.value === step.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirmLabel(step) {
|
||||||
|
return isConfirming(step) ? "Confirming..." : "Confirm";
|
||||||
|
}
|
||||||
|
|
||||||
function stepCardClass(step) {
|
function stepCardClass(step) {
|
||||||
return {
|
return {
|
||||||
done: isStepDone(step.id),
|
done: isStepDone(step.id),
|
||||||
@ -986,19 +975,31 @@ async function setStepCompletion(stepId, completed) {
|
|||||||
|
|
||||||
async function confirmStep(step) {
|
async function confirmStep(step) {
|
||||||
if (!step || isStepBlocked(step.id) || isStepDone(step.id)) return;
|
if (!step || isStepBlocked(step.id) || isStepDone(step.id)) return;
|
||||||
if (step.action === "auto") {
|
confirmingStepId.value = step.id;
|
||||||
await check();
|
try {
|
||||||
return;
|
if (step.action === "auto") {
|
||||||
|
await check();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (step.action === "keycloak_rotate") {
|
||||||
|
await check();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (step.action === "element_recovery") {
|
||||||
|
await verifyElementRecoveryKey();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (step.action === "confirm") {
|
||||||
|
await check();
|
||||||
|
if (!isStepDone(step.id)) {
|
||||||
|
await setStepCompletion(step.id, true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await setStepCompletion(step.id, true);
|
||||||
|
} finally {
|
||||||
|
confirmingStepId.value = "";
|
||||||
}
|
}
|
||||||
if (step.action === "keycloak_rotate") {
|
|
||||||
await requestKeycloakPasswordRotation();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (step.action === "element_recovery") {
|
|
||||||
await verifyElementRecoveryKey();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await setStepCompletion(step.id, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function verifyElementRecoveryKey() {
|
async function verifyElementRecoveryKey() {
|
||||||
@ -1454,6 +1455,7 @@ button.copy:disabled {
|
|||||||
|
|
||||||
.step-card.blocked {
|
.step-card.blocked {
|
||||||
opacity: 0.55;
|
opacity: 0.55;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-card.done {
|
.step-card.done {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user