src/app/core/setup/system-init-assistant/system-init-assistant.component.ts

Description

UI for initial system setup and use case selection, used within the AssistantDialog.

Implements

OnInit

Example

Metadata

Relationships

Index

Properties
Methods

Methods

Async initializeSystem
initializeSystem()
Returns : any
onProfileStepCompleted
onProfileStepCompleted(notice: string | null)
Parameters :
Name Type Optional
notice string | null No
Returns : void
onUseCaseSelected
onUseCaseSelected(selected: BaseConfig)
Parameters :
Name Type Optional
selected BaseConfig No
Returns : void
startExploring
startExploring()
Returns : void

Properties

availableLocales
Type : unknown
Default value : signal<ConfigurableEnumValue[]>([])
availableUseCases
Type : unknown
Default value : signal<BaseConfig[]>([])
demoInitialized
Type : unknown
Default value : signal<boolean>(false)
Protected Readonly environment
Type : unknown
Default value : environment

exposed for the template to branch copy that only applies to the public in-memory demo

generateDemoData
Type : unknown
Default value : signal<boolean>(environment.demo_mode)
generatingData
Type : unknown
Default value : signal<boolean>(false)
profileStepDone
Type : unknown
Default value : signal<boolean>(false)

Whether the "create your profile" step has run its course (shown or not).

profileStepNotice
Type : unknown
Default value : signal<string | null>(null)

What the profile step left to report on the final screen, if anything.

selectedUseCase
Type : unknown
Default value : signal<BaseConfig | null>(null)
import {
  ChangeDetectionStrategy,
  Component,
  inject,
  OnInit,
  signal,
} from "@angular/core";
import { SetupService } from "../setup.service";
import { BaseConfig } from "../base-config";
import { MatButtonModule } from "@angular/material/button";
import { ChooseUseCaseComponent } from "./choose-use-case/choose-use-case.component";
import { Logging } from "../../logging/logging.service";
import { ActivatedRoute } from "@angular/router";
import { DemoDataInitializerService } from "../../demo-data/demo-data-initializer.service";
import { LanguageSelectComponent } from "app/core/language/language-select/language-select.component";
import { availableLocales } from "app/core/language/languages";
import { ConfigurableEnumValue } from "app/core/basic-datatypes/configurable-enum/configurable-enum.types";
import { MatDialogRef } from "@angular/material/dialog";
import { MatCheckbox } from "@angular/material/checkbox";
import { FormsModule } from "@angular/forms";
import { environment } from "#src/environments/environment";
import { AssistantService } from "#src/app/core/setup/assistant.service";
import { UserProfileSetupComponent } from "./user-profile-setup/user-profile-setup.component";

/**
 * UI for initial system setup and use case selection,
 * used within the AssistantDialog.
 */
@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: "app-system-init-assistant",
  imports: [
    MatButtonModule,
    ChooseUseCaseComponent,
    LanguageSelectComponent,
    MatCheckbox,
    FormsModule,
    UserProfileSetupComponent,
  ],
  templateUrl: "./system-init-assistant.component.html",
  styleUrl: "./system-init-assistant.component.scss",
})
export class SystemInitAssistantComponent implements OnInit {
  private dialogRef =
    inject<MatDialogRef<SystemInitAssistantComponent>>(MatDialogRef);
  private route = inject(ActivatedRoute);

  private readonly demoDataInitializer = inject(DemoDataInitializerService);
  private readonly setupService = inject(SetupService);

  /** exposed for the template to branch copy that only applies to the public in-memory demo */
  protected readonly environment = environment;

  availableUseCases = signal<BaseConfig[]>([]);
  selectedUseCase = signal<BaseConfig | null>(null);
  generateDemoData = signal<boolean>(environment.demo_mode);

  demoInitialized = signal<boolean>(false);
  generatingData = signal<boolean>(false);
  availableLocales = signal<ConfigurableEnumValue[]>([]);

  /** Whether the "create your profile" step has run its course (shown or not). */
  profileStepDone = signal<boolean>(false);
  /** What the profile step left to report on the final screen, if anything. */
  profileStepNotice = signal<string | null>(null);

  async ngOnInit(): Promise<void> {
    this.adjustAssistantDialogPanel();

    this.availableUseCases.set(
      await this.setupService.getAvailableBaseConfig(),
    );
    this.availableLocales.set(this.getAvailableLocalesForUseCases());

    await this.initFromQueryParamAutomatically();
  }

  private adjustAssistantDialogPanel() {
    this.dialogRef.updateSize(
      "calc(100% - 100px)",
      AssistantService.ASSISTANT_DIALOG_HEIGHT,
    );
    this.dialogRef.disableClose = true;
  }

