File

C:/GoDev/src/TCSTK-Angular/projects/tibco-tcstk/tc-liveapps-lib/src/lib/components/live-apps-documents/live-apps-documents.component.ts

Description

Document List and upload Component

This Component allows to list, upload, download, Documents attached to a Case-Instance or a whole Application. In the Upload Dialog the User is able to select a local File and enter a short Description.

The Component stores also the following Data

  • uploading User
  • Timestamp
  • File Size

Document List
alt-text Document Upload Dialog
alt-text

Extends

LiveAppsComponent

Implements

OnInit

Example

<tcla-live-apps-documents></tcla-live-apps-documents>

Metadata

selector tcla-live-apps-documents
styleUrls ./live-apps-documents.component.css
templateUrl ./live-apps-documents.component.html

Index

Properties
Methods
Inputs
Outputs
HostListeners
Accessors

Constructor

constructor(liveapps: LiveAppsService, documentsService: TcDocumentService, dialog: MatDialog)
Parameters :
Name Type Optional
liveapps LiveAppsService No
documentsService TcDocumentService No
dialog MatDialog No

Inputs

customActions
Type : string[]

Custom Document Buttons (array of text)

filter
Type : string

NOT used but would allow a search filter on documents

folderDescription
Type : string

header text on component (defaults to documents)

folderId
Type : string

The organisation folder to store/retrieve documents

folderType
Type : string

orgFolders' or 'caseFolders' - different API calls made according to which one this is

sandboxId
Type : number

sandboxId - this comes from claims resolver

showHeader
Type : boolean

Outputs

customActionClicked
Type : EventEmitter<DocumentAction>

Custom Document Action Event: fired when a custom action is clicked for a document (outputs the action name and a document (DocumentAction))

HostListeners

window:resize
Arguments : '$event'
window:resize(event)
Inherited from LiveAppsComponent

Methods

attachFile
attachFile(files: FileList)
Parameters :
Name Type Optional
files FileList No
Returns : void
ngOnInit
ngOnInit()
Returns : void
openDialog
openDialog()
Returns : void
setFileDescription
setFileDescription(description: string)
Parameters :
Name Type Optional
description string No
Returns : void
uploadFile
uploadFile(fileToUpload, description)
Parameters :
Name Optional
fileToUpload No
description No
Returns : void
ngAfterViewInit
ngAfterViewInit()
Inherited from LiveAppsComponent
Returns : void
ngOnDestroy
ngOnDestroy()
Inherited from LiveAppsComponent
Returns : void
ngOnInit
ngOnInit()
Inherited from LiveAppsComponent
Returns : void
setupWidthObserver
setupWidthObserver()
Inherited from LiveAppsComponent
Returns : void

Properties

Public customActionClick
Default value : () => {...}
Public dialog
Type : MatDialog
Public documents
Type : Document[]
Public downloadDocument
Default value : () => {...}
Public errorMessage
Type : string
Public fileDescription
Type : string
Public fileToUpload
Type : File
Default value : undefined
Public listDocuments
Default value : () => {...}
Public refresh
Default value : () => {...}
Public removeDocument
Default value : () => {...}
Public showHeader
Type : boolean
Default value : true

Whether to show the header bar in the widget - eg. favorites on home page (contains icon etc) - if off icons still appear without bar

Public uploadDocument
Default value : () => {...}
uploadMessage
Type : string
Public uploadProgress
Type : number
Public viewDocument
Default value : () => {...}
Protected _destroyed$
Default value : new Subject()
Inherited from LiveAppsComponent
componentChildDivs
Type : LiveAppsComponent[]
Decorators :
@ViewChildren('componentChildDiv')
Inherited from LiveAppsComponent
componentDiv
Type : ElementRef
Decorators :
@ViewChild('componentDiv', {static: false})
Inherited from LiveAppsComponent
Protected containerChanges$
Type : Observable<TcComponent>
Inherited from LiveAppsComponent
Private observer
Inherited from LiveAppsComponent
Public resize
Default value : () => {...}
Inherited from LiveAppsComponent
Public widget
Type : TcComponent
Inherited from LiveAppsComponent

Accessors

