File

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

Implements

OnInit

Metadata

selector mev-workspace-list
styleUrls ./workspace-list.component.scss
templateUrl ./workspace-list.component.html

Index

Properties
Methods

Constructor

constructor(httpClient: HttpClient, dialog: MatDialog, workspaceService: WorkspaceService, adapter: WorkspaceAdapter)
Parameters :
Name Type Optional
httpClient HttpClient No
dialog MatDialog No
workspaceService WorkspaceService No
adapter WorkspaceAdapter No

Methods

addItem
addItem()
Returns : void
deleteItem
deleteItem(i: number, id: string, workspace_name: string)
Parameters :
Name Type Optional
i number No
id string No
workspace_name string No
Returns : void
editItem
editItem(i: number, id: string, workspace_name: string)
Parameters :
Name Type Optional
i number No
id string No
workspace_name string No
Returns : void
Public loadData
loadData()
Returns : void
ngOnInit
ngOnInit()
Returns : void
refresh
refresh()
Returns : void

Properties

dataSource
Type : ExampleDataSource | null
Public dialog
Type : MatDialog
displayedColumns
Type : []
Default value : [ 'workspace_name', 'created', 'accessed', 'file_number', 'actions' ]
exampleDatabase
Type : WorkspaceService | null
filter
Type : ElementRef
Decorators :
@ViewChild('filter', {static: true})
Public httpClient
Type : HttpClient
id
Type : string
paginator
Type : MatPaginator
Decorators :
@ViewChild(MatPaginator, {static: true})
sort
Type : MatSort
Decorators :
@ViewChild(MatSort, {static: true})
Public workspaceService
Type : WorkspaceService
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { DataSource } from '@angular/cdk/collections';
import { BehaviorSubject, fromEvent, merge, Observable } from 'rxjs';
import { map, debounceTime, distinctUntilChanged } from 'rxjs/operators';
import { MatDialog } from '@angular/material/dialog';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';

import { WorkspaceService } from '@workspace-manager/services/workspace.service';
import {
  Workspace,
  WorkspaceAdapter
} from '@workspace-manager/models/workspace';
import { AddWSDialogComponent } from '@app/features/workspace-manager/components/dialogs/add-ws-dialog/add-ws-dialog.component';
import { EditWSDialogComponent } from '@app/features/workspace-manager/components/dialogs/edit-ws-dialog/edit-ws-dialog.component';
import { DeleteWSDialogComponent } from '@app/features/workspace-manager/components/dialogs/delete-ws-dialog/delete-ws-dialog.component';

@Component({
  selector: 'mev-workspace-list',
  templateUrl: './workspace-list.component.html',
  styleUrls: ['./workspace-list.component.scss']
})
export class WorkspaceListComponent implements OnInit {
  displayedColumns = [
    'workspace_name',
    'created',
    'accessed',
    'file_number',
    'actions'
  ];
  exampleDatabase: WorkspaceService | null;
  dataSource: ExampleDataSource | null;
  id: string;

  constructor(
    public httpClient: HttpClient,
    public dialog: MatDialog,
    public workspaceService: WorkspaceService,
    private adapter: WorkspaceAdapter
  ) {}

  @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
  @ViewChild(MatSort, { static: true }) sort: MatSort;
  @ViewChild('filter', { static: true }) filter: ElementRef;

  ngOnInit() {
    this.loadData();
  }

  refresh() {
    this.loadData();
  }

  addItem() {
    const dialogRef = this.dialog.open(AddWSDialogComponent, {
      data: { workspace: Workspace }
    });

    dialogRef.afterClosed().subscribe(result => {
      if (result === 1) {
        // After dialog is closed we're doing frontend updates
        // For add we're just pushing a new row inside WorkspaceService
        this.exampleDatabase.dataChange.value.push(
          this.workspaceService.getDialogData()
        );
        this.refresh();
      }
    });
  }

