File

src/app/components/body/battery-test/show-test-result/show-test-result.component.ts

Implements

OnInit OnDestroy

Metadata

Index

Properties
Methods

Constructor

constructor(route: ActivatedRoute, _testChamberService: TestChamberService, _componentStoreService: ComponentStoreService, modalService: NgbModal, location: Location, router: Router)
Parameters :
Name Type Optional
route ActivatedRoute No
_testChamberService TestChamberService No
_componentStoreService ComponentStoreService No
modalService NgbModal No
location Location No
router Router No

Methods

appendNewData
appendNewData(prevMeasurements: MeasuredParameters, newMeasurements: MeasuredParameters)
Parameters :
Name Type Optional
prevMeasurements MeasuredParameters No
newMeasurements MeasuredParameters No
Returns : void
changeStatus
changeStatus(status: string | null)
Parameters :
Name Type Optional
status string | null No
Returns : void
createChart
createChart(channelQuickResponse: QuickResponseMeasurement)
Parameters :
Name Type Optional
channelQuickResponse QuickResponseMeasurement No
Returns : void
deleteTest
deleteTest()
Returns : void
download
download(channelNo: number)
Parameters :
Name Type Optional
channelNo number No
Returns : void
edit
edit()
Returns : void
keepUpdatingChart
keepUpdatingChart(channelQuickResponse: QuickResponseMeasurement)
Parameters :
Name Type Optional
channelQuickResponse QuickResponseMeasurement No
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
onClickChild
onClickChild(event: MouseEvent)
Parameters :
Name Type Optional
event MouseEvent No
Returns : void
onClickParent
onClickParent(event: MouseEvent)
Parameters :
Name Type Optional
event MouseEvent No
Returns : void
pause
pause()
Returns : void
play
play()
Returns : void
sampleData
sampleData(data: number[] | undefined, samplingRate: number)
Parameters :
Name Type Optional
data number[] | undefined No
samplingRate number No
Returns : void
showChartView
showChartView(channelNo: number)
Parameters :
Name Type Optional
channelNo number No
Returns : void
stop
stop()
Returns : void
toggleShowChart
toggleShowChart()
Returns : void
updateConnection
updateConnection()
Returns : void

Properties

allCharts
Type : Charts[]
Default value : []
Optional chamberId
Type : string | null
Optional charts
Type : QueryList<BaseChartDirective>
Decorators :
@ViewChildren(BaseChartDirective)
Optional chartSub
Type : Subscription
Optional connSub
Type : Subscription
isConnected
Type : boolean
Default value : false
isConnectedIntervalId
Type : any
maxNoOfDataPoints
Type : number
Default value : 1000
measurementUpdateIntervalId
Type : any
modal
Type : any
Decorators :
@ViewChild('myModal')
Optional modalBody
Type : string
Optional modalTitle
Type : string
quickResponses
Type : QuickResponseMeasurement[]
Default value : []
showChart
Type : boolean
Default value : false
subs
Type : Subscription[]
Default value : []
targetSampleSize
Type : number
Default value : 700
Optional testId
Type : string | null
Optional testInfo
Type : _TestResultDeep
testInfoIntervalId
Type : any
Optional testInfoSub
Type : Subscription
updatedUptoIndex
Type : number
Default value : 0
import { ComponentStoreService } from './../../../../services/component-store.service';
import {
  _TestResultDeep,
  QuickResponseMeasurement,
  MeasuredParameters,
  SensorObj,
} from './../../../../models/TestResult';
import { TestChamberService } from 'src/app/services/test-chamber.service';
import { of, Subscription, switchMap } from 'rxjs';
import { ActivatedRoute, Router } from '@angular/router';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { saveAs } from 'file-saver';

import { ChartConfiguration, ChartType } from 'chart.js';
import {
  Component,
  OnInit,
  OnDestroy,
  QueryList,
  ViewChildren,
  ViewChild,
} from '@angular/core';
import { BaseChartDirective } from 'ng2-charts';
import { Location } from '@angular/common';

