diff --git a/npm/ng-packs/packages/permission-management/src/lib/components/index.ts b/npm/ng-packs/packages/permission-management/src/lib/components/index.ts
index 2c1ce75527..074ddb880d 100644
--- a/npm/ng-packs/packages/permission-management/src/lib/components/index.ts
+++ b/npm/ng-packs/packages/permission-management/src/lib/components/index.ts
@@ -1,2 +1,6 @@
export * from './permission-management.component';
export * from './resource-permission-management/resource-permission-management.component';
+export * from './resource-permission-management/provider-key-search/provider-key-search.component';
+export * from './resource-permission-management/permission-checkbox-list/permission-checkbox-list.component';
+export * from './resource-permission-management/resource-permission-list/resource-permission-list.component';
+export * from './resource-permission-management/resource-permission-form/resource-permission-form.component';
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
new file mode 100644
index 0000000000..e59cc67e12
--- /dev/null
+++ b/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/permission-checkbox-list/permission-checkbox-list.component.ts
@@ -0,0 +1,57 @@
+import { Component, input, inject, ChangeDetectionStrategy } from '@angular/core';
+import { LocalizationPipe } from '@abp/ng.core';
+import { ResourcePermissionStateService } from '../../../services/resource-permission-state.service';
+
+interface PermissionItem {
+ name?: string | null;
+ displayName?: string | null;
+}
+
+@Component({
+ selector: 'abp-permission-checkbox-list',
+ template: `
+
+ @if (showTitle()) {
+
{{ title() | abpLocalization }}
+ }
+
+
+
+
+
+ @for (perm of permissions(); track perm.name) {
+
+
+
+
+ }
+
+
+ `,
+ imports: [LocalizationPipe],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class PermissionCheckboxListComponent {
+ readonly state = inject(ResourcePermissionStateService);
+
+ readonly permissions = input.required();
+ readonly idPrefix = input('default');
+ readonly title = input('AbpPermissionManagement::ResourcePermissionPermissions');
+ readonly showTitle = input(true);
+}
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
new file mode 100644
index 0000000000..17a37e7456
--- /dev/null
+++ b/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/provider-key-search/provider-key-search.component.ts
@@ -0,0 +1,105 @@
+import { Component, input, inject, output, OnInit, OnDestroy, ChangeDetectionStrategy } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { LocalizationPipe } from '@abp/ng.core';
+import { PermissionsService, SearchProviderKeyInfo } from '@abp/ng.permission-management/proxy';
+import { Subject, debounceTime, distinctUntilChanged, takeUntil } from 'rxjs';
+import { ResourcePermissionStateService } from '../../../services/resource-permission-state.service';
+
+@Component({
+ selector: 'abp-provider-key-search',
+ template: `
+
+
+
+ @if (state.searchResults().length > 0 && state.showDropdown()) {
+
+ @for (result of state.searchResults(); track result.providerKey) {
+
+ }
+
+ }
+
+ `,
+ imports: [FormsModule, LocalizationPipe],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class ProviderKeySearchComponent implements OnInit, OnDestroy {
+ readonly state = inject(ResourcePermissionStateService);
+ private readonly service = inject(PermissionsService);
+
+ readonly resourceName = input.required();
+
+ readonly keySelected = output();
+
+ private readonly searchSubject = new Subject();
+ private readonly destroy$ = new Subject();
+
+ ngOnInit() {
+ this.searchSubject.pipe(
+ debounceTime(300),
+ distinctUntilChanged(),
+ takeUntil(this.destroy$)
+ ).subscribe(filter => {
+ this.loadProviderKeys(filter);
+ });
+ }
+
+ ngOnDestroy() {
+ this.destroy$.next();
+ this.destroy$.complete();
+ }
+
+ onSearchInput(filter: string) {
+ this.state.searchFilter.set(filter);
+ this.state.showDropdown.set(true);
+ this.searchSubject.next(filter);
+ }
+
+ onSearchFocus() {
+ this.state.showDropdown.set(true);
+ this.loadProviderKeys(this.state.searchFilter() || '');
+ }
+
+ onSearchBlur(event: FocusEvent) {
+ const relatedTarget = event.relatedTarget as HTMLElement;
+ if (!relatedTarget?.closest('.list-group')) {
+ this.state.showDropdown.set(false);
+ }
+ }
+
+ selectProviderKey(key: SearchProviderKeyInfo) {
+ this.state.selectProviderKey(key);
+ this.keySelected.emit(key);
+ }
+
+ private loadProviderKeys(filter: string) {
+ const providerName = this.state.selectedProviderName();
+ if (!providerName) return;
+
+ this.service.searchResourceProviderKey(
+ this.resourceName(),
+ providerName,
+ filter,
+ 1
+ ).subscribe(res => {
+ this.state.searchResults.set(res.keys || []);
+ });
+ }
+}
diff --git a/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/resource-permission-form/resource-permission-form.component.ts b/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/resource-permission-form/resource-permission-form.component.ts
new file mode 100644
index 0000000000..afb2ff14bb
--- /dev/null
+++ b/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/resource-permission-form/resource-permission-form.component.ts
@@ -0,0 +1,70 @@
+import { Component, input, inject, output, ChangeDetectionStrategy } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { LocalizationPipe } from '@abp/ng.core';
+import { ResourcePermissionStateService } from '../../../services/resource-permission-state.service';
+import { ProviderKeySearchComponent } from '../provider-key-search/provider-key-search.component';
+import { PermissionCheckboxListComponent } from '../permission-checkbox-list/permission-checkbox-list.component';
+
+export type FormMode = 'add' | 'edit';
+
+@Component({
+ selector: 'abp-resource-permission-form',
+ template: `
+ @if (mode() === 'add') {
+
+
+
+ @for (provider of state.providers(); track provider.name; let i = $index) {
+
+
+
+
+ }
+
+
+
+
+
+
+ } @else {
+
+
{{ 'AbpPermissionManagement::Permissions' | abpLocalization }}
+
+
+ }
+ `,
+ imports: [
+ FormsModule,
+ LocalizationPipe,
+ ProviderKeySearchComponent,
+ PermissionCheckboxListComponent,
+ ],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class ResourcePermissionFormComponent {
+ readonly state = inject(ResourcePermissionStateService);
+
+ readonly mode = input.required();
+ readonly resourceName = input.required();
+
+ readonly save = output();
+ readonly cancel = output();
+}
diff --git a/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/resource-permission-list/resource-permission-list.component.ts b/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/resource-permission-list/resource-permission-list.component.ts
new file mode 100644
index 0000000000..b422d9e991
--- /dev/null
+++ b/npm/ng-packs/packages/permission-management/src/lib/components/resource-permission-management/resource-permission-list/resource-permission-list.component.ts
@@ -0,0 +1,75 @@
+import { Component, inject, output, ChangeDetectionStrategy } from '@angular/core';
+import { ListService, LocalizationPipe } from '@abp/ng.core';
+import { ExtensibleTableComponent, EXTENSIONS_IDENTIFIER } from '@abp/ng.components/extensible';
+import { ResourcePermissionGrantInfoDto } from '@abp/ng.permission-management/proxy';
+import { ResourcePermissionStateService } from '../../../services/resource-permission-state.service';
+import { ePermissionManagementComponents } from '../../../enums/components';
+import { configureResourcePermissionExtensions } from '../../../services/extensions.service';
+
+@Component({
+ selector: 'abp-resource-permission-list',
+ template: `
+
+
+
+
+
+
+
+
+
+
+
+ @if (state.resourcePermissions().length > 0) {
+
+ } @else {
+
+ {{ 'AbpPermissionManagement::NoPermissionsAssigned' | abpLocalization }}
+
+ }
+ `,
+ providers: [
+ ListService,
+ {
+ provide: EXTENSIONS_IDENTIFIER,
+ useValue: ePermissionManagementComponents.ResourcePermissions,
+ },
+ ],
+ imports: [LocalizationPipe, ExtensibleTableComponent],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class ResourcePermissionListComponent {
+ readonly state = inject(ResourcePermissionStateService);
+ readonly list = inject(ListService);
+
+ readonly addClicked = output();
+ readonly editClicked = output();
+ readonly deleteClicked = output();
+
+ constructor() {
+ configureResourcePermissionExtensions();
+ }
+}
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 b8cc1afd1e..7ffbf3b6b1 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
@@ -1,165 +1,60 @@
-
+
- @if (viewMode() === 'edit') {
+ @switch (state.viewMode()) {
+ @case ('edit') {
{{ 'AbpPermissionManagement::UpdatePermission' | abpLocalization }}
- } @else if (viewMode() === 'add') {
+ }
+ @case ('add') {
{{ 'AbpPermissionManagement::AddResourcePermission' | abpLocalization }}
- } @else {
+ }
+ @default {
{{ 'AbpPermissionManagement::ResourcePermissions' | abpLocalization }}
- @if (resourceDisplayName) {
- - {{ resourceDisplayName }}
+ @if (resourceDisplayName()) {
+ - {{ resourceDisplayName() }}
+ }
}
}
- @if (!hasResourcePermission() || !hasProviderKeyLookupService()) {
+ @if (!state.hasResourcePermission() || !state.hasProviderKeyLookupService()) {
- @if (!hasResourcePermission()) {
+ @if (!state.hasResourcePermission()) {
{{ 'AbpPermissionManagement::NoResourcePermissionFound' | abpLocalization }}
} @else {
{{ 'AbpPermissionManagement::NoResourceProviderKeyLookupServiceFound' | abpLocalization }}
}
} @else {
-
- @if (viewMode() === 'list') {
-
-
-
-
-
-
-
-
-
-
-
- @if (resourcePermissions().length > 0) {
-
- } @else {
-
- {{ 'AbpPermissionManagement::NoPermissionsAssigned' | abpLocalization }}
-
+ @switch (state.viewMode()) {
+ @case ('list') {
+
}
+ @case ('add') {
+
}
-
-
- @if (viewMode() === 'add') {
-
-
-
- @for (provider of providers(); track provider.name; let i = $index) {
-
-
-
-
- }
-
-
-
-
-
- @if (searchResults().length > 0 && showDropdown()) {
-
- @for (result of searchResults(); track result.providerKey) {
-
- }
-
- }
-
-
-
-
-
{{ 'AbpPermissionManagement::ResourcePermissionPermissions' | abpLocalization }}
-
-
-
-
-
- @for (perm of permissionDefinitions(); track perm.name) {
-
-
-
-
- }
-
-
+ @case ('edit') {
+
}
-
-
- @if (viewMode() === 'edit') {
-
-
{{ 'AbpPermissionManagement::Permissions' | abpLocalization }}
-
-
-
-
- @for (perm of permissionsWithProvider(); track perm.name) {
-
-
-
-
- }
-
}
}
- @if (viewMode() === 'list') {
+ @if (state.isListMode()) {
} @else {
-
\ No newline at end of file
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 3f0334ce5e..18b810fd51 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
@@ -10,116 +10,66 @@ import {
import {
PermissionsService,
ResourcePermissionGrantInfoDto,
- ResourceProviderDto,
- SearchProviderKeyInfo,
- ResourcePermissionDefinitionDto,
- ResourcePermissionWithProdiverGrantInfoDto,
} from '@abp/ng.permission-management/proxy';
-import {
- ExtensibleTableComponent,
- EXTENSIONS_IDENTIFIER,
-} from '@abp/ng.components/extensible';
import {
Component,
- EventEmitter,
inject,
- Input,
- Output,
- signal,
- computed,
+ input,
+ model,
OnInit,
+ effect,
} from '@angular/core';
-import { FormsModule } from '@angular/forms';
-import { finalize, switchMap, debounceTime, Subject, distinctUntilChanged, of } from 'rxjs';
-import { ePermissionManagementComponents } from '../../enums/components';
-import { configureResourcePermissionExtensions } from '../../services/extensions.service';
-
-type ViewMode = 'list' | 'add' | 'edit';
+import { finalize, switchMap, of } from 'rxjs';
+import { ResourcePermissionStateService } from '../../services/resource-permission-state.service';
+import { ResourcePermissionListComponent } from './resource-permission-list/resource-permission-list.component';
+import { ResourcePermissionFormComponent } from './resource-permission-form/resource-permission-form.component';
@Component({
selector: 'abp-resource-permission-management',
templateUrl: './resource-permission-management.component.html',
exportAs: 'abpResourcePermissionManagement',
- providers: [
- ListService,
- {
- provide: EXTENSIONS_IDENTIFIER,
- useValue: ePermissionManagementComponents.ResourcePermissions,
- },
- ],
+ providers: [ResourcePermissionStateService, ListService],
imports: [
- FormsModule,
ModalComponent,
LocalizationPipe,
ButtonComponent,
ModalCloseDirective,
- ExtensibleTableComponent,
+ ResourcePermissionListComponent,
+ ResourcePermissionFormComponent,
],
})
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;
- @Input() resourceKey!: string;
- @Input() resourceDisplayName?: string;
-
- protected _visible = false;
-
- @Input()
- get visible(): boolean {
- return this._visible;
- }
-
- set visible(value: boolean) {
- if (value === this._visible) return;
-
- if (value) {
- this.openModal();
- } else {
- this.resetState();
- }
- this._visible = value;
- this.visibleChange.emit(value);
- }
-
- @Output() readonly visibleChange = new EventEmitter();
+ protected readonly state = inject(ResourcePermissionStateService);
+ private readonly list = inject(ListService);
- viewMode = signal('list');
- modalBusy = signal(false);
- hasResourcePermission = signal(false);
- hasProviderKeyLookupService = signal(false);
+ readonly resourceName = input.required();
+ readonly resourceKey = input.required();
+ readonly resourceDisplayName = input();
- allResourcePermissions = signal([]); // All data for client-side pagination
- resourcePermissions = signal([]); // Paginated data for table
- totalCount = signal(0);
- providers = signal([]);
- permissionDefinitions = signal([]);
- searchResults = signal([]);
- permissionsWithProvider = signal([]);
+ readonly visible = model(false);
- selectedProviderName = signal('');
- selectedProviderKey = signal('');
- searchFilter = signal('');
- selectedPermissions = signal([]);
-
- editProviderName = signal('');
- editProviderKey = signal('');
-
- showDropdown = signal(false);
-
- private searchSubject = new Subject();
+ private previousVisible = false;
constructor() {
- configureResourcePermissionExtensions();
+ // Sync input values to state
+ effect(() => {
+ this.state.resourceName.set(this.resourceName());
+ this.state.resourceKey.set(this.resourceKey());
+ this.state.resourceDisplayName.set(this.resourceDisplayName());
+ });
- this.searchSubject.pipe(
- debounceTime(300),
- distinctUntilChanged()
- ).subscribe(filter => {
- this.performSearch(filter);
+ // Handle visibility changes
+ effect(() => {
+ const isVisible = this.visible();
+ if (isVisible && !this.previousVisible) {
+ this.openModal();
+ } else if (!isVisible && this.previousVisible) {
+ this.state.reset();
+ }
+ this.previousVisible = isVisible;
});
}
@@ -127,7 +77,7 @@ export class ResourcePermissionManagementComponent implements OnInit {
this.list.maxResultCount = 10;
this.list.hookToQuery(query => {
- const allData = this.allResourcePermissions();
+ const allData = this.state.allResourcePermissions();
const skipCount = query.skipCount || 0;
const maxResultCount = query.maxResultCount || 10;
@@ -138,34 +88,28 @@ export class ResourcePermissionManagementComponent implements OnInit {
totalCount: allData.length
});
}).subscribe(result => {
- this.resourcePermissions.set(result.items);
- this.totalCount.set(result.totalCount);
+ this.state.resourcePermissions.set(result.items);
+ this.state.totalCount.set(result.totalCount);
});
}
openModal() {
- this.modalBusy.set(true);
+ this.state.modalBusy.set(true);
- this.service.getResource(this.resourceName, this.resourceKey).pipe(
+ this.service.getResource(this.resourceName(), this.resourceKey()).pipe(
switchMap(permRes => {
- this.allResourcePermissions.set(permRes.permissions || []);
- this.totalCount.set(permRes.permissions?.length || 0);
+ this.state.setResourceData(permRes.permissions || []);
this.list.get();
- return this.service.getResourceProviderKeyLookupServices(this.resourceName);
+ return this.service.getResourceProviderKeyLookupServices(this.resourceName());
}),
switchMap(providerRes => {
- this.providers.set(providerRes.providers || []);
- this.hasProviderKeyLookupService.set((providerRes.providers?.length || 0) > 0);
- if (providerRes.providers?.length) {
- this.selectedProviderName.set(providerRes.providers[0].name || '');
- }
- return this.service.getResourceDefinitions(this.resourceName);
+ this.state.setProviders(providerRes.providers || []);
+ return this.service.getResourceDefinitions(this.resourceName());
}),
- finalize(() => this.modalBusy.set(false))
+ finalize(() => this.state.modalBusy.set(false))
).subscribe({
next: defRes => {
- this.permissionDefinitions.set(defRes.permissions || []);
- this.hasResourcePermission.set((defRes.permissions?.length || 0) > 0);
+ this.state.setDefinitions(defRes.permissions || []);
},
error: () => {
this.toasterService.error('AbpPermissionManagement::ErrorLoadingPermissions');
@@ -173,190 +117,29 @@ export class ResourcePermissionManagementComponent implements OnInit {
});
}
- resetState() {
- this.viewMode.set('list');
- this.allResourcePermissions.set([]);
- this.resourcePermissions.set([]);
- this.totalCount.set(0);
- this.selectedProviderName.set('');
- this.selectedProviderKey.set('');
- this.searchFilter.set('');
- this.selectedPermissions.set([]);
- this.searchResults.set([]);
+ onAddClicked() {
+ this.state.goToAddMode();
}
- goToAddMode() {
- this.viewMode.set('add');
- this.selectedPermissions.set([]);
- this.selectedProviderKey.set('');
- this.searchResults.set([]);
- }
-
- goToEditMode(grant: ResourcePermissionGrantInfoDto) {
- this.editProviderName.set(grant.providerName || '');
- this.editProviderKey.set(grant.providerKey || '');
- this.modalBusy.set(true);
+ onEditClicked(grant: ResourcePermissionGrantInfoDto) {
+ this.state.prepareEditMode(grant);
+ this.state.modalBusy.set(true);
this.service.getResourceByProvider(
- this.resourceName,
- this.resourceKey,
+ this.resourceName(),
+ this.resourceKey(),
grant.providerName || '',
grant.providerKey || ''
).pipe(
- finalize(() => this.modalBusy.set(false))
- ).subscribe({
- next: res => {
- this.permissionsWithProvider.set(res.permissions || []);
- this.selectedPermissions.set(
- (res.permissions || []).filter(p => p.isGranted).map(p => p.name || '')
- );
- this.viewMode.set('edit');
- }
- });
- }
-
- goToListMode() {
- this.viewMode.set('list');
- this.selectedPermissions.set([]);
- }
-
- onProviderChange(providerName: string) {
- this.selectedProviderName.set(providerName);
- this.selectedProviderKey.set('');
- this.searchResults.set([]);
- this.searchFilter.set('');
- }
-
- onSearchInput(filter: string) {
- this.searchFilter.set(filter);
- this.showDropdown.set(true);
- this.searchSubject.next(filter);
- }
-
- 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,
- this.selectedProviderName(),
- filter,
- 1
- ).subscribe(res => {
- this.searchResults.set(res.keys || []);
- });
- }
-
- 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);
- }
-
- togglePermission(permissionName: string) {
- const current = this.selectedPermissions();
- if (current.includes(permissionName)) {
- this.selectedPermissions.set(current.filter(p => p !== permissionName));
- } else {
- this.selectedPermissions.set([...current, permissionName]);
- }
- }
-
- toggleAllPermissions(selectAll: boolean) {
- if (this.viewMode() === 'add') {
- this.selectedPermissions.set(
- selectAll
- ? this.permissionDefinitions().map(p => p.name || '')
- : []
- );
- } else {
- this.selectedPermissions.set(
- selectAll
- ? this.permissionsWithProvider().map(p => p.name || '')
- : []
- );
- }
- }
-
- isPermissionSelected(permissionName: string): boolean {
- return this.selectedPermissions().includes(permissionName);
- }
-
- allPermissionsSelected = computed(() => {
- const definitions = this.viewMode() === 'add'
- ? this.permissionDefinitions()
- : this.permissionsWithProvider();
- return definitions.length > 0 &&
- definitions.every(p => this.selectedPermissions().includes(p.name || ''));
- });
-
- saveAddPermission() {
- if (!this.selectedProviderKey() || this.selectedPermissions().length === 0) {
- this.toasterService.warn('AbpPermissionManagement::PleaseSelectProviderAndPermissions');
- return;
- }
-
- this.modalBusy.set(true);
- this.service.updateResource(
- this.resourceName,
- this.resourceKey,
- {
- providerName: this.selectedProviderName(),
- providerKey: this.selectedProviderKey(),
- permissions: this.selectedPermissions()
- }
- ).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::SavedSuccessfully');
- this.goToListMode();
- }
- });
- }
-
- saveEditPermission() {
- this.modalBusy.set(true);
- this.service.updateResource(
- this.resourceName,
- this.resourceKey,
- {
- providerName: this.editProviderName(),
- providerKey: this.editProviderKey(),
- permissions: this.selectedPermissions()
- }
- ).pipe(
- switchMap(() => this.service.getResource(this.resourceName, this.resourceKey)),
- finalize(() => this.modalBusy.set(false))
+ finalize(() => this.state.modalBusy.set(false))
).subscribe({
next: res => {
- this.allResourcePermissions.set(res.permissions || []);
- this.list.get();
- this.toasterService.success('AbpUi::SavedSuccessfully');
- this.goToListMode();
+ this.state.setEditModePermissions(res.permissions || []);
}
});
}
- deletePermission(grant: ResourcePermissionGrantInfoDto) {
+ onDeleteClicked(grant: ResourcePermissionGrantInfoDto) {
this.confirmationService
.warn(
'AbpPermissionManagement::PermissionDeletionConfirmationMessage',
@@ -367,18 +150,18 @@ export class ResourcePermissionManagementComponent implements OnInit {
)
.subscribe((status: Confirmation.Status) => {
if (status === Confirmation.Status.confirm) {
- this.modalBusy.set(true);
+ this.state.modalBusy.set(true);
this.service.deleteResource(
- this.resourceName,
- this.resourceKey,
+ this.resourceName(),
+ this.resourceKey(),
grant.providerName || '',
grant.providerKey || ''
).pipe(
- switchMap(() => this.service.getResource(this.resourceName, this.resourceKey)),
- finalize(() => this.modalBusy.set(false))
+ switchMap(() => this.service.getResource(this.resourceName(), this.resourceKey())),
+ finalize(() => this.state.modalBusy.set(false))
).subscribe({
next: res => {
- this.allResourcePermissions.set(res.permissions || []);
+ this.state.setResourceData(res.permissions || []);
this.list.get();
this.toasterService.success('AbpUi::SuccessfullyDeleted');
}
@@ -386,4 +169,36 @@ export class ResourcePermissionManagementComponent implements OnInit {
}
});
}
+
+ savePermission() {
+ const isEdit = this.state.isEditMode();
+ const providerName = isEdit ? this.state.editProviderName() : this.state.selectedProviderName();
+ const providerKey = isEdit ? this.state.editProviderKey() : this.state.selectedProviderKey();
+
+ if (!isEdit && !this.state.canSave()) {
+ this.toasterService.warn('AbpPermissionManagement::PleaseSelectProviderAndPermissions');
+ return;
+ }
+
+ this.state.modalBusy.set(true);
+ this.service.updateResource(
+ this.resourceName(),
+ this.resourceKey(),
+ {
+ providerName,
+ providerKey,
+ permissions: this.state.selectedPermissions()
+ }
+ ).pipe(
+ switchMap(() => this.service.getResource(this.resourceName(), this.resourceKey())),
+ finalize(() => this.state.modalBusy.set(false))
+ ).subscribe({
+ next: res => {
+ this.state.setResourceData(res.permissions || []);
+ this.list.get();
+ this.toasterService.success('AbpUi::SavedSuccessfully');
+ this.state.goToListMode();
+ }
+ });
+ }
}
diff --git a/npm/ng-packs/packages/permission-management/src/lib/services/index.ts b/npm/ng-packs/packages/permission-management/src/lib/services/index.ts
index 29bda44023..f4dae3a571 100644
--- a/npm/ng-packs/packages/permission-management/src/lib/services/index.ts
+++ b/npm/ng-packs/packages/permission-management/src/lib/services/index.ts
@@ -1 +1,2 @@
export * from './extensions.service';
+export * from './resource-permission-state.service';
diff --git a/npm/ng-packs/packages/permission-management/src/lib/services/resource-permission-state.service.ts b/npm/ng-packs/packages/permission-management/src/lib/services/resource-permission-state.service.ts
new file mode 100644
index 0000000000..8fa2daeda5
--- /dev/null
+++ b/npm/ng-packs/packages/permission-management/src/lib/services/resource-permission-state.service.ts
@@ -0,0 +1,165 @@
+import { Injectable, signal, computed } from '@angular/core';
+import {
+ ResourcePermissionGrantInfoDto,
+ ResourceProviderDto,
+ ResourcePermissionDefinitionDto,
+ SearchProviderKeyInfo,
+ ResourcePermissionWithProdiverGrantInfoDto,
+} from '@abp/ng.permission-management/proxy';
+
+export type ViewMode = 'list' | 'add' | 'edit';
+
+@Injectable()
+export class ResourcePermissionStateService {
+ // View state
+ readonly viewMode = signal('list');
+ readonly modalBusy = signal(false);
+ readonly hasResourcePermission = signal(false);
+ readonly hasProviderKeyLookupService = signal(false);
+
+ // Resource data
+ readonly resourceName = signal('');
+ readonly resourceKey = signal('');
+ readonly resourceDisplayName = signal(undefined);
+
+ // Permissions data
+ readonly allResourcePermissions = signal([]);
+ readonly resourcePermissions = signal([]);
+ readonly totalCount = signal(0);
+ readonly permissionDefinitions = signal([]);
+ readonly permissionsWithProvider = signal([]);
+ readonly selectedPermissions = signal([]);
+
+ // Provider data
+ readonly providers = signal([]);
+ readonly selectedProviderName = signal('');
+ readonly selectedProviderKey = signal('');
+
+ // Edit mode specific
+ readonly editProviderName = signal('');
+ readonly editProviderKey = signal('');
+
+ // Search state
+ readonly searchFilter = signal('');
+ readonly searchResults = signal([]);
+ readonly showDropdown = signal(false);
+
+ // Computed properties
+ readonly isAddMode = computed(() => this.viewMode() === 'add');
+ readonly isEditMode = computed(() => this.viewMode() === 'edit');
+ readonly isListMode = computed(() => this.viewMode() === 'list');
+
+ readonly currentPermissionsList = computed(() =>
+ this.isAddMode() ? this.permissionDefinitions() : this.permissionsWithProvider()
+ );
+
+ readonly allPermissionsSelected = computed(() => {
+ const definitions = this.currentPermissionsList();
+ return definitions.length > 0 &&
+ definitions.every(p => this.selectedPermissions().includes(p.name || ''));
+ });
+
+ readonly canSave = computed(() => {
+ if (this.isAddMode()) {
+ return !!this.selectedProviderKey() && this.selectedPermissions().length > 0;
+ }
+ return this.selectedPermissions().length >= 0;
+ });
+
+ // State transition methods
+ goToListMode() {
+ this.viewMode.set('list');
+ this.selectedPermissions.set([]);
+ }
+
+ goToAddMode() {
+ this.viewMode.set('add');
+ this.selectedPermissions.set([]);
+ this.selectedProviderKey.set('');
+ this.searchResults.set([]);
+ this.searchFilter.set('');
+ }
+
+ prepareEditMode(grant: ResourcePermissionGrantInfoDto) {
+ this.editProviderName.set(grant.providerName || '');
+ this.editProviderKey.set(grant.providerKey || '');
+ }
+
+ setEditModePermissions(permissions: ResourcePermissionWithProdiverGrantInfoDto[]) {
+ this.permissionsWithProvider.set(permissions);
+ this.selectedPermissions.set(
+ permissions.filter(p => p.isGranted).map(p => p.name || '')
+ );
+ this.viewMode.set('edit');
+ }
+
+ // Permission selection methods
+ togglePermission(permissionName: string) {
+ const current = this.selectedPermissions();
+ if (current.includes(permissionName)) {
+ this.selectedPermissions.set(current.filter(p => p !== permissionName));
+ } else {
+ this.selectedPermissions.set([...current, permissionName]);
+ }
+ }
+
+ toggleAllPermissions(selectAll: boolean) {
+ const permissions = this.currentPermissionsList();
+ this.selectedPermissions.set(
+ selectAll ? permissions.map(p => p.name || '') : []
+ );
+ }
+
+ isPermissionSelected(permissionName: string): boolean {
+ return this.selectedPermissions().includes(permissionName);
+ }
+
+ // Provider search methods
+ onProviderChange(providerName: string) {
+ this.selectedProviderName.set(providerName);
+ this.selectedProviderKey.set('');
+ this.searchResults.set([]);
+ this.searchFilter.set('');
+ }
+
+ selectProviderKey(key: SearchProviderKeyInfo) {
+ this.selectedProviderKey.set(key.providerKey || '');
+ this.searchFilter.set(key.providerDisplayName || key.providerKey || '');
+ this.searchResults.set([]);
+ this.showDropdown.set(false);
+ }
+
+ // Reset all state
+ reset() {
+ this.viewMode.set('list');
+ this.allResourcePermissions.set([]);
+ this.resourcePermissions.set([]);
+ this.totalCount.set(0);
+ this.selectedProviderName.set('');
+ this.selectedProviderKey.set('');
+ this.searchFilter.set('');
+ this.selectedPermissions.set([]);
+ this.searchResults.set([]);
+ this.editProviderName.set('');
+ this.editProviderKey.set('');
+ }
+
+ // Data loading helpers
+ setResourceData(permissions: ResourcePermissionGrantInfoDto[]) {
+ this.allResourcePermissions.set(permissions);
+ this.totalCount.set(permissions.length);
+ }
+
+ setProviders(providers: ResourceProviderDto[]) {
+ this.providers.set(providers);
+ this.hasProviderKeyLookupService.set(providers.length > 0);
+ if (providers.length) {
+ this.selectedProviderName.set(providers[0].name || '');
+ }
+ }
+
+ setDefinitions(permissions: ResourcePermissionDefinitionDto[]) {
+ this.permissionDefinitions.set(permissions);
+ this.hasResourcePermission.set(permissions.length > 0);
+ }
+}