diff --git a/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/resource-permission-management.component.html b/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/resource-permission-management.component.html
index fa5a2d681e..b8cc1afd1e 100644
--- a/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/resource-permission-management.component.html
+++ b/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/resource-permission-management.component.html
@@ -48,7 +48,7 @@
@if (resourcePermissions().length > 0) {
+ [actionsTemplate]="actionsTemplate" actionsText="AbpUi::Actions">
} @else {
{{ 'AbpPermissionManagement::NoPermissionsAssigned' | abpLocalization }}
@@ -77,13 +77,14 @@
- @if (searchResults().length > 0) {
+ [ngModel]="searchFilter()" (ngModelChange)="onSearchInput($event)" (focus)="onSearchFocus()"
+ (blur)="onSearchBlur()" />
+ @if (searchResults().length > 0 && showDropdown()) {
@for (result of searchResults(); track result.providerKey) {
}
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 f8e951a1f1..3f0334ce5e 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
@@ -1,6 +1,8 @@
import { ListService, LocalizationPipe } from '@abp/ng.core';
import {
ButtonComponent,
+ Confirmation,
+ ConfirmationService,
ModalCloseDirective,
ModalComponent,
ToasterService,
@@ -57,6 +59,7 @@ type ViewMode = 'list' | 'add' | 'edit';
export class ResourcePermissionManagementComponent implements OnInit {
protected readonly service = inject(PermissionsService);
protected readonly toasterService = inject(ToasterService);
+ protected readonly confirmationService = inject(ConfirmationService);
readonly list = inject(ListService);
@Input() resourceName!: string;
@@ -84,13 +87,11 @@ export class ResourcePermissionManagementComponent implements OnInit {
@Output() readonly visibleChange = new EventEmitter();
- // State signals
viewMode = signal('list');
modalBusy = signal(false);
hasResourcePermission = signal(false);
hasProviderKeyLookupService = signal(false);
- // Data
allResourcePermissions = signal([]); // All data for client-side pagination
resourcePermissions = signal([]); // Paginated data for table
totalCount = signal(0);
@@ -99,21 +100,19 @@ export class ResourcePermissionManagementComponent implements OnInit {
searchResults = signal([]);
permissionsWithProvider = signal([]);
- // Form state for add/edit
selectedProviderName = signal('');
selectedProviderKey = signal('');
searchFilter = signal('');
selectedPermissions = signal([]);
- // Edit mode state
editProviderName = signal('');
editProviderKey = signal('');
- // Search subject for debounce
+ showDropdown = signal(false);
+
private searchSubject = new Subject();
constructor() {
- // Configure extensions for entity props
configureResourcePermissionExtensions();
this.searchSubject.pipe(
@@ -125,16 +124,13 @@ export class ResourcePermissionManagementComponent implements OnInit {
}
ngOnInit() {
- // Configure list service for pagination
this.list.maxResultCount = 10;
- // Hook to query for client-side pagination
this.list.hookToQuery(query => {
const allData = this.allResourcePermissions();
const skipCount = query.skipCount || 0;
const maxResultCount = query.maxResultCount || 10;
- // Client-side pagination
const paginatedData = allData.slice(skipCount, skipCount + maxResultCount);
return of({
@@ -150,12 +146,10 @@ export class ResourcePermissionManagementComponent implements OnInit {
openModal() {
this.modalBusy.set(true);
- // Load resource permissions and providers
this.service.getResource(this.resourceName, this.resourceKey).pipe(
switchMap(permRes => {
this.allResourcePermissions.set(permRes.permissions || []);
this.totalCount.set(permRes.permissions?.length || 0);
- // Trigger list refresh
this.list.get();
return this.service.getResourceProviderKeyLookupServices(this.resourceName);
}),
@@ -191,7 +185,6 @@ export class ResourcePermissionManagementComponent implements OnInit {
this.searchResults.set([]);
}
- // View mode navigation
goToAddMode() {
this.viewMode.set('add');
this.selectedPermissions.set([]);
@@ -227,7 +220,6 @@ export class ResourcePermissionManagementComponent implements OnInit {
this.selectedPermissions.set([]);
}
- // Provider selection
onProviderChange(providerName: string) {
this.selectedProviderName.set(providerName);
this.selectedProviderKey.set('');
@@ -235,14 +227,25 @@ export class ResourcePermissionManagementComponent implements OnInit {
this.searchFilter.set('');
}
- // Search
onSearchInput(filter: string) {
this.searchFilter.set(filter);
+ this.showDropdown.set(true);
this.searchSubject.next(filter);
}
- private performSearch(filter: string) {
- if (!filter || !this.selectedProviderName()) return;
+ onSearchFocus() {
+ this.showDropdown.set(true);
+ this.loadProviderKeys(this.searchFilter() || '');
+ }
+
+ onSearchBlur() {
+ setTimeout(() => {
+ this.showDropdown.set(false);
+ }, 200);
+ }
+
+ private loadProviderKeys(filter: string) {
+ if (!this.selectedProviderName()) return;
this.service.searchResourceProviderKey(
this.resourceName,
@@ -254,13 +257,17 @@ export class ResourcePermissionManagementComponent implements OnInit {
});
}
+ private performSearch(filter: string) {
+ this.loadProviderKeys(filter);
+ }
+
selectProviderKey(key: SearchProviderKeyInfo) {
this.selectedProviderKey.set(key.providerKey || '');
this.searchFilter.set(key.providerDisplayName || key.providerKey || '');
this.searchResults.set([]);
+ this.showDropdown.set(false);
}
- // Permission toggle
togglePermission(permissionName: string) {
const current = this.selectedPermissions();
if (current.includes(permissionName)) {
@@ -298,7 +305,6 @@ export class ResourcePermissionManagementComponent implements OnInit {
definitions.every(p => this.selectedPermissions().includes(p.name || ''));
});
- // Save operations
saveAddPermission() {
if (!this.selectedProviderKey() || this.selectedPermissions().length === 0) {
this.toasterService.warn('AbpPermissionManagement::PleaseSelectProviderAndPermissions');
@@ -351,21 +357,33 @@ export class ResourcePermissionManagementComponent implements OnInit {
}
deletePermission(grant: ResourcePermissionGrantInfoDto) {
- this.modalBusy.set(true);
- this.service.deleteResource(
- this.resourceName,
- this.resourceKey,
- grant.providerName || '',
- grant.providerKey || ''
- ).pipe(
- switchMap(() => this.service.getResource(this.resourceName, this.resourceKey)),
- finalize(() => this.modalBusy.set(false))
- ).subscribe({
- next: res => {
- this.allResourcePermissions.set(res.permissions || []);
- this.list.get();
- this.toasterService.success('AbpUi::SuccessfullyDeleted');
- }
- });
+ this.confirmationService
+ .warn(
+ 'AbpPermissionManagement::PermissionDeletionConfirmationMessage',
+ 'AbpPermissionManagement::AreYouSure',
+ {
+ messageLocalizationParams: [grant.providerKey || ''],
+ }
+ )
+ .subscribe((status: Confirmation.Status) => {
+ if (status === Confirmation.Status.confirm) {
+ this.modalBusy.set(true);
+ this.service.deleteResource(
+ this.resourceName,
+ this.resourceKey,
+ grant.providerName || '',
+ grant.providerKey || ''
+ ).pipe(
+ switchMap(() => this.service.getResource(this.resourceName, this.resourceKey)),
+ finalize(() => this.modalBusy.set(false))
+ ).subscribe({
+ next: res => {
+ this.allResourcePermissions.set(res.permissions || []);
+ this.list.get();
+ this.toasterService.success('AbpUi::SuccessfullyDeleted');
+ }
+ });
+ }
+ });
}
}