interface Charts {
  name?: string;
  chartData?: ChartConfiguration['data'] | any;
  ChartOptions?: ChartConfiguration['options'] | any;
  ChartType: ChartType;
}

@Component({
  selector: 'app-show-test-result',
  templateUrl: './show-test-result.component.html',
  styleUrls: ['./show-test-result.component.css'],
})
export class ShowTestResultComponent implements OnInit, OnDestroy {
  subs: Subscription[] = [];
  testInfo?: _TestResultDeep;
  showChart: boolean = false;
  allCharts: Charts[] = [];
  quickResponses: QuickResponseMeasurement[] = [];
  chartSub?: Subscription;
  testId?: string | null;
  chamberId?: string | null;
  measurementUpdateIntervalId: any;
  testInfoIntervalId: any;
  testInfoSub?: Subscription;
  modalTitle?: string;
  modalBody?: string;
  isConnected: boolean = false;
  isConnectedIntervalId: any;
  connSub?: Subscription;
  maxNoOfDataPoints: number = 1000;
  targetSampleSize: number = 700;
  updatedUptoIndex = 0;

  @ViewChildren(BaseChartDirective) charts?: QueryList<BaseChartDirective>;
  @ViewChild('myModal') modal: any;

  constructor(
    private route: ActivatedRoute,
    private _testChamberService: TestChamberService,
    private _componentStoreService: ComponentStoreService,
    private modalService: NgbModal,
    private location: Location,
    private router: Router
  ) {}

  toggleShowChart() {
    this.showChart = !this.showChart;
    clearInterval(this.measurementUpdateIntervalId);
    this.chartSub?.unsubscribe();
  }

  onClickChild(event: MouseEvent) {
    event.stopPropagation();
  }

  onClickParent(event: MouseEvent) {
    this.toggleShowChart();
  }

  showChartView(channelNo: number) {
    this.allCharts = [];
    this.toggleShowChart();
    const channelQuickResponse = this.quickResponses.find(
      (res) => res.channelNo === channelNo
    );
    if (channelQuickResponse) {
      this.createChart(channelQuickResponse);
      this.keepUpdatingChart(channelQuickResponse);
    } else {
      const sub = this._testChamberService
        .getQuickResponse(
          this.chamberId as any,
          this.testId as any,
          channelNo as any
        )
        .subscribe((data: QuickResponseMeasurement) => {
          this.createChart(data);
          this.quickResponses.push(data);
          if (data.statusCh === 'Running') {
            //if channel is running then only keep updating the channel
            this.keepUpdatingChart(data);
          }
          sub.unsubscribe();
        });
    }
  }

