File

projects/web-mev/src/app/features/workspace-detail/components/workspace-detail/workspace-detail.component.ts

Description

Workspace Detail Component

Used to display the list of files/resources included in the current workspace Also contains child components for Metadata, Analyses Flow, Tools and Analyses Result

Implements

OnInit

Metadata

changeDetection ChangeDetectionStrategy.Default
selector mev-workspace-detail
styleUrls ./workspace-detail.component.scss
templateUrl ./workspace-detail.component.html

Index

Properties
Methods

Constructor

constructor(route: ActivatedRoute, service: WorkspaceDetailService, dialog: MatDialog)
Parameters :
Name Type Optional
route ActivatedRoute No
service WorkspaceDetailService No
dialog MatDialog No

Methods

addItem
addItem()

Open a modal dialog to add files to a specific workspace

Returns : void
applyFilter
applyFilter(event: Event)
Parameters :
Name Type Optional
event Event No
Returns : void
deleteItem
deleteItem(resource)

Open a modal dialog to delete a workspace resource from the current workspace

Parameters :
Name Optional
resource No
Returns : void
editItem
editItem(resource)

Open a modal dialog to edit workspace resource Users can re-name resources

Parameters :
Name Optional
resource No
Returns : void
goToAnalysesTab
goToAnalysesTab()

Switch to Analyses tab when the user clicks the Run button on the Tools tab

Returns : void
Public loadData
loadData()
Returns : void
ngOnInit
ngOnInit()
Returns : void
onTabChanged
onTabChanged($event)

Refresh data when user switching between tabs

Parameters :
Name Optional
$event No
Returns : void
previewItem
previewItem(resourceId)

Open a modal dialog to preview workspace resource content

Parameters :
Name Optional
resourceId No
Returns : void
refresh
refresh()
Returns : void
selectResource
selectResource(resource)
Parameters :
Name Optional
resource No
Returns : void
Public showExecutedOperationResult
showExecutedOperationResult(executedOperationId: string)

Method is triggered when the user clicks on a executed operation on the Analyses Flow Tab

Parameters :
Name Type Optional
executedOperationId string No
Returns : void

Properties

Public dialog
Type : MatDialog
displayedColumns
Type : string[]
Default value : [ 'name', 'readable_resource_type', 'size', 'created', 'actions' ]
execOperationId
Type : string
isWait
Default value : false
paginator
Type : MatPaginator
Decorators :
@ViewChild(MatPaginator, {static: false})
searchText
selectedTabIndex
sort
Type : MatSort
Decorators :
@ViewChild(MatSort, {static: false})
workspace$
Type : Observable<Workspace>
workspaceId
Type : string
workspaceResources
Type : WorkspaceResource[]
workspaceResourcesDS
import {
  Component,
  OnInit,
  ChangeDetectionStrategy,
  ViewChild
} from '@angular/core';
import { WorkspaceResource } from '@features/workspace-detail/models/workspace-resource';
import { Workspace } from '@workspace-manager/models/workspace';
import { Observable } from 'rxjs';
import { ActivatedRoute } from '@angular/router';
import { MatDialog } from '@angular/material/dialog';
import { WorkspaceDetailService } from '@features/workspace-detail/services/workspace-detail.service';
import { AddDialogComponent } from '../dialogs/add-dialog/add-dialog.component';
import { PreviewDialogComponent } from '../dialogs/preview-dialog/preview-dialog.component';
import { DeleteDialogComponent } from '../dialogs/delete-dialog/delete-dialog.component';
import { EditDialogComponent } from '../dialogs/edit-dialog/edit-dialog/edit-dialog.component';
import { MatTableDataSource } from '@angular/material/table';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';

/**
 * Workspace Detail Component
 *
 * Used to display the list of files/resources included in the current workspace
 * Also contains child components for Metadata, Analyses Flow, Tools and Analyses Result
 */
@Component({
  selector: 'mev-workspace-detail',
  templateUrl: './workspace-detail.component.html',
  styleUrls: ['./workspace-detail.component.scss'],
  changeDetection: ChangeDetectionStrategy.Default
})
export class WorkspaceDetailComponent implements OnInit {
  workspaceResources: WorkspaceResource[];
  workspaceId: string;
  workspace$: Observable<Workspace>;
  searchText;
  selectedTabIndex;
  execOperationId: string;
  isWait = false;