ShowHeader
setShowHeader(showHeader: boolean)
Parameters :
Name Type Optional
showHeader boolean No
Returns : void
import {Component, EventEmitter, Inject, Input, OnDestroy, OnInit, Output} from '@angular/core';
import {LiveAppsService} from '../../services/live-apps.service';
import { take, takeUntil} from 'rxjs/operators';
import { Document, DocumentAction} from '../../models/tc-document';
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog';
import {LiveAppsComponent} from '../live-apps-component/live-apps-component.component';
import {TcDocumentService} from '../../services/tc-document.service';
import {HttpEventType} from '@angular/common/http';


/**
 * Document List and upload Component
 *
 * This Component allows to list, upload, download, Documents attached to a Case-Instance or a whole Application.
 * In the Upload Dialog the User is able to select a local File and enter a short Description.
 *
 * The Component stores also the following Data
 * - uploading User
 * - Timestamp
 * - File Size
 *
 * Document List<br>
 * ![alt-text](../live-apps-documents.png "Documents Component Image")
 * Document Upload Dialog <br>
 * ![alt-text](../Docs-Upload.png "Documents Component Image")
 *
 *@example <tcla-live-apps-documents></tcla-live-apps-documents>
 */

@Component({
  selector: 'tcla-live-apps-documents',
  templateUrl: './live-apps-documents.component.html',
  styleUrls: ['./live-apps-documents.component.css']
})
export class LiveAppsDocumentsComponent extends LiveAppsComponent implements OnInit {

  constructor(protected liveapps: LiveAppsService, protected documentsService: TcDocumentService, public dialog: MatDialog) {
    super();
  }
  /**
   * sandboxId - this comes from claims resolver
   */
  @Input() sandboxId: number;

  /**
   * orgFolders' or 'caseFolders' - different API calls made according to which one this is
   */
  @Input() folderType: string; // 'orgFolders' or 'caseFolders'

  /**
   * The organisation folder to store/retrieve documents
   */
  @Input() folderId: string;   // caseRef for caseFolder

  /**
   * NOT used but would allow a search filter on documents
   */
  @Input() filter: string;

  /**
   * header text on component (defaults to documents)
   */
  @Input() folderDescription: string;

  /**
   * Whether to show the header bar in the widget - eg. favorites on home page (contains icon etc) - if off icons still appear without bar
   */
  public showHeader: boolean = true;
  @Input('showHeader') set ShowHeader(showHeader: boolean) {
    if (showHeader){
      this.showHeader = showHeader;
    }
  }

  /**
   * Custom Document Buttons (array of text)
   */
  @Input() customActions: string[]

  /**
   * Custom Document Action Event: fired when a custom action is clicked for a document (outputs the action name and a document (DocumentAction))
   */
  @Output() customActionClicked: EventEmitter<DocumentAction> = new EventEmitter<DocumentAction>()

  public errorMessage: string;
  public documents: Document[];
  public fileToUpload: File = undefined;
  public fileDescription: string;
  uploadMessage: string;
  public uploadProgress: number;

  public refresh = () => {
    this.listDocuments();
  }

  public customActionClick = (action: string, document: Document) => {
    this.customActionClicked.emit(new DocumentAction().deserialize(
      {
        action,
        document
      }
    ));
  }

  public listDocuments = () => {
    this.documentsService.listDocuments(this.folderType, this.folderId, this.sandboxId, this.filter)
      .pipe(
        take(1),
        takeUntil(this._destroyed$)
      )
      .subscribe(documentslist => {
        this.documents = documentslist.documents;
      }, error => { this.errorMessage = 'Error retrieving case states: ' + error.error.errorMsg; });
    }

  public uploadDocument = (doc) => {
  }

  public removeDocument = (doc) => {
    this.documentsService.deleteDocument(this.folderType, this.folderId, doc.name, this.sandboxId)
      .pipe(
        take(1),
        takeUntil(this._destroyed$)
      )
      .subscribe(
        val => {
          console.log(val);
          this.refresh();
        }, error => { this.errorMessage = 'Error removing document: ' + error.errorMsg; });
  }

  public viewDocument = (doc) => {
    const viewDocDialogRef = this.dialog.open(LiveAppsDocumentViewerDialogComponent, {
      width: '75%',
      height: '75%',
      data: {
        doc: doc,
        folderType: this.folderType,
        folderId: this.folderId,
        sandboxId: this.sandboxId
      }
    });

    viewDocDialogRef.afterClosed().subscribe(result => {
    });
  }