  createChart(channelQuickResponse: QuickResponseMeasurement) {
    let blankData: MeasuredParameters = {};
    blankData.time = [];
    if (
      channelQuickResponse.measuredParameters.current &&
      channelQuickResponse.measuredParameters.current.length > 0
    ) {
      blankData.current = [];
      let chart: Charts = {
        name: 'Current',
        chartData: {
          datasets: [
            {
              data: blankData.current,
              label: 'Current',
            },
          ],
          labels: blankData.time,
        },
        ChartOptions: {
          scales: {
            xAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Time(S)',
                },
              },
            ],
            yAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Cell Current (A)',
                },
              },
            ],
          },
        },
        ChartType: 'line',
      };
      this.allCharts.push(chart);
    }
    if (
      channelQuickResponse.measuredParameters.voltage &&
      channelQuickResponse.measuredParameters.voltage.length > 0
    ) {
      blankData.voltage = [];
      let chart: Charts = {
        name: 'Voltage',
        chartData: {
          datasets: [
            {
              data: blankData.voltage,
              label: 'Voltage',
            },
          ],
          labels: blankData.time,
        },
        ChartOptions: {
          scales: {
            xAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Time(S)',
                },
              },
            ],
            yAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Cell Voltage(V)',
                },
              },
            ],
          },
        },
        ChartType: 'line',
      };
      this.allCharts.push(chart);
    }
    if (
      channelQuickResponse.measuredParameters.chamberTemp &&
      channelQuickResponse.measuredParameters.chamberTemp.length > 0
    ) {
      blankData.chamberTemp = [];
      let chart: Charts = {
        name: 'Chamber Temperature',
        chartData: {
          datasets: [
            {
              data: blankData.chamberTemp,
              label: 'Chamber Temperature',
            },
          ],
          labels: blankData.time,
        },
        ChartOptions: {
          scales: {
            xAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Time(S)',
                },
              },
            ],
            yAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Chamber Temperature (°C)',
                },
              },
            ],
          },
        },
        ChartType: 'line',
      };
      this.allCharts.push(chart);
    }
    if (
      channelQuickResponse.measuredParameters.chamberHum &&
      channelQuickResponse.measuredParameters.chamberHum.length > 0
    ) {
      blankData.chamberHum = [];
      let chart: Charts = {
        name: 'Chamber Humidity',
        chartData: {
          datasets: [
            {
              data: blankData.chamberHum,
              label: 'Chamber Humidity',
            },
          ],
          labels: blankData.time,
        },
        ChartOptions: {
          scales: {
            xAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Time(S)',
                },
              },
            ],
            yAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Chamber Humidity(%)',
                },
              },
            ],
          },
        },
        ChartType: 'line',
      };
      this.allCharts.push(chart);
    }

    if (
      channelQuickResponse.measuredParameters.cellTemp &&
      channelQuickResponse.measuredParameters.cellTemp.length > 0
    ) {
      blankData.cellTemp = [];
      let chart: Charts = {
        name: 'Cell Temperature',
        chartData: {
          datasets: [],
          labels: blankData.time,
        },
        ChartOptions: {
          scales: {
            xAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Time(S)',
                },
              },
            ],
            yAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Cell Temperatures(°C)',
                },
              },
            ],
          },
        },
        ChartType: 'line',
      };
      channelQuickResponse.measuredParameters.cellTemp.forEach(
        (tempObj: SensorObj) => {
          let d: SensorObj = { sensorId: tempObj.sensorId, values: [] };
          blankData.cellTemp?.push(d);
          chart.chartData.datasets.push({
            data: d.values,
            label: 'Sensor' + tempObj.sensorId,
          });
        }
      );
      this.allCharts.push(chart);
    }
    this.appendNewData(blankData, channelQuickResponse.measuredParameters);
  }

  keepUpdatingChart(channelQuickResponse: QuickResponseMeasurement) {
    clearInterval(this.measurementUpdateIntervalId);
    this.measurementUpdateIntervalId = setInterval(() => {
      this.chartSub = this._testChamberService
        .getQuickResponse(
          this.chamberId as any,
          this.testId as any,
          channelQuickResponse.channelNo as any,
          this.updatedUptoIndex - 1
        )
        .subscribe((data: any) => {
          this.appendNewData(
            channelQuickResponse.measuredParameters,
            data.measuredParameters as MeasuredParameters
          );
          this.charts?.forEach((chart) => chart.update());
          this.chartSub?.unsubscribe();
          if (data.status === 'Completed' || data.status === 'Stopped') {
            clearInterval(this.measurementUpdateIntervalId);
          }
        });
    }, 2000);
  }

  appendNewData(
    prevMeasurements: MeasuredParameters,
    newMeasurements: MeasuredParameters
  ) {
    if (newMeasurements.current && newMeasurements.current?.length > 0) {
      prevMeasurements.current?.push(...newMeasurements.current);
    }
    if (newMeasurements.voltage && newMeasurements.voltage?.length > 0) {
      prevMeasurements.voltage?.push(...newMeasurements.voltage);
    }
    if (newMeasurements.chamberHum && newMeasurements.chamberHum?.length > 0) {
      prevMeasurements.chamberHum?.push(...newMeasurements.chamberHum);
    }
    if (
      newMeasurements.chamberTemp &&
      newMeasurements.chamberTemp?.length > 0
    ) {
      prevMeasurements.chamberTemp?.push(...newMeasurements.chamberTemp);
    }
    if (newMeasurements.time && newMeasurements.time?.length > 0) {
      prevMeasurements.time?.push(...newMeasurements.time);
    }
    newMeasurements.cellTemp?.forEach((tempObjNew, i) => {
      const tempObjOld = prevMeasurements.cellTemp?.find(
        (tempObj) => tempObj.sensorId === tempObjNew.sensorId
      );
      if (tempObjOld) {
        tempObjOld.values.push(...tempObjNew.values);
      } else {
        prevMeasurements.cellTemp?.push(tempObjNew);
      }
    });
    this.updatedUptoIndex += newMeasurements.time
      ? newMeasurements.time.length
      : 0;

    if (
      prevMeasurements.time &&
      prevMeasurements.time.length > this.maxNoOfDataPoints
    ) {
      // Use sampling technique
      const samplingRate = prevMeasurements.time.length / this.targetSampleSize;

      this.sampleData(prevMeasurements.time, samplingRate);
      this.sampleData(prevMeasurements.current, samplingRate);
      this.sampleData(prevMeasurements.voltage, samplingRate);
      this.sampleData(prevMeasurements.chamberHum, samplingRate);
      this.sampleData(prevMeasurements.chamberTemp, samplingRate);

      prevMeasurements.cellTemp?.forEach((tempObj) => {
        this.sampleData(tempObj.values, samplingRate);
      });
    }
  }

  sampleData(data: number[] | undefined, samplingRate: number): void {
    if (!data || samplingRate <= 1) {
      return;
    }

    let writeIndex = 0;
    for (
      let readIndex = 0;
      readIndex < data.length;
      readIndex += samplingRate
    ) {
      data[writeIndex++] = data[Math.floor(readIndex)];
    }

    data.length = writeIndex;
  }

  ngOnInit(): void {
    //console.log(this.router.url);
    if (window.location.hostname != 'localhost') {
      this.location.replaceState('./'); //on prod
    }
    const os$ = this.route.paramMap.pipe(
      switchMap((params) => {
        this.testId = params.get('testId');
        this.chamberId = params.get('chamberId');
        return this._testChamberService.getTestData(
          this.chamberId as any,
          this.testId as any
        );
      })
    );
    this.testInfoSub = os$.subscribe((testInfo: _TestResultDeep) => {
      this.testInfo = testInfo;
      this.testInfoSub?.unsubscribe();
    });

    this.testInfoIntervalId = setInterval(() => {
      if (this.testId && this.chamberId) {
        this.testInfoSub?.unsubscribe();
        this.testInfoSub = this._testChamberService
          .getTestData(this.chamberId as any, this.testId as any)
          .subscribe((testInfo) => {
            this.testInfo = testInfo;
            this.testInfoSub?.unsubscribe();
            if (
              this.testInfo?.status === 'Completed' ||
              this.testInfo?.status === 'Stopped'
            ) {
              clearInterval(this.testInfoIntervalId);
            }
          });
      }
    }, 10000);

    this.updateConnection();

    this.isConnectedIntervalId = setInterval(
      () => this.updateConnection(),
      10000
    );
  }

  deleteTest() {
    this.modalTitle = 'Alert';
    this.modalBody =
      'Are you sure you want to delete all the information related to this experiment? Once you do it, you can never retrieve it.';
    this.modalService.open(this.modal, { centered: true }).result.then(
      (result) => {
        //console.log('accepted');
        this._testChamberService
          .deleteTest(this.chamberId as any, this.testId as any)
          .subscribe((res) => {
            let url = '';
            let path = this.router.url;
            if (path.indexOf('view-all') > 0) {
              url = '../../../../';
            } else {
              url = '../../../';
            }
            this.router.navigate([url], {
              relativeTo: this.route,
              skipLocationChange: true,
            });
          });
      },
      (reason) => {
        //console.log('closed');
      }
    );
  }

  updateConnection() {
    if (this.chamberId) {
      this.connSub?.unsubscribe();
      this.connSub = this._testChamberService
        .getConnectionStatus(this.chamberId as any)
        .subscribe({
          next: (pay: any) => {
            this.isConnected = pay.isConnected;
            this.connSub?.unsubscribe();
          },
          error: (err) => {
            this.isConnected = false;
          },
        });
    }
  }

  edit() {}
  play() {
    this.changeStatus('Running');
  }
  pause() {
    this.changeStatus('Paused');
  }
  stop() {
    this.modalTitle = 'Alert';
    this.modalBody =
      'Are you sure you want to stop the experiment? Once you stop it, you can never start it again.';
    this.modalService.open(this.modal, { centered: true }).result.then(
      (result) => {
        //console.log('accepted');
        this.changeStatus('Stopped');
      },
      (reason) => {
        //console.log('closed');
      }
    );
  }
  changeStatus(status: string | null) {
    const sub = this._testChamberService
      .forceStatus(this.chamberId as any, this.testId as any, status)
      .subscribe((res: any) => {
        if (res.acknowledged) {
          this._componentStoreService.sendToastMsg({
            msg: 'Status has been sent to the cloud. Wait for the Test Chamber to reflect the status',
            timeOut: 10000,
            color: 'black',
          });
        }
      });
    this.subs.push(sub);
  }

  download(channelNo: number) {
    this._testChamberService
      .downloadTestResult(this.chamberId as any, this.testId as any, channelNo)
      .subscribe((response) => {
        const blob = new Blob([response.body], {
          type: 'text/csv;charset=utf-8;',
        });
        const url = URL.createObjectURL(blob);
        const contentDispositionHeader = response.headers.get(
          'content-disposition'
        );
        const filename = contentDispositionHeader
          ? contentDispositionHeader.split('filename=')[1].replace(/"/g, '')
          : 'testResult.csv';
        saveAs(url, filename);
      });
  }
  ngOnDestroy(): void {
    this.subs.forEach((sub) => sub.unsubscribe());
    this.testInfoSub?.unsubscribe();
    this.chartSub?.unsubscribe();
    clearInterval(this.measurementUpdateIntervalId);
    clearInterval(this.testInfoIntervalId);
    this.connSub?.unsubscribe();
    clearInterval(this.isConnectedIntervalId);
  }
}
<div class="card test-info-container" *ngIf="testInfo">
  <div class="card-header">
    <div class="row">
      <div class="col">Test Data</div>
      <div class="col text-end">
        Chamber -
        <span *ngIf="isConnected; else not_connected"
          >Online
          <div
            class="spinner-grow spinner-grow-sm text-light"
            role="status"
            *ngIf="true"
          >
            <span class="sr-only">Loading...</span>
          </div>
        </span>
        <ng-template #not_connected>
          <span>Offline</span>
        </ng-template>
      </div>
    </div>
  </div>
  <div class="card-body">
    <div class="overall">
      <div class="row">
        <div class="col-md-4"><strong>Test Id:</strong></div>
        <div class="col-md-8">{{ testInfo._id }}</div>
      </div>
      <div class="row">
        <div class="col-md-4"><strong>Test Name:</strong></div>
        <div class="col-md-8">{{ testInfo.testName }}</div>
      </div>
      <div class="row">
        <div class="col-md-4"><strong>Chamber Name:</strong></div>
        <div class="col-md-8">{{ testInfo.chamberName }}</div>
      </div>
      <div class="row">
        <div class="col-md-4"><strong>Status:</strong></div>
        <div class="col-md-8">{{ testInfo.status }}</div>
      </div>
      <div class="row" *ngIf="testInfo.testScheduleDate">
        <div class="col-4"><strong>Test Scheduled Date</strong></div>
        <div class="col-8">
          {{ testInfo.testScheduleDate | date : "MMM d, y, h:mm a" }}
        </div>
      </div>
      <div class="row" *ngIf="testInfo.testStartDate">
        <div class="col-4"><strong>Test Start Date</strong></div>
        <div class="col-8">
          {{ testInfo.testStartDate | date : "MMM d, y, h:mm a" }}
        </div>
      </div>
      <div class="row" *ngIf="testInfo.testEndDate">
        <div class="col-4"><strong>Test End Date</strong></div>
        <div class="col-8">
          {{ testInfo.testEndDate | date : "MMM d, y, h:mm a" }}
        </div>
      </div>
      <div
        class="row control justify-content-end text-end"
        *ngIf="
          testInfo.accessType === 'write' || testInfo.accessType === 'admin'
        "
      >
        <div class="col">
          <ng-container *ngIf="testInfo.status === 'Scheduled'">
            <button class="btn btn-info" type="button" (click)="edit()">
              <span class="material-symbols-outlined align-middle"> edit </span>
            </button>
          </ng-container>
          <ng-container *ngIf="testInfo.status === 'Running'">
            <button class="btn btn-warning" type="button" (click)="pause()">
              <span class="material-symbols-outlined align-middle">
                pause
              </span>
            </button>
          </ng-container>
          <ng-template #resume_btn>
            <button type="button" class="btn btn-success" (click)="play()">
              <span class="material-symbols-outlined align-middle"> play </span>
            </button>
          </ng-template>
          <ng-container
            *ngIf="
              testInfo.status !== 'Scheduled' && testInfo.status !== 'Completed'
            "
          >
            <button type="button" class="btn btn-danger">
              <span
                class="material-symbols-outlined align-middle"
                type="button"
                (click)="stop()"
              >
                stop
              </span>
            </button>
          </ng-container>
        </div>
      </div>
    </div>

    <div class="channel-container">
      <div class="row" *ngFor="let channel of testInfo.channels">
        <div class="col">
          <div class="card mb-3">
            <div class="card-header">
              <div class="row justify-content-between">
                <div class="col">Channel {{ channel.channelNumber }}</div>
                <div class="col text-end">
                  <ng-container
                    *ngIf="channel.status && channel.status !== 'Scheduled'"
                  >
                    <span class="text-nowrap">
                      <span
                        class="material-symbols-outlined show-chart align-middle text-center"
                        (click)="showChartView(channel.channelNumber)"
                      >
                        monitoring
                      </span>
                      <span
                        class="material-symbols-outlined download align-middle text-center"
                        (click)="download(channel.channelNumber)"
                      >
                        download
                      </span>
                    </span>
                  </ng-container>
                  {{ channel.status }}
                  <div
                    class="spinner-border spinner-border-sm text-primary align-middle"
                    role="status"
                    *ngIf="channel.status === 'Running'"
                  >
                    <span class="visually-hidden">Loading...</span>
                  </div>
                </div>
              </div>
            </div>
            <div class="card-body">
              <div
                class="row mb-3"
                *ngFor="let row of channel.testFormats; let i = index"
              >
                <div class="col-md-1">
                  <strong class="text-center">{{ i + 1 }}</strong>
                </div>
                <div class="col md-11">
                  <div
                    class="row mb-2 justify-content-between align-items-center"
                  >
                    <div class="col">
                      <span class="badge bg-info">
                        <ng-container *ngFor="let field of row.fields">
                          <ng-container *ngIf="field.visibility">
                            <span
                              *ngIf="field.type !== 'file'; else drive_cycle"
                              >{{ field.value }}</span
                            >
                            <ng-template #drive_cycle>
                              <span>X</span>
                            </ng-template>
                          </ng-container>
                        </ng-container>
                      </span>
                      <span class="badge bg-info">
                        <span
                          class="material-symbols-outlined align-middle field"
                        >
                          cycle
                        </span>
                        <span>{{ row.multiplier }}</span>
                      </span>
                      <span class="badge bg-info">
                        <span
                          class="material-symbols-outlined align-middle field"
                        >
                          device_thermostat
                        </span>
                        <span> {{ row.ambTemp }}°C</span>
                      </span>
                    </div>
                    <div
                      class="col-md-2 text-end"
                      *ngIf="channel.rows && channel.rows[i]"
                    >
                      <small>{{ channel.rows[i].status }}</small>
                    </div>
                  </div>
                  <div
                    class="row mb-2 align-items-center"
                    *ngIf="
                      channel.rows && channel.rows[i];
                      else default_template
                    "
                  >
                    <div class="col-md-1 text-center">
                      @ {{ channel.rows[i].currentMultiplierIndex }}
                    </div>
                    <div class="col">
                      <div class="progress" style="padding: 0px">
                        <div
                          class="progress-bar progress-bar-striped"
                          role="progressbar"
                          [style.width.%]="
                            (channel.rows[i].currentMultiplierIndex /
                              channel.rows[i].multiplier) *
                            100
                          "
                          [attr.aria-valuenow]="
                            (channel.rows[i].currentMultiplierIndex /
                              channel.rows[i].multiplier) *
                            100
                          "
                          aria-valuemin="0"
                          aria-valuemax="100"
                          [class]="
                            channel.rows[i].status === 'Running'
                              ? 'progress-bar-animated'
                              : null
                          "
                        ></div>
                      </div>
                    </div>
                  </div>
                  <ng-template #default_template>
                    <div class="row mb-2">
                      <div class="col">
                        <small style="padding-left: 3px"
                          >Not yet started.</small
                        >
                      </div>
                    </div>
                  </ng-template>
                </div>
              </div>
              <div class="row mb-3" style="border-top: 1px solid gray">
                <div class="col text-start">Overall</div>
              </div>
              <ng-container
                *ngIf="
                  channel.status && channel.status !== 'Scheduled';
                  else default_overall
                "
              >
                <div class="row mb-2">
                  <div class="col-md-2">Current Cycle</div>
                  <div class="col-md-10">
                    <div class="row align-items-center">
                      <div class="col-md-1">
                        {{ channel.currentMultiplierIndex }}
                      </div>
                      <div class="col-md-11">
                        <div class="progress" style="padding: 0px">
                          <div
                            class="progress-bar bg-danger progress-bar-striped"
                            role="progressbar"
                            [style.width.%]="
                              channel.currentMultiplierIndex &&
                              channel.multiplier
                                ? (channel.currentMultiplierIndex /
                                    channel.multiplier) *
                                  100
                                : 0
                            "
                            [attr.aria-valuenow]="
                              channel.currentMultiplierIndex &&
                              channel.multiplier
                                ? (channel.currentMultiplierIndex /
                                    channel.multiplier) *
                                  100
                                : 0
                            "
                            aria-valuemin="0"
                            aria-valuemax="100"
                            [class]="
                              channel.status === 'Running'
                                ? 'progress-bar-animated'
                                : null
                            "
                          ></div>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
                <div class="row" *ngIf="channel.chStartDate">
                  <div class="col-md-2">Channel Start Date</div>
                  <div class="col-md-10">
                    {{ channel.chStartDate | date : "MMM d, y, h:mm a" }}
                  </div>
                </div>
                <div class="row" *ngIf="channel.chEndDate">
                  <div class="col-md-2">Channel Start Date</div>
                  <div class="col-md-10">
                    {{ channel.chEndDate | date : "MMM d, y, h:mm a" }}
                  </div>
                </div>
              </ng-container>

              <ng-template #default_overall>
                <div class="row mb-w">
                  <div class="col">Channel result not available</div>
                </div>
              </ng-template>
            </div>
          </div>
        </div>
      </div>
      <div class="row mb-3" style="border-top: 1px solid gray"></div>
      <div class="row">
        <div class="col">
          <small>@ Progress shows in terms of multiplier count.</small>
        </div>
        <div
          class="col text-end align-middle"
          *ngIf="
            (testInfo.status == 'Scheduled' ||
              testInfo.status == 'Completed' ||
              testInfo.status == 'Stopped') &&
            testInfo.accessType == 'admin'
          "
        >
          <span class="material-symbols-outlined delete" (click)="deleteTest()">
            delete_forever
          </span>
        </div>
      </div>
    </div>
  </div>