  private getAvailableLocalesForUseCases() {
    const availableDemoLocale = new Set(
      this.availableUseCases()
        .map((useCase) => useCase.locale)
        .filter(Boolean),
    );

    return availableLocales.values.filter((locale) =>
      availableDemoLocale.has(locale.id),
    );
  }

  /**
   * The system can be opened with a pre-selected use case: ?useCase=useCaseId
   * @private
   */
  private async initFromQueryParamAutomatically() {
    const preSelectedUseCase = this.route.snapshot.queryParamMap.get("useCase");
    if (!preSelectedUseCase) {
      return;
    }

    const useCase =
      this.availableUseCases().find(
        (config) =>
          // Using lowercase comparison to avoid mismatches due to URL parameter casing or caching issues
          config.id.toLowerCase() === preSelectedUseCase.toLowerCase(),
      ) || null;

    this.selectedUseCase.set(useCase);

    await this.initializeSystem();
  }

  async initializeSystem() {
    if (!this.selectedUseCase()) {
      return;
    }

    this.generatingData.set(true);

    try {
      await this.setupService.initSystemWithBaseConfig(this.selectedUseCase()!);

      if (this.generateDemoData()) {
        await this.demoDataInitializer.generateDemoData();
      }

      // this also mounts the profile step, which relies on a config having been imported
      // successfully - on failure there is none to read entity types from.
      this.demoInitialized.set(true);
    } catch (error) {
      Logging.error("Error initializing demo data:", error);
    } finally {
      this.generatingData.set(false);
    }
  }

  onUseCaseSelected(selected: BaseConfig) {
    this.selectedUseCase.set(selected);
  }

  onProfileStepCompleted(notice: string | null) {
    this.profileStepNotice.set(notice);
    this.profileStepDone.set(true);
  }

  startExploring() {
    this.dialogRef.close();
  }
}
<div class="flex-column gap-regular">
  @if (!demoInitialized() && !generatingData()) {
    <app-language-select
      [availableLocales]="availableLocales()"
    ></app-language-select>
  }

  <h1 i18n>Welcome to Aam Digital!</h1>

  @if (!demoInitialized() && !generatingData()) {
    <p i18n>
      We have built this platform to help you digitize information and case
      files of your project, make it easy to collaborate with your team, track
      individual progress of participants, and be alerted about critical
      developments. With Aam Digital, you can access your data across all
      devices, even when offline.
    </p>

    <app-choose-use-case
      [useCases]="availableUseCases()"
      (selectionChanged)="onUseCaseSelected($event)"
      class="margin-top-large margin-bottom-large"
    >
    </app-choose-use-case>

    <mat-checkbox
      [checked]="generateDemoData()"
      (change)="generateDemoData.set($event.checked)"
      i18n
      >Generate demo data</mat-checkbox
    >

    <p class="footer-note" i18n>
      Aam Digital is very flexible and can be quickly adapted to your needs and
      data structures. It is not limited to the scenarios above. After
      initializing your system, you can further customize it to track, measure,
      and manage your project.
    </p>

    <div class="demo-actions">
      <button
        mat-raised-button
        class="full-width"
        color="accent"
        (click)="initializeSystem()"
        [disabled]="!selectedUseCase()"
        i18n
      >
        Create System
      </button>
    </div>
  } @else if (generatingData()) {
    <p i18n>Generating sample data for this demo ...</p>
  } @else if (!profileStepDone()) {
    <app-user-profile-setup
      (completed)="onProfileStepCompleted($event)"
    ></app-user-profile-setup>
  } @else {
    @if (environment.demo_mode) {
      <p i18n>
        We have loaded some sample data into this demo system. Explore and play
        around – you can’t break anything!<br />
        Changes you make in this demo will <em>not</em> be saved anywhere. The
        system is reset after you close or reload the page.
      </p>

      <p i18n>
        You can get assistance by clicking the "Assistant" button on the top
        right of the toolbar. From there you can also switch to other demo
        scenarios.
      </p>
    } @else {
      <p i18n>Your system is ready to use.</p>

      @if (profileStepNotice()) {
        <p>{{ profileStepNotice() }}</p>
      }

      <p i18n>
        You can get assistance any time by clicking the "Assistant" button on
        the top right of the toolbar.
      </p>
    }

    <div class="demo-actions">
      <button
        mat-raised-button
        class="full-width"
        color="accent"
        (click)="startExploring()"
        [disabled]="generatingData()"
        i18n
      >
        Start Exploring
      </button>
    </div>
  }
</div>

./system-init-assistant.component.scss

Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""