Feature Management modal (Angular): parent/child toggle cascade does nothing when the group display name differs from the group name
ABP Framework version: 10.6.0. The code is unchanged in 10.6.1 and 10.7.0-rc.5.
UI type: Angular (@abp/ng.feature-management)
Database provider: EF Core (PostgreSQL)
Tiered (for MVC) or Auth Server separated (for Angular): no
Exception message and full stack trace: none. This is a silent logic error.
Steps to reproduce
Define a feature group whose localized display name differs from its name, with a toggle feature and a child toggle:
var group = context.AddGroup("Clubs", L("Feature:Clubs")); // localized as "Clubes" in Spanish var parent = group.AddFeature("Clubs.Enabled", "false", valueType: new ToggleStringValueType()); parent.CreateChild("Clubs.Members", "false", valueType: new ToggleStringValueType());Switch the UI language to one where the display name is translated (for example Spanish, so "Clubs" becomes "Clubes").
Open Saas > Tenants > Features for any tenant and select the "Clubes" tab.
Check the child
Clubs.Members.
Expected
Checking the child also checks its parent, and unchecking the parent unchecks its children (checkToggleAncestors / uncheckToggleDescendants).
Actual
Only the clicked checkbox changes. A child can be saved as enabled while its parent is disabled.
With an English UI, where the display name "Clubs" equals the name, the cascade works.
Root cause
In FeatureManagementComponent, features() is keyed by the group name:
this.features.set(res.groups.reduce((acc, val) => ({
...acc,
[val.name]: mapFeatures(val.features, this.document.body?.dir),
}), {}));
The template also reads it by name (features()[group.name]). But getCurrentGroup(), which findParentByType and findChildrenByType use, indexes it by the selected display name:
getCurrentGroup() {
const selectedGroup = this.selectedGroupDisplayName();
return selectedGroup ? this.features()[selectedGroup] ?? [] : [];
}
When the display name differs from the name, this returns [], so no parent or children are ever found. The tabs use group.displayName as their value, which is probably how the mismatch was introduced.
Suggested fix
getCurrentGroup() {
const group = this.groups().find(g => g.displayName === this.selectedGroupDisplayName());
return group ? this.features()[group.name] ?? [] : [];
}
A cleaner option is to use group.name as the tab value and keep the display name only for rendering. That also avoids clashes when two groups share a display name.
1 Answer(s)
-
0
Hi,
This is a bug in the feature management modal. It also breaks built-in groups like Setting Management, since their display names differ from their names too.
You can use this workaround for now. Create
src/app/feature-management.patch.ts:import { FeatureManagementComponent } from '@abp/ng.feature-management'; const proto = FeatureManagementComponent.prototype as any; proto.getCurrentGroup = function (this: any) { const group = this.groups().find((g: { name: string; displayName: string }) => g.displayName === this.selectedGroupDisplayName()); return group ? (this.features()[group.name] ?? []) : []; };Then import it at the top of
src/main.ts:import './app/feature-management.patch';The fix is in https://github.com/abpframework/abp/pull/26241. Please remove the patch when you upgrade to a version that includes it, because the fix renames the field the patch reads.
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)