From b587458245231e374dcc4a68c328a4aa26272c31 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 23 Aug 2026 10:06:46 +0200 Subject: [PATCH] Add support to remove a received access on the access page --- apps/api/src/app/access/access.controller.ts | 4 +- .../user-account-access.component.ts | 45 +++++++++++++++++-- .../user-account-access.html | 4 +- libs/ui/src/lib/services/data.service.ts | 3 +- 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/apps/api/src/app/access/access.controller.ts b/apps/api/src/app/access/access.controller.ts index a2701dd0f..b8772e3bb 100644 --- a/apps/api/src/app/access/access.controller.ts +++ b/apps/api/src/app/access/access.controller.ts @@ -114,7 +114,7 @@ export class AccessController { @Delete(':id') @HasPermission(permissions.deleteAccess) @UseGuards(AuthGuard('jwt'), HasPermissionGuard) - public async deleteAccess(@Param('id') id: string): Promise { + public async deleteAccess(@Param('id') id: string): Promise { const originalAccess = await this.accessService.access({ id, OR: [ @@ -130,7 +130,7 @@ export class AccessController { ); } - return this.accessService.deleteAccess({ + await this.accessService.deleteAccess({ id }); } diff --git a/apps/client/src/app/components/user-account-access/user-account-access.component.ts b/apps/client/src/app/components/user-account-access/user-account-access.component.ts index 350d18bd8..eb1a590d4 100644 --- a/apps/client/src/app/components/user-account-access/user-account-access.component.ts +++ b/apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -1,4 +1,5 @@ import { GfAccessTableComponent } from '@ghostfolio/client/components/access-table/access-table.component'; +import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { CreateAccessDto } from '@ghostfolio/common/dtos'; import { ConfirmationDialogType } from '@ghostfolio/common/enums'; @@ -63,6 +64,7 @@ import { CreateOrUpdateAccessDialogParams } from './create-or-update-access-dial export class GfUserAccountAccessComponent implements OnInit { protected accessesGet: Access[]; protected accessesGive: Access[]; + protected hasImpersonationId: boolean; protected hasPermissionToCreateAccess: boolean; protected hasPermissionToDeleteAccess: boolean; protected hasPermissionToUpdateOwnAccessToken: boolean; @@ -84,6 +86,9 @@ export class GfUserAccountAccessComponent implements OnInit { private readonly destroyRef = inject(DestroyRef); private readonly deviceDetectorService = inject(DeviceDetectorService); private readonly dialog = inject(MatDialog); + private readonly impersonationStorageService = inject( + ImpersonationStorageService + ); private readonly notificationService = inject(NotificationService); private readonly route = inject(ActivatedRoute); private readonly router = inject(Router); @@ -97,6 +102,15 @@ export class GfUserAccountAccessComponent implements OnInit { permissions.deleteAccess ); + this.impersonationStorageService + .onChangeHasImpersonation() + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe((impersonationId) => { + this.hasImpersonationId = !!impersonationId; + + this.changeDetectorRef.markForCheck(); + }); + this.userService.stateChanged .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { @@ -140,18 +154,41 @@ export class GfUserAccountAccessComponent implements OnInit { } protected onDeleteAccess(aId: string) { + this.dataService + .deleteAccess(aId) + .pipe( + catchError(() => { + this.notificationService.alert({ + title: $localize`Oops! Could not revoke the granted access.` + }); + + return EMPTY; + }), + takeUntilDestroyed(this.destroyRef) + ) + .subscribe(() => { + this.update(); + }); + } + + protected onDeleteReceivedAccess(aId: string) { this.dataService .deleteAccess(aId) .pipe( switchMap(() => { return this.userService.get(true); }), + catchError(() => { + this.notificationService.alert({ + title: $localize`Oops! Could not remove the received access.` + }); + + return EMPTY; + }), takeUntilDestroyed(this.destroyRef) ) - .subscribe({ - next: () => { - this.update(); - } + .subscribe(() => { + this.update(); }); } diff --git a/apps/client/src/app/components/user-account-access/user-account-access.html b/apps/client/src/app/components/user-account-access/user-account-access.html index 8a733fee6..a2f755029 100644 --- a/apps/client/src/app/components/user-account-access/user-account-access.html +++ b/apps/client/src/app/components/user-account-access/user-account-access.html @@ -57,9 +57,9 @@ class="mb-5" [accesses]="accessesGet" [isReceivedAccess]="true" - [showActions]="hasPermissionToDeleteAccess" + [showActions]="hasPermissionToDeleteAccess && !hasImpersonationId" [user]="user" - (accessDeleted)="onDeleteAccess($event)" + (accessDeleted)="onDeleteReceivedAccess($event)" /> }

diff --git a/libs/ui/src/lib/services/data.service.ts b/libs/ui/src/lib/services/data.service.ts index fb9376041..fc9c90886 100644 --- a/libs/ui/src/lib/services/data.service.ts +++ b/libs/ui/src/lib/services/data.service.ts @@ -70,7 +70,6 @@ import { inject, Service } from '@angular/core'; import { SortDirection } from '@angular/material/sort'; import { utc } from '@date-fns/utc'; import { - Access as AccessModel, Account, AccountBalance, DataSource, @@ -316,7 +315,7 @@ export class DataService { } public deleteAccess(aId: string) { - return this.http.delete(`/api/v1/access/${aId}`); + return this.http.delete(`/api/v1/access/${aId}`); } public deleteAccount(aId: string) {