Merge pull request #5538 from abpframework/feat/5328

Add some improvements on FeatureManagement
pull/5567/head
Mehmet Erim 5 years ago committed by GitHub
commit ce67f4e4b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -23,20 +23,22 @@
<hr class="mt-2 mb-3" />
<div
class="row my-3"
class="mt-2"
*ngFor="let feature of features[group.name]; let i = index; trackBy: track.by('id')"
[ngStyle]="feature.style"
[ngSwitch]="feature.valueType?.name"
(keyup.enter)="save()"
>
<div *ngSwitchCase="valueTypes.ToggleStringValueType">
<ng-container *ngSwitchCase="valueTypes.ToggleStringValueType">
<div class="custom-checkbox custom-control">
<input
class="custom-control-input"
type="checkbox"
[id]="feature.name"
[(ngModel)]="feature.value"
(ngModelChange)="onCheckboxClick($event, feature)"
/>
<label class="custom-control-label" [htmlFor]="feature.name">{{
feature.displayName
}}</label>
@ -44,27 +46,32 @@
*ngTemplateOutlet="descTmp; context: { $implicit: feature.description }"
></ng-container>
</div>
</div>
<div *ngSwitchCase="valueTypes.FreeTextStringValueType">
<div class="form-group mb-0">
</ng-container>
<ng-container *ngSwitchCase="valueTypes.FreeTextStringValueType">
<div class="form-group">
<label [htmlFor]="feature.name">{{ 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>
</div>
<div *ngSwitchCase="valueTypes.SelectionStringValueType">
</ng-container>
<ng-container *ngSwitchCase="valueTypes.SelectionStringValueType">
<ng-container *ngIf="feature.valueType.itemSource?.items?.length">
<div class="form-group mb-0">
<div class="form-group">
<label [htmlFor]="feature.name">{{ feature.displayName }}</label>
<select class="form-control" [id]="feature.name" [(ngModel)]="feature.value">
<select
class="form-control custom-select"
[id]="feature.name"
[(ngModel)]="feature.value"
>
<option
*ngFor="
let item of feature.valueType.itemSource?.items;
@ -83,8 +90,8 @@
></ng-container>
</div>
</ng-container>
</div>
<div *ngSwitchDefault>{{ feature.displayName }}</div>
</ng-container>
<ng-container *ngSwitchDefault>{{ feature.displayName }}</ng-container>
</div>
</ng-template>
</li>

@ -119,6 +119,70 @@ export class FeatureManagementComponent
}
});
}
onCheckboxClick(val: boolean, feature: FeatureDto) {
if (val) {
this.checkToggleAncestors(feature);
} else {
this.uncheckToggleDescendants(feature);
}
}
private uncheckToggleDescendants(feature: FeatureDto) {
this.findAllDescendantsOfByType(feature, ValueTypes.ToggleStringValueType).forEach(node =>
this.setFeatureValue(node, false),
);
}
private checkToggleAncestors(feature: FeatureDto) {
this.findAllAncestorsOfByType(feature, ValueTypes.ToggleStringValueType).forEach(node =>
this.setFeatureValue(node, true),
);
}
private findAllAncestorsOfByType(feature: FeatureDto, type: ValueTypes) {
let parent = this.findParentByType(feature, type);
const ancestors = [];
while (parent) {
ancestors.push(parent);
parent = this.findParentByType(parent, type);
}
return ancestors;
}
private findAllDescendantsOfByType(feature: FeatureDto, type: ValueTypes) {
const descendants = [];
const queue = [feature];
while (queue.length) {
const node = queue.pop();
const newDescendants = this.findChildrenByType(node, type);
descendants.push(...newDescendants);
queue.push(...newDescendants);
}
return descendants;
}
private findParentByType(feature: FeatureDto, type: ValueTypes) {
return this.getCurrentGroup().find(
f => f.valueType.name === type && f.name === feature.parentName,
);
}
private findChildrenByType(feature: FeatureDto, type: ValueTypes) {
return this.getCurrentGroup().filter(
f => f.valueType.name === type && f.parentName === feature.name,
);
}
private getCurrentGroup() {
return this.features[this.selectedGroupDisplayName] ?? [];
}
private setFeatureValue(feature: FeatureDto, val: boolean) {
feature.value = val as any;
}
}
function mapFeatures(features: FeatureDto[], dir: LocaleDirection) {

@ -0,0 +1,38 @@
import { Directive, Input, HostBinding } from '@angular/core';
// TODO: improve this type
export interface FreeTextType {
valueType: {
validator: {
name: string;
};
};
}
export const INPUT_TYPES = {
numeric: 'number',
default: 'text',
};
@Directive({
selector: 'input[abpFeatureManagementFreeText]',
exportAs: 'inputAbpFeatureManagementFreeText',
})
export class FreeTextInputDirective {
_feature: FreeTextType;
@Input('abpFeatureManagementFreeText') set feature(val: FreeTextType) {
this._feature = val;
this.setInputType();
}
get feature() {
return this._feature;
}
@HostBinding('type') type: string;
private setInputType() {
const validatorType = this.feature?.valueType?.validator?.name.toLowerCase();
this.type = INPUT_TYPES[validatorType] ?? INPUT_TYPES.default;
}
}

@ -0,0 +1 @@
export * from './free-text-input.directive';

@ -1,19 +1,22 @@
import { CoreModule } from '@abp/ng.core';
import { ThemeSharedModule } from '@abp/ng.theme.shared';
import { NgModule } from '@angular/core';
import { FeatureManagementComponent } from './components/feature-management/feature-management.component';
import { NgxsModule } from '@ngxs/store';
import { FeatureManagementState } from './states/feature-management.state';
import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
import { FreeTextInputDirective } from './directives/free-text-input.directive';
import { FeatureManagementComponent } from './components/feature-management/feature-management.component';
import { FeatureManagementState } from './states/feature-management.state';
const exported = [FeatureManagementComponent, FreeTextInputDirective];
@NgModule({
declarations: [FeatureManagementComponent],
declarations: [...exported],
imports: [
CoreModule,
ThemeSharedModule,
NgbNavModule,
NgxsModule.forFeature([FeatureManagementState]),
],
exports: [FeatureManagementComponent],
exports: [...exported],
})
export class FeatureManagementModule {}

Loading…
Cancel
Save