  editItem(i: number, id: string, workspace_name: string) {
    this.id = id;
    const dialogRef = this.dialog.open(EditWSDialogComponent, {
      data: { id: id, workspace_name: workspace_name }
    });

    dialogRef.afterClosed().subscribe(result => {
      if (result === 1) {
        // When using an edit things are little different, firstly we find record inside WorkspaceService by id
        const foundIndex = this.exampleDatabase.dataChange.value.findIndex(
          x => x.id === this.id
        );
        // Then you update that record using data from dialogData (values you entered)
        this.exampleDatabase.dataChange.value[
          foundIndex
        ] = this.workspaceService.getDialogData();
        // And lastly refresh table

        this.refresh();
      }
    });
  }

  deleteItem(i: number, id: string, workspace_name: string) {
    this.id = id;
    const dialogRef = this.dialog.open(DeleteWSDialogComponent, {
      data: { id: id, workspace_name: workspace_name }
    });

    dialogRef.afterClosed().subscribe(result => {
      if (result === 1) {
        const foundIndex = this.exampleDatabase.dataChange.value.findIndex(
          x => x.id === this.id
        );
        // for delete we use splice in order to remove single object from WorkspaceService
        this.exampleDatabase.dataChange.value.splice(foundIndex, 1);
        this.refresh();
      }
    });
  }

  public loadData() {
    this.exampleDatabase = new WorkspaceService(this.httpClient, this.adapter);
    this.dataSource = new ExampleDataSource(
      this.exampleDatabase,
      this.paginator,
      this.sort
    );
    fromEvent(this.filter.nativeElement, 'keyup')
      .pipe(debounceTime(150), distinctUntilChanged())
      .subscribe(() => {
        if (!this.dataSource) {
          return;
        }
        this.dataSource.filter = this.filter.nativeElement.value;
      });
  }
}

export class ExampleDataSource extends DataSource<Workspace> {
  _filterChange = new BehaviorSubject('');

  get filter(): string {
    return this._filterChange.value;
  }

  set filter(filter: string) {
    this._filterChange.next(filter);
  }

  filteredData: Workspace[] = [];
  renderedData: Workspace[] = [];

  constructor(
    public _exampleDatabase: WorkspaceService,
    public _paginator: MatPaginator,
    public _sort: MatSort
  ) {
    super();
    // Reset to the first page when the user changes the filter.
    this._filterChange.subscribe(() => (this._paginator.pageIndex = 0));
  }

  /** Connect function called by the table to retrieve one stream containing the data to render. */
  connect(): Observable<Workspace[]> {
    // Listen for any changes in the base data, sorting, filtering, or pagination
    const displayDataChanges = [
      this._exampleDatabase.dataChange,
      this._sort.sortChange,
      this._filterChange,
      this._paginator.page
    ];

    this._exampleDatabase.getAllWorkspaces();

    return merge(...displayDataChanges).pipe(
      map(() => {
        // Filter data
        this.filteredData = this._exampleDatabase.data
          .slice()
          .filter((workspace: Workspace) => {
            const searchStr = (
              workspace.id + workspace.workspace_name
            ).toLowerCase();
            return searchStr.indexOf(this.filter.toLowerCase()) !== -1;
          });

        // Sort filtered data
        const sortedData = this.sortData(this.filteredData.slice());

        // Grab the page's slice of the filtered sorted data.
        const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
        this.renderedData = sortedData.splice(
          startIndex,
          this._paginator.pageSize
        );
        return this.renderedData;
      })
    );
  }

  disconnect() {}

  /** Returns a sorted copy of the database data. */
  sortData(data: Workspace[]): Workspace[] {
    if (!this._sort.active || this._sort.direction === '') {
      return data;
    }

    return data.sort((a, b) => {
      let propertyA: number | string | Date = '';
      let propertyB: number | string | Date = '';

      switch (this._sort.active) {
        case 'id':
          [propertyA, propertyB] = [a.id, b.id];
          break;
        case 'workspace_name':
          [propertyA, propertyB] = [a.workspace_name, b.workspace_name];
          break;
        case 'url':
          [propertyA, propertyB] = [a.url, b.url];
          break;
        case 'created':
          [propertyA, propertyB] = [a.created, b.created];
          break;
      }

      const valueA = isNaN(+propertyA) ? propertyA : +propertyA;
      const valueB = isNaN(+propertyB) ? propertyB : +propertyB;

      return (
        (valueA < valueB ? -1 : 1) * (this._sort.direction === 'asc' ? 1 : -1)
      );
    });
  }
}
<div class="instruction">
  To keep your different projects separate, we require that all your analyses are run in the
  context of a ‘workspace.’ Navigate to your workspaces below, or create a new one to get
  started.
