Description
Dialog component to edit a single menu item's details.
Implements
Example
Methods
|
onEntityTypeSelected
|
onEntityTypeSelected(entityType: string | string[])
|
|
|
Parameters :
| Name |
Type |
Optional |
| entityType |
string | string[]
|
No
|
|
|
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)
|
|
|
|
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>
Legend
Html element with directive