@iotize/ionic
Version:
Iotize specific building blocks on top of @ionic/angular.
834 lines (826 loc) • 440 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, Component, Input, NgModule, EventEmitter, Directive, Output, HostListener, PLATFORM_ID, ChangeDetectionStrategy, Inject, ViewChild, TemplateRef, ViewEncapsulation, ContentChild, ElementRef, NgZone, ChangeDetectorRef, Pipe } from '@angular/core';
import { BehaviorSubject, Observable, Subject, NEVER, combineLatest } from 'rxjs';
import * as i1 from '@angular/forms';
import { ReactiveFormsModule, FormControl, Validators, FormsModule } from '@angular/forms';
import * as i1$1 from '@ionic/angular';
import { IonicModule, ModalController, AlertController, ActionSheetController, Platform } from '@ionic/angular';
import * as i1$3 from '@iotize/ionic';
import { getFormFieldOrError, ExportToCsv, LibError, PendingCallManager, TapValueEditorContainerModule, InlineEditorModule, CurrentDeviceService, getAbstractVariableOrError, LibCommonModule } from '@iotize/ionic';
import * as i2 from '@angular/common';
import { CommonModule, DecimalPipe } from '@angular/common';
import * as i3 from '@swimlane/ngx-charts';
import { BaseChartComponent, LegendPosition, NgxChartsModule, GaugeComponent, HeatMapComponent, LineChartComponent, NumberCardComponent, PieChartComponent, PolarChartComponent, PieChartModule } from '@swimlane/ngx-charts';
import { takeUntil, switchMap, shareReplay, map } from 'rxjs/operators';
import * as i1$2 from '@awesome-cordova-plugins/file/ngx';
import { File } from '@awesome-cordova-plugins/file/ngx';
import { createDebugger } from '@iotize/common/debug';
import * as i3$1 from '@iotize/app-common';
import { IconModule } from '@iotize/app-common';
import { variableDataTypeToByteSize, TapVariable } from '@iotize/tap/data';
import * as i2$1 from '@angular/material/table';
import { MatTableModule } from '@angular/material/table';
import * as i3$2 from '@angular/cdk/table';
import { DataSource, CdkTableModule } from '@angular/cdk/table';
import { __decorate, __metadata } from 'tslib';
import { deepCopy, listEnumKeys } from '@iotize/common/utility';
import { TapStreamReader, NumberConverter, TapStreamWriter } from '@iotize/tap/client/impl';
import { VariableType } from '@iotize/tap/service/impl/variable';
import { GPIOMode } from '@iotize/tap/service/impl/gpio';
import * as shape from 'd3-shape';
import * as i3$3 from '@swimlane/ngx-datatable';
import { ColumnMode, NgxDatatableModule } from '@swimlane/ngx-datatable';
import * as i1$4 from '@angular/router';
import { bufferToHexString } from '@iotize/common/byte-converter';
class MonitoringSettingsService {
constructor() {
this.subject = new BehaviorSubject({
period: 1000,
});
}
set settings(value) {
this.subject.next(value);
}
get settings() {
return this.subject.value;
}
get settings$() {
return this.subject;
}
}
/** @nocollapse */ MonitoringSettingsService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MonitoringSettingsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
/** @nocollapse */ MonitoringSettingsService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MonitoringSettingsService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MonitoringSettingsService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}], ctorParameters: function () { return []; } });
class TapMonitoringSettingsComponent {
get period() {
return getFormFieldOrError(this.form, 'period');
}
get dataSource() {
return getFormFieldOrError(this.form, 'dataSource');
}
constructor(formBuilder, monitoringSettingsService, modalController) {
this.formBuilder = formBuilder;
this.monitoringSettingsService = monitoringSettingsService;
this.modalController = modalController;
this.showDataSource = false;
this.form = this.formBuilder.group({
period: [this.monitoringSettingsService.settings.period],
dataSource: ['live'],
});
}
ngOnInit() {
this.form.valueChanges.subscribe(() => {
this.monitoringSettingsService.settings = {
period: this.period.value,
};
});
}
async dismiss() {
const topOverlay = await this.modalController.getTop();
if (topOverlay) {
await this.modalController.dismiss(topOverlay.id);
}
}
}
/** @nocollapse */ TapMonitoringSettingsComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapMonitoringSettingsComponent, deps: [{ token: i1.FormBuilder }, { token: MonitoringSettingsService }, { token: i1$1.ModalController }], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ TapMonitoringSettingsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: TapMonitoringSettingsComponent, selector: "tap-monitoring-settings", inputs: { showDataSource: "showDataSource" }, ngImport: i0, template: "<ion-header>\n <ion-toolbar color=\"primary\">\n <ion-buttons slot=\"start\">\n <ion-button (click)=\"dismiss()\">\n <ion-icon name=\"arrow-back\"></ion-icon>\n </ion-button>\n </ion-buttons>\n <ion-title class=\"text-center\">\n Monitoring Settings\n </ion-title>\n </ion-toolbar>\n</ion-header>\n<ion-content>\n <form [formGroup]=\"form\">\n <ion-list>\n <ion-item>\n <ion-label>Frequency (in milliseconds)</ion-label>\n <ion-input\n [formControlName]=\"'period'\"\n slot=\"end\"\n text-right\n type=\"number\"\n ></ion-input>\n </ion-item>\n <ion-item *ngIf=\"showDataSource\">\n <ion-label>Data source</ion-label>\n <ion-select [formControlName]=\"'dataSource'\" slot=\"end\">\n <ion-select-option value=\"live\">Live data</ion-select-option>\n <ion-select-option value=\"datalog\">Data log</ion-select-option>\n </ion-select>\n </ion-item>\n </ion-list>\n </form>\n</ion-content>\n<ion-footer>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button (click)=\"dismiss()\">Ok</ion-button>\n </ion-buttons>\n </ion-toolbar>\n</ion-footer>\n", styles: [""], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i1$1.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i1$1.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i1$1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i1$1.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i1$1.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i1$1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i1$1.IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: i1$1.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i1$1.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i1$1.IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: i1$1.IonSelect, selector: "ion-select", inputs: ["cancelText", "compareWith", "disabled", "interface", "interfaceOptions", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "value"] }, { kind: "component", type: i1$1.IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }, { kind: "component", type: i1$1.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: i1$1.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "directive", type: i1$1.NumericValueAccessor, selector: "ion-input[type=number]" }, { kind: "directive", type: i1$1.SelectValueAccessor, selector: "ion-range, ion-select, ion-radio-group, ion-segment, ion-datetime" }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapMonitoringSettingsComponent, decorators: [{
type: Component,
args: [{ selector: 'tap-monitoring-settings', template: "<ion-header>\n <ion-toolbar color=\"primary\">\n <ion-buttons slot=\"start\">\n <ion-button (click)=\"dismiss()\">\n <ion-icon name=\"arrow-back\"></ion-icon>\n </ion-button>\n </ion-buttons>\n <ion-title class=\"text-center\">\n Monitoring Settings\n </ion-title>\n </ion-toolbar>\n</ion-header>\n<ion-content>\n <form [formGroup]=\"form\">\n <ion-list>\n <ion-item>\n <ion-label>Frequency (in milliseconds)</ion-label>\n <ion-input\n [formControlName]=\"'period'\"\n slot=\"end\"\n text-right\n type=\"number\"\n ></ion-input>\n </ion-item>\n <ion-item *ngIf=\"showDataSource\">\n <ion-label>Data source</ion-label>\n <ion-select [formControlName]=\"'dataSource'\" slot=\"end\">\n <ion-select-option value=\"live\">Live data</ion-select-option>\n <ion-select-option value=\"datalog\">Data log</ion-select-option>\n </ion-select>\n </ion-item>\n </ion-list>\n </form>\n</ion-content>\n<ion-footer>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button (click)=\"dismiss()\">Ok</ion-button>\n </ion-buttons>\n </ion-toolbar>\n</ion-footer>\n" }]
}], ctorParameters: function () { return [{ type: i1.FormBuilder }, { type: MonitoringSettingsService }, { type: i1$1.ModalController }]; }, propDecorators: { showDataSource: [{
type: Input
}] } });
class TapMonitoringSettingsModule {
}
/** @nocollapse */ TapMonitoringSettingsModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapMonitoringSettingsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
/** @nocollapse */ TapMonitoringSettingsModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: TapMonitoringSettingsModule, declarations: [TapMonitoringSettingsComponent], imports: [CommonModule, IonicModule, ReactiveFormsModule], exports: [TapMonitoringSettingsComponent] });
/** @nocollapse */ TapMonitoringSettingsModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapMonitoringSettingsModule, imports: [CommonModule, IonicModule, ReactiveFormsModule] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapMonitoringSettingsModule, decorators: [{
type: NgModule,
args: [{
declarations: [TapMonitoringSettingsComponent],
exports: [TapMonitoringSettingsComponent],
entryComponents: [TapMonitoringSettingsComponent],
imports: [CommonModule, IonicModule, ReactiveFormsModule],
}]
}] });
class ChartDataModel {
constructor() {
this.subList = [];
this.currentData = [];
}
initLabel(indexOrArray) {
if (indexOrArray) {
this.labels = indexOrArray;
}
}
initVariable(variableOrArray) {
if (!variableOrArray) {
return [];
}
const vArray = Array.isArray(variableOrArray)
? variableOrArray
: [variableOrArray];
return vArray.map((variable) => {
return {
stream: variable.values,
label: variable.id?.toString() || '',
};
});
}
/**
* @param inputs data inputs
* @param history to show data with time
* @param valueCountLimit when history has true, this one define the limit of length
*/
defineInputStreamSingle(inputs, history, valueCountLimit, forceHistory) {
this.currentData = inputs;
return new Observable((observer) => {
let results = [];
if (inputs) {
if (!Array.isArray(inputs)) {
inputs = [inputs];
}
inputs.forEach((input) => {
if (input) {
const inputStream = input;
this.subList.push(inputStream.stream.subscribe({
next: (data) => {
if (Array.isArray(data) && !forceHistory) {
if (data.length > 1) {
history = false;
}
}
let i = 0;
if (history) {
if (Array.isArray(data)) {
const vals = JSON.parse('{"name": "' + this.currentDate() + '"}');
data.forEach((d) => {
vals[i] = d;
i++;
});
results.push(vals);
results = [
...results.map((r) => {
let newKeys = {};
let i = 0;
for (const [key, value] of Object.entries(r)) {
if (key !== 'name') {
if (typeof key === 'number') {
newKeys[key] = this.labelConfig(key, input.label);
}
else {
newKeys[key] = this.labelConfig(i, input.label);
}
}
else {
newKeys[key] = key;
}
if (!(key === 'name' && i === 0)) {
i++;
}
}
const renamedObj = this.renameKeys(r, newKeys);
const mappedObj = {};
mappedObj['name'] = renamedObj['name'];
for (const [key, v] of Object.entries(renamedObj)) {
if (key !== 'name') {
mappedObj[key] = v;
}
}
return mappedObj;
}),
];
const itemCount = results.length;
if (valueCountLimit !== undefined &&
itemCount > valueCountLimit) {
const toRemove = itemCount - valueCountLimit;
results.splice(0, toRemove);
}
}
else {
results.push({
name: this.currentDate(),
value: data,
extra: 0,
});
const itemCount = results.length;
if (valueCountLimit !== undefined &&
itemCount > valueCountLimit) {
const toRemove = itemCount - valueCountLimit;
results.splice(0, toRemove);
}
}
}
else {
if (Array.isArray(data)) {
data.map(() => {
results[i] = {
name: this.labelConfig(i, input.label),
value: data[i],
extra: i,
};
i++;
});
}
else {
results[i] = {
name: this.labelConfig(i, input.label),
value: data,
extra: i,
};
}
}
results = [...results];
observer.next(results);
},
error: (err) => {
console.log(err);
observer.next([]);
},
}));
}
});
}
});
}
defineMultiInputStream(inputs) {
this.currentData = inputs;
return new Observable((observer) => {
let results = [];
let indexInputs = 0;
inputs.forEach((input) => {
this.subList.push(input.stream.subscribe({
next: (values) => {
let indexInput = 0;
if (!Array.isArray(values)) {
values = [values];
}
values.map((value) => {
let indexOfLabel = 0;
for (const inputLabel of inputs) {
if (inputLabel.label === input.label) {
indexInputs = indexOfLabel;
}
indexOfLabel++;
}
if (!results[indexInput]) {
results[indexInput] = {
name: this.labelConfig(indexInput, 'Index '),
series: [],
};
}
results[indexInput].series[indexInputs] = {
name: inputs[indexInputs].label,
value: value,
extra: indexInput,
};
indexInput++;
});
results = [...results];
observer.next(results);
},
error: (err) => {
console.log(err);
observer.next([]);
},
}));
});
});
}
defineMultiInputStreamTable(inputs) {
this.currentData = inputs;
return new Observable((observer) => {
let results = [];
inputs.forEach((input) => {
let indexValues = 0;
this.subList.push(input.stream.subscribe({
next: (values) => {
let indexOfLabel = 0;
for (const inputLabel of inputs) {
if (inputLabel.label === input.label) {
indexValues = indexOfLabel;
}
indexOfLabel++;
}
const vals = JSON.parse('{"Name": "' + input.label + '"}');
let turn = 0;
if (!Array.isArray(values)) {
values = [values];
}
for (const val of values) {
vals[this.labelConfig(turn, 'Index')] = val;
turn++;
}
results[indexValues] = vals;
results = [...results];
observer.next(results);
},
error: (error) => {
console.log(error);
observer.next([]);
},
}));
});
});
}
defineInputStreamMulti(inputs, history, valueCountLimit) {
this.currentData = inputs;
return new Observable((observer) => {
let results = [];
if (inputs) {
if (!Array.isArray(inputs)) {
inputs = [inputs];
}
inputs.map((input) => {
const inputStream = input;
this.subList.push(inputStream.stream.subscribe({
next: (data) => {
const seriesData = [];
let indexLabel = 0;
if (history) {
if (Array.isArray(data)) {
data.forEach((element) => {
seriesData.push({
name: this.labelConfig(indexLabel, inputStream.label),
value: element,
extra: indexLabel,
});
indexLabel++;
});
results.push({
name: this.currentDate(),
series: seriesData,
});
const itemCount = results.length;
if (valueCountLimit !== undefined &&
itemCount > valueCountLimit) {
const toRemove = itemCount - valueCountLimit;
results.splice(0, toRemove);
}
}
else {
results.push({
name: new Date(),
series: [
{
name: inputStream.label,
value: data,
extra: 0,
},
],
});
const itemCount = results.length;
if (valueCountLimit !== undefined &&
itemCount > valueCountLimit) {
const toRemove = itemCount - valueCountLimit;
results.splice(0, toRemove);
}
}
}
else {
if (Array.isArray(data)) {
data.map((element) => {
seriesData.push({
name: this.labelConfig(indexLabel, inputStream.label),
value: element,
extra: indexLabel,
});
indexLabel++;
});
results = [
{
name: inputStream.label,
series: seriesData,
},
];
}
else {
results = [
{
name: inputStream.label,
series: [
{
name: this.labelConfig(indexLabel, inputStream.label),
value: data,
extra: indexLabel,
},
],
},
];
}
}
results = [...results];
observer.next(results);
},
error: (err) => {
console.log(err);
observer.next([]);
},
}));
});
}
});
}
defineInputStreamHistoryMultiLegend(inputs, valueCountLimit) {
this.currentData = inputs;
return new Observable((observer) => {
let results = [];
if (inputs) {
if (!Array.isArray(inputs)) {
inputs = [inputs];
}
results = [];
inputs.map((input) => {
if (input.stream) {
const inputStream = input;
this.subList.push(inputStream.stream.subscribe({
next: (value) => {
let indexLabel = 0;
if (Array.isArray(value)) {
value.map(() => {
if (!results[indexLabel]) {
results.push({
name: this.labelConfig(indexLabel, inputStream.label),
series: [],
});
}
else {
results[indexLabel].name = this.labelConfig(indexLabel, inputStream.label);
}
results[indexLabel].series.push({
name: new Date(),
value: value[indexLabel],
extra: indexLabel,
});
const itemCount = results[indexLabel].series.length;
if (valueCountLimit !== undefined &&
itemCount > valueCountLimit) {
const toRemove = itemCount - valueCountLimit;
results[indexLabel].series.splice(0, toRemove);
}
indexLabel++;
});
}
else {
if (!results[0]) {
results.push({
name: inputStream.label,
series: [],
});
}
results[0].series.push({
name: new Date(),
value: value,
extra: 0,
});
const itemCount = results[0].series.length;
if (valueCountLimit !== undefined &&
itemCount > valueCountLimit) {
const toRemove = itemCount - valueCountLimit;
results[0].series.splice(0, toRemove);
}
}
results = [...results];
observer.next(results);
},
error: (err) => {
console.log(err);
observer.next([]);
},
}));
}
});
}
});
}
labelConfig(index, labelBundle) {
let labelToReturn = '';
if (typeof this.labels === 'function') {
labelToReturn = this.labels(index);
}
else if (!this.labels) {
labelToReturn = labelBundle + (index + 1);
}
else {
if (Array.isArray(this.labels)) {
if (this.labels[index]) {
labelToReturn = this.labels[index];
}
else {
labelToReturn = labelBundle + (index + 1);
}
}
else if (!Array.isArray(this.labels) && index < 1) {
labelToReturn = this.labels;
}
else if (!Array.isArray(this.labels) && index > 0) {
labelToReturn = labelBundle + (index + 1);
}
}
return labelToReturn;
}
digit(n) {
return n > 9 ? '' + n : '0' + n;
}
renameKeys(obj, newKeys) {
const keyValues = Object.entries(obj).map(([key, value]) => {
const newKey = newKeys[key] || key;
return { [newKey]: value };
});
return Object.assign({}, ...keyValues);
}
async showDetail(event, mod, component) {
const modal = await mod.create({
component: component,
cssClass: 'modal-class',
componentProps: {
label: event.label,
value: event.value,
index: event.extra,
variable: this.currentData[0],
},
});
return await modal.present();
}
currentDate() {
return ('' +
this.digit(+new Date().getHours()) +
':' +
this.digit(+new Date().getMinutes()) +
':' +
this.digit(+new Date().getSeconds()));
}
destroyCurrentSub() {
for (const sub of this.subList) {
sub.unsubscribe();
}
}
}
class ExportDataFormat {
}
function dataWithSeriesToCsv(dataReceive) {
if (dataReceive.length === 0) {
return [];
}
else {
const data = [];
dataReceive[0].series.forEach((value) => {
const element = {};
if (!isNaN(new Date(value.name).getDate())) {
element['time'] = value.name;
}
else {
element['label'] = value.name;
}
dataReceive.forEach((a) => {
const tab = a.series.filter((n) => value.name.toString() === n.name.toString());
if (tab.length !== 0) {
if (!element[a.name]) {
element[a.name] = tab[0].value;
}
}
});
data.push(element);
});
return data;
}
}
class TapVariableDataPopupComponent {
set variable(inputs) {
this.results.push({
name: this.label,
series: [],
});
inputs.stream.pipe(takeUntil(this.destroyed)).subscribe((value) => {
if (Array.isArray(value)) {
this.currentValue = value[this.index];
}
else {
this.currentValue = value;
}
const seriesData = {
name: new Date(),
value: this.currentValue,
extra: 0,
};
this.results[0].series.push(seriesData);
const itemCount = this.results[0].series.length;
if (itemCount > 10) {
const toRemove = itemCount - 10;
this.results[0].series.splice(0, toRemove);
}
this.results = [...this.results];
});
}
constructor(modalController) {
this.modalController = modalController;
this.legend = false;
this.showLabels = false;
this.animations = true;
this.xAxis = true;
this.yAxis = true;
this.showYAxisLabel = false;
this.showXAxisLabel = false;
this.timeline = false;
this.colorScheme = {
domain: ['#5AA454', '#A10A28', '#C7B42C', '#AAAAAA'],
};
this.results = [];
this.destroyed = new Subject();
this.currentDate =
'' +
this.digit(+new Date().getHours()) +
':' +
this.digit(+new Date().getMinutes()) +
':' +
this.digit(+new Date().getSeconds());
}
ngOnDestroy() {
this.destroyed.next();
}
async dismissModal() {
await this.modalController.dismiss();
}
digit(n) {
return n > 9 ? '' + n : '0' + n;
}
}
/** @nocollapse */ TapVariableDataPopupComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapVariableDataPopupComponent, deps: [{ token: i1$1.ModalController }], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ TapVariableDataPopupComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: TapVariableDataPopupComponent, selector: "tap-tap-variable-data-popup", inputs: { value: "value", label: "label", index: "index", variable: "variable" }, ngImport: i0, template: "<ion-header translucent>\n <ion-toolbar>\n <ion-buttons slot=\"start\">\n <ion-button (click)=\"dismissModal()\"\n ><ion-icon name=\"arrow-back-outline\"></ion-icon\n ></ion-button>\n </ion-buttons>\n <ion-title>{{ label }}</ion-title>\n <ion-buttons slot=\"end\">\n <span>Details</span>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n<ion-content>\n <ion-list>\n <ion-item>\n <ion-label>Value on click</ion-label>\n <ion-note class=\"value\" slot=\"end\">{{ value }}</ion-note>\n </ion-item>\n <ion-item>\n <ion-label>Time on click</ion-label>\n <ion-note class=\"value\" slot=\"end\">{{ currentDate }}</ion-note>\n </ion-item>\n\n <ion-item>\n <ion-label>Current value</ion-label>\n <ion-note class=\"value\" slot=\"end\">{{ currentValue }}</ion-note>\n </ion-item>\n\n <!-- <ion-item>\n <ion-label>Dynamic graphic</ion-label>\n <div #containerRef style=\"height: 30vh; width: 100%\">\n <ngx-charts-line-chart\n [view]=\"[containerRef.offsetWidth, containerRef.offsetHeight]\"\n [scheme]=\"colorScheme\"\n [showXAxisLabel]=\"showXAxisLabel\"\n [showYAxisLabel]=\"showYAxisLabel\"\n [legend]=\"legend\"\n [xAxis]=\"xAxis\"\n [yAxis]=\"yAxis\"\n [timeline]=\"timeline\"\n [results]=\"results\"\n >\n </ngx-charts-line-chart>\n </div>\n </ion-item> -->\n </ion-list>\n</ion-content>\n", styles: [".my-custom-modal-css{--background: transparent !important}.value{font-size:1.3em;font-weight:700}\n"], dependencies: [{ kind: "component", type: i1$1.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i1$1.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i1$1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i1$1.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i1$1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i1$1.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i1$1.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i1$1.IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: i1$1.IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "component", type: i1$1.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: i1$1.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapVariableDataPopupComponent, decorators: [{
type: Component,
args: [{ selector: 'tap-tap-variable-data-popup', template: "<ion-header translucent>\n <ion-toolbar>\n <ion-buttons slot=\"start\">\n <ion-button (click)=\"dismissModal()\"\n ><ion-icon name=\"arrow-back-outline\"></ion-icon\n ></ion-button>\n </ion-buttons>\n <ion-title>{{ label }}</ion-title>\n <ion-buttons slot=\"end\">\n <span>Details</span>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n<ion-content>\n <ion-list>\n <ion-item>\n <ion-label>Value on click</ion-label>\n <ion-note class=\"value\" slot=\"end\">{{ value }}</ion-note>\n </ion-item>\n <ion-item>\n <ion-label>Time on click</ion-label>\n <ion-note class=\"value\" slot=\"end\">{{ currentDate }}</ion-note>\n </ion-item>\n\n <ion-item>\n <ion-label>Current value</ion-label>\n <ion-note class=\"value\" slot=\"end\">{{ currentValue }}</ion-note>\n </ion-item>\n\n <!-- <ion-item>\n <ion-label>Dynamic graphic</ion-label>\n <div #containerRef style=\"height: 30vh; width: 100%\">\n <ngx-charts-line-chart\n [view]=\"[containerRef.offsetWidth, containerRef.offsetHeight]\"\n [scheme]=\"colorScheme\"\n [showXAxisLabel]=\"showXAxisLabel\"\n [showYAxisLabel]=\"showYAxisLabel\"\n [legend]=\"legend\"\n [xAxis]=\"xAxis\"\n [yAxis]=\"yAxis\"\n [timeline]=\"timeline\"\n [results]=\"results\"\n >\n </ngx-charts-line-chart>\n </div>\n </ion-item> -->\n </ion-list>\n</ion-content>\n", styles: [".my-custom-modal-css{--background: transparent !important}.value{font-size:1.3em;font-weight:700}\n"] }]
}], ctorParameters: function () { return [{ type: i1$1.ModalController }]; }, propDecorators: { value: [{
type: Input
}], label: [{
type: Input
}], index: [{
type: Input
}], variable: [{
type: Input
}] } });
class ExportDataService {
constructor(file, platform) {
this.file = file;
this.platform = platform;
}
async triggerDownload(blob, filename) {
if (this.platform.is('cordova')) {
const directory = this.getDownloadDirectory();
filename = await this.ensureFileNameAvailable(directory, filename);
await this.file.writeFile(directory, filename, blob);
return directory;
}
else {
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.setAttribute('visibility', 'hidden');
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
return undefined;
}
}
getDownloadDirectory() {
let directory;
if (this.file.externalRootDirectory) {
directory = this.file.externalRootDirectory;
if (this.platform.is('android')) {
directory += 'Download/';
}
}
else if (this.file.dataDirectory) {
directory = this.file.dataDirectory;
}
else if (this.file.documentsDirectory) {
directory = this.file.documentsDirectory;
}
if (!directory) {
throw new Error('Cannot find a valid directory to download the log file');
}
return directory;
}
async ensureFileNameAvailable(directory, filename) {
const parts = filename.split('.');
const extension = parts.length > 1 ? '.' + parts[parts.length - 1] : '';
const filenameWithoutExt = parts.length > 1 ? parts.slice(0, parts.length - 1).join('.') : parts[0];
let count = 1;
while (await this.file
.checkFile(directory, filename)
.then((_) => true)
.catch((err) => {
console.log('Check file err', err);
return false;
})) {
filename = `${filenameWithoutExt} (${count})${extension}`;
count++;
}
return filename;
}
}
/** @nocollapse */ ExportDataService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ExportDataService, deps: [{ token: i1$2.File }, { token: i1$1.Platform }], target: i0.ɵɵFactoryTarget.Injectable });
/** @nocollapse */ ExportDataService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ExportDataService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ExportDataService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}], ctorParameters: function () { return [{ type: i1$2.File }, { type: i1$1.Platform }]; } });
class ExportDataDirective {
constructor(alertController, platform, dataToExportService) {
this.alertController = alertController;
this.platform = platform;
this.dataToExportService = dataToExportService;
this.exportDataError = new EventEmitter();
}
async onClickEvent() {
if (this.exportedFileName === undefined) {
this.exportedFileName = 'data';
}
let alert;
let data = typeof this.dataToExport === 'function'
? this.dataToExport()
: this.dataToExport;
if (data?.length !== 0) {
if (!this.format) {
alert = await this.alertController.create({
header: 'Export data',
cssClass: 'custom-alert',
message: 'Select file format',
buttons: [
{
text: 'CSV',
handler: async () => {
this.exportToCsv(data);
},
},
{
text: 'JSON',
handler: () => {
this.exportToJson(data);
},
},
],
});
await alert.present();
}
else {
switch (this.format) {
case 'csv':
await this.exportToCsv(data);
break;
case 'json':
await this.exportToJson(data);
break;
}
}
}
else {
const alert = await this.alertController.create({
header: 'Export data',
message: 'Cannot export empty data.',
buttons: [
{
text: 'OK',
},
],
});
await alert.present();
}
}
exportToJson(data) {
try {
this.dataToExportService.triggerDownload(new Blob([JSON.stringify(data, null, 4)]), `${this.exportedFileName}.json`);
}
catch (e) {
this.exportDataError.emit(e);
}
}
async exportToCsv(data) {
try {
if (data) {
if (!this.exportedFileName) {
this.exportedFileName = 'data';
}
const csvExport = new ExportToCsv(data, this.exportedFileName, {
headers: Object.keys(data[0]),
});
const csvString = csvExport.csvToString();
await this.dataToExportService.triggerDownload(new Blob([csvString]), `${this.exportedFileName}.csv`);
}
}
catch (e) {
this.exportDataError.emit(e);
}
}
}
/** @nocollapse */ ExportDataDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ExportDataDirective, deps: [{ token: i1$1.AlertController }, { token: i1$1.Platform }, { token: ExportDataService }], target: i0.ɵɵFactoryTarget.Directive });
/** @nocollapse */ ExportDataDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.10", type: ExportDataDirective, selector: "[tapExportData]", inputs: { exportedFileName: "exportedFileName", dataToExport: "dataToExport", format: "format" }, outputs: { exportDataError: "exportDataError" }, host: { listeners: { "click": "onClickEvent()" } }, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ExportDataDirec