</div>
<ng-container *ngIf="showChart">
  <div class="chart-background" (click)="onClickParent($event)">
    <div class="charts" (click)="onClickChild($event)">
      <div class="card">
        <div class="card-header">
          <div class="row justify-content-between">
            <div class="col">
              <span
                class="material-symbols-outlined align-middle cross"
                (click)="toggleShowChart()"
              >
                close
              </span>
              <span class="align-middle">Charts</span>
            </div>
          </div>
        </div>
        <div class="card-body">
          <ng-container *ngIf="allCharts.length > 0; else no_chart">
            <div class="row justify-content-center">
              <div
                class="col-md-6"
                *ngFor="let chart of allCharts; let i = index"
              >
                <canvas
                  baseChart
                  height="150"
                  [data]="chart.chartData"
                  [options]="chart.ChartOptions"
                  [type]="chart.ChartType"
                >
                </canvas>
              </div>
            </div>
          </ng-container>
          <ng-template #no_chart>
            <span> Hold on, loading your charts.</span>
          </ng-template>
        </div>
      </div>
    </div>
  </div>
</ng-container>

<ng-template #myModal let-modal>
  <div class="modal-header">
    <h4 class="modal-title" id="modal-basic-title">{{ modalTitle }}</h4>
    <button
      type="button"
      class="close btn btn-danger"
      aria-label="Close"
      (click)="modal.dismiss('Cross click')"
    >
      <span aria-hidden="true">X</span>
    </button>
  </div>
  <div class="modal-body">{{ modalBody }}</div>
  <div class="modal-footer">
    <button
      type="button"
      class="btn btn-outline-dark"
      (click)="modal.close('Save click')"
    >
      Ok
    </button>
  </div>
