src/app/core/admin/admin-entity-types/admin-entity-types.component.ts

Description

Manage the configuration of all entity types. Currently, this only serves as a utility for internal use, speeding up setup processes.

TODO: This component is only a raw prototype! Needs further concept and implementation.

Implements

OnInit

Example

Metadata

Relationships

Used by

No results matching.

Depends on

Index

Properties
Methods

Methods

Async create
create()
Returns : any
Protected loadEntityTypes
loadEntityTypes(onlyUserFacing: unknown)
Parameters :
Name Type Optional Default value
onlyUserFacing unknown No true
Returns : void

Properties

columnsToDisplay
Type : string[]
Default value : ["label", "id", "icon"]
entityTypes
Type : EntityConstructor[]
Default value : []
import {
  Component,
  OnInit,
  inject,
  ChangeDetectionStrategy,
} from "@angular/core";
import { EntityRegistry } from "../../entity/database-entity.decorator";
import {
  MatCell,
  MatCellDef,
  MatColumnDef,
  MatHeaderCell,
  MatHeaderCellDef,
  MatHeaderRow,
  MatHeaderRowDef,
  MatRow,
  MatRowDef,
  MatTable,
} from "@angular/material/table";
import { MatButton } from "@angular/material/button";
import { FaDynamicIconComponent } from "../../common-components/fa-dynamic-icon/fa-dynamic-icon.component";
import { EntityConstructor } from "../../entity/model/entity";
import { RouterLink } from "@angular/router";
import { generateIdFromLabel } from "../../../utils/generate-id-from-label/generate-id-from-label";
import { EntityMapperService } from "../../entity/entity-mapper/entity-mapper.service";
import { EntityConfig } from "../../entity/entity-config";
import { ViewTitleComponent } from "../../common-components/view-title/view-title.component";
import { EntityDetailsConfig } from "../../entity-details/EntityDetailsConfig";
import { EntityListConfig } from "../../entity-list/EntityListConfig";
import { Config } from "../../config/config";
import { EntityConfigService } from "../../entity/entity-config.service";
import { DynamicComponentConfig } from "../../config/dynamic-components/dynamic-component-config.interface";

/**
 * Manage the configuration of all entity types.
 * Currently, this only serves as a utility for internal use, speeding up setup processes.
 *
 * TODO: This component is only a raw prototype! Needs further concept and implementation.
 */
@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: "app-admin-entity-types",
  imports: [
    ViewTitleComponent,
    MatHeaderRow,
    MatHeaderRowDef,
    MatRow,
    MatRowDef,
    MatCell,
    MatHeaderCell,
    MatColumnDef,
    MatTable,
    MatButton,
    MatCellDef,
    MatHeaderCellDef,
    FaDynamicIconComponent,
    RouterLink,
  ],
  templateUrl: "./admin-entity-types.component.html",
  styleUrl: "./admin-entity-types.component.scss",
})
export class AdminEntityTypesComponent implements OnInit {
  private entities = inject(EntityRegistry);
  private entityMapper = inject(EntityMapperService);

  entityTypes: EntityConstructor[] = [];
  columnsToDisplay: string[] = ["label", "id", "icon"];

  ngOnInit() {
    this.loadEntityTypes();
  }

  protected loadEntityTypes(onlyUserFacing = true) {
    this.entityTypes = this.entities
      .getEntityTypes(onlyUserFacing)
      .map((e) => e.value);
  }

  async create() {
    const name = prompt("Please enter record type name:");
    if (!name) {
      return;
    }
    const id = generateIdFromLabel(name);
    if (this.entityTypeExists(id)) {
      alert("Record type already exists.");
      return;
    }

    // save default entity schema
    await this.saveDefaultEntityConfig(
      id,
      this.getDefaultEntityConfig(id, name),
      this.getDefaultDetailsViewConfig(id),
      this.getDefaultListViewConfig(id),
    );
  }

  private entityTypeExists(id: string) {
    return Array.from(this.entities.keys()).some(
      (key) => key.toLowerCase() === id.toLowerCase(),
    );
  }

