basic account management (Login/Logout)
This commit is contained in:
		@@ -4,19 +4,21 @@
 | 
			
		||||
    <a routerLink="/samples" routerLinkActive="active" rbLoadingLink *ngIf="loginService.isLoggedIn">Samples</a>
 | 
			
		||||
  </nav>
 | 
			
		||||
 | 
			
		||||
  <nav *rbActionNavItems>
 | 
			
		||||
    <a href="javascript:"  [rbPopover]="userPopover" [anchor]="popoverAnchor">
 | 
			
		||||
      Account <span class="rb-ic rb-ic-my-brand-frame" #popoverAnchor></span></a>
 | 
			
		||||
  </nav>
 | 
			
		||||
  <ng-template #userPopover>
 | 
			
		||||
    <div class="spacing">
 | 
			
		||||
      <p>
 | 
			
		||||
        Some user specific information
 | 
			
		||||
      </p>
 | 
			
		||||
  <ng-container *ngIf="loginService.isLoggedIn">
 | 
			
		||||
    <nav *rbActionNavItems>
 | 
			
		||||
      <a href="javascript:"  [rbPopover]="userPopover" [anchor]="popoverAnchor">
 | 
			
		||||
        {{loginService.username}} <span class="rb-ic rb-ic-my-brand-frame" #popoverAnchor></span></a>
 | 
			
		||||
    </nav>
 | 
			
		||||
    <ng-template #userPopover>
 | 
			
		||||
      <div class="spacing">
 | 
			
		||||
        <p>
 | 
			
		||||
<!--          Some user specific information-->
 | 
			
		||||
        </p>
 | 
			
		||||
 | 
			
		||||
      <a href="javascript:" class="rb-btn rb-primary">Logout</a>
 | 
			
		||||
    </div>
 | 
			
		||||
  </ng-template>
 | 
			
		||||
        <button type="button" class="rb-btn rb-primary" (click)="logout()">Logout</button>
 | 
			
		||||
      </div>
 | 
			
		||||
    </ng-template>
 | 
			
		||||
  </ng-container>
 | 
			
		||||
 | 
			
		||||
  <div *rbSubBrandHeader><span class="dev-label" *ngIf="devMode">DEVELOPMENT</span>Digital Fingerprint of Plastics</div>
 | 
			
		||||
</rb-full-header>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
import { Component, isDevMode} from '@angular/core';
 | 
			
		||||
import {LoginService} from './services/login.service';
 | 
			
		||||
import {Router} from '@angular/router';
 | 
			
		||||
 | 
			
		||||
// TODO: add multiple samples at once
 | 
			
		||||
// TODO: guess properties from material name
 | 
			
		||||
@@ -16,11 +17,17 @@ import {LoginService} from './services/login.service';
 | 
			
		||||
export class AppComponent {
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    public loginService: LoginService
 | 
			
		||||
    public loginService: LoginService,
 | 
			
		||||
    private router: Router
 | 
			