</ng-template>

./show-test-result.component.css

.test-info-container {
  margin-top: 10px;
}
.test-info-container > .card-header {
  background-color: #010305cf;
  color: white;
}
.channel-container {
  border-top: 5px solid #91699b57;
  margin-top: 10px;
  padding-top: 10px;
}
.badge .material-symbols-outlined {
  font-size: inherit;
}
.badge > span {
  height: 100%;
  padding: 0px 2px;
  vertical-align: middle;
  font-size: large;
}
.badge {
  margin: 2px 2px;
}
.overall .row {
  margin-bottom: 3px;
  font-family: Verdana, sans-serif;
}
.show-chart,
.download,
.cross {
  margin: 0px 10px;
}
.show-chart:hover,
.download:hover,
.cross:hover {
  color: red;
  cursor: pointer;
}
.chart-background {
  position: fixed;
  top: 0px;
  left: 0px;
  height: 100%;
  width: 100%;
  z-index: 7;
  background: rgba(255, 255, 255, 0.192);
  backdrop-filter: blur(10px);
  overflow: hidden;
}
.cross {
  float: right;
}

.charts {
  position: relative;
  top: 10%;
  z-index: 8;
  margin: auto;
  width: 80%;
  max-height: 80%;
  overflow-y: auto;
}
.chart-background .card {
  margin: 0px 10px;
}
.control button {
  margin: 0px 2px;
}

.delete {
  margin: 0px 2px;
}
.delete:hover {
  color: red;
  cursor: pointer;
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""