</div>

<div class="workspace-btn-group">
  <button mat-raised-button color="accent" (click)="addItem()">
    <mat-icon aria-label="Create a workspace">add</mat-icon> Create a workspace
  </button>
  <button mat-raised-button color="accent" (click)="refresh()">
    <mat-icon aria-label="Refresh">refresh</mat-icon> Refresh
  </button>
</div>


<div class="workspace-list-container">

  <div class="form">
    <mat-form-field floatPlaceholder="never" color="accent">
      <input matInput #filter placeholder="Filter workspaces">
    </mat-form-field>
  </div>

  <mat-table #table [dataSource]="dataSource" matSort matSortActive="accessed" matSortDirection="desc" class="mat-cell">

    <ng-container matColumnDef="id">
      <mat-header-cell *matHeaderCellDef mat-sort-header>Id</mat-header-cell>
      <mat-cell *matCellDef="let row">{{ row.id }}</mat-cell>
    </ng-container>

    <ng-container matColumnDef="workspace_name">
      <mat-header-cell *matHeaderCellDef mat-sort-header class="workspace-table-header">Workspace name</mat-header-cell>
      <mat-cell *matCellDef="let row">
        <a [routerLink]="['/workspace', row.id]">
          {{ row.workspace_name }}
        </a>
      </mat-cell>

    </ng-container>

    <ng-container matColumnDef="created">
      <mat-header-cell *matHeaderCellDef mat-sort-header class="workspace-table-header">Created date</mat-header-cell>
      <mat-cell *matCellDef="let row"> {{ row.created | date :'medium' }}</mat-cell>
    </ng-container>

    <ng-container matColumnDef="accessed">
      <mat-header-cell *matHeaderCellDef mat-sort-header class="workspace-table-header">Last accessed date
      </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{ row.accessed | date :'medium' }}</mat-cell>
    </ng-container>

    <ng-container matColumnDef="file_number">
      <mat-header-cell *matHeaderCellDef mat-sort-header class="workspace-table-header">Number of files
      </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{ row.file_number }}</mat-cell>
    </ng-container>


    <!-- actions -->
    <ng-container matColumnDef="actions">
      <mat-header-cell *matHeaderCellDef class="workspace-table-header">Actions</mat-header-cell>

      <mat-cell *matCellDef="let row; let i=index;">
        <button mat-icon-button color="accent" title="Edit workspace" (click)="editItem(i, row.id, row.workspace_name)">
          <mat-icon aria-label="Edit">edit</mat-icon>
        </button>

        <button mat-icon-button color="accent" title="Delete workspace"
          (click)="deleteItem(i, row.id, row.workspace_name)">
          <mat-icon aria-label="Delete">delete</mat-icon>
        </button>

        <button mat-icon-button color="accent" title="Go to workspace" [routerLink]="['/workspace', row.id]">
          <mat-icon aria-label="Go to workspace">launch</mat-icon>
        </button>

      </mat-cell>
    </ng-container>

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


  <div class="no-results" [style.display]="dataSource.renderedData.length == 0 ? '' : 'none'">
    No results are available
  </div>

  <mat-paginator #paginator [length]="dataSource.filteredData.length" [pageIndex]="0" [pageSize]="10"
    [pageSizeOptions]="[10, 25, 100]">
  </mat-paginator>
</div>

./workspace-list.component.scss

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

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

.workspace-btn-group {
  display: flex;
  justify-content: space-between;
  padding-top: 20px;
}

.mat-cell a {
  color: #03a9f4;
  text-decoration: underline;
}

.no-results {
  font-family: Roboto, 'Helvetica Neue', sans-serif;
  font-size: 12px;
}
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""