portal: improve onboarding login UX
This commit is contained in:
parent
59830e19c8
commit
72dae3e7a2
@ -92,10 +92,17 @@ export async function initAuth() {
|
|||||||
return initPromise;
|
return initPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function login(redirectPath = window.location.pathname + window.location.search + window.location.hash) {
|
export async function login(
|
||||||
|
redirectPath = window.location.pathname + window.location.search + window.location.hash,
|
||||||
|
loginHint = "",
|
||||||
|
) {
|
||||||
if (!keycloak) return;
|
if (!keycloak) return;
|
||||||
const redirectUri = new URL(redirectPath, window.location.origin).toString();
|
const redirectUri = new URL(redirectPath, window.location.origin).toString();
|
||||||
await keycloak.login({ redirectUri });
|
const options = { redirectUri };
|
||||||
|
if (typeof loginHint === "string" && loginHint.trim()) {
|
||||||
|
options.loginHint = loginHint.trim();
|
||||||
|
}
|
||||||
|
await keycloak.login(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function logout() {
|
export async function logout() {
|
||||||
|
|||||||
@ -26,7 +26,10 @@
|
|||||||
<div v-if="requestUsername" class="status-meta">
|
<div v-if="requestUsername" class="status-meta">
|
||||||
<div class="meta-row">
|
<div class="meta-row">
|
||||||
<span class="label mono">Username</span>
|
<span class="label mono">Username</span>
|
||||||
<span class="value mono">{{ requestUsername }}</span>
|
<button class="copy mono" type="button" @click="copyUsername">
|
||||||
|
{{ requestUsername }}
|
||||||
|
<span v-if="usernameCopied" class="copied">copied</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -87,7 +90,8 @@
|
|||||||
<div v-if="initialPassword" class="initial-password">
|
<div v-if="initialPassword" class="initial-password">
|
||||||
<h3>Temporary password</h3>
|
<h3>Temporary password</h3>
|
||||||
<p class="muted">
|
<p class="muted">
|
||||||
Use this password to log in for the first time. Keycloak will prompt you to change it.
|
Use this password to log in for the first time. Keycloak will prompt you to change it. This password is shown
|
||||||
|
once — copy it now.
|
||||||
</p>
|
</p>
|
||||||
<div class="request-code-row">
|
<div class="request-code-row">
|
||||||
<span class="label mono">Password</span>
|
<span class="label mono">Password</span>
|
||||||
@ -212,6 +216,7 @@ const error = ref("");
|
|||||||
const onboarding = ref({ required_steps: [], completed_steps: [] });
|
const onboarding = ref({ required_steps: [], completed_steps: [] });
|
||||||
const initialPassword = ref("");
|
const initialPassword = ref("");
|
||||||
const copied = ref(false);
|
const copied = ref(false);
|
||||||
|
const usernameCopied = ref(false);
|
||||||
const tasks = ref([]);
|
const tasks = ref([]);
|
||||||
const blocked = ref(false);
|
const blocked = ref(false);
|
||||||
|
|
||||||
@ -304,8 +309,35 @@ async function copyInitialPassword() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function copyUsername() {
|
||||||
|
if (!requestUsername.value) return;
|
||||||
|
try {
|
||||||
|
if (navigator?.clipboard?.writeText) {
|
||||||
|
await navigator.clipboard.writeText(requestUsername.value);
|
||||||
|
} else {
|
||||||
|
const textarea = document.createElement("textarea");
|
||||||
|
textarea.value = requestUsername.value;
|
||||||
|
textarea.setAttribute("readonly", "");
|
||||||
|
textarea.style.position = "fixed";
|
||||||
|
textarea.style.top = "-9999px";
|
||||||
|
textarea.style.left = "-9999px";
|
||||||
|
document.body.appendChild(textarea);
|
||||||
|
textarea.select();
|
||||||
|
textarea.setSelectionRange(0, textarea.value.length);
|
||||||
|
document.execCommand("copy");
|
||||||
|
document.body.removeChild(textarea);
|
||||||
|
}
|
||||||
|
usernameCopied.value = true;
|
||||||
|
setTimeout(() => (usernameCopied.value = false), 1500);
|
||||||
|
} catch (err) {
|
||||||
|
error.value = err?.message || "Failed to copy username";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function loginToContinue() {
|
async function loginToContinue() {
|
||||||
await login(`/onboarding?code=${encodeURIComponent(requestCode.value.trim())}`);
|
const trimmedCode = requestCode.value.trim();
|
||||||
|
const hint = requestUsername.value.trim() || trimmedCode.split("~", 1)[0] || "";
|
||||||
|
await login(`/onboarding?code=${encodeURIComponent(trimmedCode)}`, hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function toggleStep(step, event) {
|
async function toggleStep(step, event) {
|
||||||
|
|||||||
@ -112,10 +112,6 @@
|
|||||||
Verifying email…
|
Verifying email…
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="onboardingUrl" class="actions" style="margin-top: 12px;">
|
|
||||||
<a class="primary" :href="onboardingUrl">Continue onboarding</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="tasks.length" class="task-box">
|
<div v-if="tasks.length" class="task-box">
|
||||||
<div class="module-head" style="margin-bottom: 10px;">
|
<div class="module-head" style="margin-bottom: 10px;">
|
||||||
<h2>Automation</h2>
|
<h2>Automation</h2>
|
||||||
@ -134,6 +130,13 @@
|
|||||||
One or more automation steps failed. Fix the error above, then check again.
|
One or more automation steps failed. Fix the error above, then check again.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="onboardingUrl && (status === 'awaiting_onboarding' || status === 'ready')"
|
||||||
|
class="actions onboarding-actions"
|
||||||
|
>
|
||||||
|
<a class="primary onboarding-cta" :href="onboardingUrl">Continue onboarding</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="error" class="error-box">
|
<div v-if="error" class="error-box">
|
||||||
@ -429,6 +432,15 @@ h1 {
|
|||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.onboarding-actions {
|
||||||
|
margin-top: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.onboarding-cta {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.status-form {
|
.status-form {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user