  public downloadDocument = (doc) => {
    this.documentsService.downloadDocument(this.folderType, this.folderId, doc.name, doc.artifactVersion, this.sandboxId)
      .pipe(
        take(1),
        takeUntil(this._destroyed$)
      )
      .subscribe(
        data => {
          // todo: check if this works on all browsers
          const downloadURL = window.URL.createObjectURL(data);
          const link = document.createElement('a');
          link.href = downloadURL;
          link.download = doc.name;
          link.click();
        }, error => { this.errorMessage = 'Error downloading document: ' + error.errorMsg; });
  }

  attachFile(files: FileList) {
    this.uploadMessage = '';
    this.fileToUpload = files.item(0);
  }

  setFileDescription(description: string) {
    this.fileDescription = description;
  }

  uploadFile(fileToUpload, description) {
    this.fileToUpload = fileToUpload;
    this.uploadMessage = 'Uploading: ' + fileToUpload.name;
    this.fileDescription = description;
    this.uploadProgress = 0;
    if (this.fileToUpload) {
      this.documentsService.uploadDocument(this.folderType, this.folderId, this.sandboxId,
        this.fileToUpload, this.fileToUpload.name, this.fileDescription)
        .subscribe(
          (response: any) => {
            if (response.type === HttpEventType.UploadProgress) {
              this.uploadProgress = Math.round(100 * response.loaded / response.total);
              if (this.uploadProgress === 100) {
                this.fileToUpload = undefined;
                this.uploadMessage = 'Uploaded: ' + fileToUpload.name;
                // api seems not to show new documents straight away sometimes - so this minimizes the chances of that
                setTimeout(() => { this.refresh(); }, 1000);
                setTimeout(() => { this.uploadMessage = ''; this.uploadProgress = undefined; }, 5000);
              }
            }
          },
          error => { console.log('error'); this.errorMessage = 'Error uploading document: ' + error.errorMsg; });
    }
  }

  openDialog(): void {
    // only allow if upload not in progress
    if (!this.uploadProgress || this.uploadProgress === 100) {
      const dialogRef = this.dialog.open(LiveAppsDocumentUploadDialogComponent, {
        width: '500px',
        data: {}
      });

      dialogRef.componentInstance.fileevent.subscribe(($e) => {
        this.uploadFile($e.file, $e.description);
      })

      dialogRef.afterClosed().subscribe(result => {
      });
    }
  }

  ngOnInit() {
    this.refresh();
  }
}

@Component({
  selector: 'tcla-live-apps-document-upload-dialog',
  templateUrl: 'app-live-apps-document-upload-dialog.html',
  styleUrls: [ 'app-live-apps-document-upload-dialog.css']
})
export class LiveAppsDocumentUploadDialogComponent {

  @Output() fileevent = new EventEmitter<any>();
  public fileToUpload: File = undefined;
  public description: string = undefined;

  constructor(
    public dialogRef: MatDialogRef<LiveAppsDocumentUploadDialogComponent>) {}


  public uploadFile = () => {
    if (this.fileToUpload) {
      this.fileevent.emit({ file: this.fileToUpload, description: this.description });
      this.dialogRef.close();
    }
  }

  setFileDescription(description: string) {
    this.description = description;
  }

  attachFile(files: FileList) {
    // this.uploadMessage = '';
    this.fileToUpload = files.item(0);
  }

  onNoClick(): void {
    this.dialogRef.close();
  }

}

@Component({
  selector: 'tcla-live-apps-document-viewer-dialog',
  templateUrl: 'app-live-apps-document-viewer-dialog.html',
  styleUrls: [ 'app-live-apps-document-viewer-dialog.css']
})
export class LiveAppsDocumentViewerDialogComponent {
  public doc: Document;
  public folderType: string;
  public folderId: string;
  public sandboxId: number;

  constructor(
    public dialogRef: MatDialogRef<LiveAppsDocumentUploadDialogComponent>,
    @Inject(MAT_DIALOG_DATA) public data: any) {
    this.doc = this.data.doc;
    this.folderType = this.data.folderType;
    this.folderId = this.data.folderId;
    this.sandboxId = this.data.sandboxId;
  }

  onNoClick(): void {
    this.dialogRef.close();
  }

}