		||||
  ) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get devMode() {
 | 
			
		||||
    return isDevMode();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  logout() {
 | 
			
		||||
    this.loginService.logout();
 | 
			
		||||
    this.router.navigate(['/']);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
import { BrowserModule } from '@angular/platform-browser';
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { ChartsModule } from 'ng2-charts';
 | 
			
		||||
 | 
			
		||||
import { AppRoutingModule } from './app-routing.module';
 | 
			
		||||
import { AppComponent } from './app.component';
 | 
			
		||||
@@ -16,6 +17,7 @@ import { ValidateDirective } from './validate.directive';
 | 
			
		||||
import {CommonModule} from '@angular/common';
 | 
			
		||||
import { ErrorComponent } from './error/error.component';
 | 
			
		||||
import { ObjectPipe } from './object.pipe';
 | 
			
		||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  declarations: [
 | 
			
		||||
@@ -34,6 +36,7 @@ import { ObjectPipe } from './object.pipe';
 | 
			
		||||
      storageType: 'localStorage'
 | 
			
		||||
    }),
 | 
			
		||||
    BrowserModule,
 | 
			
		||||
    BrowserAnimationsModule,
 | 
			
		||||
    AppRoutingModule,
 | 
			
		||||
    RbUiComponentsModule,
 | 
			
		||||
    FormsModule,
 | 
			
		||||
@@ -41,7 +44,8 @@ import { ObjectPipe } from './object.pipe';
 | 
			
		||||
    RbTableModule,
 | 
			
		||||
    ReactiveFormsModule,
 | 
			
		||||
    FormFieldsModule,
 | 
			
		||||
    CommonModule
 | 
			
		||||
    CommonModule,
 | 
			
		||||
    ChartsModule
 | 
			
		||||
  ],
 | 
			
		||||
  providers: [
 | 
			
		||||
    ModalService
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ export class LoginComponent implements OnInit {
 | 
			
		||||
  login() {
 | 
			
		||||
    this.loginService.login(this.username, this.password).then(ok => {
 | 
			
		||||
      if (ok) {
 | 
			
		||||
        this.message = 'Login successful';  // TODO: think about following action
 | 
			
		||||
        this.message = 'Login successful';
 | 
			
		||||
        this.router.navigate(['/samples']);
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
 
 | 
			
		||||
@@ -6,14 +6,14 @@
 | 
			
		||||
<!--<form #sampleForm="ngForm">-->
 | 
			
		||||
  <div class="sample">
 | 
			
		||||
    <div>
 | 
			
		||||
      <rb-form-input name="materialname" label="material name" [rbFormInputAutocomplete]="autocomplete.bind(this, materialNames)" [rbDebounceTime]="0" [rbInitialOpen]="true" (keydown)="preventSubmit($event)" (ngModelChange)="findMaterial($event)" appValidate="stringOf" [appValidateArgs]="[materialNames]" required [(ngModel)]="material.name" [autofocus]="true" #materialNameInput="ngModel">
 | 
			
		||||
      <rb-form-input name="materialname" label="material name" [rbFormInputAutocomplete]="autocomplete.bind(this, materialNames)" [rbDebounceTime]="0" [rbInitialOpen]="true" (keydown)="preventDefault($event)" (ngModelChange)="findMaterial($event)" appValidate="stringOf" [appValidateArgs]="[materialNames]" required [(ngModel)]="material.name" [autofocus]="true" #materialNameInput="ngModel">
 | 
			
		||||
        <ng-template rbFormValidationMessage="required">Cannot be empty</ng-template>
 | 
			
		||||
        <ng-template rbFormValidationMessage="failure">Unknown material, add properties for new material</ng-template>
 | 
			
		||||
      </rb-form-input>
 | 
			
		||||
      <button class="rb-btn rb-secondary" type="button" (click)="setNewMaterial(true)"><span class="rb-ic rb-ic-add"></span> New material</button>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="material shaded-container" *ngIf="newMaterial">
 | 
			
		||||
    <div class="material shaded-container" *ngIf="newMaterial" [@inOut]>
 | 
			
		||||
      <h4>Material properties</h4>
 | 
			
		||||
      <rb-form-input name="supplier" label="supplier" [rbFormInputAutocomplete]="autocomplete.bind(this, suppliers)" [rbDebounceTime]="0" [rbInitialOpen]="true" appValidate="string" required [(ngModel)]="material.supplier" #supplierInput="ngModel">
 | 
			
		||||
        <ng-template rbFormValidationMessage="failure">{{supplierInput.errors.failure}}</ng-template>
 | 
			
		||||
@@ -38,7 +38,7 @@
 | 
			
		||||
      </rb-form-input>
 | 
			
		||||
 | 
			
		||||
      <div class="material-numbers">
 | 
			
		||||
        <div *ngFor="let number of material.numbers; index as i" class="two-col">
 | 
			
		||||
        <div *ngFor="let number of material.numbers; index as i" class="two-col" [@inOut]>
 | 
			
		||||
          <rb-form-input label="color" appValidate="string" [required]="i < material.numbers.length - 1" (keyup)="handleMaterialNumbers()" [(ngModel)]="number.color" ngModel [ngModelOptions]="{standalone: true}">
 | 
			
		||||
          </rb-form-input>
 | 
			
		||||
          <rb-form-input label="material number" appValidate="string" [(ngModel)]="number.number" ngModel [ngModelOptions]="{standalone: true}">
 | 
			
		||||
@@ -69,7 +69,7 @@
 | 
			
		||||
      <ng-template rbFormValidationMessage="failure">{{commentInput.errors.failure}}</ng-template>
 | 
			
		||||
    </rb-form-input>
 | 
			
		||||
    <h5>Additional properties</h5>
 | 
			
		||||
    <div *ngFor="let field of customFields; index as i" class="two-col">
 | 
			
		||||
    <div *ngFor="let field of customFields; index as i" class="two-col" [@inOut]>
 | 
			
		||||
      <div>
 | 
			
		||||
        <rb-form-input [name]="'cf-key' + i" label="key" [rbFormInputAutocomplete]="autocomplete.bind(this, availableCustomFields)" [rbDebounceTime]="0" [rbInitialOpen]="true" appValidate="unique" [appValidateArgs]="[uniqueCfValues(i)]" (ngModelChange)="adjustCustomFields($event, i)" [ngModel]="field[0]" #keyInput="ngModel">
 | 
			
		||||
          <ng-template rbFormValidationMessage="failure">{{keyInput.errors.failure}}</ng-template>
 | 
			
		||||
@@ -89,7 +89,7 @@
 | 
			
		||||
      Condition
 | 
			
		||||
      <button class="rb-btn rb-secondary condition-set" type="button" (click)="toggleCondition()" [disabled]="!conditionTemplates">{{condition ? 'Do not set condition' : 'Set condition'}}</button>
 | 
			
		||||
    </h4>
 | 
			
		||||
    <div *ngIf="condition">
 | 
			
		||||
    <div *ngIf="condition" [@inOut]>
 | 
			
		||||
      <rb-form-select name="conditionSelect" label="Condition" (ngModelChange)="selectCondition($event)" [ngModel]="condition._id">
 | 
			
		||||
        <option *ngFor="let c of conditionTemplates" [value]="c._id">{{c.name}}</option>
 | 
			
		||||
      </rb-form-select>
 | 
			
		||||
@@ -105,8 +105,8 @@
 | 
			
		||||
 | 
			
		||||
  <div class="measurements shaded-container">
 | 
			
		||||
    <h4>Measurements</h4>
 | 
			
		||||
    <div *ngFor="let measurement of sample.measurements; index as mIndex">
 | 
			
		||||
      <rb-form-select name="measurementTemplateSelect" label="Template" [(ngModel)]="measurement.measurement_template">
 | 
			
		||||
    <div *ngFor="let measurement of sample.measurements; index as mIndex" [@inOut]>
 | 
			
		||||
      <rb-form-select name="measurementTemplateSelect" label="Template" [(ngModel)]="measurement.measurement_template" (ngModelChange)="clearChart(mIndex)">
 | 
			
		||||
        <option *ngFor="let m of measurementTemplates" [value]="m._id">{{m.name}}</option>
 | 
			
		||||
      </rb-form-select>
 | 
			
		||||
 | 
			
		||||
@@ -115,9 +115,16 @@
 | 
			
		||||
          <ng-template rbFormValidationMessage="failure">{{parameterInput.errors.failure}}</ng-template>
 | 
			
		||||
          <ng-template rbFormValidationMessage="required">Cannot be empty</ng-template>
 | 
			
		||||
        </rb-form-input>
 | 
			
		||||
        <rb-form-file *ngIf="parameter.range.type" [name]="'measurementParameter' + mIndex + '-' + pIndex" [label]="parameter.name" maxSize="10000000" (change)="fileToArray($event, mIndex, parameter.name)" required ngModel>
 | 
			
		||||
        <rb-form-file *ngIf="parameter.range.type" [name]="'measurementParameter' + mIndex + '-' + pIndex" [label]="parameter.name" maxSize="10000000" (ngModelChange)="fileToArray($event, mIndex, parameter.name)" placeholder="Select file or drag and drop" dragDrop required ngModel>
 | 
			
		||||
          <ng-template rbFormValidationMessage="required">Cannot be empty</ng-template>
 | 
			
		||||
        </rb-form-file>
 | 
			
		||||
        <canvas baseChart *ngIf="parameter.range.type && charts[mIndex][0].data.length > 0"  class="dpt-chart" [@inOut]
 | 
			
		||||
                [datasets]="charts[mIndex]"
 | 
			
		||||
                [labels]="[]"
 | 
			
		||||
                [options]="chartOptions"
 | 
			
		||||
                [legend]="false"
 | 
			
		||||
                chartType="scatter">
 | 
			
		||||
        </canvas>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <button class="rb-btn rb-danger" type="button" (click)="removeMeasurement(mIndex)"><span class="rb-ic rb-ic-delete"></span> Delete measurement</button>
 | 
			
		||||
@@ -130,7 +137,6 @@
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
   
 | 
			
		||||
 | 
			
		||||
  <div>
 | 
			
		||||
    <button class="rb-btn rb-primary" type="submit" (click)="saveSample()" [disabled]="!sampleForm.form.valid">Save sample</button>
 | 
			
		||||
 
 | 
			
		||||
@@ -15,3 +15,7 @@ td:first-child {
 | 
			
		||||
  grid-template-columns: 1fr 1fr;
 | 
			
		||||
  grid-column-gap: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dpt-chart {
 | 
			
		||||
  max-width: 400px;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,20 +14,35 @@ import {NgForm, Validators} from '@angular/forms';
 | 
			
		||||
import {ValidationService} from '../services/validation.service';
 | 
			
		||||
import {TemplateModel} from '../models/template.model';
 | 
			
		||||
import {MeasurementModel} from '../models/measurement.model';
 | 
			
		||||
import { ChartOptions } from 'chart.js';
 | 
			
		||||
import {animate, style, transition, trigger} from '@angular/animations';
 | 
			
		||||
 | 
			
		||||
// TODO: tests
 | 
			
		||||
// TODO: confirmation for new group/supplier
 | 
			
		||||
// TODO: DPT preview
 | 
			
		||||
// TODO: work on better recognition for file input
 | 
			
		||||
// TODO: only show condition (if not set) and measurements in edit sample dialog at first
 | 
			
		||||
// TODO: multiple spectra, drag and drop
 | 
			
		||||
// TODO: multiple spectra
 | 
			
		||||
// TODO: multiple samples for base data, extend multiple measurements, conditions
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-sample',
 | 
			
		||||
  templateUrl: './sample.component.html',
 | 
			
		||||
  styleUrls: ['./sample.component.scss']
 | 
			
		||||
  styleUrls: ['./sample.component.scss'],
 | 
			
		||||
  animations: [
 | 
			
		||||
    trigger(
 | 
			
		||||
      'inOut', [
 | 
			
		||||
        transition(':enter', [
 | 
			
		||||
          style({height: 0, opacity: 0}),
 | 
			
		||||
          animate('0.5s ease-out', style({height: '*', opacity: 1}))
 | 
			
		||||
        ]),
 | 
			
		||||
        transition(':leave', [
 | 
			
		||||
          style({height: '*', opacity: 1}),
 | 
			
		||||
          animate('0.5s ease-in', style({height: 0, opacity: 0}))
 | 
			
		||||
        ])
 | 
			
		||||
      ]
 | 
			
		||||
    )
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class SampleComponent implements OnInit, AfterContentChecked {
 | 
			
		||||
 | 
			
		||||
@@ -49,6 +64,27 @@ export class SampleComponent implements OnInit, AfterContentChecked {
 | 
			
		||||
  measurementTemplates: TemplateModel[];
 | 
			
		||||
  loading = 0;  // number of currently loading instances
 | 
			
		||||
  checkFormAfterInit = false;
 | 
			
		||||
  charts = [];  // chart data for spectrums
 | 
			
		||||
  readonly chartInit = [{
 | 
			
		||||
    data: [],
 | 
			
		||||
    label: 'Spectrum',
 | 
			
		||||
    showLine: true,
 | 
			
		||||
    fill: false,
 | 
			
		||||
    pointRadius: 0,
 | 
			
		||||
    borderColor: '#00a8b0',
 | 
			
		||||
    borderWidth: 2
 | 
			
		||||
  }];
 | 
			
		||||
  readonly chartOptions: ChartOptions = {
 | 
			
		||||
    scales: {
 | 
			
		||||
      xAxes: [{ticks: {min: 400, max: 4000, stepSize: 400, reverse: true}}],
 | 
			
		||||
      yAxes: [{ticks: {min: 0, max: 1}}]
 | 
			
		||||
    },
 | 
			
		||||
    responsive: true,
 | 
			
		||||
    tooltips: {enabled: false},
 | 
			
		||||
    hover: {mode: null},
 | 
			
		||||
    maintainAspectRatio: true,
 | 
			
		||||
    plugins: {datalabels: {display: false}}
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private router: Router,
 | 
			
		||||
@@ -90,6 +126,19 @@ export class SampleComponent implements OnInit, AfterContentChecked {
 | 
			
		||||
      this.loading++;
 | 
			
		||||
      this.api.get<SampleModel>('/sample/' + this.route.snapshot.paramMap.get('id'), sData => {
 | 
			
		||||
        this.sample.deserialize(sData);
 | 
			
		||||
        this.charts = [];
 | 
			
		||||
        const spectrumTemplate = this.measurementTemplates.find(e => e.name === 'spectrum')._id;
 | 
			
		||||
        let spectrumCounter = 0;
 | 
			
		||||
        this.sample.measurements.forEach((measurement, i) => {
 | 
			
		||||
          this.charts.push(_.cloneDeep(this.chartInit));
 | 
			
		||||
          if (measurement.measurement_template === spectrumTemplate) {
 | 
			
		||||
            setTimeout(() => {
 | 
			
		||||
              this.generateChart(measurement.values.dpt, i);
 | 
			
		||||
              console.log(this.charts);
 | 
			
		||||
            }, spectrumCounter * 20);
 | 
			
		||||
            spectrumCounter ++;
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
        this.material = sData.material;
 | 
			
		||||
        this.customFields = this.sample.notes.custom_fields && this.sample.notes.custom_fields !== {} ? Object.keys(this.sample.notes.custom_fields).map(e => [e, this.sample.notes.custom_fields[e]]) : [['', '']];
 | 
			
		||||
        if ('condition_template' in this.sample.condition) {
 | 
			
		||||
@@ -225,8 +274,8 @@ export class SampleComponent implements OnInit, AfterContentChecked {
 | 
			
		||||
    this.setNewMaterial();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  preventSubmit(event) {
 | 
			
		||||
    if (event.key === 'Enter') {
 | 
			
		||||
  preventDefault(event) {
 | 
			
		||||
    if (event.key && event.key === 'Enter' || event.type === 'dragover') {
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@@ -285,6 +334,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
 | 
			
		||||
 | 
			
		||||
  addMeasurement() {
 | 
			
		||||
    this.sample.measurements.push(new MeasurementModel(this.measurementTemplates[0]._id));
 | 
			
		||||
    this.charts.push(_.cloneDeep(this.chartInit));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  removeMeasurement(index) {
 | 
			
		||||
@@ -292,14 +342,24 @@ export class SampleComponent implements OnInit, AfterContentChecked {
 | 
			
		||||
      this.api.delete('/measurement/' + this.sample.measurements[index]._id);
 | 
			
		||||
    }
 | 
			
		||||
    this.sample.measurements.splice(index, 1);
 | 
			
		||||
    this.charts.splice(index, 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fileToArray(event, mIndex, parameter) {
 | 
			
		||||
  clearChart(index) {
 | 
			
		||||
    this.charts[index][0].data = [];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fileToArray(files, mIndex, parameter) {
 | 
			
		||||
    const fileReader = new FileReader();
 | 
			
		||||
    fileReader.onload = () => {
 | 
			
		||||
      this.sample.measurements[mIndex].values[parameter] = fileReader.result.toString().split('\r\n').map(e => e.split(','));
 | 
			
		||||
      this.generateChart(this.sample.measurements[mIndex].values[parameter], mIndex);
 | 
			
		||||
    };
 | 
			
		||||
    fileReader.readAsText(event.target.files[0]);
 | 
			
		||||
    fileReader.readAsText(files[0]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  generateChart(spectrum, index) {
 | 
			
		||||
    this.charts[index][0].data = spectrum.map(e => ({x: parseFloat(e[0]), y: parseFloat(e[1])}));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  toggleCondition() {
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,7 @@
 | 
			
		||||
            <option value="in">∈</option>
 | 
			
		||||
            <option value="nin">∉</option>
 | 
			
		||||
          </rb-form-select>
 | 
			
		||||
          <div>
 | 
			
		||||
          <div class="filter-inputs">
 | 
			
		||||
            <ng-container *ngFor="let ignore of [].constructor(filter.values.length); index as i">
 | 
			
		||||
              <rb-form-date-input *ngIf="filter.field === 'added'; else noDate" [name]="'filter-' + filter.field + i" [label]="filter.label" [(ngModel)]="filter.values[i]" (ngModelChange)="updateFilterFields(filter.field)"></rb-form-date-input>
 | 
			
		||||
              <ng-template #noDate>
 | 
			
		||||
@@ -54,11 +54,6 @@
 | 
			
		||||
              </ng-template>
 | 
			
		||||
            </ng-container>
 | 
			
		||||
          </div>
 | 
			
		||||
<!--          <rb-form-date-input *ngIf="filter.field === 'added'; else noDate" [name]="'filter-' + filter.field" [label]="filter.label" [(ngModel)]="filter.values[0]" (ngModelChange)="loadSamples({firstPage: true})"></rb-form-date-input>-->
 | 
			
		||||
<!--          <ng-template #noDate>-->
 | 
			
		||||
<!--            <rb-form-input *ngIf="!filter.autocomplete.length" [name]="'filter-' + filter.field" [label]="filter.label" [(ngModel)]="filter.values[0]" (ngModelChange)="loadSamples({firstPage: true})"></rb-form-input>-->
 | 
			
		||||
<!--            <rb-form-input *ngIf="filter.autocomplete.length" [name]="'filter-' + filter.field" [label]="filter.label" [rbFormInputAutocomplete]="autocomplete.bind(this, filter.autocomplete)" [rbDebounceTime]="0" (keydown)="preventDefault($event, 'Enter')" [(ngModel)]="filter.values[0]" (ngModelChange)="loadSamples({firstPage: true})" ngModel></rb-form-input>-->
 | 
			
		||||
<!--          </ng-template>-->
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
@@ -91,8 +86,6 @@
 | 
			
		||||
    <th *ngFor="let key of activeKeysArray()">
 | 
			
		||||
      <div class="sort-header">
 | 
			
		||||
        <span>{{key.label}}</span>
 | 
			
		||||
<!--        <span class="rb-ic rb-ic-up" [ngClass]="{'sort-active-desc': filters.sort === key.id + '-' + 'desc'}" (click)="setSort(key.id + '-' + 'desc')"></span>-->
 | 
			
		||||
<!--        <span class="rb-ic rb-ic-down" [ngClass]="{'sort-active-asc': filters.sort === key.id + '-' + 'asc'}" (click)="setSort(key.id + '-' + 'asc')"></span>-->
 | 
			
		||||
        <span class="rb-ic rb-ic-up sort-arr-up" (click)="setSort(key.id + '-' + 'desc')"><span *ngIf="filters.sort === key.id + '-' + 'desc'"></span></span>
 | 
			
		||||
        <span class="rb-ic rb-ic-down sort-arr-down" (click)="setSort(key.id + '-' + 'asc')"><span *ngIf="filters.sort === key.id + '-' + 'asc'"></span></span>
 | 
			
		||||
      </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -169,3 +169,8 @@ textarea.linkmodal {
 | 
			
		||||
  min-height: 200px;
 | 
			
		||||
  border: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.filter-inputs > * {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  max-width: 250px;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -42,6 +42,11 @@ export class LoginService implements CanActivate {
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  logout() {
 | 
			
		||||
    this.storage.remove('basicAuth');
 | 
			
		||||
    this.loggedIn = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  canActivate(route: ActivatedRouteSnapshot = null, state: RouterStateSnapshot = null): Observable<boolean> {
 | 
			
		||||
    return new Observable<boolean>(observer => {
 | 
			
		||||
      if (this.loggedIn === undefined) {
 | 
			
		||||
@@ -60,4 +65,8 @@ export class LoginService implements CanActivate {
 | 
			
		||||
  get isLoggedIn() {
 | 
			
		||||
    return this.loggedIn;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get username() {
 | 
			
		||||
    return atob(this.storage.get('basicAuth')).split(':')[0];
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user