  workspaceResourcesDS;
  displayedColumns: string[] = [
    'name',
    'readable_resource_type',
    'size',
    'created',
    'actions'
  ];
  @ViewChild(MatPaginator, { static: false }) paginator: MatPaginator;
  @ViewChild(MatSort, { static: false }) sort: MatSort;

  constructor(
    private route: ActivatedRoute,
    private service: WorkspaceDetailService,
    public dialog: MatDialog
  ) {}

  ngOnInit(): void {
    this.loadData();
  }

  public loadData() {
    this.workspaceId = this.route.snapshot.paramMap.get('workspaceId');
    this.service.getConnectedResources(this.workspaceId).subscribe(data => {
      this.workspaceResources = data;

      this.workspaceResourcesDS = new MatTableDataSource(data);
      this.workspaceResourcesDS.paginator = this.paginator;
      this.workspaceResourcesDS.sort = this.sort;
    });
    this.workspace$ = this.service.getWorkspaceDetail(this.workspaceId);
  }

  refresh() {
    this.loadData();
  }

  applyFilter(event: Event) {
    const filterValue = (event.target as HTMLInputElement).value;
    this.workspaceResourcesDS.filter = filterValue.trim().toLowerCase();
  }

  selectResource(resource) {
    console.log(`The selected resource is::  ${resource.name}`);
  }

  /**
   * Open a modal dialog to add files to a specific workspace
   *
   */
  addItem() {
    const dialogRef = this.dialog.open(AddDialogComponent, {
      data: { workspaceId: this.workspaceId }
    });

    dialogRef.afterClosed().subscribe(result => {
      if (result === 1) {
        this.refresh();
      }
    });
  }

  /**
   * Open a modal dialog to preview workspace resource content
   *
   */
  previewItem(resourceId) {
    this.isWait = true;
    this.service.getResourcePreview(resourceId).subscribe(data => {
      const previewData = {};
      if (data?.results?.length && 'rowname' in data.results[0]) {
        const minN = Math.min(data.results.length, 10);
        let slicedData = data.results.slice(0, minN);
        const columns = Object.keys(slicedData[0].values);
        const rows = slicedData.map(elem => elem.rowname);
        const values = slicedData.map(elem => {
          let rowValues = [];
          const elemValues = elem.values;
          columns.forEach(col => rowValues.push(elemValues[col]));
          return rowValues;
        });
        previewData['columns'] = columns;
        previewData['rows'] = rows;
        previewData['values'] = values;
      }
      setTimeout(() => {
        this.isWait = false;
        this.dialog.open(PreviewDialogComponent, {
          data: {
            previewData: previewData
          }
        });
      }, 1000); // time-out for spinner
    });
  }