<div class="tcs-documents-pane" fxFill fxLayout="column">
  <div *ngIf="showHeader" class="tcs-documents-header" fxLayout="row" fxLayoutAlign="space-between center">
    <div fxLayoutAlign="start center">
      <mat-icon class="tcs-icon tcs-icon-active tcs-collaboration-feed" svgIcon="tcs-document-library"></mat-icon>
      <div class="tcs-documents-header-text">{{folderDescription ? folderDescription : 'Documents'}}</div>
    </div>
    <mat-icon (click)="openDialog()" [ngClass]="{'tcs-icon-disabled' : uploadProgress < 100}" class="tcs-icon tcs-icon-active tcs-document-edit-buttons tcs-document-upload-icon" [matTooltip]="(uploadProgress && uploadProgress !== 100) ? 'Please wait for existing document to upload' : 'Upload Document'" matTooltipPosition="left" matTooltipShowDelay="1000" svgIcon="tcs-document-upload"></mat-icon>
  </div>
  <div *ngIf="!showHeader" fxLayout="row" fxLayoutAlign="end center">
    <mat-icon style="margin: 5px" [ngClass]="{'tcs-icon-disabled' : uploadProgress < 100}" (click)="openDialog()" class="tcs-icon tcs-icon-active tcs-document-edit-buttons tcs-document-upload-icon" [matTooltip]="(uploadProgress && uploadProgress !== 100) ? 'Please wait for existing document to upload' : 'Upload Document'" matTooltipPosition="left" matTooltipShowDelay="1000" svgIcon="tcs-document-upload"></mat-icon>
  </div>
  <div fxLayout="column" style="overflow: auto">
    <div *ngIf="uploadProgress">
      <div>{{uploadMessage}}</div>
      <mat-progress-bar
        mode="determinate"
        [value]="uploadProgress"
      >
      </mat-progress-bar>
    </div>
    <div class="tcs-document-list" fxLayout="column">
      <div *ngIf="documents && documents.length > 0">
        <div class="tcs-document-detail-box tcs-document" *ngFor="let document of documents | orderByDate: 'lastModifiedDate'" fxLayout="column">
          <div class="tcs-document-box" fxLayoutAlign="space-between center" fxLayout="row" fxFlex>
            <div fxLayoutAlign="start center">
              <mat-icon class="tcs-icon tcs-icon-active tcs-document-type-icon" svgIcon="tcs-document-{{document.fileIcon}}"></mat-icon>
            </div>
            <div class="tcs-document-details-text-box" fxLayout="column" fxLayoutAlign="center start" fxFlex>
                <div fxLayout="row" fxLayoutAlign="start center" fxFill>
                  <div class="tcs-document-name-text" matTooltip="{{document.name}}" matTooltipShowDelay="1000" matTooltipPosition="below">{{document.name | ellipsis: 30}}</div>
                  <div fxLayout="row" fxLayoutAlign="end center" fxFlex>
                    <div class="tcs-document-filesize-text">&nbsp;({{document.fileSize}})</div>
                  </div>
                </div>
                <div class="tcs-document-comment-text" matTooltip="{{document.description}}" matTooltipShowDelay="1000" matTooltipPosition="below">{{document.description | ellipsis: 50}}</div>
              <div fxLayout="row" fxLayoutAlign="start center">
                <div class="tcs-document-modified-text">{{document.lastModifiedDate | durationSince}}</div>
                <div *ngIf="document.lastModifiedByDetails" class="tcs-document-modified-text" matTooltip="{{document.lastModifiedByDetails.username}}" matTooltipShowDelay="1000" matTooltipPosition="below">&nbsp;by {{document.lastModifiedByDetails.username | ellipsis: 40}}</div>
              </div>
            </div>

            <div fxLayoutAlign="end center">
              <mat-icon [matMenuTriggerFor]="docActionMenu" class="tcs-icon tcs-icon-active tcs-document-action-icon" svgIcon="tcs-document-action"></mat-icon>
              <mat-menu #docActionMenu="matMenu" class="tcs-icon tcs-icon-active tcs-document-action-icon">
                <button class="tcs-document-action-text" mat-menu-item (click)="viewDocument(document)">View</button>
                <button class="tcs-document-action-text" mat-menu-item (click)="downloadDocument(document)">Download</button>
                <button class="tcs-document-action-text" mat-menu-item (click)="removeDocument(document)">Delete</button>
                <button *ngFor="let customAction of customActions" class="tcs-document-action-text" mat-menu-item (click)="customActionClick(customAction, document)">{{customAction}}</button>
              </mat-menu>


            </div>
          </div>
          <div class="tcs-document-line"></div>
        </div>
      </div>
      <div *ngIf="!(documents?.length > 0)" fxLayout="row" fxLayoutAlign="center start" fxLayoutGap="10px" style="margin-top: 20px;">
        <mat-icon [svgIcon]="'ic-no-docs-icon'" style="height: 48px; width: 48px;"></mat-icon>
        <div style="height: 100%" fxLayoutAlign="start center">
          <span class="tcs-no-item-text">No documents found</span>
        </div>
      </div>
    </div>
  </div>
