src/app/features/api-client/api-client-credentials-dialog/api-client-credentials-dialog.component.ts

Description

Shows the credentials of an API client right after it was created (or its secret was regenerated), which is the only time its secret is available, so that they can be passed on to the external system.

Example

Metadata

Relationships

Used by

No results matching.

Depends on

Index

Properties
Methods

Constructor

constructor()

Methods

copy
copy(value: string)
Parameters :
Name Type Optional
value string No
Returns : void
copyAll
copyAll()
Returns : void

Properties

Readonly fields
Type : { label: string; value: string; copyLabel: string }[]
Readonly scopeLabels
Type : unknown
Default value : this.data.scopes.map((s) => getScopeLabel(s))
import { ChangeDetectionStrategy, Component, inject } from "@angular/core";
import { Clipboard } from "@angular/cdk/clipboard";
import { MAT_DIALOG_DATA, MatDialogModule } from "@angular/material/dialog";
import { MatButtonModule } from "@angular/material/button";
import { MatTooltipModule } from "@angular/material/tooltip";
import { FaIconComponent } from "@fortawesome/angular-fontawesome";
import { DialogCloseComponent } from "#src/app/core/common-components/dialog-close/dialog-close.component";
import { HintBoxComponent } from "#src/app/core/common-components/hint-box/hint-box.component";
import { AlertService } from "#src/app/core/alerts/alert.service";
import { ApiClientCredentials, ApiClientService } from "../api-client.service";
import { getScopeLabel } from "../api-client-scopes";

export interface ApiClientCredentialsDialogData {
  credentials: ApiClientCredentials;
  /** the client scopes of the API client */
  scopes: string[];
}

/**
 * Shows the credentials of an API client right after it was created (or its secret was regenerated),
 * which is the only time its secret is available, so that they can be passed on to the external system.
 */
@Component({
  selector: "app-api-client-credentials-dialog",
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [
    MatDialogModule,
    MatButtonModule,
    MatTooltipModule,
    FaIconComponent,
    DialogCloseComponent,
    HintBoxComponent,
  ],
  templateUrl: "./api-client-credentials-dialog.component.html",
  styleUrl: "./api-client-credentials-dialog.component.scss",
})
export class ApiClientCredentialsDialogComponent {
  private readonly apiClientService = inject(ApiClientService);
  private readonly alertService = inject(AlertService);
  private readonly clipboard = inject(Clipboard);
  private readonly data =
    inject<ApiClientCredentialsDialogData>(MAT_DIALOG_DATA);

  readonly fields: { label: string; value: string; copyLabel: string }[];
  readonly scopeLabels = this.data.scopes.map((s) => getScopeLabel(s));

  constructor() {
    const connection = this.apiClientService.getConnectionDetails();
    this.fields = [
      { label: $localize`API base URL`, value: connection.apiBaseUrl },
      { label: $localize`Token URL`, value: connection.tokenUrl },
      { label: $localize`Client ID`, value: this.data.credentials.clientId },
      {
        label: $localize`Client secret`,
        value: this.data.credentials.clientSecret,
      },
    ].map((field) => ({
      ...field,
      copyLabel: $localize`:aria label of a copy button:Copy ${field.label}:fieldName:`,
    }));
  }

  copy(value: string) {
    if (this.clipboard.copy(value)) {
      this.alertService.addInfo($localize`Copied to clipboard`);
    } else {
      this.alertService.addWarning(
        $localize`Could not copy to the clipboard. Please select and copy the text instead.`,
      );
    }
  }

  copyAll() {
    return this.copy(
      this.apiClientService.formatForSharing(
        this.data.credentials,
        this.data.scopes,
      ),
    );
  }
}
<h2 mat-dialog-title i18n>API credentials</h2>
<app-dialog-close mat-dialog-close></app-dialog-close>

<mat-dialog-content>
  <app-hint-box>
    <span i18n>
      Copy the client secret now and pass it on securely, e.g. through a
      password manager. It is not shown again. If it gets lost, you can generate
      a new secret, which stops the previous one from working.
    </span>
  </app-hint-box>

  <dl class="credentials">
    @for (field of fields; track field.label) {
      <dt>{{ field.label }}</dt>
      <dd class="flex-row align-center">
        <code class="credential-value flex-grow">{{ field.value }}</code>
        <button
          mat-icon-button
          type="button"
          (click)="copy(field.value)"
          matTooltip="Copy"
          i18n-matTooltip
          [attr.aria-label]="field.copyLabel"
        >
          <fa-icon [icon]="['far', 'copy']"></fa-icon>
        </button>
      </dd>
    }
    <dt i18n>Access</dt>
    <dd>
      <ul class="scopes">
        @for (label of scopeLabels; track label) {
          <li>{{ label }}</li>
        }
      </ul>
    </dd>
  </dl>
</mat-dialog-content>

<mat-dialog-actions>
  <button
    mat-raised-button
    color="accent"
    type="button"
    (click)="copyAll()"
    cdkFocusInitial
  >
    <fa-icon [icon]="['far', 'copy']" class="standard-icon-with-text"></fa-icon>
    <span i18n>Copy all</span>
  </button>
  <button mat-button mat-dialog-close i18n="Button label">Done</button>
</mat-dialog-actions>

./api-client-credentials-dialog.component.scss

.credentials {
  margin: 0;

  dt {
    font-weight: bold;
    margin-top: 12px;
  }

  dd {
    margin: 0;
  }
}

.credential-value {
  overflow-wrap: anywhere;
}

.scopes {
  margin: 4px 0 0;
  padding-left: 20px;
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""