File

src/app/core/basic-datatypes/entity/entity-block/entity-block.component.ts

Description

Display an inline block representing an entity.

Metadata

Index

Properties
Methods
Inputs

Inputs

entity
Type : Entity

The entity to display directly. Takes precedence over entityId.

entityId
Type : string

If entity is not set, entityId (with prefix) is used to load the entity.

linkDisabled
Default value : false

Methods

showDetailsPage
showDetailsPage()
Returns : void

Properties

entityBlockConfig
Type : unknown
Default value : computed(() => { return this.entityResource.value()?.getConstructor() ?.toBlockDetailsAttributes; })
entityColor
Type : unknown
Default value : computed(() => { const entity = this.entityResource.value(); if (!entity) return undefined; const colorConfig = entity.getConstructor().color; if (!colorConfig) return undefined; return Entity.getColorWithConditions(entity); })
entityIcon
Type : unknown
Default value : computed(() => { return this.entityResource.value()?.getConstructor()?.icon || "diamond"; })
entityResource
Type : unknown
Default value : resourceWithRetention({ params: () => ({ entity: this.entity(), entityId: this.entityId() }), loader: async ({ params: { entity, entityId } }) => { if (entity) return entity; if (!entityId) return undefined; try { return await this.entityMapper.load( Entity.extractTypeFromId(entityId), entityId, ); } catch (e) { Logging.debug("[DISPLAY_ENTITY] Could not find entity.", entityId, e); return undefined; } }, })
initialLoading
Type : unknown
Default value : computed( () => this.entityResource.isLoading() && !this.entityResource.value(), )

True during initial loading when no entity value is available yet. Otherwise, we want to use the previous value through the resource's retention.

import {
  ChangeDetectionStrategy,
  Component,
  computed,
  inject,
  input,
} from "@angular/core";
import { Router } from "@angular/router";
import { MatProgressSpinnerModule } from "@angular/material/progress-spinner";
import { DisplayImgComponent } from "../../../../features/file/display-img/display-img.component";
import { FaDynamicIconComponent } from "../../../common-components/fa-dynamic-icon/fa-dynamic-icon.component";
import { TemplateTooltipDirective } from "../../../common-components/template-tooltip/template-tooltip.directive";
import { DynamicComponent } from "../../../config/dynamic-components/dynamic-component.decorator";
import { EntityFieldViewComponent } from "../../../entity/entity-field-view/entity-field-view.component";
import { EntityMapperService } from "../../../entity/entity-mapper/entity-mapper.service";
import { Entity } from "../../../entity/model/entity";
import { Logging } from "../../../logging/logging.service";
import { resourceWithRetention } from "../../../../utils/resourceWithRetention";

/**
 * Display an inline block representing an entity.
 */
@DynamicComponent("EntityBlock")
@Component({
  selector: "app-entity-block",
  templateUrl: "./entity-block.component.html",
  styleUrls: ["./entity-block.component.scss"],
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [
    FaDynamicIconComponent,
    TemplateTooltipDirective,
    DisplayImgComponent,
    EntityFieldViewComponent,
    MatProgressSpinnerModule,
  ],
})
export class EntityBlockComponent {
  private entityMapper = inject(EntityMapperService);
  private router = inject(Router);

  /** The entity to display directly. Takes precedence over entityId. */
  entity = input<Entity>();

  /** If entity is not set, entityId (with prefix) is used to load the entity. */
  entityId = input<string>();

  linkDisabled = input(false);

  entityResource = resourceWithRetention({
    params: () => ({ entity: this.entity(), entityId: this.entityId() }),
    loader: async ({ params: { entity, entityId } }) => {
      if (entity) return entity;
      if (!entityId) return undefined;
      try {
        return await this.entityMapper.load(
          Entity.extractTypeFromId(entityId),
          entityId,
        );
      } catch (e) {
        Logging.debug("[DISPLAY_ENTITY] Could not find entity.", entityId, e);
        return undefined;
      }
    },
  });

  /**
   * True during initial loading when no entity value is available yet.
   * Otherwise, we want to use the previous value through the resource's retention.
   */
  initialLoading = computed(
    () => this.entityResource.isLoading() && !this.entityResource.value(),
  );

  entityBlockConfig = computed(() => {
    return this.entityResource.value()?.getConstructor()
      ?.toBlockDetailsAttributes;
  });

  entityIcon = computed(() => {
    return this.entityResource.value()?.getConstructor()?.icon || "diamond";
  });

  entityColor = computed(() => {
    const entity = this.entityResource.value();
    if (!entity) return undefined;
    const colorConfig = entity.getConstructor().color;
    if (!colorConfig) return undefined;
    return Entity.getColorWithConditions(entity);
  });

  showDetailsPage() {
    const entity = this.entityResource.value();
    if (this.linkDisabled() || !entity) {
      return;
    }

    this.router.navigate([entity.getConstructor().route, entity.getId(true)]);
  }
}
@if (initialLoading()) {
  <span class="block-height">
    <mat-spinner diameter="16" class="inline-spinner"></mat-spinner>
  </span>
} @else {
  <span
    class="block-height truncate-text"
    [class.clickable]="!linkDisabled()"
    [class.inactive]="!entityResource.value()?.isActive"
    (click)="showDetailsPage()"
    [appTemplateTooltip]="tooltip"
    [tooltipDisabled]="!entityBlockConfig()"
    [title]="entityResource.value()?.toString()"
  >
    <app-fa-dynamic-icon
      [icon]="entityIcon()"
      [style.color]="entityColor()"
      class="margin-right-small"
    ></app-fa-dynamic-icon>

    {{ entityResource.value()?.toString() }}
  </span>
}

<!-- Tooltip on Hover -->
<ng-template #tooltip>
  <div class="tooltip-container">
    @if (entityBlockConfig()?.image) {
      <app-display-img
        class="tooltip-photo"
        [entity]="entityResource.value()"
        [imgProperty]="entityBlockConfig()?.image"
      ></app-display-img>
    }

    <div>
      <!-- Font-weight is applied as style to override the default -->
      <h3 style="font-weight: bold">
        @if (entityBlockConfig()?.title) {
          <app-entity-field-view
            [entity]="entityResource.value()"
            [field]="entityBlockConfig()?.title"
          ></app-entity-field-view>
        } @else {
          {{ entityResource.value()?.toString() }}
        }
      </h3>

      @for (field of entityBlockConfig()?.fields; track field) {
        <app-entity-field-view
          [entity]="entityResource.value()"
          [field]="field"
        ></app-entity-field-view>
      }
    </div>
  </div>
</ng-template>

./entity-block.component.scss

@use "variables/sizes";
@use "variables/colors";

.block-height {
  line-height: sizes.$icon-block;
}

.inactive {
  color: colors.$inactive;
}

.inline-spinner {
  display: inline-block;
  vertical-align: middle;
}

.tooltip-container {
  padding: 0.5em;
  display: flex;
  flex-direction: row;
  gap: 2em;
  align-items: center;
}

.tooltip-photo ::ng-deep img {
  width: 80px;
  height: 80px;
  object-fit: cover;
  overflow: hidden;
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""