File
Index
Properties
|
|
|
Methods
|
|
|
Inputs
|
|
|
Outputs
|
|
|
|
navigateOnDelete
|
Type : boolean
|
Default value : false
|
|
|
whether the "delete" action will trigger a navigation back to the parent list.
This is useful when the entity is deleted from a fullscreen detail view but not for an overlay.
|
|
showExpanded
|
Type : boolean | undefined
|
|
|
Whether some buttons should be displayed directly, outside the three-dot menu in dialog views.
|
Methods
|
Protected
getActionTooltip
|
getActionTooltip(action: EntityAction)
|
|
|
|
|
|
Readonly
actions
|
Type : unknown
|
Default value : computed(() => this.actionsResource.value() ?? [])
|
|
|
|
Protected
viewContext
|
Type : unknown
|
Default value : inject(ViewComponentContext, { optional: true })
|
|
|
import {
Component,
computed,
inject,
resource,
ChangeDetectionStrategy,
input,
output,
} from "@angular/core";
import { Entity } from "../../entity/model/entity";
import { MatButtonModule } from "@angular/material/button";
import { FontAwesomeModule } from "@fortawesome/angular-fontawesome";
import { FaDynamicIconComponent } from "../../common-components/fa-dynamic-icon/fa-dynamic-icon.component";
import { MatMenuModule } from "@angular/material/menu";
import { Angulartics2Module } from "angulartics2";
import { DisableEntityOperationDirective } from "../../permissions/permission-directive/disable-entity-operation.directive";
import { MatTooltipModule } from "@angular/material/tooltip";
import { ViewComponentContext } from "../../ui/abstract-view/view-component-context";
import { EntityActionsMenuService } from "./entity-actions-menu.service";
import { EntityAction } from "./entity-action.interface";
import { MatDialogRef } from "@angular/material/dialog";
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: "app-entity-actions-menu",
templateUrl: "./entity-actions-menu.component.html",
styleUrls: ["./entity-actions-menu.component.scss"],
imports: [
MatButtonModule,
FontAwesomeModule,
MatMenuModule,
Angulartics2Module,
DisableEntityOperationDirective,
MatTooltipModule,
FaDynamicIconComponent,
],
})
export class EntityActionsMenuComponent {
private entityActionsMenuService = inject(EntityActionsMenuService);
protected viewContext = inject(ViewComponentContext, { optional: true });
private readonly dialogRef = inject(MatDialogRef, { optional: true });
entity = input<Entity>();
/**
* whether the "delete" action will trigger a navigation back to the parent list.
* This is useful when the entity is deleted from a fullscreen detail view but not for an overlay.
*/
navigateOnDelete = input<boolean>(false);
actionTriggered = output<string>();
/**
* The actions being displayed as menu items.
*/
private readonly actionsResource = resource({
params: () => this.entity(),
loader: ({ params: entity }) =>
entity
? this.entityActionsMenuService.getActionsForSingle(entity)
: Promise.resolve([]),
});
readonly actions = computed(() => this.actionsResource.value() ?? []);
/**
* Whether some buttons should be displayed directly, outside the three-dot menu in dialog views.
*/
showExpanded = input<boolean | undefined>();
async executeAction(action: EntityAction) {
const entity = this.entity();
if (!entity) {
return;
}
const result = await action.execute(
entity,
this.navigateOnDelete() && !this.viewContext?.isDialog,
);
if (result) {
this.actionTriggered.emit(action.action);
// Close dialog after successful delete action
if (
action.action === "delete" &&
this.viewContext?.isDialog &&
this.dialogRef
) {
this.dialogRef.close();
}
}
this.actionsResource.reload();
}
protected getActionTooltip(action: EntityAction): string {
return action.tooltip || action.label;
}
}
@if (!entity()?.isNew) {
<!-- inline display of primary actions -->
@for (a of actions(); track a.action) {
@if (showExpanded() && viewContext?.isDialog && a.primaryAction) {
<button
mat-stroked-button
(click)="executeAction(a)"
*appDisabledEntityOperation="{
operation: a.permission,
entity: entity(),
}"
angulartics2On="click"
[angularticsCategory]="entity()?.getType()"
[angularticsAction]="'entity_' + a.action"
[matTooltip]="getActionTooltip(a)"
>
<app-fa-dynamic-icon
class="standard-icon-with-text color-accent"
[icon]="a.icon"
></app-fa-dynamic-icon>
<span>{{ a.label }}</span>
</button>
}
}
<!-- context menu -->
<button
mat-icon-button
color="primary"
style="margin-top: -8px; margin-bottom: -8px"
[matMenuTriggerFor]="additional"
>
<fa-icon icon="ellipsis-v" class="standard-icon"></fa-icon>
</button>
<!-- context menu -->
<mat-menu #additional>
<!-- standard actions -->
@for (a of actions(); track a.action) {
@if (!a.primaryAction || !showExpanded() || !viewContext?.isDialog) {
<button
mat-menu-item
(click)="executeAction(a)"
*appDisabledEntityOperation="{
operation: a.permission,
entity: entity(),
}"
angulartics2On="click"
[angularticsCategory]="entity()?.getType()"
[angularticsAction]="'entity_' + a.action"
[matTooltip]="getActionTooltip(a)"
matTooltipPosition="before"
>
<app-fa-dynamic-icon
class="standard-icon-with-text color-accent"
[icon]="a.icon"
></app-fa-dynamic-icon>
<span>{{ a.label }}</span>
</button>
}
}
<!-- additional actions -->
<ng-content></ng-content>
</mat-menu>
}
:host {
display: flex;
align-items: center;
}
Legend
Html element with directive