  /**
   * Open a modal dialog to edit workspace resource
   * Users can re-name resources
   */
  editItem(resource) {
    const dialogRef = this.dialog.open(EditDialogComponent, {
      data: {
        id: resource.id,
        name: resource.name,
        resource_type: resource.resource_type
      }
    });

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

  /**
   * Open a modal dialog to delete a workspace resource from the current workspace
   *
   */
  deleteItem(resource) {
    const dialogRef = this.dialog.open(DeleteDialogComponent, {
      data: { workspaceId: this.workspaceId, resource: resource }
    });

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

  /**
   * Switch to Analyses tab when the user clicks the Run button  on the Tools tab
   *
   */
  goToAnalysesTab() {
    this.selectedTabIndex = 4;
  }

  /**
   * Refresh data when user switching between tabs
   *
   */
  onTabChanged($event) {
    const clickedIndex = $event.index;
    if (clickedIndex === 0) {
      this.refresh();
    }
  }

  /**
   * Method is triggered when the user clicks on a executed operation on the Analyses Flow Tab
   *
   */
  public showExecutedOperationResult(executedOperationId: string) {
    this.execOperationId = executedOperationId;
    this.goToAnalysesTab();
  }
}
<mev-spinner-overlay *ngIf="isWait"></mev-spinner-overlay>

<div class="workspace-header">
  <a routerLink='/workarea' class="workspace-header__nav nav">
    <mat-icon class="nav__icon" aria-label="Next step">reply</mat-icon>
    <span class="nav__text">Back to File & Workspace list</span>
  </a>
  <span class="workspace-header__title" *ngIf="workspace$ | async as workspace">
    Workspace
    <b> {{ workspace.workspace_name }} </b>
    <mat-icon class="workspace-header__icon" matTooltipClass="tooltip" fontSet="material-icons-outlined" matTooltip="Workspace: {{ workspace.workspace_name }} &#13;
                          Created: {{ workspace.created }} &#13;
                          Owner: {{ workspace.owner_email }}" aria-label="Info tooltip about the workspace">info
    </mat-icon>
  </span>
</div>


<mat-tab-group animationDuration="0ms" color="accent" [(selectedIndex)]="selectedTabIndex"
  (selectedTabChange)="onTabChanged($event);">
  <mat-tab label="Resources">
    <ng-template matTabContent>
      <div *ngIf="!workspaceResources?.length" class="instruction">
        To perform analyses, you need to add or import data into the workspace. Select
        from among the files you uploaded or import public data (if available)
      </div>
      <mat-toolbar>
        <mat-form-field floatLabel='never' class='search-field'>
          <input matInput [(ngModel)]="searchText" (keyup)="applyFilter($event)"  autocomplete="off">
          <mat-placeholder class="placeholder">Search</mat-placeholder>
        </mat-form-field>
      </mat-toolbar>

      <div class="btn-panel">
        <div class="btn-group">
          <button mat-raised-button color="accent" (click)="addItem()">
            <mat-icon aria-label="Add local data">add</mat-icon>
            Add local data
          </button>
  
          <button mat-raised-button color="accent" (click)="addItem()">
            <mat-icon aria-label="Add external data">add</mat-icon>
            Add external data
          </button>
        </div>
       

        <mat-button-toggle-group #viewMode="matButtonToggleGroup" value="tableMode">
          <mat-button-toggle value="tableMode" aria-label="Text align left">
            Table view
          </mat-button-toggle>
          <mat-button-toggle value="cardMode" aria-label="Text align center">
            Card view
          </mat-button-toggle>
        </mat-button-toggle-group>
      </div>


      


      <div *ngIf="viewMode.value === 'cardMode'"  class="cardList">
        <a *ngFor="let resource of workspaceResources | filter : searchText" (click)="selectResource(resource);"
          class="cardList__item card" matRipple matRippleColor="rgba(158, 158, 158, 0.22)">
          <mat-card>
            <mat-card-title class="card-title">
              {{ resource.name }}
            </mat-card-title>
            <mat-card-content>
              <ul>
                <li>Resource type: {{ resource.readable_resource_type }}</li>
                <li>Size: {{ resource.size | byteName}}</li>
                <li>Date added: {{ resource.created | date :'medium' }}</li>
              </ul>

            </mat-card-content>
            <mat-card-footer>
              <mat-icon fontSet="material-icons-outlined" title="Edit resource" (click)="editItem(resource)">
                edit</mat-icon>
              <mat-icon fontSet="material-icons-outlined" title="Preview resource" (click)="previewItem(resource.id)">
                search</mat-icon>
              <mat-icon fontSet="material-icons-outlined" title="Delete resource" (click)="deleteItem(resource)">delete
              </mat-icon>
            </mat-card-footer>
          </mat-card>
        </a>
      </div>
      <div *ngIf="viewMode.value === 'tableMode'" class="resource-table-container mat-elevation-z8">
        <table mat-table [dataSource]="workspaceResourcesDS" matSort matSortActive="date" matSortDirection="desc">
       
        <ng-container matColumnDef="name">
          <th mat-header-cell *matHeaderCellDef mat-sort-header> Resource name </th>
          <td mat-cell *matCellDef="let resource">
            {{ resource.name }}
          </td>
        </ng-container>

        <ng-container matColumnDef="readable_resource_type">
          <th mat-header-cell *matHeaderCellDef mat-sort-header> Resource type </th>
          <td mat-cell *matCellDef="let resource">
            {{ resource.readable_resource_type }}
          </td>
        </ng-container>

        <ng-container matColumnDef="size">
          <th mat-header-cell *matHeaderCellDef mat-sort-header> Size </th>
          <td mat-cell *matCellDef="let resource"> {{ resource.size | byteName }} </td>
        </ng-container>

        <ng-container matColumnDef="created">
          <th mat-header-cell *matHeaderCellDef mat-sort-header> Creation date </th>
          <td mat-cell *matCellDef="let resource"> {{ resource.created | date :'medium' }} </td>
        </ng-container>

        <ng-container matColumnDef="actions">
          <th mat-header-cell *matHeaderCellDef>Actions</th>
          <td mat-cell *matCellDef="let resource">
            <button mat-icon-button color="accent" title="Preview" (click)="previewItem(resource.id)">
              <mat-icon aria-label="View">visibility</mat-icon>
            </button>
            <button mat-icon-button color="accent" title="Delete" (click)="deleteItem(resource)">
              <mat-icon aria-label="Delete">delete</mat-icon>
            </button>
            <button mat-icon-button color="accent" title="Edit" (click)="editItem(resource)">
              <mat-icon aria-label="Edit">edit</mat-icon>
            </button>
          </td>
        </ng-container>

        <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
        <tr mat-row *matRowDef="let row; columns: displayedColumns;">

      </table>
      <mat-paginator #paginator [pageSizeOptions]="[5, 10, 25]" [pageIndex]="0" [pageSize]="10">
      </mat-paginator>
    </div>
    </ng-template>
  </mat-tab>

  <mat-tab label="Metadata">
    <ng-template matTabContent>
      <mev-metadata *ngIf='workspaceResources' [workspaceResources]="workspaceResources"></mev-metadata>
    </ng-template>
  </mat-tab>

  <mat-tab label="Analysis Flow">
    <ng-template matTabContent>
      <mev-analysis-flow (executedOperationId)="showExecutedOperationResult($event)"></mev-analysis-flow>
    </ng-template>
  </mat-tab>

  <mat-tab label="Tools">
    <ng-template matTabContent>
      <mev-analyses (executedOperationId)="showExecutedOperationResult($event)"></mev-analyses>
    </ng-template>
  </mat-tab>

  <mat-tab label="Analyses Result">
    <ng-template matTabContent>
      <mev-executed-operation [execOperationId]="execOperationId"></mev-executed-operation>
    </ng-template>
  </mat-tab>

</mat-tab-group>

./workspace-detail.component.scss

.workspace-header {
  display: flex;
  justify-content: flex-start;
  padding: 10px;
}
.workspace-header__nav {
  color: #03a9f4;
  font-size: 14px;

  .nav__icon {
    vertical-align: bottom;
  }
}
.workspace-header__title {
  position: relative;
  margin: auto;
  left: -100px;
}

.workspace-header__icon {
  vertical-align: top;
}

.instruction {
  font-size: 14px;
  padding: 16px;
}

.mat-toolbar {
  background-color: transparent;
}

.search-field {
  min-width: 250px;
}

.search-field .placeholder {
  font-size: 12px;
  color: #666666;
}

.btn-panel {
  display: flex;
  justify-content: space-between;
  padding: 16px;
}

button {
  margin-right: 10px;
}

::ng-deep {
  .tooltip {
    white-space: pre-line !important;
  }

  .mat-button-toggle-group {
    font-size: 14px;
  }

  .mat-button-toggle-label-content {
    line-height: 36px !important;
  }

  .mat-button-toggle-checked {
    background-color: #c8ebfa !important;
  }
}

.resource-table-container {
  margin: 15px;

  table {
    width: 100%;
  }

  .mat-header-cell {
    background: #eeeeee;
  }

  .mat-column-name {
    padding-right: 5px;
    word-wrap: break-word !important;
    white-space: unset !important;
    flex: 0 0 40% !important;
    width: 40% !important;
    overflow-wrap: break-word;
    word-wrap: break-word;
    word-break: break-word;
    -ms-hyphens: auto;
    -moz-hyphens: auto;
    -webkit-hyphens: auto;
    hyphens: auto;
  }
}

.cardList {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: flex-start;
}

.cardList > * {
  box-sizing: border-box;
}

.cardList__item {
  margin: 15px;
  flex: 0 1 calc(33.3% - 32px);
}

@media screen and (max-width: 959px) {
  .cardListItem {
    flex: 0 1 calc(50% - 32px);
  }
}

@media screen and (max-width: 599px) {
  .cardList {
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
  }
}

.card-title {
  word-wrap: break-word;
}

.mat-card-footer {
  padding: 7px;
  text-align: right;

  .mat-icon {
    margin-right: 10px;
    cursor: pointer;

    &:hover {
      color: #666;
    }
  }
}

.workspace-footer {
  float: right;
  padding: 20px;
}
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""