Activities of "maliming"

👍

Hi,

The Admin Console doesn't render module extension properties yet. Its user, organization unit and tenant forms post a fixed set of fields, so your extra properties never reach the server and the required validation rejects the request.

We're adding support for this, planned for a release after 10.7. The built-in Identity, organization unit and Saas tenant screens will then read your extension definitions and render them on the create/edit forms and in the tables, including the validation attributes you configured.

Thanks

Hi,

This is a regression in the account switching flow: the previous session is now revoked during the switch, so any request the browser still has in flight with the old cookie signs itself out and clears the authentication cookie that the switch has just issued.

Until we ship the fix, you can skip the session revocation for the switch request. Add this to the ConfigureServices method of your *WebModule:

context.Services.ConfigureApplicationCookie(options =>
{
    var previousOnSigningOut = options.Events.OnSigningOut;
    options.Events.OnSigningOut = async signingOutContext =>
    {
        if (signingOutContext.HttpContext.Request.Path.StartsWithSegments("/Account/LinkLogin"))
        {
            return;
        }

        await previousOnSigningOut(signingOutContext);
    };
});

This brings the switch flow back to the 10.4 behavior, where the previous session is kept instead of being revoked. We're tracking the AbpDbConcurrencyException separately.

For the Hangfire error on 10.6: RecurringJob.RemoveIfExists("HangfirePeriodicBackgroundWorkerAdapter<BackgroundJobWorker>.DoWorkAsync") is the correct cleanup for the stale recurring job persisted by the earlier versions.

We'll fix the account switching issue in the next release and add the Hangfire cleanup step to the migration guide. Your ticket has been refunded.

Thanks

Answer

Hi,

The React settings and profile pages don't have a time zone selector, so granting that permission won't bring a dropdown. For what you described you don't need one, but nothing happens automatically either - with a React UI the conversion is done where you render and where you send.

On the backend AbpClockOptions.Kind = DateTimeKind.Utc is enough: your DateTime properties are stored as UTC and returned as UTC ISO strings (2026-08-14T10:30:00Z). Rendering them in the browser's local time zone is a helper you can reuse everywhere:

const formatDateTime = (value?: string) =>
  value ? new Date(value).toLocaleString() : ''

The other direction is on you. A datetime string without a time zone is stored as-is - the template's DatePicker emits 2026-08-14T10:30 once you enable withTime - so convert it before sending it to the API:

await createEvent({
  ...values,
  startTime: new Date(values.startTime).toISOString(),
})

Only for real timestamps though. Date-only values like publishDate (2026-08-14) should go as they are, otherwise they can shift by a day.

If your database already has rows, keep in mind that switching the clock kind doesn't rewrite them - values written as server local time are read back as UTC from now on.

The Account module can keep a time zone per user, but the React UI doesn't apply it when formatting, so keep the browser time zone as your source of truth for now.

Thanks

Hi,

You're right, this is a bug on our side.

Until the fix ships, open the account pages from your SPA in a new tab, so closing the tab is the way back for the users you send there:

<a
  href={`${backendUrl}/admin-console/account/manage`}
  target="_blank"
  rel="noopener noreferrer"
>
  {t('AbpAccount::MyAccount')}
</a>

The next version fixes it the way you suggested — set the application url and those links become plain anchors to it:

{
  "AdminConsole": {
    "ReturnUrl": "https://example.org/app"
  }
}

Your ticket has been refunded.

Thanks

Hi,

Confirmed, all six are real, and all six are fixed on our side. Sorry it took a second report to get here — the fix landed right after 10.6.0 was cut, and the patch release hasn't gone out yet, so there's nothing you can pick up from the feed today. We'll get it out as soon as we can and post the version here.

Until then, please keep the rewriting middleware you have. There's no configuration in 10.6.0 that can replace it, and it's the right shape for the problem.

One thing you can fix properly today, if your host project has the generated wwwroot/global-styles.css: drop the leading slash from every url('/...') in it, otherwise the LeptonX logo and the login background 404 under a prefix.

Un-minified sources aren't distributed and the package ships no source maps, so there's no channel you missed.

On sub-path deployment in the regression suite: fair ask, and I'll take it to the team.

Both tickets have been refunded — this one and https://abp.io/support/questions/10823.

Thanks

Hi,

We've updated the sample, so grab a fresh copy from https://abp.io/api/download/samples/elsaworkflow and work with that one. It ships with ABP 10.5.0 now and builds as it is, so you no longer need to update the packages yourself or add a migration.

Two things from my previous answer still apply:

  • Redis and RabbitMQ have to be up and reachable before you start ElsaDemoApp.Server.
  • Run abp install-libs once in the ElsaDemoApp.Server folder, the sample doesn't ship wwwroot/libs.

