src/app/core/admin/admin-menu/admin-menu-item-details/admin-menu-item-details.component.ts

Description

Dialog component to edit a single menu item's details.

Implements

OnInit

Example

Metadata

Relationships

Used by

No results matching.

Depends on

Index

Properties
Methods

Constructor

constructor()

Methods

cancel
cancel()
Returns : void
onEntityTypeSelected
onEntityTypeSelected(entityType: string | string[])
Parameters :
Name Type Optional
entityType string | string[] No
Returns : void
save
save()
Returns : void

Properties

allowEntityLinks
Type : boolean

Whether entity type links are allowed (false for shortcuts, true for admin menu)

availableRoutes
Type : { value: string; label: string }[]
data
Type : unknown
Default value : inject<{ item: MenuItem; isNew?: boolean; allowEntityLinks?: boolean; }>(MAT_DIALOG_DATA)
dialogRef
Type : unknown
Default value : inject<MatDialogRef<AdminMenuItemDetailsComponent>>(MatDialogRef)
isNew
Type : boolean
item
Type : MenuItem | EntityMenuItem
linkError
Type : unknown
Default value : false
import {
  Component,
  ViewChild,
  inject,
  OnInit,
  ChangeDetectionStrategy,
} from "@angular/core";
import {
  MAT_DIALOG_DATA,
  MatDialogModule,
  MatDialogRef,
} from "@angular/material/dialog";
import { MatFormFieldModule } from "@angular/material/form-field";
import { MatInputModule } from "@angular/material/input";
import { MatSelectModule } from "@angular/material/select";
import { MatButtonModule } from "@angular/material/button";
import { EntityMenuItem, MenuItem } from "app/core/ui/navigation/menu-item";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { EntityTypeSelectComponent } from "../../../entity/entity-type-select/entity-type-select.component";
import { MenuItemFormComponent } from "#src/app/core/admin/admin-menu/menu-item-form/menu-item-form.component";
import {
  PREFIX_VIEW_CONFIG,
  ViewConfig,
} from "#src/app/core/config/dynamic-routing/view-config.interface";
import { ConfigService } from "#src/app/core/config/config.service";
import { isManualItemWithoutLink } from "../menu-item-for-admin-ui";
import { getRuntimePathFromViewConfig } from "#src/app/core/config/dynamic-routing/route-paths";

/**
 * Dialog component to edit a single menu item's details.
 */
@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: "app-admin-menu-item-details",
  standalone: true,
  imports: [
    FormsModule,
    ReactiveFormsModule,
    MatFormFieldModule,
    MatInputModule,
    MatSelectModule,
    MatButtonModule,
    MatDialogModule,
    EntityTypeSelectComponent,
    MenuItemFormComponent,
  ],
  templateUrl: "./admin-menu-item-details.component.html",
  styleUrls: ["./admin-menu-item-details.component.scss"],
})
export class AdminMenuItemDetailsComponent implements OnInit {
  private readonly configService = inject(ConfigService);
  @ViewChild(MenuItemFormComponent)
  private readonly menuItemForm?: MenuItemFormComponent;

  dialogRef = inject<MatDialogRef<AdminMenuItemDetailsComponent>>(MatDialogRef);
  data = inject<{
    item: MenuItem;
    isNew?: boolean;
    allowEntityLinks?: boolean;
  }>(MAT_DIALOG_DATA);

  item: MenuItem | EntityMenuItem;
  availableRoutes: { value: string; label: string }[];
  isNew: boolean;
  /** Whether entity type links are allowed (false for shortcuts, true for admin menu) */
  allowEntityLinks: boolean;
  linkError = false;

  constructor() {
    const data = this.data;

    this.item = data.item;
    this.isNew = data.isNew;
    this.allowEntityLinks = data.allowEntityLinks ?? true;
  }

  ngOnInit(): void {
    this.availableRoutes = this.loadAvailableRoutes();
  }

  private loadAvailableRoutes(): { value: string; label: string }[] {
    const allConfigs: ViewConfig[] =
      this.configService.getAllConfigs<ViewConfig>(PREFIX_VIEW_CONFIG);

    const availableViews = allConfigs.filter(
      (view) => !view._id.includes("/:id"),
    ); // skip details views (with "/:id" placeholder)

    return availableViews.map((view) => {
      const runtimePath = getRuntimePathFromViewConfig(view);
      const link = runtimePath ? `/${runtimePath}` : "/";
      const label =
        view.config?.entityType?.trim() || view.component || runtimePath;
      return { value: link, label };
    });
  }

  onEntityTypeSelected(entityType: string | string[]) {
    const entityTypeValue = entityType as string; // multi is set to false, so this is always a string

    if (entityTypeValue?.trim()) {
      (this.item as EntityMenuItem).entityType = entityTypeValue.trim();
    } else {
      // Clear entity type when empty or null is selected
      delete (this.item as EntityMenuItem).entityType;
    }
  }

  save() {
    const entityMenuItem = this.item as EntityMenuItem;
    const hasValidEntityType = entityMenuItem.entityType?.trim();
    const isNoLinkModeActive =
      this.menuItemForm?.isNoLinkModeEnabled() ?? false;

    if (hasValidEntityType) {
      // For entity type items, remove manual properties
      delete this.item.label;
      delete this.item.icon;
      delete this.item.link;
      entityMenuItem.entityType = hasValidEntityType;
    } else {
      // For manual items, remove entity type property
      delete entityMenuItem.entityType;

      if (isManualItemWithoutLink(this.item) && !isNoLinkModeActive) {
        // Validation: manual items require a link unless noLinkMode is active
        this.linkError = true;
        return;
      }

      if (isNoLinkModeActive) {
        // Ensure link is fully absent (not an empty string)
        delete this.item.link;
      }
    }

    this.dialogRef.close(this.item);
  }

  cancel() {
    this.dialogRef.close();
  }
}
<h2 mat-dialog-title>
  @if (isNew) {
    <ng-container i18n="menu item edit title">Add New Item</ng-container>
  } @else {
    <ng-container i18n="menu item edit title">Edit Item</ng-container>
  }
</h2>

<mat-dialog-content>
  <form class="flex-column gap-regular">
    @if (allowEntityLinks) {
      <p i18n>
        Optionally select a record type to automatically use its name, icon and
        list view (as link) for this menu item. Otherwise, you can select a
        custom name and icon below.
      </p>

      <!-- EntityType -->
      <mat-form-field appearance="fill" class="margin-bottom-large">
        <mat-label i18n>Record Type</mat-label>
        <app-entity-type-select
          [value]="item?.['entityType']"
          (valueChange)="onEntityTypeSelected($event)"
          [multi]="false"
        ></app-entity-type-select>
      </mat-form-field>

      @if (item?.["entityType"]) {
        <p i18n>
          To manually define a label and link, clear the record type field
          above.
        </p>
      }
    }

    <!-- Show manual form for shortcuts OR when no entity type is selected -->
    @if (!allowEntityLinks || !item?.["entityType"]) {
      <app-menu-item-form
        [item]="item"
        (itemChange)="item = $event; linkError = false"
        [linkOptions]="availableRoutes"
        [isNew]="isNew"
        [showLinkError]="linkError"
      ></app-menu-item-form>
    }
  </form>
</mat-dialog-content>

<mat-dialog-actions>
  <button mat-raised-button color="accent" (click)="save()" i18n>Apply</button>
  <button mat-button (click)="cancel()" cdkFocusInitial i18n>Cancel</button>
</mat-dialog-actions>

./admin-menu-item-details.component.scss

Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""