</div>

./live-apps-documents.component.css

.tcs-hidden-input {
  display: none;
}

.tcs-small-pane {
  width: 400px;
  max-width: 400px;
  height: 386px;
  max-height: 400px;
  border-radius: 3px;
  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.33);
  background-color: #ffffff;
  margin: 0;
  padding: 0;
}

.tcs-documents-pane {
  border-radius: 3px;
  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.33);
  background-color: #ffffff;
}

.tcs-documents-header {
  min-height: 40px;
  height: 40px;
  border-radius: 3px 3px 0px 0px;
  box-shadow: 0 1px 2px 0 #dedede;
  padding-left: 20px;
  padding-right: 20px;
}

.tcs-documents-header-text {
  margin-left: 10px;
  font-family: Source Sans Pro;
  font-size: 18px;
  font-weight: 600;
  font-style: normal;
  font-stretch: normal;
  line-height: 1.5;
  letter-spacing: 0.3px;
}

.tcs-document-name-text {
  font-family: Source Sans Pro;
  font-size: 16px;
  font-weight: 600;
  font-style: normal;
  font-stretch: normal;
  line-height: normal;
  letter-spacing: normal;
  color: #0081cb;
}

.tcs-document-comment-text {
  font-family: Source Sans Pro;
  font-size: 12px;
  font-weight: normal;
  font-style: normal;
  font-stretch: normal;
  line-height: normal;
  letter-spacing: normal;
  color: #727272;
}

.tcs-document-modified-text {
  font-family: Source Sans Pro;
  font-size: 10px;
  font-weight: 600;
  font-style: normal;
  font-stretch: normal;
  line-height: normal;
  letter-spacing: -0.1px;
  color: #b6b6b6;
}

.tcs-document-filesize-text {
  font-family: Source Sans Pro;
  font-size: 10px;
  font-weight: 600;
  font-style: normal;
  font-stretch: normal;
  line-height: normal;
  letter-spacing: -0.1px;
  color: #b6b6b6;
}


.tcs-document-details-text-box {
  padding-left: 10px;
  padding-right: 10px;
  padding-top: 2px;
  padding-bottom: 2px;
}

:host ::ng-deep .tcs-icon-disabled.tcs-icon.tcs-document-edit-buttons path.svg-content {
  fill: #b6b6b6;
}

:host ::ng-deep .tcs-icon-disabled.tcs-icon.tcs-document-edit-buttons:hover path.svg-content {
  fill: #b6b6b6;
  cursor: not-allowed;
}

:host ::ng-deep .tcs-icon.tcs-document-edit-buttons:hover path.svg-content {
  fill: #0081cb;
  cursor: pointer;
}

:host ::ng-deep .tcs-icon.tcs-document-edit-icon:hover path.svg-content {
  fill: #0081cb;
  cursor: pointer;
}

.tcs-document-detail-box {
  min-height: 85px;
  flex-shrink: 0;
  padding-left: 20px;
  padding-right: 20px;
}

.tcs-document-detail-box:hover {
  background-color: #EEF0F7;
  transition: background-color 0.5s;
}

.tcs-document-line {
  margin-left: 20px;
  padding: 0px;
  margin-top: 0px;
  margin-right: 20px;
  margin-bottom: 0px;
  border-bottom-color: #f4f4f4;
  border-bottom-width: 1.1px;
  border-bottom-style: solid;
}

.tcs-document-list {
  overflow-y: auto;
}

.tcs-no-item-text {
  font-family: Source Sans Pro;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  font-stretch: normal;
  line-height: normal;
  letter-spacing: normal;
  color: #b6b6b6;
}
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""