mirror of https://github.com/abpframework/abp.git
Browse Source
Replaced [ngStyle] with [style] bindings in multiple components for improved Angular compatibility and performance. Removed unnecessary NgStyle imports from affected components and updated their module imports accordingly.pull/24579/head
10 changed files with 264 additions and 302 deletions
@ -1,181 +1,146 @@ |
|||
@if (visible) { |
|||
<abp-modal [(visible)]="visible" [busy]="modalBusy" [options]="{ size: 'lg' }"> |
|||
<ng-template #abpHeader> |
|||
<h3> |
|||
{{ 'AbpFeatureManagement::Features' | abpLocalization }} |
|||
@if (providerTitle) { |
|||
- {{ providerTitle }} |
|||
} |
|||
</h3> |
|||
</ng-template> |
|||
<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" /> |
|||
<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) { |
|||
@let provider = feature.provider.name; |
|||
@let isFeatureDisabled = !feature.parentName ? isParentDisabled(feature.name, group.name, provider) : |
|||
(provider !== providerName && provider !== defaultProviderName); |
|||
@for (feature of features[group.name]; track feature.id || i; let i = $index) { |
|||
@let provider = feature.provider.name; |
|||
@let isFeatureDisabled = !feature.parentName ? isParentDisabled(feature.name, group.name, provider) : |
|||
(provider !== providerName && provider !== defaultProviderName); |
|||
|
|||
<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)" |
|||
[disabled]="isFeatureDisabled" |
|||
/> |
|||
<div class="mt-2" [style]="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)" [disabled]="isFeatureDisabled" /> |
|||
|
|||
<label class="form-check-label" [htmlFor]="feature.name"> |
|||
{{ feature.displayName }} |
|||
@if (isFeatureDisabled) { |
|||
<span>({{ provider }})</span> |
|||
} |
|||
</label> |
|||
<ng-container |
|||
*ngTemplateOutlet=" |
|||
<label class="form-check-label" [htmlFor]="feature.name"> |
|||
{{ feature.displayName }} |
|||
@if (isFeatureDisabled) { |
|||
<span>({{ provider }})</span> |
|||
} |
|||
</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 }} |
|||
@if (isFeatureDisabled) { |
|||
<span>({{ provider }})</span> |
|||
} |
|||
</label> |
|||
<input |
|||
class="form-control" |
|||
type="text" |
|||
[id]="feature.name" |
|||
[(ngModel)]="feature.value" |
|||
[abpFeatureManagementFreeText]="feature" |
|||
[disabled]="isFeatureDisabled" |
|||
/> |
|||
"></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 }} |
|||
@if (isFeatureDisabled) { |
|||
<span>({{ provider }})</span> |
|||
} |
|||
</label> |
|||
<input class="form-control" type="text" [id]="feature.name" [(ngModel)]="feature.value" |
|||
[abpFeatureManagementFreeText]="feature" [disabled]="isFeatureDisabled" /> |
|||
|
|||
<ng-container |
|||
*ngTemplateOutlet=" |
|||
<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 }} |
|||
@if (isFeatureDisabled) { |
|||
<span>({{ provider }})</span> |
|||
} |
|||
</label> |
|||
<select |
|||
class="form-select" |
|||
[id]="feature.name" |
|||
[(ngModel)]="feature.value" |
|||
[disabled]="isFeatureDisabled" |
|||
> |
|||
@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=" |
|||
"></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 }} |
|||
@if (isFeatureDisabled) { |
|||
<span>({{ provider }})</span> |
|||
} |
|||
</label> |
|||
<select class="form-select" [id]="feature.name" [(ngModel)]="feature.value" |
|||
[disabled]="isFeatureDisabled"> |
|||
@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> |
|||
"></ng-container> |
|||
</div> |
|||
} |
|||
} |
|||
@default { |
|||
{{ feature.displayName }} |
|||
} |
|||
} |
|||
</div> |
|||
} |
|||
</ul> |
|||
</div> |
|||
|
|||
<ng-template #descTmp let-description> |
|||
@if (description) { |
|||
<small class="d-block form-text text-muted">{{ description }}</small> |
|||
} |
|||
</ng-template> |
|||
</ng-template> |
|||
</li> |
|||
} |
|||
</ul> |
|||
</div> |
|||
|
|||
<div class="col-md-8"><div class="py-0" [ngbNavOutlet]="nav"></div></div> |
|||
<ng-template #descTmp let-description> |
|||
@if (description) { |
|||
<small class="d-block form-text text-muted">{{ description }}</small> |
|||
} |
|||
</ng-template> |
|||
|
|||
@if (!groups.length) { |
|||
<div class="col"> |
|||
{{ 'AbpFeatureManagement::NoFeatureFoundMessage' | abpLocalization }} |
|||
</div> |
|||
} |
|||
<div class="col-md-8"> |
|||
<div class="py-0" [ngbNavOutlet]="nav"></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> |
|||
@if (!groups.length) { |
|||
<div class="col"> |
|||
{{ 'AbpFeatureManagement::NoFeatureFoundMessage' | abpLocalization }} |
|||
</div> |
|||
} |
|||
</ng-template> |
|||
</abp-modal> |
|||
} |
|||
</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> |
|||
} |
|||
@ -1,118 +1,116 @@ |
|||
import { NgClass, NgStyle } from '@angular/common'; |
|||
import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit, inject } from '@angular/core'; |
|||
import { combineLatest, Subscription, timer } from 'rxjs'; |
|||
import { HttpWaitService, RouterWaitService, SubscriptionService } from '@abp/ng.core'; |
|||
|
|||
@Component({ |
|||
selector: 'abp-loader-bar', |
|||
template: ` |
|||
<div id="abp-loader-bar" [ngClass]="containerClass" [class.is-loading]="isLoading"> |
|||
<div |
|||
class="abp-progress" |
|||
[class.progressing]="progressLevel" |
|||
[style.width.vw]="progressLevel" |
|||
[ngStyle]="{ |
|||
'background-color': color, |
|||
'box-shadow': boxShadow, |
|||
}" |
|||
></div> |
|||
</div> |
|||
`,
|
|||
styleUrls: ['./loader-bar.component.scss'], |
|||
providers: [SubscriptionService], |
|||
imports: [NgClass, NgStyle], |
|||
}) |
|||
export class LoaderBarComponent implements OnDestroy, OnInit { |
|||
private cdRef = inject(ChangeDetectorRef); |
|||
private subscription = inject(SubscriptionService); |
|||
private httpWaitService = inject(HttpWaitService); |
|||
private routerWaitService = inject(RouterWaitService); |
|||
|
|||
protected _isLoading!: boolean; |
|||
|
|||
@Input() |
|||
set isLoading(value: boolean) { |
|||
this._isLoading = value; |
|||
this.cdRef.detectChanges(); |
|||
} |
|||
get isLoading(): boolean { |
|||
return this._isLoading; |
|||
} |
|||
|
|||
@Input() |
|||
containerClass = 'abp-loader-bar'; |
|||
|
|||
@Input() |
|||
color = '#77b6ff'; |
|||
|
|||
progressLevel = 0; |
|||
|
|||
interval = new Subscription(); |
|||
|
|||
timer = new Subscription(); |
|||
|
|||
intervalPeriod = 350; |
|||
|
|||
stopDelay = 800; |
|||
|
|||
private readonly clearProgress = () => { |
|||
this.progressLevel = 0; |
|||
this.cdRef.detectChanges(); |
|||
}; |
|||
|
|||
private readonly reportProgress = () => { |
|||
if (this.progressLevel < 75) { |
|||
this.progressLevel += 1 + Math.random() * 9; |
|||
} else if (this.progressLevel < 90) { |
|||
this.progressLevel += 0.4; |
|||
} else if (this.progressLevel < 100) { |
|||
this.progressLevel += 0.1; |
|||
} else { |
|||
this.interval.unsubscribe(); |
|||
} |
|||
this.cdRef.detectChanges(); |
|||
}; |
|||
|
|||
get boxShadow(): string { |
|||
return `0 0 10px rgba(${this.color}, 0.5)`; |
|||
} |
|||
|
|||
ngOnInit() { |
|||
this.subscribeLoading(); |
|||
} |
|||
|
|||
subscribeLoading() { |
|||
this.subscription.addOne( |
|||
combineLatest([this.httpWaitService.getLoading$(), this.routerWaitService.getLoading$()]), |
|||
([httpLoading, routerLoading]) => { |
|||
if (httpLoading || routerLoading) this.startLoading(); |
|||
else this.stopLoading(); |
|||
}, |
|||
); |
|||
} |
|||
|
|||
ngOnDestroy() { |
|||
this.interval.unsubscribe(); |
|||
} |
|||
|
|||
startLoading() { |
|||
if (this.isLoading || !this.interval.closed) return; |
|||
|
|||
this.isLoading = true; |
|||
this.progressLevel = 0; |
|||
this.cdRef.detectChanges(); |
|||
this.interval = timer(0, this.intervalPeriod).subscribe(this.reportProgress); |
|||
this.timer.unsubscribe(); |
|||
} |
|||
|
|||
stopLoading() { |
|||
this.interval.unsubscribe(); |
|||
|
|||
this.progressLevel = 100; |
|||
this.isLoading = false; |
|||
|
|||
if (!this.timer.closed) return; |
|||
|
|||
this.timer = timer(this.stopDelay).subscribe(this.clearProgress); |
|||
} |
|||
} |
|||
import { NgClass }ngular/common'; |
|||
import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit, inject } from '@angular/core'; |
|||
import { combineLatest, Subscription, timer } from 'rxjs'; |
|||
import { HttpWaitService, RouterWaitService, SubscriptionService } from '@abp/ng.core'; |
|||
|
|||
@Component({ |
|||
selector: 'abp-loader-bar', |
|||
template: ` |
|||
<di |
|||
<div id="abp-loader-bar" [ngClass]="containerClass" [class.is-loading]="isLoading"> |
|||
<div |
|||
class="abp-progress" |
|||
[class.progressing]="progressLevel" |
|||
[style.width.vw]="progressLevel" |
|||
[style]="{ |
|||
'background-color': color, |
|||
'box-shadow': boxShadow, |
|||
}" |
|||
></div> |
|||
</div> |
|||
Urls: ['./loader-bar.component.scss'], |
|||
providers: [SubscriptionService], |
|||
imports: [NgClass],
[NgClass]LoaderBarComponent implements OnDestroy, OnInit { |
|||
private cdRef = inject(ChangeDetectorRef); |
|||
private subscription = inject(SubscriptionService); |
|||
private httpWaitService = inject(HttpWaitService); |
|||
private routerWaitService = inject(RouterWaitService); |
|||
|
|||
protected _isLoading!: boolean; |
|||
|
|||
@Input() |
|||
set isLoading(value: boolean) { |
|||
this._isLoading = value; |
|||
this.cdRef.detectChanges(); |
|||
} |
|||
get isLoading(): boolean { |
|||
return this._isLoading; |
|||
} |
|||
|
|||
@Input() |
|||
containerClass = 'abp-loader-bar'; |
|||
|
|||
@Input() |
|||
color = '#77b6ff'; |
|||
|
|||
progressLevel = 0; |
|||
|
|||
interval = new Subscription(); |
|||
|
|||
timer = new Subscription(); |
|||
|
|||
intervalPeriod = 350; |
|||
|
|||
stopDelay = 800; |
|||
|
|||
private readonly clearProgress = () => { |
|||
this.progressLevel = 0; |
|||
this.cdRef.detectChanges(); |
|||
}; |
|||
|
|||
private readonly reportProgress = () => { |
|||
if (this.progressLevel < 75) { |
|||
this.progressLevel += 1 + Math.random() * 9; |
|||
} else if (this.progressLevel < 90) { |
|||
this.progressLevel += 0.4; |
|||
} else if (this.progressLevel < 100) { |
|||
this.progressLevel += 0.1; |
|||
} else { |
|||
this.interval.unsubscribe(); |
|||
} |
|||
this.cdRef.detectChanges(); |
|||
}; |
|||
|
|||
get boxShadow(): string { |
|||
return `0 0 10px rgba(${this.color}, 0.5)`; |
|||
} |
|||
|
|||
ngOnInit() { |
|||
this.subscribeLoading(); |
|||
} |
|||
|
|||
subscribeLoading() { |
|||
this.subscription.addOne( |
|||
combineLatest([this.httpWaitService.getLoading$(), this.routerWaitService.getLoading$()]), |
|||
([httpLoading, routerLoading]) => { |
|||
if (httpLoading || routerLoading) this.startLoading(); |
|||
else this.stopLoading(); |
|||
}, |
|||
); |
|||
} |
|||
|
|||
ngOnDestroy() { |
|||
this.interval.unsubscribe(); |
|||
} |
|||
|
|||
startLoading() { |
|||
if (this.isLoading || !this.interval.closed) return; |
|||
|
|||
this.isLoading = true; |
|||
this.progressLevel = 0; |
|||
this.cdRef.detectChanges(); |
|||
this.interval = timer(0, this.intervalPeriod).subscribe(this.reportProgress); |
|||
this.timer.unsubscribe(); |
|||
} |
|||
|
|||
stopLoading() { |
|||
this.interval.unsubscribe(); |
|||
|
|||
this.progressLevel = 100; |
|||
this.isLoading = false; |
|||
|
|||
if (!this.timer.closed) return; |
|||
|
|||
this.timer = timer(this.stopDelay).subscribe(this.clearProgress); |
|||
} |
|||
} |
|||
|
|||
Loading…
Reference in new issue