All files / src/app/components/multi-select-signals multi-select-signals.component.ts

97.05% Statements 66/68
86.36% Branches 19/22
100% Functions 18/18
96.61% Lines 57/59

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                            83x 12x 12x 12x 12x 12x 12x 12x 12x 12x   12x 12x 12x 12x     12x     12x 12x 12x   12x 23x 23x 12x 11x     1x   12x 1x   12x     11x       12x       12x   12x   1200x 100x 100x 1x     1200x   12x 12x           31x 18x   46x     102x     3701x 46x         400x 13x         19x       59x 59x 59x         70x 139x 139x 139x 93x       139x 139x            
import { Component, EventEmitter, OnInit, OnChanges, Input, Output } from '@angular/core';
import { TwinpadApiService } from '../../services/twinpad-api.service';
import { Signal } from '../../models/signals';
import { MultiSelectModule } from 'primeng/multiselect';
import { FormsModule } from '@angular/forms';
import { Router, ActivatedRoute, Params } from '@angular/router';
 
 
@Component({
  selector: 'app-multi-select-signals',
  imports: [MultiSelectModule, FormsModule],
  templateUrl: './multi-select-signals.component.html',
  styleUrl: './multi-select-signals.component.scss'
})
export class MultiSelectSignalsComponent implements OnInit, OnChanges {
  @Input() selectionLimit: number | null = null;
  @Input() isLive: boolean = true;
  @Input() graphId: string = "";
  @Output() selectionChanged = new EventEmitter<string[]>();
  @Output() finishedLoadingSignals = new EventEmitter<boolean>();
  virtualScrollItemSize: number = 25;
  totalSignals: number = 0;
  isFiltering: boolean = false;
  signalIds: string[] = [];
  signalsById: Map<string, Signal>;
  signalIdsToDisplay: string[] = [];
  signalIdsToPlot: string[] = [];
  loadedFromUrl: boolean = false;
  querySignalId: string = "signal_id";
 
 
  constructor(private twinpadApiService: TwinpadApiService, private router: Router, private route: ActivatedRoute) { }
 
  ngOnInit(): void {
    this.signalIds = [];
    this.signalsById = new Map();
    this.querySignalId = `signal_id${this.graphId}`;
 
    this.route.queryParams.subscribe(params => {
      const signalIds = params[this.querySignalId];
      if (signalIds) {
        if (signalIds instanceof Array) {
          this.signalIdsToPlot = signalIds;
        }
        else {
          this.signalIdsToPlot = [signalIds];
        }
        if (!this.signalIds || this.signalIds.length == 0) {
          this.signalIds = this.signalIdsToPlot.map(x => x);
        }
        this.loadedFromUrl = true;
      }
      else {
        this.signalIdsToPlot = [];
      }
    });
 
    this.loadSignalIds(this.loadedFromUrl);
  }
 
  loadSignalIds(loadedFromUrl: boolean) {
    this.twinpadApiService.getSignalsIds().subscribe({
      next: signalIds => {
        for (const signalId of signalIds) {
          // This is done to not disturb the signals' order when they've been added from url query
          if (loadedFromUrl) {
            const index: number = this.signalIds.indexOf(signalId);
            if (index > -1) {
              this.signalIds.splice(index, 1);
            }
          }
          this.signalIds.push(signalId);
        }
        this.filterSignalIds();
        this.finishedLoadingSignals.emit(true);
      }
    });
  }
 
  filterSignalIds() {
    if (this.isLive) {
      this.twinpadApiService.devicesBehaviorSubject$.subscribe({
        next: devices => {
          Iif (devices === undefined) {
            return;
          }
          const downDeviceIds: string[] = devices.filter(device => device.status !== "up").map(device => device.device_id);
          // display only signals of devices who are not down
          // can't filter on devices who are up since some signals don't come from real devices (data storage)
          this.signalIdsToDisplay = this.signalIds.filter(signalId => downDeviceIds.indexOf(signalId.split(".")[0]) === -1);
          this.cleanSelectedSignals();
        }
      });
    }
    else {
      this.signalIdsToDisplay = this.signalIds.map(signalId => signalId);
      this.cleanSelectedSignals();
    }
  }
 
  ngOnChanges() {
    this.filterSignalIds();
  }
 
  cleanSelectedSignals() {
    const newSelection = this.signalIdsToPlot.filter(signalId => this.signalIdsToDisplay.indexOf(signalId) !== -1);
    Eif (newSelection !== this.signalIdsToPlot) {
      this.onChangeSelection(newSelection);
    }
  }
 
  onChangeSelection(newSelection: string[]){
    this.route.queryParams.subscribe(queryParams => {
      const params: Params = {};
      const signal_id_string = this.querySignalId;
      for (const [key, value] of Object.entries(queryParams)) {
        Iif (key !== signal_id_string) {
          params[key] = value;
        }
      }
      params[signal_id_string] = newSelection;
      this.router.navigate([], {
        queryParams: params
      });
    });
  }
}