From faf4ea1bda24c4f0eb4441e95bde43d8718ca821 Mon Sep 17 00:00:00 2001 From: Fahri Gedik <53567152+fahrigedik@users.noreply.github.com> Date: Thu, 25 Dec 2025 15:40:27 +0300 Subject: [PATCH] Refactor lookup and permission components, add styles Refactored lookup-search and permission-checkbox-list components to use SCSS for dropdown and list container styling. Improved resource permission management component with signals and untracked for state updates, and replaced manual destroy logic with Angular's DestroyRef and takeUntilDestroyed. Updated HTML templates for better readability and accessibility. --- .../src/lib/lookup-search.component.html | 83 +++++++------------ .../src/lib/lookup-search.component.scss | 5 ++ .../lookup/src/lib/lookup-search.component.ts | 23 +++-- .../permission-checkbox-list.component.html | 10 +-- .../permission-checkbox-list.component.scss | 4 + .../permission-checkbox-list.component.ts | 1 + .../provider-key-search.component.ts | 17 ++-- ...esource-permission-management.component.ts | 29 +++++-- 8 files changed, 83 insertions(+), 89 deletions(-) create mode 100644 npm/ng-packs/packages/components/lookup/src/lib/lookup-search.component.scss create mode 100644 npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/permission-checkbox-list/permission-checkbox-list.component.scss diff --git a/npm/ng-packs/packages/components/lookup/src/lib/lookup-search.component.html b/npm/ng-packs/packages/components/lookup/src/lib/lookup-search.component.html index 23e812717c..e795025aec 100644 --- a/npm/ng-packs/packages/components/lookup/src/lib/lookup-search.component.html +++ b/npm/ng-packs/packages/components/lookup/src/lib/lookup-search.component.html @@ -1,64 +1,45 @@
@if (label()) { - + }
- + @if (displayValue() && !disabled()) { - + }
@if (showDropdown() && !disabled()) { -
- @if (isLoading()) { -
- - {{ 'AbpUi::Loading' | abpLocalization }} -
- } @else if (searchResults().length > 0) { - @for (item of searchResults(); track item.key) { - - } - } @else if (displayValue()) { - @if (noResultsTemplate()) { - - } @else { -
- {{ 'AbpUi::NoRecordsFound' | abpLocalization }} -
- } +
+ @if (isLoading()) { +
+ + {{ 'AbpUi::Loading' | abpLocalization }} +
+ } @else if (searchResults().length > 0) { + @for (item of searchResults(); track item.key) { + + } + } @else if (displayValue()) { + @if (noResultsTemplate()) { + + } @else { +
+ {{ 'AbpUi::NoRecordsFound' | abpLocalization }}
+ } + } +
} -
+
\ No newline at end of file diff --git a/npm/ng-packs/packages/components/lookup/src/lib/lookup-search.component.scss b/npm/ng-packs/packages/components/lookup/src/lib/lookup-search.component.scss new file mode 100644 index 0000000000..6fd1e2dc26 --- /dev/null +++ b/npm/ng-packs/packages/components/lookup/src/lib/lookup-search.component.scss @@ -0,0 +1,5 @@ +.abp-lookup-dropdown { + z-index: 1050; + max-height: 200px; + overflow-y: auto; +} diff --git a/npm/ng-packs/packages/components/lookup/src/lib/lookup-search.component.ts b/npm/ng-packs/packages/components/lookup/src/lib/lookup-search.component.ts index 80770839bf..9633b15ab8 100644 --- a/npm/ng-packs/packages/components/lookup/src/lib/lookup-search.component.ts +++ b/npm/ng-packs/packages/components/lookup/src/lib/lookup-search.component.ts @@ -5,15 +5,17 @@ import { model, signal, OnInit, - OnDestroy, ChangeDetectionStrategy, TemplateRef, contentChild, + DestroyRef, + inject, } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { LocalizationPipe } from '@abp/ng.core'; -import { Subject, Observable, debounceTime, distinctUntilChanged, takeUntil, of } from 'rxjs'; +import { Subject, Observable, debounceTime, distinctUntilChanged, of, finalize } from 'rxjs'; export interface LookupItem { key: string; @@ -26,10 +28,12 @@ export type LookupSearchFn = (filter: string) => Observable @Component({ selector: 'abp-lookup-search', templateUrl: './lookup-search.component.html', + styleUrl: './lookup-search.component.scss', imports: [CommonModule, FormsModule, LocalizationPipe], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class LookupSearchComponent implements OnInit, OnDestroy { +export class LookupSearchComponent implements OnInit { + private readonly destroyRef = inject(DestroyRef); readonly label = input(); readonly placeholder = input(''); @@ -55,23 +59,17 @@ export class LookupSearchComponent implements readonly isLoading = signal(false); private readonly searchSubject = new Subject(); - private readonly destroy$ = new Subject(); ngOnInit() { this.searchSubject.pipe( debounceTime(this.debounceTime()), distinctUntilChanged(), - takeUntil(this.destroy$) + takeUntilDestroyed(this.destroyRef) ).subscribe(filter => { this.performSearch(filter); }); } - ngOnDestroy() { - this.destroy$.next(); - this.destroy$.complete(); - } - onSearchInput(filter: string) { this.displayValue.set(filter); this.showDropdown.set(true); @@ -120,15 +118,14 @@ export class LookupSearchComponent implements this.isLoading.set(true); this.searchFn()(filter).pipe( - takeUntil(this.destroy$) + takeUntilDestroyed(this.destroyRef), + finalize(() => this.isLoading.set(false)) ).subscribe({ next: results => { this.searchResults.set(results); - this.isLoading.set(false); }, error: () => { this.searchResults.set([]); - this.isLoading.set(false); } }); } diff --git a/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/permission-checkbox-list/permission-checkbox-list.component.html b/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/permission-checkbox-list/permission-checkbox-list.component.html index 87c8f27d70..07db143b00 100644 --- a/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/permission-checkbox-list/permission-checkbox-list.component.html +++ b/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/permission-checkbox-list/permission-checkbox-list.component.html @@ -3,20 +3,20 @@
{{ title() | abpLocalization }}
}
- -
-
+
@for (perm of permissions(); track perm.name) {
- -
diff --git a/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/permission-checkbox-list/permission-checkbox-list.component.scss b/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/permission-checkbox-list/permission-checkbox-list.component.scss new file mode 100644 index 0000000000..0562864716 --- /dev/null +++ b/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/permission-checkbox-list/permission-checkbox-list.component.scss @@ -0,0 +1,4 @@ +.abp-permission-list-container { + max-height: 300px; + overflow-y: auto; +} \ No newline at end of file diff --git a/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/permission-checkbox-list/permission-checkbox-list.component.ts b/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/permission-checkbox-list/permission-checkbox-list.component.ts index fe36cbb800..26c5a314f9 100644 --- a/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/permission-checkbox-list/permission-checkbox-list.component.ts +++ b/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/permission-checkbox-list/permission-checkbox-list.component.ts @@ -10,6 +10,7 @@ interface PermissionItem { @Component({ selector: 'abp-permission-checkbox-list', templateUrl: './permission-checkbox-list.component.html', + styleUrl: './permission-checkbox-list.component.scss', imports: [LocalizationPipe], changeDetection: ChangeDetectionStrategy.OnPush, }) diff --git a/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/provider-key-search/provider-key-search.component.ts b/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/provider-key-search/provider-key-search.component.ts index 1e7e54b88c..0aceed0c5f 100644 --- a/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/provider-key-search/provider-key-search.component.ts +++ b/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/provider-key-search/provider-key-search.component.ts @@ -1,7 +1,8 @@ -import { Component, input, inject, OnInit, OnDestroy, ChangeDetectionStrategy } from '@angular/core'; +import { Component, input, inject, OnInit, ChangeDetectionStrategy, DestroyRef } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { PermissionsService } from '@abp/ng.permission-management/proxy'; import { LookupSearchComponent, LookupItem } from '@abp/ng.components/lookup'; -import { Observable, map, Subject, takeUntil } from 'rxjs'; +import { Observable, map } from 'rxjs'; import { ResourcePermissionStateService } from '../../../services/resource-permission-state.service'; interface ProviderKeyLookupItem extends LookupItem { @@ -15,25 +16,19 @@ interface ProviderKeyLookupItem extends LookupItem { imports: [LookupSearchComponent], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class ProviderKeySearchComponent implements OnInit, OnDestroy { +export class ProviderKeySearchComponent implements OnInit { readonly state = inject(ResourcePermissionStateService); private readonly service = inject(PermissionsService); + private readonly destroyRef = inject(DestroyRef); readonly resourceName = input.required(); - private readonly destroy$ = new Subject(); - searchFn: (filter: string) => Observable = () => new Observable(); ngOnInit() { this.searchFn = (filter: string) => this.loadProviderKeys(filter); } - ngOnDestroy() { - this.destroy$.next(); - this.destroy$.complete(); - } - onItemSelected(item: ProviderKeyLookupItem) { // State is already updated via displayValue and selectedValue bindings // This handler can be used for additional side effects if needed @@ -60,7 +55,7 @@ export class ProviderKeySearchComponent implements OnInit, OnDestroy { providerKey: k.providerKey || '', providerDisplayName: k.providerDisplayName || undefined, }))), - takeUntil(this.destroy$) + takeUntilDestroyed(this.destroyRef) ); } } diff --git a/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/resource-permission-management.component.ts b/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/resource-permission-management.component.ts index c38d6036ee..fc534f128d 100644 --- a/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/resource-permission-management.component.ts +++ b/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/resource-permission-management.component.ts @@ -18,6 +18,8 @@ import { model, OnInit, effect, + untracked, + signal, } from '@angular/core'; import { finalize, switchMap, of } from 'rxjs'; import { ResourcePermissionStateService } from '../../services/resource-permission-state.service'; @@ -26,6 +28,8 @@ import { ResourcePermissionFormComponent } from './resource-permission-form/reso import { eResourcePermissionViewModes } from '../../enums/view-modes'; +const DEFAULT_MAX_RESULT_COUNT = 10; + @Component({ selector: 'abp-resource-permission-management', templateUrl: './resource-permission-management.component.html', @@ -55,33 +59,40 @@ export class ResourcePermissionManagementComponent implements OnInit { readonly visible = model(false); - private previousVisible = false; + private readonly previousVisible = signal(false); constructor() { effect(() => { - this.state.resourceName.set(this.resourceName()); - this.state.resourceKey.set(this.resourceKey()); - this.state.resourceDisplayName.set(this.resourceDisplayName()); + const resourceName = this.resourceName(); + const resourceKey = this.resourceKey(); + const resourceDisplayName = this.resourceDisplayName(); + + untracked(() => { + this.state.resourceName.set(resourceName); + this.state.resourceKey.set(resourceKey); + this.state.resourceDisplayName.set(resourceDisplayName); + }); }); effect(() => { const isVisible = this.visible(); - if (isVisible && !this.previousVisible) { + const wasVisible = this.previousVisible(); + if (isVisible && !wasVisible) { this.openModal(); - } else if (!isVisible && this.previousVisible) { + } else if (!isVisible && wasVisible) { this.state.reset(); } - this.previousVisible = isVisible; + untracked(() => this.previousVisible.set(isVisible)); }); } ngOnInit() { - this.list.maxResultCount = 10; + this.list.maxResultCount = DEFAULT_MAX_RESULT_COUNT; this.list.hookToQuery(query => { const allData = this.state.allResourcePermissions(); const skipCount = query.skipCount || 0; - const maxResultCount = query.maxResultCount || 10; + const maxResultCount = query.maxResultCount || DEFAULT_MAX_RESULT_COUNT; const paginatedData = allData.slice(skipCount, skipCount + maxResultCount);