I figured you'd ask for this, but if you go ahead and produce your own test project and use the code I've included in the ticket I'm sure you'll receive the same error. Let me know when you've done this and then we can proceed.
I have already tried that with no difference
I'm trying to override the login page in my tired solution following this example (https://abp.io/docs/latest/framework/ui/mvc-razor-pages/customization-user-interface) and I am getting the following error in the browser.
Login.cshtml `@page @using Microsoft.AspNetCore.Mvc.Localization @using Volo.Abp.AspNetCore.Mvc.UI.Theming @using Microsoft.Extensions.Options @using Owl.reCAPTCHA @using Volo.Abp.Account.Localization @using Volo.Abp.Account.Public.Web.Pages.Account; @using Volo.Abp.Account.Public.Web.Security.Recaptcha @using Volo.Abp.Account.Settings @using Volo.Abp.Identity; @using Volo.Abp.Settings
@model CFData.Strucutre.Account.CustomLoginModel @inject IThemeManager ThemeManager @inject IHtmlLocalizer L @inject Volo.Abp.AspNetCore.Mvc.UI.Layout.IPageLayout PageLayout @inject ISettingProvider SettingProvider
@{ PageLayout.Content.Title = L["Login"].Value; Layout = ThemeManager.CurrentTheme.GetAccountLayout(); var reCaptchaVersion = await SettingProvider.GetAsync(AccountSettingNames.Captcha.Version); if (Model.UseCaptcha) { await Model.ReCaptchaOptions.SetAsync(reCaptchaVersion == 3 ? reCAPTCHAConsts.V3 : reCAPTCHAConsts.V2); }
}
@section scripts {
}
@if (Model.IsLinkLogin) {
@L["LinkAccountWarning", Url.PageLink()]
}
@if (Model.BackToExternalLogins) {
<a class="mb-3 btn btn-primary btn-block" href="@Url.Page("./ExternalLogins")">@L["Back"]
}
@if (Model.IsSelfRegistrationEnabled)
{
<h5 class="mb-2">@L["NotAMemberYet"] <a class="text-decoration-none" href="@Url.Page("./Register", new {returnUrl = Model.ReturnUrl, returnUrlHash = Model.ReturnUrlHash})">@L["Register"]</a></h5>
}
@if (Model.EnableLocalLogin)
{
<form method="post" id="loginForm">
@if (Model.UseCaptcha)
{
<input class="mb-3" data-captcha="true" type="hidden" name="@RecaptchaValidatorBase.RecaptchaResponseKey" id="@RecaptchaValidatorBase.RecaptchaResponseKey"/>
}
<div>
<div class="form-floating mb-2">
<input asp-for="LoginInput.UserNameOrEmailAddress" type="text" class="form-control" placeholder="name@example.com">
@Html.LabelFor(m => m.LoginInput.UserNameOrEmailAddress)
<span asp-validation-for="LoginInput.UserNameOrEmailAddress"/>
</div>
<div class="form-floating mb-2">
<input asp-for="LoginInput.Password" id="password-input" type="password" class="form-control" placeholder="Password">
@Html.LabelFor(m => m.LoginInput.Password)
<i id="PasswordVisibilityButton" class="bi bi-eye-slash show-pass-icon" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-html="true" aria-label="@L["ShowPassword"]" data-bs-original-title="@L["ShowPassword"]"></i>
<i id="capslockicon" class="bi bi-capslock caps-lock-icon" style="display: none;" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-html="true" aria-label="<i class='bi bi-exclamation-circle'></i> @L["CapsLockOn"]!" data-bs-original-title="<i class='bi bi-exclamation-circle'></i> @L["CapsLockOn"]!"></i>
<span asp-validation-for="LoginInput.Password"/>
</div>
</div>
<abp-row>
<abp-column>
<div class="form-switch ps-2">
<abp-input asp-for="LoginInput.RememberMe" class="mb-4"/>
</div>
</abp-column>
<abp-column class="text-end">
<a href="@Url.Page("./ForgotPassword", new {returnUrl = Model.ReturnUrl, returnUrlHash = Model.ReturnUrlHash})">@L["ForgotPassword"]</a>
</abp-column>
</abp-row>
@if (reCaptchaVersion == 2)
{
<script>
recaptchaCallback = function (token) {
$('form button[type=submit]').removeAttr("disabled");
$('#@RecaptchaValidatorBase.RecaptchaResponseKey').val(token)
};
</script>
<div class="mb-3">
<recaptcha-div-v2 callback="recaptchaCallback"/>
</div>
}
<div class="d-grid gap-2">
<abp-button button-type="Primary" type="submit" class="mb-3" name="Action" value="Login" disabled="true">
<i class="bi bi-box-arrow-in-right me-1"></i>
@L["Login"]
</abp-button>
</div>
@if (Model.ShowCancelButton)
{
<div class="d-grid gap-2">
<abp-button button-type="Secondary" type="submit" formnovalidate="formnovalidate" class="mb-3" name="Action" value="Cancel">@L["Cancel"]</abp-button>
</div>
}
</form>
}
@if (Model.VisibleExternalProviders.Any())
{
if(Model.EnableLocalLogin)
{
<hr/>
@L["OrSignInWith"]
<br/>
}
else
{
@L["SignInWithOneOfTheFollowingProviders"]
}
<form asp-page="./Login" asp-page-handler="ExternalLogin"
asp-route-returnUrl="@Model.ReturnUrl"
asp-route-returnUrlHash="@Model.ReturnUrlHash"
asp-route-linkTenantId="@Model.LinkTenantId"
asp-route-linkUserId="@Model.LinkUserId"
asp-route-linkToken="@Model.LinkToken"
method="post">
@foreach (var provider in Model.VisibleExternalProviders)
{
<button type="submit"
class="mt-2 me-2 btn btn-outline-primary btn-sm"
name="provider"
value="@provider.AuthenticationScheme"
data-busy-text="@L["ProcessingWithThreeDot"]">
@if (provider.Icon != null)
{
<i class="@provider.Icon"></i>
}
<span>@provider.DisplayName</span>
</button>
}
</form>
}
` Login.cs `using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Options; using Owl.reCAPTCHA; using Volo.Abp.Account.Security.Recaptcha; using Volo.Abp.Account.ExternalProviders; using Volo.Abp.Security.Claims; using Volo.Abp.Account.Public.Web.Pages.Account; using Volo.Abp.Account.Public.Web;
namespace CFData.Strucutre.Account;
public class CustomLoginModel : LoginModel {
public CustomLoginModel(
IAuthenticationSchemeProvider schemeProvider,
IOptions<AbpAccountOptions> accountOptions,
IAbpRecaptchaValidatorFactory recaptchaValidatorFactory,
IAccountExternalProviderAppService accountExternalProviderAppService,
ICurrentPrincipalAccessor currentPrincipalAccessor,
IOptions<IdentityOptions> identityOptions,
IOptionsSnapshot<reCAPTCHAOptions> reCaptchaOptions) : base (
schemeProvider,
accountOptions,
recaptchaValidatorFactory,
accountExternalProviderAppService,
currentPrincipalAccessor,
identityOptions,
reCaptchaOptions)
{
}
}
Login.js `$(function () {
var isRecaptchaEnabled = typeof grecaptcha !== 'undefined';
if (isRecaptchaEnabled) {
grecaptcha.ready(function () {
$("#loginForm button[type=submit]").removeAttr("disabled");
});
} else {
$("#loginForm button[type=submit]").removeAttr("disabled");
}
$("#loginForm button[type=submit]").click(function (e) {
e.preventDefault();
var form = $("#loginForm");
if (form.valid() && isRecaptchaEnabled && abp.utils.isFunction(grecaptcha.reExecute)) {
grecaptcha.reExecute(function (token) {
form.find("input[type=hidden][data-captcha=true]").val(token);
form.submit();
})
} else {
form.submit();
}
});
$("#PasswordVisibilityButton").click(function (e) {
let button = $(this);
let passwordInput = $('#password-input');
if (!passwordInput) {
return;
}
if (passwordInput.attr("type") === "password") {
passwordInput.attr("type", "text");
}
else {
passwordInput.attr("type", "password");
}
let icon = $("#PasswordVisibilityButton");
if (icon) {
icon.toggleClass("bi-eye-slash").toggleClass("bi-eye");
}
});
// CAPS LOCK CONTROL
const password = document.getElementById('password-input');
const passwordMsg = document.getElementById('capslockicon');
if (password && passwordMsg) {
password.addEventListener('keyup', e => {
if (typeof e.getModifierState === 'function') {
passwordMsg.style = e.getModifierState('CapsLock') ? 'display: inline' : 'display: none';
}
});
}
});
Hi,
Ok, I've implemented the changes in your last commit and that has resolved the issue I'm having with the stylesheets loading multiple times as well as the user menu not being clickable. I appreciate your help in resolving this issue.
Curious though if with abp9+ there is a better way of implementing custom layouts on a page by page basis while utilizing all the underlying leptonx components, etc. We have purchased the full source code and I see abp developer comments indicating that there should be a better way of doing this in the future.
Thanks again.
checking it now, but any resolution to the js function that does not exist in 7.3.0-rc.3?
Hi,
You have not address the issue with the stylesheets loading multiple times as stated in bullet point #1 in my previous response. Additionally when I apply these fixes to my actual project which is based on ABP 7.3.0-rc.3 I get the following error when my blazor app launches.
Hi,
So the sample has been updated completely now it Git to show you the problems I'm having.
Thanks.
I've updated the solution in git for you
Hi,
For starters change the .RequiredPermissions on sample1, sample2 and sample3 in the menu contribution to host
context.Menu.AddItem(
new ApplicationMenuItem(
"Sample1",
"Sample1",
"/Sample1",
icon: "fa fa-chart-line",
order: 3
).RequirePermissions(ABPSamplePermissions.Dashboard.Host)
);
context.Menu.AddItem(
new ApplicationMenuItem(
"Sample2",
"Sample2",
"/Sample2",
icon: "fa fa-chart-line",
order: 4
).RequirePermissions(ABPSamplePermissions.Dashboard.Host)
);
context.Menu.AddItem(
new ApplicationMenuItem(
"Sample3",
"Sample3",
"/Sample3",
icon: "fa fa-chart-line",
order: 5
).RequirePermissions(ABPSamplePermissions.Dashboard.Host)
);
and then start gong to them. you'll see the css stylesheet files bein loaded several times.
Any update?