All files / chat-messages si-attachment-list.component.ts

56.25% Statements 9/16
0% Branches 0/4
50% Functions 2/4
56.25% Lines 9/16

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150                                                                                                                                                                              1x 16x           16x           16x           16x                   16x 16x           16x                                             40x      
/**
 * Copyright (c) Siemens 2016 - 2025
 * SPDX-License-Identifier: MIT
 */
import { booleanAttribute, Component, inject, input, output, TemplateRef } from '@angular/core';
import { SiIconComponent } from '@siemens/element-ng/icon';
import { SiModalService } from '@siemens/element-ng/modal';
import { SiTranslatePipe, t } from '@siemens/element-translate-ng/translate';
 
/**
 * Attachment item interface for file attachments in chat messages.
 *
 * @experimental
 */
export interface Attachment {
  /** File name */
  name: string;
  /** Optionally show a preview of the attachment by providing a template that is shown in a modal when clicked (optional) */
  previewTemplate?: TemplateRef<any> | (() => TemplateRef<any>);
}
 
/**
 * Attachment list component for displaying file attachments in chat messages.
 *
 * This component renders a list of file attachments with icons, names, and optional
 * preview and remove functionality. It's designed to work with chat message components
 * to show files that have been uploaded or shared in conversations.
 *
 * @remarks
 * This component provides:
 * - Automatic file type detection with appropriate icons
 * - Optional preview modal for attachments
 * - Optional remove functionality for editable messages
 * - Flexible alignment (start/end) to match message alignment
 * - Support for various file types (images, videos, audio, documents, archives)
 *
 * The component is typically used within {@link SiUserMessageComponent} or {@link SiAiMessageComponent}
 * to display uploaded files, but can also be used standalone.
 *
 * @example
 * Basic usage with attachments:
 * ```html
 * <si-attachment-list [attachments]="files" />
 * ```
 *
 * @example
 * With remove functionality and custom alignment:
 * ```typescript
 * import { Component } from '@angular/core';
 * import { SiAttachmentListComponent, Attachment } from '@siemens/element-ng/chat-messages';
 *
 * @Component({
 *   selector: 'app-chat',
 *   imports: [SiAttachmentListComponent],
 *   template: `
 *     <si-attachment-list
 *       [attachments]="attachments"
 *       [alignment]="'end'"
 *       [removable]="true"
 *       (remove)="handleRemove($event)"
 *     />
 *   `
 * })
 * export class ChatComponent {
 *   attachments: Attachment[] = [
 *     { id: '1', name: 'report.pdf' },
 *     { id: '2', name: 'image.png', previewTemplate: this.imagePreview }
 *   ];
 *
 *   handleRemove(attachment: Attachment) {
 *     this.attachments = this.attachments.filter(a => a !== attachment);
 *   }
 * }
 * ```
 *
 * @see {@link SiUserMessageComponent} for user message display
 * @see {@link SiAiMessageComponent} for AI message display
 * @see {@link Attachment} for attachment data structure
 *
 * @experimental
 */
@Component({
  selector: 'si-attachment-list',
  imports: [SiIconComponent, SiTranslatePipe],
  templateUrl: './si-attachment-list.component.html',
  styleUrl: './si-attachment-list.component.scss'
})
export class SiAttachmentListComponent {
  protected modalService = inject(SiModalService);
 
  /**
   * List of attachments to display
   * @defaultValue []
   */
  readonly attachments = input<Attachment[]>([]);
 
  /**
   * Whether to align attachments to the end (right) or start (left)
   * @defaultValue 'start'
   */
  readonly alignment = input<'start' | 'end'>('start');
 
  /**
   * Whether to show remove buttons on attachments
   * @defaultValue false
   */
  readonly removable = input(false, { transform: booleanAttribute });
 
  /**
   * Label for remove attachment button
   *
   * @defaultValue
   * ```
   * t(() => $localize`:@@SI_ATTACHMENT_LIST.REMOVE_ATTACHMENT:Remove attachment`)
   * ```
   */
  readonly removeLabel = input(
    t(() => $localize`:@@SI_ATTACHMENT_LIST.REMOVE_ATTACHMENT:Remove attachment`)
  );
 
  /**
   * Emitted when an attachment should be removed
   */
  readonly remove = output<Attachment>();
 
  private getPreviewTemplate(attachment: Attachment): any | undefined {
    Iif (attachment.previewTemplate) {
      return typeof attachment.previewTemplate === 'function'
        ? attachment.previewTemplate()
        : attachment.previewTemplate;
    }
    return undefined;
  }
 
  protected openPreview(event: Event, attachment: Attachment): void {
    const template = this.getPreviewTemplate(attachment);
    Iif (template) {
      event.preventDefault();
      this.modalService.show(template, {
        inputValues: { 'attachment': attachment }
      });
    }
  }
 
  protected getFileIcon(name: string): string {
    // TODO: Accept map and default it in file upload directive.
    return 'element-document';
  }
}