0
cangunaydin created
-
ABP Framework version: v9.1
-
UI Type: Angular
-
Database System: EF Core (PostgreSQL)
-
Tiered (for MVC) or Auth Server Separated (for Angular): no (but does not matter)
When you have a feature in 3 layers structure like
* Signage
* Playlist
* ShareOfVoice
in angular ui you can not see the branches in this order. it is always 2 layers.
here is the sample code.
public class BookStoreFeatureDefinitionProvider : FeatureDefinitionProvider
{
public override void Define(IFeatureDefinitionContext context)
{
var group = context.AddGroup(BookStoreFeatures.GroupName,
L("Feature:BookStore"));
var signageFeature = group.AddFeature(BookStoreFeatures.Signage.Default,
"false",
L("Feature:BookStoreSignage"),
L("Feature:BookStoreSignageDescription"),
new ToggleStringValueType());
var playlistFeature = signageFeature.CreateChild(BookStoreFeatures.Signage.Playlist.Default,
"false",
L("Feature:BookStorePlaylist"),
L("Feature:BookStorePlaylistDescription"),
new ToggleStringValueType());
var playlistShareOfVoiceFeature = playlistFeature.CreateChild(BookStoreFeatures.Signage.Playlist.ShareOfVoice,
"false",
L("Feature:BookStorePlaylistShareOfVoice"),
L("Feature:BookStorePlaylistShareOfVoiceDescription"),
new ToggleStringValueType());
}
private static LocalizableString L(string name)
{
return LocalizableString.Create(name);
}
}
here is the output for it.
3 Answer(s)
-
0
Hello, thank you for reporting this, and it will be fixed within the next release. I am refunding your ticket as well.
-
0
Is there a way that I can fix it in my version ? Can you give step by step instructions
-
0
Yes, you can use this workaround until we release the solution:
-
Patch the feature management setting tab.
//app.component.ts import { SettingTabsService } from '@abp/ng.setting-management/config'; import { NewFeatureManagementTabComponent } from './new-feature-management-tab/new-feature-management-tab.component'; @Component(...) export class AppComponent { protected settingTabs = inject(SettingTabsService); constructor() { this.settingTabs.patch('AbpFeatureManagement::Permission:FeatureManagement', { name: 'New Feature Management', order: 100, requiredPolicy: 'FeatureManagement.ManageHostFeatures', component: NewFeatureManagementTabComponent, }); } }
-
Implement
NewFeatureManagementTabComponent
as follows:
// new-feature-management-tab.component.ts import { LocalizationModule } from '@abp/ng.core'; import { Component } from '@angular/core'; import { NewFeatureManagementComponent } from '../new-feature-management/new-feature-management.component'; import { FeatureManagementTabComponent } from '@abp/ng.feature-management'; @Component({ selector: 'app-new-feature-management-tab', imports: [LocalizationModule, NewFeatureManagementComponent], template: ` <p class="pt-2 text-wrap"> {{ 'AbpFeatureManagement::ManageHostFeaturesText' | abpLocalization }} </p> <button class="btn btn-primary" type="button" (click)="openFeaturesModal()"> <i class="me-1 fa fa-cog" aria-hidden="true"></i> {{ 'AbpFeatureManagement::ManageHostFeatures' | abpLocalization }} </button> @if (visibleFeatures) { <app-new-feature-management [(visible)]="visibleFeatures" providerName="T" [providerKey]="providerKey" /> } `, styleUrl: './new-feature-management-tab.component.scss', }) export class NewFeatureManagementTabComponent extends FeatureManagementTabComponent {}
-
Add
NewFeatureManagementComponent
.
// new-feature-management.component.ts import { LocalizationModule } from '@abp/ng.core'; import { ThemeSharedModule } from '@abp/ng.theme.shared'; import { Component } from '@angular/core'; import { CommonModule, NgTemplateOutlet } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap'; import { FeatureManagementComponent, FreeTextInputDirective } from '@abp/ng.feature-management'; @Component({ selector: 'app-new-feature-management', imports: [ CommonModule, ThemeSharedModule, LocalizationModule, FormsModule, NgbNavModule, FreeTextInputDirective, NgTemplateOutlet, ], template: ` @if (visible) { <abp-modal [(visible)]="visible" [busy]="modalBusy" [options]="{ size: 'lg' }"> <ng-template #abpHeader> <h3> {{ 'AbpFeatureManagement::Features' | abpLocalization }} @if (providerTitle) { - {{ providerTitle }} } </h3> </ng-template> <ng-template #abpBody> <div class="row"> @if (groups.length) { <div class="col-md-4"> <ul ngbNav #nav="ngbNav" [(activeId)]="selectedGroupDisplayName" class="nav-pills" orientation="vertical" > @for (group of groups; track group.name) { <li [ngbNavItem]="group.displayName"> <a ngbNavLink>{{ group.displayName }}</a> <ng-template ngbNavContent> <h4>{{ selectedGroupDisplayName }}</h4> <hr class="mt-2 mb-3" /> @for (feature of features[group.name]; track feature.id || i; let i = $index) { <div class="mt-2" [ngStyle]="feature.style" (keyup.enter)="save()"> @switch (feature.valueType?.name) { @case (valueTypes.ToggleStringValueType) { <div class="form-check" [class.px-4]="!!feature.parentName"> <input class="form-check-input" type="checkbox" [id]="feature.name" [(ngModel)]="feature.value" (ngModelChange)="onCheckboxClick($event, feature)" /> <label class="form-check-label" [htmlFor]="feature.name">{{ feature.displayName }}</label> <ng-container *ngTemplateOutlet="descTmp; context: { $implicit: feature.description }" ></ng-container> </div> } @case (valueTypes.FreeTextStringValueType) { <div class="mb-3 form-group" [class.px-2]="!!feature.parentName"> <label [htmlFor]="feature.name" class="form-label">{{ feature.displayName }}</label> <input class="form-control" type="text" [id]="feature.name" [(ngModel)]="feature.value" [abpFeatureManagementFreeText]="feature" /> <ng-container *ngTemplateOutlet="descTmp; context: { $implicit: feature.description }" ></ng-container> </div> } @case (valueTypes.SelectionStringValueType) { @if (feature.valueType.itemSource?.items?.length) { <div class="mb-3 form-group" [class.px-2]="!!feature.parentName"> <label [htmlFor]="feature.name" class="form-label">{{ feature.displayName }}</label> <select class="form-select" [id]="feature.name" [(ngModel)]="feature.value"> @for ( item of feature.valueType.itemSource?.items; track item.value ) { <option [ngValue]="item.value"> {{ item.displayText?.resourceName + '::' + item.displayText?.name | abpLocalization }} </option> } </select> <ng-container *ngTemplateOutlet="descTmp; context: { $implicit: feature.description }" ></ng-container> </div> } } @default { {{ feature.displayName }} } } </div> } </ng-template> </li> } </ul> </div> <ng-template #descTmp let-description> @if (description) { <small class="d-block form-text text-muted">{{ description }}</small> } </ng-template> <div class="col-md-8"><div class="py-0" [ngbNavOutlet]="nav"></div></div> } @if (!groups.length) { <div class="col"> {{ 'AbpFeatureManagement::NoFeatureFoundMessage' | abpLocalization }} </div> } </div> </ng-template> <ng-template #abpFooter> <button abpClose type="button" class="btn btn-link"> {{ 'AbpFeatureManagement::Cancel' | abpLocalization }} </button> @if (groups.length) { <abp-button buttonClass="btn btn-outline-primary" [disabled]="modalBusy" (click)="resetToDefault()" aria-hidden="true" > {{ 'AbpFeatureManagement::ResetToDefault' | abpLocalization }} </abp-button> } @if (groups.length) { <abp-button iconClass="fa fa-check" [disabled]="modalBusy" (click)="save()" aria-hidden="true" > {{ 'AbpFeatureManagement::Save' | abpLocalization }} </abp-button> } </ng-template> </abp-modal> } `, styleUrl: './new-feature-management.component.scss', }) export class NewFeatureManagementComponent extends FeatureManagementComponent {}
-