Thanks

Hi,

The demo needs SQL Server, Redis and RabbitMQ all reachable before it can start. Redis isn't reachable at 127.0.0.1:6379 and RabbitMQ isn't accepting connections on 127.0.0.1:5672 (the Windows service being Running doesn't mean the broker is listening).

The safest way on Windows is to run both in Docker instead of installing them locally:

docker run -d --name redis -p 6379:6379 redis:alpine
docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:management-alpine

If the RabbitMQ Windows service is still installed, stop it first so it doesn't hold port 5672.

Two more things for the sample itself. The download still ships ABP 10.0.0-rc.1 packages, so keep all Volo.Abp.* packages aligned on 10.6.0 after your update. The Identity schema changed between those versions, so add a migration in the ElsaDemoApp.Server folder and apply it:

dotnet ef migrations add Upgrade_To_10_6
dotnet run --migrate-database

Without it, seeding fails with Invalid column name 'LastSignInTime'.

The sample also doesn't ship wwwroot/libs, so run this once in the same folder:

abp install-libs

Then start the projects in the order from the docs: ElsaDemoApp.Server, ElsaDemoApp.Studio.WASM, ElsaDemoApp.Ordering, ElsaDemoApp.Payment.

Thanks

Hi,

All four are supported through ReplaceableComponentsService with the LeptonX component keys, and the data behind those components comes from services you can inject directly.

Keys

| What you replace | eThemeLeptonXComponents key | |---|---| | lpx-toolbar-container | Theme.ToolbarComponent | | lpx-navbar (desktop sidebar) | Theme.NavbarComponent | | lpx-settings | Theme.SettingsComponent | | whole application layout | Theme.ApplicationLayoutComponent |

Two things about the toolbar slot: the user avatar and the profile dropdown live inside lpx-toolbar-container, so replacing it means you rebuild those controls yourself. The settings panel is a sibling slot and keeps rendering unless you also replace Theme.SettingsComponent. The mobile sidebar is Theme.MobileNavbarComponent, separate from Theme.NavbarComponent.

Where to register

Register the replacements in AppComponent's constructor. That runs after all app initializers and before abp-dynamic-layout creates the layout, so you don't depend on provider ordering:

@Component({
  selector: 'app-root',
  template: `
    &lt;abp-loader-bar /&gt;
    &lt;abp-dynamic-layout /&gt;
  `,
  imports: [LoaderBarComponent, DynamicLayoutComponent],
})
export class AppComponent {
  private readonly replaceable = inject(ReplaceableComponentsService);

  constructor() {
    // keep the stock shell, swap individual slots
    this.replaceable.add({ key: eThemeLeptonXComponents.Toolbar, component: MyToolbarComponent });
    this.replaceable.add({ key: eThemeLeptonXComponents.Navbar, component: MyNavbarComponent });

    // or take over the whole shell instead — see the last section
    // this.replaceable.add({ key: eThemeLeptonXComponents.ApplicationLayout, component: MyLayoutComponent });
  }
}

Pick one of the two: once Theme.ApplicationLayoutComponent is replaced, the stock layout is gone and nothing consumes the slot keys anymore.

Keep <abp-dynamic-layout /> in the template — it picks the layout from route metadata through the same store. Register before the first layout resolution: DynamicLayoutComponent keeps the resolved layout while the layout type stays the same, so a replacement added later won't be picked up.

Services to inject

| Data | Service | Package | |---|---|---| | Menu items, groups | NavbarService (navbarItems$, groupedNavbarItems$) | @volo/ngx-lepton-x.core | | Toolbar entries | ToolbarService.items$, fed from ABP NavItemsService.addItems() | @volo/ngx-lepton-x.core, @abp/ng.theme.shared | | User info + profile actions | UserProfileService.user$ (user.userActionGroups) | @volo/ngx-lepton-x.core | | User menu entries | UserMenuService (addItems / patchItem / removeItem) | @abp/ng.theme.shared | | Authentication, login/logout | AuthService (isAuthenticated, navigateToLogin(), logout()) | @abp/ng.core | | Theme | ThemeService (styles$, selectedStyle$, setTheme()) | @volosoft/ngx-lepton-x | | Language | LanguageService (languages$, selectedLanguage$, setSelectedLanguage()) | @volo/ngx-lepton-x.core |

These are all public exports of the package entry points in your version. Four details that bite once you render the data yourself:

  • Permission filtering is applied upstream: ABP's RoutesService.visible$ filters by requiredPolicy and feeds NavbarService, so a route the user can't see never reaches your component. It re-runs when the application configuration refreshes (login, tenant switch, page reload) — a permission changed on the server in another session won't push into the menu until then.

  • Active route and expand/collapse state: on your version this is computed by lpx-navbar-routes (NavbarRoutesComponent), not by NavbarService — NavbarService applies it once, on the first navigation. It moved into NavbarService in 5.6.0. Rendering the items through that component inside your navbar works on both:

    <lpx-navbar-routes
      [navbarItems]="navbarService.navbarItems$ | async"
      [groupedItems]="navbarService.groupedNavbarItems$ | async"
    />
    

    It renders the menu list only — the logo, collapse behaviour and menu filter of lpx-navbar are not part of it. Two cases where you need to track the route yourself: your own markup instead of this component, and grouped menus, because the grouped branch renders groupedItems as given.

  • visible predicates: toolbar items and user actions can carry a visible predicate returning a boolean, a Promise or an Observable, and AbpToolbarService only applies requiredPolicy. Evaluate it with LpxVisibleDirective (@volo/ngx-lepton-x.core) the way the stock components do — inject Injector and use *lpxVisible="!item.visible || item.visible(item, injector)".

  • Localization: entries coming from UserMenuService carry raw keys (AbpAccount::MyAccount), so pipe them through | abpLocalization. Navbar item texts are already localized, but the group value on a navbar item is still a raw key, so localize it if you render grouped menus yourself.

AuthService.logout() returns an Observable, so subscribe to it — otherwise nothing runs.

Which setting groups show up

That's a DI token rather than a component. lpx-settings renders whatever LPX_SETTINGS_SERVICE provides, so wrap the default service and filter its two streams (LPX_SETTINGS_SERVICE, ISettingsService and SettingsService all come from @volosoft/ngx-lepton-x/layouts):

@Injectable()
export class CustomSettingsService implements ISettingsService {
  private defaults = inject(SettingsService);
  private themeService = inject(ThemeService);

  settings$ = this.defaults.settings$.pipe(
    map(groups => groups.filter(group => group.id === this.themeService.id)),
  );

  selectedSettings$ = this.defaults.selectedSettings$.pipe(
    map(groups => groups.filter(group => group.id === this.themeService.id)),
  );
}

Register it after provideSideMenuLayout() so it wins over the default:

provideThemeLeptonX(),
provideSideMenuLayout(),
{ provide: LPX_SETTINGS_SERVICE, useClass: CustomSettingsService },

For your second goal you don't need lpx-settings at all — inject ThemeService and LanguageService into your toolbar replacement and build the controls there. If you keep the stock layout, replace Theme.SettingsComponent with an empty component so the old panel stops rendering next to your toolbar.

Replacing the whole layout

Once you take over Theme.ApplicationLayoutComponent, the stock layout is gone and nothing consumes the slot keys anymore — your components go into your own template. There are two ways to write that template.

Keep <lpx-layout> (SideMenuLayoutComponent from @volosoft/ngx-lepton-x/layouts) and fill only the panels you want to change. This is what the stock ABP layout does, and it keeps the responsive breakpoints, the wrapper/container classes, the layout setting group and <lpx-topbar-content> working, with defaults for everything you don't fill. The panel directives come from @volo/ngx-lepton-x.core: lpx-navbar-panel, lpx-content, lpx-breadcrumb-panel, lpx-toolbar-panel, lpx-settings-panel, lpx-footer-panel, lpx-logo-panel, lpx-current-user-image-panel, lpx-mobile-navbar-panel, lpx-mobile-navbar-settings-panel, lpx-mobile-navbar-profile-panel.

Or write the shell from scratch, in which case everything you want is yours to place: <router-outlet>, abp-page-alert-container, the desktop navbar, breadcrumb, toolbar, settings, <lpx-topbar-content> (otherwise entries added through TopbarContentService disappear), footer, logo, the mobile navbar with its settings and profile panels, and the responsive/container classes. Routing, permissions, theme and localization keep working either way, but as services you consume, not as behaviour the layout gives you for free.

Source code

abp get-source Volo.Abp.LeptonXTheme -v <your LeptonX version> gives you an angular/projects/volo-lepton-x folder with the full TS/HTML of @volosoft/abp.ng.theme.lepton-x — the side-menu and top-menu layout components and their providers, which is the best reference for how the slots are wired. Pass the version explicitly, otherwise you get the latest one and it won't match what you run. The lower-level UI kit (lpx-navbar, lpx-toolbar-container, lpx-settings) isn't in that package, but the published packages ship their original sources inside the sourcemaps under node_modules if you want to read those implementations — as a reference only, the supported contract is what the package entry points export.

Thanks

: )

Showing 171 to 180 of 12921 entries
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.8.0-preview. Updated on November 02, 2026, 06:56
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.