src/app/features/api-client/api-client-scope-selection/api-client-scope-selection.component.ts

Description

Select the access (client scopes) of an API client, from those the backend offers.

Example

Metadata

Relationships

Index

Properties
Inputs

Inputs

control
Type : FormControl<string[]>
Required :  true

the names of the selected client scopes

Properties

Readonly loadingError
Type : unknown
Default value : computed(() => this.scopes.error() ? errorMessageOf(this.scopes.error()) : undefined, )
Readonly scopes
Type : unknown
Default value : resource({ loader: async () => (await this.apiClientService.getScopes()).map((scope) => ({ name: scope.name, label: getScopeLabel(scope.name, scope.description), })), })

the client scopes the API client can be given

Readonly singleSignOnSelected
Type : unknown
Default value : computed(() => this.selectedScopes().includes(SINGLE_SIGN_ON_SCOPE), )
import { Component, computed, inject, input, resource } from "@angular/core";
import { toObservable, toSignal } from "@angular/core/rxjs-interop";
import { FormControl, ReactiveFormsModule } from "@angular/forms";
import { MatListModule } from "@angular/material/list";
import { MatProgressBarModule } from "@angular/material/progress-bar";
import { startWith, switchMap } from "rxjs";
import { HintBoxComponent } from "#src/app/core/common-components/hint-box/hint-box.component";
import { ApiClientService, errorMessageOf } from "../api-client.service";
import { getScopeLabel, SINGLE_SIGN_ON_SCOPE } from "../api-client-scopes";

/**
 * Select the access (client scopes) of an API client, from those the backend offers.
 */
@Component({
  selector: "app-api-client-scope-selection",
  imports: [
    MatListModule,
    MatProgressBarModule,
    ReactiveFormsModule,
    HintBoxComponent,
  ],
  templateUrl: "./api-client-scope-selection.component.html",
})
export class ApiClientScopeSelectionComponent {
  private readonly apiClientService = inject(ApiClientService);

  /** the names of the selected client scopes */
  readonly control = input.required<FormControl<string[]>>();

  /** the client scopes the API client can be given */
  readonly scopes = resource({
    loader: async () =>
      (await this.apiClientService.getScopes()).map((scope) => ({
        name: scope.name,
        label: getScopeLabel(scope.name, scope.description),
      })),
  });
  readonly loadingError = computed(() =>
    this.scopes.error() ? errorMessageOf(this.scopes.error()) : undefined,
  );

  private readonly selectedScopes = toSignal(
    toObservable(this.control).pipe(
      switchMap((control) =>
        control.valueChanges.pipe(startWith(control.value)),
      ),
    ),
    { initialValue: [] as string[] },
  );

  readonly singleSignOnSelected = computed(() =>
    this.selectedScopes().includes(SINGLE_SIGN_ON_SCOPE),
  );
}
@if (scopes.hasValue()) {
  @let offeredScopes = scopes.value();
  <mat-selection-list
    [formControl]="control()"
    aria-label="Access"
    i18n-aria-label
  >
    @for (scope of offeredScopes; track scope.name) {
      <mat-list-option [value]="scope.name">
        <span matListItemTitle>{{ scope.label }}</span>
      </mat-list-option>
    }
  </mat-selection-list>
} @else if (scopes.isLoading()) {
  <mat-progress-bar mode="indeterminate"></mat-progress-bar>
} @else if (loadingError(); as loadingError) {
  <p class="color-error" role="alert">{{ loadingError }}</p>
}

@if (singleSignOnSelected()) {
  <app-hint-box type="warning" class="margin-top-small">
    <span i18n>
      With single sign-on, the external system can sign in to this system as any
      of its users, including administrators, without their password. Only give
      this access to systems you fully trust.
    </span>
  </app-hint-box>
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""