  private async saveDefaultEntityConfig(
    id: string,
    entityConfig: EntityConfig,
    detailsViewConfig: DynamicComponentConfig,
    listViewConfig: DynamicComponentConfig,
  ) {
    const originalConfig = await this.entityMapper.load(
      Config,
      Config.CONFIG_KEY,
    );
    const newConfig = originalConfig.copy();

    newConfig.data[EntityConfigService.PREFIX_ENTITY_CONFIG + id] =
      entityConfig;
    newConfig.data[EntityConfigService.getDetailsViewId(entityConfig)] =
      detailsViewConfig;
    newConfig.data[EntityConfigService.getListViewId(entityConfig)] =
      listViewConfig;

    this.addEntityMenuItem(newConfig.data as { [key: string]: any }, id);

    await this.entityMapper.save(newConfig);
  }

  private addEntityMenuItem(data: { [key: string]: any }, id: string) {
    if (!data.navigationMenu) {
      data.navigationMenu = { items: [] };
    }
    const menuItems = data.navigationMenu.items;

    // Avoid duplicate menu items
    if (!menuItems.some((item: any) => item.entityType === id)) {
      menuItems.push({
        entityType: id,
      });
    }
  }

  private getDefaultEntityConfig(
    entityTypeId: string,
    name: string,
  ): EntityConfig {
    return {
      label: name,
      route: entityTypeId,
    };
  }

  private getDefaultDetailsViewConfig(
    entityType: string,
  ): DynamicComponentConfig<EntityDetailsConfig> {
    return {
      component: "EntityDetails",
      config: {
        entityType: entityType,
        panels: [
          {
            title: "Basic Information",
            components: [
              {
                title: "",
                component: "Form",
                config: {
                  fieldGroups: [{ fields: [] }],
                },
              },
            ],
          },
        ],
      },
    };
  }

  private getDefaultListViewConfig(
    entityType: string,
  ): DynamicComponentConfig<EntityListConfig> {
    return {
      component: "EntityList",
      config: {
        entityType: entityType,
        columnGroups: {
          default: "Overview",
          mobile: "Overview",
          groups: [
            {
              name: "Overview",
              columns: [],
            },
          ],
        },
      },
    };
  }
}
<app-view-title i18n>Data Structures & Entity Types</app-view-title>

<p style="color: red">
  <span i18n
    >This is an internal server admin preview and not stable functionality
    yet.</span
  >
</p>

<div class="flex-row gap-regular">
  <button mat-raised-button color="accent" (click)="create()" i18n>
    Add New Record Type
  </button>

  <button
    mat-stroked-button
    color="accent"
    (click)="loadEntityTypes(false)"
    i18n
  >
    Also load internal types
  </button>
</div>

<table mat-table [dataSource]="entityTypes">
  <ng-container matColumnDef="label">
    <th mat-header-cell *matHeaderCellDef class="table-header" i18n>
      Record Type
    </th>

    <td mat-cell *matCellDef="let row">
      {{ row.label }}
    </td>
  </ng-container>

  <ng-container matColumnDef="id">
    <th mat-header-cell *matHeaderCellDef class="table-header" i18n>
      Record Type (ID)
    </th>

    <td mat-cell *matCellDef="let row">
      {{ row.ENTITY_TYPE }}
    </td>
  </ng-container>

  <ng-container matColumnDef="icon">
    <th mat-header-cell *matHeaderCellDef class="table-header" i18n>Icon</th>

    <td mat-cell *matCellDef="let row">
      @if (row.icon) {
        <app-fa-dynamic-icon [icon]="row.icon"></app-fa-dynamic-icon>
      }
    </td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
  <tr
    mat-row
    *matRowDef="let row; columns: columnsToDisplay"
    [routerLink]="['/admin', 'entity', row.ENTITY_TYPE]"
    style="cursor: pointer"
  ></tr>
</table>

./admin-entity-types.component.scss

.table-header {
  font-weight: bold;
  font-style: italic;
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""