[KEYCLOAK-17166] Use radio buttons for otp select
This commit is contained in:
parent
a60cb65252
commit
0033b7daf7
4 changed files with 71 additions and 84 deletions
|
@ -89,7 +89,7 @@ public class LoginTotpPage extends LanguageComboboxAwarePage {
|
|||
// If false, we don't expect that credentials combobox is available. If true, we expect that it is available on the page
|
||||
public void assertOtpCredentialSelectorAvailability(boolean expectedAvailability) {
|
||||
try {
|
||||
driver.findElement(By.className("otp-tile"));
|
||||
driver.findElement(By.className("pf-c-tile"));
|
||||
Assert.assertTrue(expectedAvailability);
|
||||
} catch (NoSuchElementException nse) {
|
||||
Assert.assertFalse(expectedAvailability);
|
||||
|
@ -105,7 +105,7 @@ public class LoginTotpPage extends LanguageComboboxAwarePage {
|
|||
|
||||
public String getSelectedOtpCredential() {
|
||||
try {
|
||||
WebElement selected = driver.findElement(getXPathForLookupActiveCard());
|
||||
WebElement selected = driver.findElement(getCssSelectorForLookupActiveCard());
|
||||
return selected.getText();
|
||||
} catch (NoSuchElementException nse) {
|
||||
// No selected element found
|
||||
|
@ -114,20 +114,20 @@ public class LoginTotpPage extends LanguageComboboxAwarePage {
|
|||
}
|
||||
|
||||
private By getXPathForLookupAllCards() {
|
||||
return By.xpath("//div[contains(@class, 'pf-c-tile otp-tile')]");
|
||||
return By.xpath("//span[contains(@class, 'pf-c-tile__title')]");
|
||||
}
|
||||
|
||||
private By getXPathForLookupActiveCard() {
|
||||
return By.xpath("//div[contains(@class, 'otp-tile pf-m-selected')]");
|
||||
private By getCssSelectorForLookupActiveCard() {
|
||||
return By.cssSelector(".pf-c-tile__input:checked + .pf-c-tile .pf-c-tile__title");
|
||||
}
|
||||
|
||||
private By getXPathForLookupCardWithName(String credentialName) {
|
||||
return By.xpath("//div[contains(@class, 'otp-tile')][normalize-space() = '"+ credentialName +"']");
|
||||
return By.xpath("//label[contains(@class, 'pf-c-tile')][normalize-space() = '"+ credentialName +"']");
|
||||
}
|
||||
|
||||
|
||||
public void selectOtpCredential(String credentialName) {
|
||||
waitForElement(getXPathForLookupActiveCard());
|
||||
waitForElement(getCssSelectorForLookupActiveCard());
|
||||
|
||||
WebElement webElement = driver.findElement(
|
||||
getXPathForLookupCardWithName(credentialName));
|
||||
|
|
|
@ -1,77 +1,58 @@
|
|||
<#import "template.ftl" as layout>
|
||||
<@layout.registrationLayout displayMessage=!messagesPerField.existsError('totp'); section>
|
||||
<#if section="header">
|
||||
${msg("doLogIn")}
|
||||
<#elseif section="form">
|
||||
<form id="kc-otp-login-form" class="${properties.kcFormClass!}" action="${url.loginAction}"
|
||||
method="post">
|
||||
<#if otpLogin.userOtpCredentials?size gt 1>
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div class="${properties.kcInputWrapperClass!}">
|
||||
<#list otpLogin.userOtpCredentials as otpCredential>
|
||||
<div class="${properties.kcLoginOTPListClass!}" tabindex="${otpCredential?index}">
|
||||
<input type="hidden" value="${otpCredential.id}">
|
||||
<div class="${properties.kcLoginOTPListItemHeaderClass!}">
|
||||
<div class="${properties.kcLoginOTPListItemIconBodyClass!}">
|
||||
<i class="${properties.kcLoginOTPListItemIconClass!}" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="${properties.kcLoginOTPListItemTitleClass!}">${otpCredential.userLabel}</div>
|
||||
</div>
|
||||
</div>
|
||||
</#list>
|
||||
</div>
|
||||
</div>
|
||||
</#if>
|
||||
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="otp" class="${properties.kcLabelClass!}">${msg("loginOtpOneTime")}</label>
|
||||
</div>
|
||||
|
||||
<@layout.registrationLayout displayMessage=!messagesPerField.existsError('totp'); section>
|
||||
<#if section="header">
|
||||
${msg("doLogIn")}
|
||||
<#elseif section="form">
|
||||
<form id="kc-otp-login-form" class="${properties.kcFormClass!}" action="${url.loginAction}"
|
||||
method="post">
|
||||
<#if otpLogin.userOtpCredentials?size gt 1>
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div class="${properties.kcInputWrapperClass!}">
|
||||
<input id="otp" name="otp" autocomplete="off" type="text" class="${properties.kcInputClass!}"
|
||||
autofocus aria-invalid="<#if messagesPerField.existsError('totp')>true</#if>"/>
|
||||
<#list otpLogin.userOtpCredentials as otpCredential>
|
||||
<input id="kc-otp-credential-${otpCredential?index}" class="${properties.kcLoginOTPListInputClass!}" type="radio" name="selectedCredentialId" value="${otpCredential.id}" <#if otpCredential.id == otpLogin.selectedCredentialId>checked="checked"</#if>>
|
||||
<label for="kc-otp-credential-${otpCredential?index}" class="${properties.kcLoginOTPListClass!}" tabindex="${otpCredential?index}">
|
||||
<span class="${properties.kcLoginOTPListItemHeaderClass!}">
|
||||
<span class="${properties.kcLoginOTPListItemIconBodyClass!}">
|
||||
<i class="${properties.kcLoginOTPListItemIconClass!}" aria-hidden="true"></i>
|
||||
</span>
|
||||
<span class="${properties.kcLoginOTPListItemTitleClass!}">${otpCredential.userLabel}</span>
|
||||
</span>
|
||||
</label>
|
||||
</#list>
|
||||
</div>
|
||||
</div>
|
||||
</#if>
|
||||
|
||||
<#if messagesPerField.existsError('totp')>
|
||||
<span id="input-error-otp-code" class="${properties.kcInputErrorMessageClass!}"
|
||||
aria-live="polite">
|
||||
${kcSanitize(messagesPerField.get('totp'))?no_esc}
|
||||
</span>
|
||||
</#if>
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="otp" class="${properties.kcLabelClass!}">${msg("loginOtpOneTime")}</label>
|
||||
</div>
|
||||
|
||||
<div class="${properties.kcInputWrapperClass!}">
|
||||
<input id="otp" name="otp" autocomplete="off" type="text" class="${properties.kcInputClass!}"
|
||||
autofocus aria-invalid="<#if messagesPerField.existsError('totp')>true</#if>"/>
|
||||
|
||||
<#if messagesPerField.existsError('totp')>
|
||||
<span id="input-error-otp-code" class="${properties.kcInputErrorMessageClass!}"
|
||||
aria-live="polite">
|
||||
${kcSanitize(messagesPerField.get('totp'))?no_esc}
|
||||
</span>
|
||||
</#if>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
|
||||
<div class="${properties.kcFormOptionsWrapperClass!}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
|
||||
<div class="${properties.kcFormOptionsWrapperClass!}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
|
||||
<input
|
||||
class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}"
|
||||
name="login" id="kc-login" type="submit" value="${msg("doLogIn")}" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<script type="text/javascript" src="${url.resourcesCommonPath}/node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
// Card Single Select
|
||||
$('.otp-tile').click(function() {
|
||||
if ($(this).hasClass('pf-m-selected'))
|
||||
{ $(this).removeClass('pf-m-selected'); $(this).children().removeAttr('name'); }
|
||||
else
|
||||
{ $('.otp-tile').removeClass('pf-m-selected');
|
||||
$('.otp-tile').children().removeAttr('name');
|
||||
$(this).addClass('pf-m-selected'); $(this).children().attr('name', 'selectedCredentialId'); }
|
||||
});
|
||||
|
||||
var defaultCred = $('.otp-tile')[0];
|
||||
if (defaultCred) {
|
||||
defaultCred.click();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
||||
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
|
||||
<input
|
||||
class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}"
|
||||
name="login" id="kc-login" type="submit" value="${msg("doLogIn")}" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
|
@ -35,11 +35,11 @@
|
|||
.pf-c-tile:hover .pf-c-tile__icon {
|
||||
color: #06c;
|
||||
}
|
||||
.pf-c-tile.pf-m-selected .pf-c-tile__title,
|
||||
.pf-c-tile.pf-m-selected .pf-c-tile__icon {
|
||||
.pf-c-tile__input:checked + .pf-c-tile .pf-c-tile__title,
|
||||
.pf-c-tile__input:checked + .pf-c-tile .pf-c-tile__icon {
|
||||
color: #06c;
|
||||
}
|
||||
.pf-c-tile.pf-m-selected {
|
||||
.pf-c-tile__input:checked + .pf-c-tile {
|
||||
border: 2px solid #06c;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
@ -119,6 +119,7 @@
|
|||
cursor: pointer;
|
||||
background-color: var(--pf-c-tile--BackgroundColor);
|
||||
grid-template-rows: min-content;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.pf-c-tile::before {
|
||||
|
@ -139,7 +140,7 @@
|
|||
--pf-c-tile--before--BorderColor: var(--pf-c-tile--hover--before--BorderColor);
|
||||
}
|
||||
|
||||
.pf-c-tile.pf-m-selected {
|
||||
.pf-c-tile__input:checked + .pf-c-tile {
|
||||
--pf-c-tile__title--Color: var(--pf-c-tile--m-selected__title--Color);
|
||||
--pf-c-tile__icon--Color: var(--pf-c-tile--m-selected__icon--Color);
|
||||
--pf-c-tile--before--BorderWidth: var(--pf-c-tile--m-selected--before--BorderWidth);
|
||||
|
@ -166,6 +167,10 @@
|
|||
--pf-c-tile__icon--FontSize: var(--pf-c-tile--m-display-lg__header--m-stacked__icon--FontSize);
|
||||
}
|
||||
|
||||
.pf-c-tile__input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pf-c-tile__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
@ -103,9 +103,10 @@ kcAuthenticatorWebAuthnClass=fa fa-key list-view-pf-icon-lg
|
|||
kcAuthenticatorWebAuthnPasswordlessClass=fa fa-key list-view-pf-icon-lg
|
||||
|
||||
##### css classes for the OTP Login Form
|
||||
kcLoginOTPListClass=pf-c-tile otp-tile
|
||||
kcLoginOTPListClass=pf-c-tile
|
||||
kcLoginOTPListInputClass=pf-c-tile__input
|
||||
kcLoginOTPListItemHeaderClass=pf-c-tile__header
|
||||
kcLoginOTPListItemIconBodyClass=pf-c-tile__icon otp-tile-icon
|
||||
kcLoginOTPListItemIconBodyClass=pf-c-tile__icon
|
||||
kcLoginOTPListItemIconClass=fa fa-mobile
|
||||
kcLoginOTPListItemTitleClass=pf-c-tile__title
|
||||
|
||||
|
|
Loading…
Reference in a new issue