diff --git a/frontend/src/auth.js b/frontend/src/auth.js index 27bcd76..b9667cf 100644 --- a/frontend/src/auth.js +++ b/frontend/src/auth.js @@ -92,10 +92,17 @@ export async function initAuth() { 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; 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() { diff --git a/frontend/src/views/OnboardingView.vue b/frontend/src/views/OnboardingView.vue index 5aeb678..6ee5107 100644 --- a/frontend/src/views/OnboardingView.vue +++ b/frontend/src/views/OnboardingView.vue @@ -26,7 +26,10 @@
Username - {{ requestUsername }} +
@@ -87,7 +90,8 @@

Temporary password

- 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.

Password @@ -212,6 +216,7 @@ const error = ref(""); const onboarding = ref({ required_steps: [], completed_steps: [] }); const initialPassword = ref(""); const copied = ref(false); +const usernameCopied = ref(false); const tasks = ref([]); 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() { - 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) { diff --git a/frontend/src/views/RequestAccessView.vue b/frontend/src/views/RequestAccessView.vue index c984be2..6101fb2 100644 --- a/frontend/src/views/RequestAccessView.vue +++ b/frontend/src/views/RequestAccessView.vue @@ -112,10 +112,6 @@ Verifying email…
-
- Continue onboarding -
-

Automation

@@ -134,6 +130,13 @@ One or more automation steps failed. Fix the error above, then check again.

+ +
@@ -429,6 +432,15 @@ h1 { margin-top: 6px; } +.onboarding-actions { + margin-top: 14px; +} + +.onboarding-cta { + flex: 1; + text-align: center; +} + .status-form { display: flex; gap: 10px;