import { ConfirmationDialogType } from '@ghostfolio/common/enums'; import { Access, User } from '@ghostfolio/common/interfaces'; import { publicRoutes } from '@ghostfolio/common/routes/routes'; import { NotificationService } from '@ghostfolio/ui/notifications'; import { Clipboard, ClipboardModule } from '@angular/cdk/clipboard'; import { ChangeDetectionStrategy, Component, computed, CUSTOM_ELEMENTS_SCHEMA, effect, inject, input, output } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatMenuModule } from '@angular/material/menu'; import { MatSnackBar } from '@angular/material/snack-bar'; import { MatTableDataSource, MatTableModule } from '@angular/material/table'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { copyOutline, createOutline, ellipsisHorizontal, linkOutline, lockClosedOutline, lockOpenOutline, removeCircleOutline } from 'ionicons/icons'; import ms from 'ms'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, imports: [ ClipboardModule, IonIcon, MatButtonModule, MatMenuModule, MatTableModule, RouterModule ], schemas: [CUSTOM_ELEMENTS_SCHEMA], selector: 'gf-access-table', templateUrl: './access-table.component.html', styleUrls: ['./access-table.component.scss'] }) export class GfAccessTableComponent { public readonly accesses = input.required(); public readonly showActions = input(false); public readonly user = input.required(); public readonly accessDeleted = output(); public readonly accessToUpdate = output(); protected readonly baseUrl = window.location.origin; protected readonly dataSource = new MatTableDataSource(); protected readonly displayedColumns = computed(() => { const columns = ['alias', 'grantee', 'type', 'details']; if (this.showActions()) { columns.push('actions'); } return columns; }); private readonly clipboard = inject(Clipboard); private readonly notificationService = inject(NotificationService); private readonly snackBar = inject(MatSnackBar); public constructor() { addIcons({ copyOutline, createOutline, ellipsisHorizontal, linkOutline, lockClosedOutline, lockOpenOutline, removeCircleOutline }); effect(() => { this.dataSource.data = this.accesses() ?? []; }); } protected getPublicUrl(aId: string) { const languageCode = this.user().settings.language; return `${this.baseUrl}/${languageCode}/${publicRoutes.public.path}/${aId}`; } protected onCopyUrlToClipboard(aId: string) { this.clipboard.copy(this.getPublicUrl(aId)); this.snackBar.open( '✅ ' + $localize`Link has been copied to the clipboard`, undefined, { duration: ms('3 seconds') } ); } protected onDeleteAccess(aId: string) { this.notificationService.confirm({ confirmFn: () => { this.accessDeleted.emit(aId); }, confirmType: ConfirmationDialogType.Warn, title: $localize`Do you really want to revoke this granted access?` }); } protected onUpdateAccess(aId: string) { this.accessToUpdate.emit(aId); } }