@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
1,230 lines • 83.3 kB
JavaScript
import * as i0 from '@angular/core';
import { Pipe, Injectable, inject, ViewChild, Input, Component, Optional, EventEmitter, forwardRef, Output } from '@angular/core';
import * as i1 from '@c8y/ngx-components';
import { ThemeSwitcherService, MeasurementRealtimeService, DatePipe, CommonModule, FormGroupComponent, MessagesComponent, FormsModule } from '@c8y/ngx-components';
import * as i1$2 from '@angular/common';
import { AsyncPipe, NgIf, NgFor, NgStyle, DecimalPipe } from '@angular/common';
import { of, BehaviorSubject, switchMap, tap, Subject, takeUntil, debounceTime } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import * as i2 from '@c8y/ngx-components/context-dashboard';
import { defaultWidgetIds } from '@c8y/ngx-components/widgets/definitions';
import * as i1$1 from 'ngx-echarts';
import { NgxEchartsModule, NGX_ECHARTS_CONFIG } from 'ngx-echarts';
import { gettext } from '@c8y/ngx-components/gettext';
import * as i1$3 from '@angular/forms';
import { NG_VALUE_ACCESSOR, Validators, NgForm, ControlContainer, ReactiveFormsModule } from '@angular/forms';
import * as i5 from '@c8y/ngx-components/datapoint-selector';
import { DatapointSelectorModule } from '@c8y/ngx-components/datapoint-selector';
import { EditorComponent, MonacoEditorMarkerValidatorDirective } from '@c8y/ngx-components/editor';
import * as i4 from 'ngx-bootstrap/collapse';
import { CollapseModule } from 'ngx-bootstrap/collapse';
const INFO_GAUGE_COLORS = {
GREEN: 'var(--c8y-brand-50)',
YELLOW: 'var(--c8y-palette-status-warning)',
RED: 'var(--c8y-palette-status-danger)'
};
class InfoGaugeCurrentMeasurementPipe {
constructor(measurementRealtime, alert) {
this.measurementRealtime = measurementRealtime;
this.alert = alert;
}
transform(datapoint, calculateGauge) {
return this.measurementRealtime
.latestValueOfSpecificMeasurement$(datapoint.fragment, datapoint.series, datapoint.__target, 1, true)
.pipe(map(m => {
// in case measurement is not stored in DB when initially requested.
if (!m) {
return { value: Number.NaN, date: '', unit: datapoint.unit || '', notFound: true };
}
const measurementValue = m[datapoint.fragment][datapoint.series];
const data = {
value: measurementValue.value,
unit: measurementValue.unit || datapoint.unit,
date: m.time
};
if (!calculateGauge) {
return data;
}
const gauge = this.calculateGauge(datapoint, measurementValue.value);
return { ...data, ...gauge };
}), catchError(e => {
this.alert.addServerFailure(e);
return of({ value: Number.NaN, date: '', unit: '' });
}));
}
calculateGauge(datapoint, value) {
const val = value;
const min = Number(datapoint.min || 0);
const max = Number(datapoint.max || 0);
const yMin = Number(datapoint.yellowRangeMin);
const yMax = Number(datapoint.yellowRangeMax);
const rMin = Number(datapoint.redRangeMin);
const rMax = Number(datapoint.redRangeMax);
// Previously d3 was used for linear scale: d3.scale.linear().domain([min, max]).range([0, 100]);
// wanted to avoid importing d3 just for this.
const scale = (value1) => (value1 - min) / ((max - min) / 100);
const strokeDashOffset = 125.75 + (377.25 - (scale(val) / 100) * 377.25);
let color = INFO_GAUGE_COLORS.GREEN;
if (Number.isFinite(yMin) && Number.isFinite(yMax)) {
if (val >= yMin && val <= yMax) {
color = INFO_GAUGE_COLORS.YELLOW;
}
}
if (Number.isFinite(rMin) && Number.isFinite(rMax)) {
if (val >= rMin && val <= rMax) {
color = INFO_GAUGE_COLORS.RED;
}
}
return { color, strokeDashOffset };
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: InfoGaugeCurrentMeasurementPipe, deps: [{ token: i1.MeasurementRealtimeService }, { token: i1.AlertService }], target: i0.ɵɵFactoryTarget.Pipe }); }
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: InfoGaugeCurrentMeasurementPipe, isStandalone: true, name: "infoGaugeCurrentMeasurement" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: InfoGaugeCurrentMeasurementPipe, decorators: [{
type: Pipe,
args: [{
name: 'infoGaugeCurrentMeasurement',
pure: true,
standalone: true
}]
}], ctorParameters: () => [{ type: i1.MeasurementRealtimeService }, { type: i1.AlertService }] });
const GAUGE_PRESET_NAMES = {
DEFAULT: gettext('Default'),
CUSTOM: gettext('Custom preset'),
POINTER: gettext('Pointer'),
PROGRESS_BAR: gettext('Progress bar'),
PROGRESS_INDICATOR: gettext('Progress indicator'),
GRADE_RATING: gettext('Grade rating')
};
const GAUGE_PRESETS = [
{
// General properties
name: GAUGE_PRESET_NAMES.DEFAULT,
id: 'default',
radius: '90%',
startAngle: 240,
endAngle: 300,
// Split properties
splitNumber: 10,
splitLineLengthRatio: 0.3,
splitLineColor: '#fff',
splitLineWidth: 4,
splitLineDistanceRatio: -0.3,
// Tick properties
tickShow: true,
tickDistanceRatio: -0.16,
tickWidth: 2,
tickColor: '#fff',
tickLengthRatio: 0.16,
// Axis properties
axisLabelDistanceRatio: 0.25,
axisLabelColor: 'black',
axisLabelFontSizeMin: 8,
axisLabelFontSizeRatio: 0.04,
axisLabelFontSizeMax: 32,
axisLineWidthRatio: 0.125,
// Pointer properties
showPointer: true,
pointerColor: '#222',
pointerStyle: 'triangle',
pointerWidthRatio: 2,
pointerLength: '55%',
pointerOffset: 0,
// Progress bar properties
progressBar: false,
progressBarColor: '#119d11',
// Detail properties
showDetail: false,
showMarkPoint: true,
// Typography & Anchor
measurementValueFontRatio: 0.08,
measurementValueFontMin: 16,
measurementValueFontMax: 56,
measurementValueColor: 'white',
unitFontSize: 18,
unitFontRatio: 0.045,
unitFontMin: 14,
unitFontMax: 40,
unitColor: 'white',
dateFontSize: 0.001,
dateFontRatio: 0.03,
dateFontMin: 10,
dateFontMax: 16,
dateColor: 'gray',
anchor: {
show: true,
sizeRatio: 0.5,
itemStyle: {
color: '#222' // Color of the anchor
}
}
},
{
// General properties
name: GAUGE_PRESET_NAMES.POINTER,
id: 'pointer',
radius: '90%',
startAngle: 240,
endAngle: 300,
// Split properties
splitNumber: 10,
splitLineLengthRatio: 1,
splitLineColor: '#fff',
splitLineWidth: 4,
splitLineDistanceRatio: -1,
// Tick properties
tickShow: true,
tickDistanceRatio: -1,
tickWidth: 2,
tickColor: '#fff',
tickLengthRatio: 0.2666666667,
// Axis properties
axisLabelColor: '#212121',
axisLabelFontSizeMin: 8,
axisLabelFontSizeRatio: 0.04,
axisLabelFontSizeMax: 32,
axisLineWidthRatio: 0.075,
axisLabelDistanceRatio: 1.1666666667,
// Pointer properties
showPointer: true,
pointerStyle: 'default',
pointerColor: 'black',
pointerWidthRatio: 0.2666666667,
pointerLength: '70%',
pointerOffset: 5,
// Progress bar properties
progressBar: false,
progressBarColor: '#119d11',
// Detail properties
showDetail: true,
detailOffsetCenter: ['0%', '35%'],
showMarkPoint: false,
// Typography specs
measurementValueFontRatio: 0.08,
measurementValueFontMin: 16,
measurementValueFontMax: 56,
measurementValueColor: 'black',
unitFontSize: 18,
unitFontRatio: 0.045,
unitFontMin: 8,
unitFontMax: 40,
unitColor: 'black',
dateFontRatio: 0.03,
dateFontMin: 10,
dateFontMax: 16,
dateColor: 'black'
},
{
// General properties
name: GAUGE_PRESET_NAMES.PROGRESS_BAR,
id: 'progress-bar',
radius: '85%',
center: ['50%', '57%'],
startAngle: 200,
endAngle: -20,
// Split properties
splitNumber: 10,
splitLineLengthRatio: 1,
splitLineColor: '#fff',
splitLineWidth: 3,
splitLineDistanceRatio: -1,
// Tick properties
tickShow: false,
// Axis properties
axisLabelColor: '#212121',
axisLabelFontSizeMin: 8,
axisLabelFontSizeRatio: 0.04,
axisLabelFontSizeMax: 32,
axisLineWidthRatio: 0.075,
axisLabelDistanceRatio: -0.8,
// Pointer properties
showPointer: false,
// Progress bar properties
progressBar: true,
progressBarWidthRatio: 0.3333,
progressBarRoundCap: false,
progressBarColor: '#119d11',
additionalGaugeColors: ['#FFAB91', '#FD7347'],
// Detail properties
showDetail: true,
detailOffsetCenter: ['0%', '0%'],
showMarkPoint: false,
// Typography specs
measurementValueFontRatio: 0.12,
measurementValueFontMin: 16,
measurementValueFontMax: 72,
measurementValueColor: 'black',
unitFontSize: 18,
unitFontRatio: 0.085,
unitFontMin: 10,
unitFontMax: 40,
unitColor: 'black',
dateFontRatio: 0.03,
dateFontMin: 10,
dateFontMax: 16,
dateColor: 'black'
},
{
// General properties
name: GAUGE_PRESET_NAMES.PROGRESS_INDICATOR,
id: 'progress-indicator',
radius: '85%',
startAngle: 240,
endAngle: 300,
// Split line properties
splitNumber: 4,
splitLineLengthRatio: 1,
splitLineColor: '#fff',
splitLineWidth: 2,
splitLineDistanceRatio: -1,
// Tick properties
tickShow: false,
// Axis properties
axisLabelColor: '#212121',
axisLabelFontSizeMin: 7,
axisLabelFontSizeRatio: 0.04,
axisLabelFontSizeMax: 32,
axisLineWidthRatio: 0.075,
axisLabelDistanceRatio: -1,
// Pointer properties
showPointer: true,
pointerStyle: 'default',
pointerColor: 'black',
pointerWidthRatio: 0.2,
pointerLength: '100%',
pointerOffset: 5,
// Progress bar properties
progressBar: true,
progressBarWidthRatio: 0.3333,
progressBarRoundCap: false,
progressBarColor: '#119d11',
// Detail properties
showDetail: true,
detailOffsetCenter: ['0%', '35%'],
showMarkPoint: false,
// Typography & Anchor
measurementValueFontRatio: 0.08,
measurementValueFontMin: 12,
measurementValueFontMax: 56,
measurementValueColor: 'black',
unitFontSize: 18,
unitFontRatio: 0.045,
unitFontMin: 10,
unitFontMax: 40,
unitColor: 'black',
dateFontRatio: 0.03,
dateFontMin: 10,
dateFontMax: 16,
dateColor: 'black',
anchor: {
show: true,
showAbove: true,
sizeRatio: 0.1,
itemStyle: {
borderWidth: 10
}
}
},
{
// General properties
name: GAUGE_PRESET_NAMES.GRADE_RATING,
id: 'grade-rating',
radius: '75%',
startAngle: 180,
endAngle: 360,
center: ['50%', '65%'],
// Split line properties
splitNumber: 4,
splitLineLengthRatio: 3,
splitLineColor: 'auto',
splitLineWidth: 6,
splitLineDistanceRatio: -3,
// Tick properties
tickShow: true,
tickDistanceRatio: -2,
tickWidth: 2,
tickColor: 'auto',
tickLengthRatio: 2,
// Axis properties
axisLabelDistanceRatio: -6,
axisLabelColor: 'auto',
axisLabelFontSizeMin: 6,
axisLabelFontSizeRatio: 0.04,
axisLabelFontSizeMax: 32,
axisLineWidthRatio: 0.02,
// Pointer properties
showPointer: true,
pointerColor: 'black',
pointerStyle: 'triangle',
pointerWidthRatio: 2,
pointerLength: '12%',
pointerOffset: '-50%',
// Progress bar properties
progressBar: false,
progressBarColor: '#119d11',
// Detail properties
showDetail: true,
detailOffsetCenter: ['0%', '0%'],
showMarkPoint: false,
// Typography
measurementValueFontRatio: 0.08,
measurementValueFontMin: 16,
measurementValueFontMax: 56,
measurementValueColor: 'black',
unitFontRatio: 0.045,
unitFontMin: 8,
unitFontMax: 40,
unitColor: 'black',
dateFontRatio: 0.03,
dateFontMin: 10,
dateFontMax: 16,
dateColor: 'black'
}
];
class RadialGaugeService {
constructor(c8yDatePipe) {
this.c8yDatePipe = c8yDatePipe;
this.containerSize = 400;
}
setChart(chart) {
this.chart = chart;
}
getChartOptions(gaugeOptions, activeDatapointGauge, selectedPresetId, gaugeOptionsColors, rangeColors, measurement, fractionSize) {
const colorArray = this.getColorArray(activeDatapointGauge, rangeColors);
return {
series: [
{
type: 'gauge',
radius: gaugeOptions?.radius || '90%',
center: gaugeOptions?.center || ['50%', '50%'],
startAngle: gaugeOptions?.startAngle || 240,
endAngle: gaugeOptions?.endAngle || 300,
min: activeDatapointGauge?.min || 0,
max: activeDatapointGauge?.max !== undefined && activeDatapointGauge?.max !== null
? activeDatapointGauge.max
: 100,
// Split properties
splitNumber: gaugeOptions?.splitNumber || 10,
splitLine: {
distance: gaugeOptions?.splitLineDistanceRatio
? this.containerSize *
gaugeOptions?.axisLineWidthRatio *
gaugeOptions?.splitLineDistanceRatio
: gaugeOptions?.splitLineDistance || -30,
length: gaugeOptions?.splitLineLengthRatio
? this.containerSize *
gaugeOptions?.axisLineWidthRatio *
gaugeOptions?.splitLineLengthRatio
: gaugeOptions?.splitLineLength || 30,
lineStyle: {
color: selectedPresetId === 'custom' || selectedPresetId === 'grade-rating'
? gaugeOptions?.splitLineColor
: gaugeOptionsColors?.splitLineColor || '#fff',
width: gaugeOptions?.splitLineWidth || 4
}
},
// Tick properties
axisTick: {
show: gaugeOptions?.tickShow || false,
distance: gaugeOptions?.tickDistanceRatio
? this.containerSize *
gaugeOptions?.axisLineWidthRatio *
gaugeOptions?.tickDistanceRatio
: gaugeOptions?.tickDistance || -30,
length: gaugeOptions?.tickLengthRatio
? this.containerSize *
gaugeOptions?.axisLineWidthRatio *
gaugeOptions?.tickLengthRatio
: gaugeOptions?.tickLength || 8,
lineStyle: {
color: selectedPresetId === 'custom' || selectedPresetId === 'grade-rating'
? gaugeOptions.tickColor
: gaugeOptionsColors?.tickColor || '#fff',
width: gaugeOptions?.tickWidth || 2
}
},
// Axis properties
axisLine: {
lineStyle: {
width: gaugeOptions?.axisLineWidthRatio
? this.containerSize * gaugeOptions?.axisLineWidthRatio
: gaugeOptions?.axisLineWidth || 30,
color: colorArray
}
},
axisLabel: {
color: selectedPresetId === 'custom' || selectedPresetId === 'grade-rating'
? gaugeOptions.axisLabelColor
: gaugeOptionsColors?.axisLabelColor || 'inherit',
distance: gaugeOptions?.axisLabelDistanceRatio
? this.containerSize *
gaugeOptions?.axisLineWidthRatio *
gaugeOptions?.axisLabelDistanceRatio
: gaugeOptions?.axisLabelDistance || 40,
fontSize: gaugeOptions?.axisLabelFontSizeRatio
? this.clampRelative(gaugeOptions?.axisLabelFontSizeRatio, gaugeOptions?.axisLabelFontSizeMin, gaugeOptions?.axisLabelFontSizeMax)
: gaugeOptions?.axisLabelFontSize || 16,
fontWeight: 'bold',
fontFamily: gaugeOptionsColors?.fontFamily
},
// pointer properties
pointer: {
...(gaugeOptions?.pointerStyle !== 'default' && {
icon: gaugeOptions?.pointerStyle
}),
show: gaugeOptions?.showPointer || false,
length: gaugeOptions?.pointerLengthRatio
? gaugeOptions?.pointerLengthRatio *
(this.containerSize * gaugeOptions?.axisLineWidthRatio)
: gaugeOptions?.pointerLength || '65%',
width: gaugeOptions?.pointerWidthRatio
? this.containerSize *
gaugeOptions?.axisLineWidthRatio *
gaugeOptions?.pointerWidthRatio
: gaugeOptions?.pointerWidth || 40,
offsetCenter: selectedPresetId === 'default'
? [0, this.containerSize * gaugeOptions?.axisLineWidthRatio * -1]
: [0, gaugeOptions?.pointerOffset || -30],
itemStyle: {
color: selectedPresetId === 'custom'
? gaugeOptions.pointerColor
: gaugeOptionsColors?.pointerColor || 'inherit'
}
},
// Progress bar properties
progress: {
show: gaugeOptions?.progressBar || false,
roundCap: gaugeOptions?.progressBarRoundCap || false,
width: gaugeOptions?.progressBarWidthRatio
? this.containerSize *
gaugeOptions?.axisLineWidthRatio *
gaugeOptions?.progressBarWidthRatio
: gaugeOptions?.progressBarWidth || 18,
itemStyle: {
color: selectedPresetId === 'custom'
? gaugeOptions.progressBarColor
: gaugeOptionsColors?.progressBarColor || 'inherit'
}
},
// Anchor properties
anchor: gaugeOptions?.anchor
? {
...gaugeOptions.anchor,
size: gaugeOptions?.anchor?.sizeRatio
? this.containerSize * gaugeOptions?.anchor?.sizeRatio
: gaugeOptions?.anchor?.size || 45,
itemStyle: {
color: selectedPresetId === 'custom'
? gaugeOptions.pointerColor
: gaugeOptionsColors?.pointerColor
}
}
: undefined,
// Detail properties
detail: {
show: gaugeOptions?.showDetail || false,
valueAnimation: true,
offsetCenter: gaugeOptions?.detailOffsetCenterYRatio
? [0, gaugeOptions?.detailOffsetCenterYRatio * this.containerSize]
: gaugeOptions?.detailOffsetCenter || [0, 0],
formatter: () => {
const value = measurement?.value.toFixed(fractionSize) || 0;
const unit = activeDatapointGauge?.unit || measurement?.unit || '';
const date = new Date(measurement?.date);
const formattedDate = this.c8yDatePipe.transform(date);
return `{value|${value}}{unit|${unit}} \n {date|${formattedDate}} `;
},
color: 'inherit',
lineHeight: gaugeOptions?.measurementValueFontRatio
? this.clampRelative(gaugeOptions?.measurementValueFontRatio * 0.9, gaugeOptions?.measurementValueFontSizeMin, gaugeOptions?.measurementValueFontSizeMax)
: gaugeOptions?.measurementValueFontSize || 32,
rich: {
value: {
fontSize: gaugeOptions?.measurementValueFontRatio
? this.clampRelative(fractionSize > 5 || measurement?.value > 9999
? gaugeOptions?.measurementValueFontRatio * 0.5
: gaugeOptions?.measurementValueFontRatio, gaugeOptions?.measurementValueFontSizeMin, gaugeOptions?.measurementValueFontSizeMax)
: gaugeOptions?.measurementValueFontSize || 32,
fontWeight: 'bolder',
fontFamily: gaugeOptionsColors?.fontFamily,
color: selectedPresetId === 'custom'
? gaugeOptions.measurementValueColor
: gaugeOptionsColors?.measurementValueColor || '#777'
},
unit: {
fontSize: gaugeOptions?.unitFontRatio
? this.clampRelative(gaugeOptions?.unitFontRatio, gaugeOptions?.unitFontMin, gaugeOptions?.unitFontMax)
: gaugeOptions?.unitFontSize || 20,
fontFamily: gaugeOptionsColors?.fontFamily,
color: selectedPresetId === 'custom'
? gaugeOptions?.unitColor
: gaugeOptionsColors?.unitColor || '#999'
},
date: {
fontSize: gaugeOptions?.dateFontRatio
? this.clampRelative(gaugeOptions?.dateFontRatio, gaugeOptions?.dateFontSizeMin, gaugeOptions?.dateFontSizeMax)
: gaugeOptions?.dateFontSize || 12,
fontFamily: gaugeOptionsColors?.fontFamily,
color: selectedPresetId === 'custom'
? gaugeOptions?.dateColor
: gaugeOptionsColors?.dateColor || '#555'
}
}
},
markPoint: {
symbolSize: 0,
offsetCenter: gaugeOptions?.detailOffsetCenter || [0, 0],
data: [
{
x: '50%',
y: '50%',
label: {
show: gaugeOptions?.showMarkPoint,
formatter: () => {
const value = measurement?.value.toFixed(fractionSize) || 0;
const unit = activeDatapointGauge?.unit || measurement?.unit || '';
const date = new Date(measurement?.date);
const formattedDate = this.c8yDatePipe.transform(date);
return `{value|${value}}{unit|${unit}} \n {date|${formattedDate}} `;
},
color: '#fff',
align: 'center',
rich: {
value: {
fontSize: gaugeOptions?.measurementValueFontRatio
? this.clampRelative(fractionSize > 5
? gaugeOptions?.measurementValueFontRatio * 0.5
: gaugeOptions?.measurementValueFontRatio, fractionSize > 5
? gaugeOptions.measurementValueFontMin * 0.5
: gaugeOptions?.measurementValueFontSizeMin, gaugeOptions?.measurementValueFontSizeMax)
: gaugeOptions?.measurementValueFontSize || 32,
fontFamily: gaugeOptionsColors?.fontFamily,
fontWeight: 'bolder',
color: gaugeOptionsColors?.knobFontColor || '#777'
},
unit: {
fontSize: gaugeOptions?.unitFontRatio
? this.clampRelative(gaugeOptions?.unitFontRatio, gaugeOptions?.unitFontSizeMin, gaugeOptions?.unitFontSizeMax)
: gaugeOptions?.unitFontSize || 20,
fontFamily: gaugeOptionsColors?.fontFamily,
color: gaugeOptionsColors?.knobFontColor || '#999'
},
date: {
fontSize: gaugeOptions?.dateFontRatio
? this.clampRelative(gaugeOptions?.dateFontRatio, gaugeOptions?.dateFontSizeMin, gaugeOptions?.dateFontSizeMax)
: gaugeOptions?.dateFontSize || 12,
fontFamily: gaugeOptionsColors?.fontFamily,
color: gaugeOptionsColors?.knobFontColor || '#555'
}
}
}
}
]
},
data: [
{
value: 0 || measurement?.value
}
]
}
]
};
}
updateRangeColors() {
if (!this.chart) {
return;
}
return {
default: getComputedStyle(this.chart.nativeElement).getPropertyValue('--c8y-form-control-border-color-default'),
yellow: getComputedStyle(this.chart.nativeElement).getPropertyValue('--c8y-palette-status-warning'),
red: getComputedStyle(this.chart.nativeElement).getPropertyValue('--c8y-palette-status-danger')
};
}
updateGaugeOptionsColors() {
if (!this.chart) {
return;
}
return {
splitLineColor: getComputedStyle(this.chart.nativeElement).getPropertyValue('--c8y-root-component-background-default'),
tickColor: getComputedStyle(this.chart.nativeElement).getPropertyValue('--c8y-root-component-background-default'),
axisLabelColor: getComputedStyle(this.chart.nativeElement).getPropertyValue('--c8y-root-component-color-default'),
pointerColor: getComputedStyle(this.chart.nativeElement).getPropertyValue('--c8y-root-component-color-default'),
knobColor: getComputedStyle(this.chart.nativeElement).getPropertyValue('--c8y-root-component-color-default'),
knobFontColor: getComputedStyle(this.chart.nativeElement).getPropertyValue('--c8y-root-component-background-default'),
measurementValueColor: getComputedStyle(this.chart.nativeElement).getPropertyValue('--c8y-root-component-color-default'),
unitColor: getComputedStyle(this.chart.nativeElement).getPropertyValue('--c8y-root-component-color-default'),
dateColor: getComputedStyle(this.chart.nativeElement).getPropertyValue('--c8y-root-component-text-muted'),
progressBarColor: getComputedStyle(this.chart.nativeElement).getPropertyValue('--c8y-root-component-brand-primary'),
fontFamily: getComputedStyle(document.body).getPropertyValue('font-family')
};
}
getColorArray(activeDatapointGauge, rangeColors) {
const min = activeDatapointGauge?.min ?? 0;
const max = activeDatapointGauge?.max ?? 100;
const range = max - min;
const yellowMin = activeDatapointGauge?.yellowRangeMin;
const yellowMax = activeDatapointGauge?.yellowRangeMax;
const redMin = activeDatapointGauge?.redRangeMin;
const redMax = activeDatapointGauge?.redRangeMax;
const ranges = [];
// First add red range
if (redMin != null && redMax != null && redMin < redMax) {
ranges.push({ start: redMin, end: redMax, color: rangeColors.red });
}
// Then add yellow, but clip out any overlap with red
if (yellowMin != null && yellowMax != null && yellowMin < yellowMax) {
const redRange = ranges.find(r => r.color === rangeColors.red);
if (!redRange ||
yellowMax <= redRange.start || // yellow ends before red
yellowMin >= redRange.end // yellow starts after red
) {
// no overlap
ranges.push({ start: yellowMin, end: yellowMax, color: rangeColors.yellow });
}
else {
// partial overlap – split yellow into non-overlapping parts
if (yellowMin < redRange.start) {
ranges.push({
start: yellowMin,
end: Math.min(yellowMax, redRange.start),
color: rangeColors.yellow
});
}
if (yellowMax > redRange.end) {
ranges.push({
start: Math.max(yellowMin, redRange.end),
end: yellowMax,
color: rangeColors.yellow
});
}
}
}
// Sort by start position
ranges.sort((a, b) => a.start - b.start);
// Build segments
const segments = [];
let current = min;
for (const { start, end, color } of ranges) {
if (start > current) {
// Default fill before this range
segments.push([(start - min) / range, rangeColors.default]);
}
// Start color
segments.push([(start - min) / range, color]);
// End color
segments.push([(end - min) / range, color]);
current = Math.max(current, end);
}
// Fill remaining with default
if (current < max) {
segments.push([(current - min) / range, rangeColors.default]);
}
if (segments.length === 0 || segments[segments.length - 1][0] < 1) {
segments.push([1, rangeColors.default]);
}
return segments;
}
clampRelative(ratio, min, max) {
const clampedValue = this.containerSize * ratio;
if (clampedValue < min) {
return min;
}
else if (clampedValue > max) {
return max;
}
else {
return clampedValue;
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: RadialGaugeService, deps: [{ token: i1.DatePipe }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: RadialGaugeService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: RadialGaugeService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: () => [{ type: i1.DatePipe }] });
class RadialGaugeViewComponent {
constructor() {
this.fractionSize = 2;
this.selectedPresetId = '';
this.rangeColors = { default: '#E8EBED', yellow: '#ff8800', red: '#d70f0f' };
this.configChangedSubject = new BehaviorSubject(null);
this.themeSwitcherService = inject(ThemeSwitcherService);
this.radialGaugeService = inject(RadialGaugeService);
this.chartOptions$ = this.configChangedSubject.pipe(switchMap(() => of(this.radialGaugeService.getChartOptions(this.gaugeOptions, this.activeDatapointGauge, this.selectedPresetId, this.gaugeOptionsColors, this.rangeColors, this.measurement, this.fractionSize))), tap(options => {
if (this.echartsInstance) {
this.echartsInstance.setOption(options, false, true);
}
}));
}
ngOnInit() {
if (!this.gaugeOptions) {
this.gaugeOptions = GAUGE_PRESETS[0];
}
this.themeSubscription = this.themeSwitcherService.currentlyAppliedTheme$.subscribe(() => {
queueMicrotask(() => {
this.radialGaugeService.setChart(this.chart);
this.rangeColors = this.radialGaugeService.updateRangeColors();
this.gaugeOptionsColors = this.radialGaugeService.updateGaugeOptionsColors();
requestAnimationFrame(() => {
this.configChangedSubject.next();
});
});
});
}
ngAfterViewInit() {
this.resizeObserver = new ResizeObserver(entries => {
for (const entry of entries) {
if (entry.contentRect.width > 0 && entry.contentRect.height > 0) {
this.radialGaugeService.containerSize =
entry.contentRect.width >= entry.contentRect.height
? entry.contentRect.height
: entry.contentRect.width;
this.configChangedSubject.next();
}
}
});
this.resizeObserver.observe(this.chart.nativeElement);
}
ngOnDestroy() {
if (this.themeSubscription) {
this.themeSubscription.unsubscribe();
}
if (this.resizeObserver) {
this.resizeObserver.disconnect();
}
}
ngOnChanges(changes) {
if (changes.gaugeOptions || changes.measurement || changes.activeDatapointGauge) {
this.configChangedSubject.next();
}
}
onChartInit(ec) {
this.echartsInstance = ec;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: RadialGaugeViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: RadialGaugeViewComponent, isStandalone: true, selector: "c8y-radial-gauge", inputs: { activeDatapointGauge: "activeDatapointGauge", measurement: "measurement", fractionSize: "fractionSize", gaugeOptions: "gaugeOptions", selectedPresetId: "selectedPresetId" }, host: { classAttribute: "c8y-radial-gauge" }, providers: [
MeasurementRealtimeService,
RadialGaugeService,
{ provide: NGX_ECHARTS_CONFIG, useFactory: () => ({ echarts: () => import('echarts') }) }
], viewQueries: [{ propertyName: "chart", first: true, predicate: ["chart"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"p-absolute fit-w fit-h\"\n data-cy=\"c8y-radial-gauge--chart\"\n #chart\n echarts\n [options]=\"chartOptions$ | async\"\n (chartInit)=\"onChartInit($event)\"\n></div>\n", dependencies: [{ kind: "ngmodule", type: NgxEchartsModule }, { kind: "directive", type: i1$1.NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: RadialGaugeViewComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-radial-gauge', host: { class: 'c8y-radial-gauge' }, providers: [
MeasurementRealtimeService,
RadialGaugeService,
{ provide: NGX_ECHARTS_CONFIG, useFactory: () => ({ echarts: () => import('echarts') }) }
], standalone: true, imports: [AsyncPipe, NgxEchartsModule], template: "<div\n class=\"p-absolute fit-w fit-h\"\n data-cy=\"c8y-radial-gauge--chart\"\n #chart\n echarts\n [options]=\"chartOptions$ | async\"\n (chartInit)=\"onChartInit($event)\"\n></div>\n" }]
}], ctorParameters: () => [], propDecorators: { activeDatapointGauge: [{
type: Input
}], measurement: [{
type: Input
}], fractionSize: [{
type: Input
}], gaugeOptions: [{
type: Input
}], selectedPresetId: [{
type: Input
}], chart: [{
type: ViewChild,
args: ['chart', { static: false }]
}] } });
class InfoGaugeWidgetViewComponent {
constructor(dashboard, dynamicComponent) {
this.dashboard = dashboard;
this.dynamicComponent = dynamicComponent;
this.activeDatapointLabels = [];
this.fractionSize = '1.1-1';
}
ngOnInit() {
if (this.config?.datapoints && !this.config.datapointsGauge) {
this.config.datapointsGauge = this.config.datapoints;
}
}
ngOnChanges() {
if (this.config?.datapointsLabels && Array.isArray(this.config?.datapointsLabels)) {
this.config.datapointsLabels.forEach(dp => this.assignContextFromContextDashboard(dp));
this.activeDatapointLabels = this.config?.datapointsLabels.filter(dp => dp.__active);
}
if (this.config?.datapointsGauge && Array.isArray(this.config?.datapointsGauge)) {
this.config.datapointsGauge.forEach(dp => this.assignContextFromContextDashboard(dp));
this.activeDatapointGauge = this.config?.datapointsGauge.find(dp => dp.__active);
}
if (this.config?.datapoints &&
Array.isArray(this.config?.datapoints) &&
this.config?.datapoints.length > 0 &&
!this.config?.datapointsGauge) {
this.config.datapoints.forEach(dp => this.assignContextFromContextDashboard(dp));
this.activeDatapointGauge = this.config?.datapoints.find(dp => dp.__active);
}
if (this.config &&
typeof this.config.fractionSize === 'number' &&
!Number.isNaN(this.config.fractionSize)) {
this.fractionSize = `1.${this.config.fractionSize}-${this.config.fractionSize}`;
}
this.isInfoGauge = this.dynamicComponent?.componentId === defaultWidgetIds.INFO_GAUGE;
}
assignContextFromContextDashboard(datapoint) {
if (!this.dashboard?.isDeviceTypeDashboard) {
return;
}
const context = this.dashboard?.context;
if (context?.id) {
const { name, id } = context;
datapoint.__target = { name, id };
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: InfoGaugeWidgetViewComponent, deps: [{ token: i2.ContextDashboardComponent, optional: true }, { token: i1.DynamicComponentComponent, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: InfoGaugeWidgetViewComponent, isStandalone: true, selector: "c8y-info-gauge-widget-view", inputs: { config: "config" }, host: { classAttribute: "d-contents" }, providers: [MeasurementRealtimeService], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"label-value-unit-gauge new-radial\"\n *ngIf=\"isInfoGauge\"\n>\n <div\n class=\"gauge-legend\"\n *ngIf=\"activeDatapointLabels?.length && isInfoGauge\"\n >\n <ng-container *ngFor=\"let dp of activeDatapointLabels\">\n <ng-container *ngIf=\"dp | infoGaugeCurrentMeasurement | async as measurement\">\n <label\n class=\"text-truncate\"\n title=\"{{ dp.label }}\"\n >\n {{ dp.label }}\n </label>\n <h3\n class=\"text-truncate\"\n title=\"{{ measurement.value | number: fractionSize }} {{ dp.unit || measurement.unit }}\"\n *ngIf=\"!measurement.notFound; else notFound\"\n >\n {{ measurement.value | number: fractionSize }} {{ dp.unit || measurement.unit }}\n </h3>\n <ng-template #notFound>\n <h3>--</h3>\n </ng-template>\n <p class=\"text-muted m-b-8\">\n <small>\n <em>{{ measurement.date | c8yDate: 'short' }}</em>\n </small>\n </p>\n </ng-container>\n </ng-container>\n </div>\n\n <ng-container *ngIf=\"activeDatapointGauge && isInfoGauge\">\n <div\n class=\"gauge-svg\"\n *ngIf=\"activeDatapointGauge | infoGaugeCurrentMeasurement: true | async as measurement\"\n >\n <svg\n height=\"214px\"\n width=\"214px\"\n viewBox=\"0 0 214 214\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n >\n <desc>radial gauge</desc>\n <g\n id=\"scale\"\n stroke=\"none\"\n stroke-width=\"1\"\n fill=\"none\"\n fill-rule=\"evenodd\"\n stroke-dasharray=\"1,5\"\n >\n <circle\n id=\"Oval\"\n stroke=\"#CACECE\"\n stroke-width=\"7\"\n cx=\"107\"\n cy=\"107\"\n r=\"103\"\n ></circle>\n <rect\n id=\"mask\"\n height=\"214\"\n stroke=\"none\"\n fill-rule=\"evenodd\"\n x=\"0\"\n y=\"0\"\n width=\"214\"\n transform=\"rotate(-45 290 182)\"\n ></rect>\n </g>\n <path\n class=\"track\"\n d=\"M 107 27 a 80 80 0 1 0.1 0 Z\"\n transform=\"rotate(-135 107 107)\"\n ></path>\n <path\n class=\"track-value\"\n [ngStyle]=\"{\n stroke: measurement.color,\n 'stroke-dashoffset': -measurement.strokeDashOffset\n }\"\n d=\"M 107 27 a 80 80 0 1 0.1 0 Z\"\n transform=\"rotate(-135 107 107)\"\n ></path>\n <foreignObject\n class=\"d-flex a-i-center j-c-center\"\n height=\"100%\"\n width=\"100%\"\n requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\"\n >\n <div\n class=\"d-flex d-col fit-h a-i-center j-c-center\"\n style=\"padding: 3rem\"\n xmlns=\"http://www.w3.org/1999/xhtml\"\n >\n <p\n class=\"text-truncate text-center\"\n title=\"{{ activeDatapointGauge.label }}\"\n >\n {{ activeDatapointGauge.label }}\n </p>\n <p\n class=\"center-value text-truncate\"\n title=\"{{ measurement.value | number: fractionSize }}\"\n *ngIf=\"!measurement.notFound; else notFoundSVG\"\n >\n {{ measurement.value | number: fractionSize }}\n </p>\n <ng-template #notFoundSVG>\n <p class=\"center-value\">--</p>\n </ng-template>\n <p class=\"center-unit strong\">{{ activeDatapointGauge.unit || measurement.unit }}</p>\n <p class=\"center-date-time\">{{ measurement.date | c8yDate: 'short' }}</p>\n </div>\n </foreignObject>\n </svg>\n </div>\n </ng-container>\n\n <div class=\"clearfix\"></div>\n</div>\n<ng-container *ngIf=\"!isInfoGauge\">\n <c8y-radial-gauge\n *ngIf=\"activeDatapointGauge | infoGaugeCurrentMeasurement | async as measurement\"\n [activeDatapointGauge]=\"activeDatapointGauge\"\n [measurement]=\"measurement\"\n [fractionSize]=\"config.fractionSize\"\n [gaugeOptions]=\"config.gaugeOptions\"\n [selectedPresetId]=\"config.selectedPresetId\"\n ></c8y-radial-gauge>\n</ng-container>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: RadialGaugeViewComponent, selector: "c8y-radial-gauge", inputs: ["activeDatapointGauge", "measurement", "fractionSize", "gaugeOptions", "selectedPresetId"] }, { kind: "pipe", type: InfoGaugeCurrentMeasurementPipe, name: "infoGaugeCurrentMeasurement" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: DecimalPipe, name: "number" }, { kind: "pipe", type: DatePipe, name: "c8yDate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: InfoGaugeWidgetViewComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-info-gauge-widget-view', host: { class: 'd-contents' }, providers: [MeasurementRealtimeService], standalone: true, imports: [
NgIf,
NgFor,
NgStyle,
InfoGaugeCurrentMeasurementPipe,
AsyncPipe,
DecimalPipe,
DatePipe,
RadialGaugeViewComponent
], template: "<div\n class=\"label-value-unit-gauge new-radial\"\n *ngIf=\"isInfoGauge\"\n>\n <div\n class=\"gauge-legend\"\n *ngIf=\"activeDatapointLabels?.length && isInfoGauge\"\n >\n <ng-container *ngFor=\"let dp of activeDatapointLabels\">\n <ng-container *ngIf=\"dp | infoGaugeCurrentMeasurement | async as measurement\">\n <label\n class=\"text-truncate\"\n title=\"{{ dp.label }}\"\n >\n {{ dp.label }}\n </label>\n <h3\n class=\"text-truncate\"\n title=\"{{ measurement.value | number: fractionSize }} {{ dp.unit || measurement.unit }}\"\n *ngIf=\"!measurement.notFound; else notFound\"\n >\n {{ measurement.value | number: fractionSize }} {{ dp.unit || measurement.unit }}\n </h3>\n <ng-template #notFound>\n <h3>--</h3>\n </ng-template>\n <p class=\"text-muted m-b-8\">\n <small>\n <em>{{ measurement.date | c8yDate: 'short' }}</em>\n </small>\n </p>\n </ng-container>\n </ng-container>\n </div>\n\n <ng-container *ngIf=\"activeDatapointGauge && isInfoGauge\">\n <div\n class=\"gauge-svg\"\n *ngIf=\"activeDatapointGauge | infoGaugeCurrentMeasurement: true | async as measurement\"\n >\n <svg\n height=\"214px\"\n width=\"214px\"\n viewBox=\"0 0 214 214\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n >\n <desc>radial gauge</desc>\n <g\n id=\"scale\"\n stroke=\"none\"\n stroke-width=\"1\"\n fill=\"none\"\n fill-rule=\"evenodd\"\n stroke-dasharray=\"1,5\"\n >\n <circle\n id=\"Oval\"\n stroke=\"#CACECE\"\n stroke-width=\"7\"\n cx=\"107\"\n cy=\"107\"\n r=\"103\"\n ></circle>\n <rect\n id=\"mask\"\n height=\"214\"\n stroke=\"none\"\n fill-rule=\"evenodd\"\n x=\"0\"\n y=\"0\"\n width=\"214\"\n transform=\"rotate(-45 290 182)\"\n ></rect>\n </g>\n <path\n class=\"track\"\n d=\"M 107 27 a 80 80 0 1 0.1 0 Z\"\n transform=\"rotate(-135 107 107)\"\n ></path>\n <path\n class=\"track-value\"\n [ngStyle]=\"{\n stroke: measurement.color,\n 'stroke-dashoffset': -measurement.strokeDashOffset\n }\"\n d=\"M 107 27 a 80 80 0 1 0.1 0 Z\"\n transform=\"rotate(-135 107 107)\"\n ></path>\n <foreignObject\n class=\"d-flex a-i-center j-c-center\"\n height=\"100%\"\n width=\"100%\"\n requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\"\n >\n <div\n class=\"d-flex d-col fit-h a-i-center j-c-center\"\n style=\"padding: 3rem\"\n xmlns=\"http://www.w3.org/1999/xhtml\"\n >\n <p\n class=\"text-truncate text-center\"\n title=\"{{ activeDatapointGauge.label }}\"\n >\n {{ activeDatapointGauge.label }}\n </p>\n <p\n class=\"center-value text-truncate\"\n title=\"{{ measurement.value | number: fractionSize }}\"\n *ngIf=\"!measurement.notFound; else notFoundSVG\"\n >\n {{ measurement.value | number: fractionSize }}\n </p>\n <ng-template #notFoundSVG>\n <p class=\"center-value\">--</p>\n </ng-template>\n <p class=\"center-unit strong\">{{ activeDatapointGauge.unit || measurement.unit }}</p>\n <p class=\"center-date-time\">{{ measurement.date | c8yDate: 'short' }}</p>\n </div>\n </foreignObject>\n </svg>\n </div>\n </ng-container>\n\n <div class=\"clearfix\"></div>\n</div>\n<ng-container *ngIf=\"!isInfoGauge\">\n <c8y-radial-gauge\n *ngIf=\"activeDatapointGauge | infoGaugeCurrentMeasurement | async as measurement\"\n [activeDatapointGauge]=\"activeDatapointGauge\"\n [measurement]=\"measurement\"\n [fractionSize]=\"config.fractionSize\"\n [gaugeOptions]=\"config.gaugeOptions\"\n [selectedPresetId]=\"config.selectedPresetId\"\n ></c8y-radial-gauge>\n</ng-container>\n" }]
}], ctorParameters: () => [{ type: i2.ContextDashboardComponent, decorators: [{
type: Optional
}] }, { type: i1.DynamicComponentComponent, decorators: [{
type: Optional
}] }], propDecorators: { config: [{
type: Input
}] } });
class PresetPreviewComponent {
constructor() {
this.onPresetChange = new EventEmitter();
this.measurement = {
value: Math.floor(Math.random() * 9) + 1,
unit: 'ºC',
date: '2025-04-22T20:07:49.354Z'
};
this.activeDatapointGauge = {
fragment: 'c8y_Kpi',
series: 'preview',
unit: 'ºC',
min: 0,
max: 10,
yellowRangeMax: 8,
yellowRangeMin: 5,
redRangeMin: 8,
redRangeMax: 10
};
this.selectedPresetId = null;
}
writeValue(value) {
this.selectedPresetId = value;
}
registerOnChange(fn) {
this.onChange = fn;
}
registerOnTouched(fn) {
this.onTouched = fn;
}
emitPresetChange(presetId) {
this.selectedPresetId = presetId;
this.onChange(presetId);
this.onTouched();
this.onPresetChange.emit(presetId);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PresetPreviewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: PresetPreviewComponent, isStandalone: true, selector: "c8y-preset-preview", inputs: { ALL_GAUGE_PRESETS: "ALL_GAUGE_PRESETS" }, outputs: { onPresetChange: "onPresetChange" }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => PresetPreviewComponent),
multi: true
}
], ngImport: i0, template: "<div class=\"d-grid grid__col--4-4-4 gap-4\">\n <button\n class=\"c8y-radial-gauge__preset preset-{{ preset.id }}\"\n [class.selected]=\"preset.id === selectedPresetId\"\n [attr.aria-label]=\"preset.name | translate\"\n type=\"button\"\n *ngFor=\"let preset of ALL_GAUGE_PRESETS\"\n (click)=\"emitPresetChange(preset.id)\"\n >\n <c8y-radial-gauge\n class=\"c8y-radial-gauge--square\"\n *ngIf=\"preset.id !== 'custom'\"\n [activeDatapointGauge]=\"activeDatapointGauge\"\n [measurement]=\"measurement\"\n [fractionSize]=\"2\"\n [selectedPresetId]=\"preset.id\"\n [gaugeOptions]=\"preset\"\n ></c8y-radial-gauge>\n <span>{{ preset.name | translate }}</span>\n </button>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: RadialGaugeViewComponent, selector: "c8y-radial-gauge", inputs: ["activeDatapointGauge", "measurement", "fractionSize", "gaugeOptions", "selectedPresetId"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PresetPreviewComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-preset-preview', standalone: true, imports: [CommonModule, RadialGaugeViewComponent], providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => PresetPreviewComponent),
multi: true
}
], template: "<div class=\"d-grid grid__col--4-4-4 gap-4\">\n <button\n class=\"c8y-radial-gauge__preset preset-{{ preset.id }}\"\n [class.selected]=\"preset.id === selectedPresetId\"\n [attr.aria-label]=\"preset.name | translate\"\n type=\"button\"\n *ngFor=\"let preset of ALL_GAUGE_PRESETS\"\n (click)=\"emitPresetChange(preset.id)\"\n >\n <c8y-radial-gauge\n class=\"c8y-radial-gauge--square\"\n *ngIf=\"preset.id !== 'custom'\"\n [activeDatapointGauge]=\"activeDatapointGauge\"\n [measurement]=\"measurement\"\n [fractionSize]=\"2\"\n [selectedPresetId]=\"preset.id\"\n [gaugeOptions]=\"preset\"\n ></c8y-radial-gauge>\n <span>{{ preset.name | translate }}</span>\n </button>\n</div>\n" }]
}], propDecorators: { ALL_GAUGE_PRESETS: [{
type: Input
}], onPresetChange: [{
type: Output
}] } });
function ensureAtLeastOneDatapointSelectedAndActive(datapointListAttributes) {
return (control) => {
const formValue = control.value;
for (const listAttributeName of datapointListAttributes) {
const valueForList = formValue[listAttributeName];
if (!valueForList || !Array.isArray(valueForList)) {
continue;
}
if (valueForList.find(dp => dp.__active)) {
return null;
}
}
return { noActiveDatapoint: true };
};
}
class InfoGaugeWidgetConfigComponent {
set previewMapSet(template) {
if (template) {
this.widgetConfigService.setPreview(template);
return;
}
this.widgetConfigService.setPreview(null);
}
constructor(formBuilder, form, widgetConfig, widgetConfigService, dynamicComponent) {
this.formBuilder = formBuilder;
this.form = form;
this.widgetConfig = widgetConfig;
this.widgetConfigService = widgetConfigService;
this.dynamicComponent = dynamicComponent;
this.datapointSelectionConfig = {};
this.defaultFormOptions = {
showRedRange: true,
showYellowRange: true,
showRange: true,
selectableChartRenderTypes: []
};
this.showAdvancedOptions = false;
this.gaugeOptionsString = '';
this.showAdvancedOptionsLabel = gettext('Show advanced options');
this.hideAdvancedOptionsLabel = gettext('Hide advanced options');
this.ALL_GAUGE_PRESETS = [...GAUGE_PRESETS];
this.limits = {
numberOfDecimalPlacesMax: 10,
numberOfDecimalPlacesMin: 0
};
this.GAUGE_PRESETS = GAUGE_PRESETS;
this.destroy$ = new Subject();
this.jsonChange$ = new Subject();
}
onBeforeSave(config) {
if (this.formGroup.valid) {
Object.assign(config, this.formGroup.value);
Object.assign(config, {
gaugeOptions: this.gaugeOptions,
selectedPresetId: this.isInfoGauge ? null : this.getPresetId(this.gaugeOptions)
});
return true;
}
return false;
}
ngOnInit() {
if (this.widgetConfig.context?.id) {
this.datapointSelectionConfig.contextAsset = this.widgetConfig?.context;
}
this.initForm();
if (this.config?.datapointsLabels) {
this.formGroup.patchValue({ datapointsLabels: this.config.datapointsLabels });
}
if (this.config?.datapointsGauge) {
this.formGroup.patchValue({ datapointsGauge: this.config.datapointsGauge });
}
if (typeof this.config?.fractionSize === 'number' && !Number.isNaN(this.config?.fractionSize)) {
this.formGroup.patchValue({ fractionSize: this.config.fractionSize });
}
this.isInfoGauge = this.dynamicComponent?.componentId === defaultWidgetIds.INFO_GAUGE;
this.previewConfig = {
...this.config,
fractionSize: this.config?.fractionSize ?? 2,
datapointsGauge: this.config?.datapointsGauge ?? [],
datapointsLabels: this.config?.datapointsLabels ?? []
};
const isRadialGauge = !this.isInfoGauge;
if (isRadialGauge) {
this.setupRadialGauge();
}
this.formGroup.valueChanges.pipe(takeUntil(this.destroy$)).subscribe(value => {
if (value.datapointsGauge) {
this.activeDatapointGauge = value.datapointsGauge.find(dp => dp.__active);
}
if (value.datapointsLabels) {
this.activeDatapointLabel = value.datapointsLabels.find(dp => dp.__active);
}
// this.previewConfig = { ...this.previewConfig, gaugeOptions: this.gaugeOptions };
this.previewConfig = {
...this.previewConfig,
...value,
selectedPresetId: value.gaugePresetId,
gaugeOptions: this.gaugeOptions
};
});
this.jsonChange$
.pipe(takeUntil(this.destroy$), debounceTime(500))
.subscribe(value => this.processJSONChange(value));
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
this.jsonChange$.complete();
}
onRadioPresetChange(presetId) {
// Find the selected preset
const selectedPreset = this.ALL_GAUGE_PRESETS.find(preset => preset.id === presetId);
if (selectedPreset) {
this.gaugeOptions = { ...selectedPreset }; // Update gaugeOptions with the selected preset
this.gaugeOptionsString = JSON.stringify(this.gaugeOptions, null, 2);
// If the selected preset is not custom, hide advanced options
if (selectedPreset.id !== 'custom') {
this.showAdvancedOptions = false;
}
this.previewConfig = {
...this.previewConfig,
selectedPresetId: selectedPreset.id,
gaugeOptions: this.gaugeOptions
};
// Update the form control value
this.formGroup.patchValue({ gaugePresetId: selectedPreset.id });
}
}
async assignSchema() {
const { schema } = await import('c8y-schema-loader?interfaceName=GaugeOptions!@c8y/ngx-components/widgets/implementations/info-gauge');
this.editorComponent.monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
validate: true,
schemas: [
{
uri: 'gauge-schema.json',
schema: schema,
fileMatch: ['*']
}
],
enableSchemaRequest: false,
allowComments: false
});
}
gaugeJSONChange(value) {
this.jsonChange$.next(value);
}
trackByFn(_index, item) {
return item.id;
}
processJSONChange(value) {
try {
const parsedOptions = JSON.parse(value);
// Check if the parsed options match any existing preset
const matchingPreset = this.GAUGE_PRESETS.find(preset => JSON.stringify(preset) === JSON.stringify(parsedOptions));
if (matchingPreset) {
this.formGroup.patchValue({ gaugePresetId: matchingPreset.id });
}
else {
this.gaugeOptions = parsedOptions;
this.gaugeOptions.name = GAUGE_PRESET_NAMES.CUSTOM;
this.gaugeOptions.id = 'custom';
const customPresetExists = this.ALL_GAUGE_PRESETS.some(preset => preset.id === 'custom');
if (!customPresetExists) {
this.ALL_GAUGE_PRESETS = [...this.ALL_GAUGE_PRESETS, this.gaugeOptions];
}
else {
this.ALL_GAUGE_PRESETS = this.ALL_GAUGE_PRESETS.map(preset => preset.id === 'custom' ? this.gaugeOptions : preset);
}
this.formGroup.patchValue({ gaugePresetId: 'custom' });
this.previewConfig = {
...this.previewConfig,
selectedPresetId: 'custom',
gaugeOptions: this.gaugeOptions
};
}
}
catch (error) {
console.error('Invalid JSON:', error);
}
}
getPresetId(gaugeOptions) {
const matchingPreset = this.GAUGE_PRESETS.find(preset => preset.id === gaugeOptions.id);
return matchingPreset ? matchingPreset.id : 'custom';
}
setupRadialGauge() {
if (this.config.datapoints && !this.config.datapointsGauge) {
this.config.datapointsGauge = this.config.datapoints;
}
this.gaugeOptions = this.config.gaugeOptions || { ...this.GAUGE_PRESETS[0] };
if (this.config.selectedPresetId === 'custom') {
this.gaugeOptions.name = GAUGE_PRESET_NAMES.CUSTOM;
this.gaugeOptions.id = 'custom';
this.previewConfig = {
...this.previewConfig,
selectedPresetId: 'custom',
gaugeOptions: this.gaugeOptions
};
this.ALL_GAUGE_PRESETS = [...this.GAUGE_PRESETS, this.config.gaugeOptions];
this.formGroup.patchValue({ gaugePresetId: 'custom' });
}
this.gaugeOptionsString = JSON.stringify(this.gaugeOptions, null, 2);
}
initForm() {
this.formGroup = this.createForm();
this.form.form.addControl('config', this.formGroup);
this.formGroup.patchValue(this.config);
}
createForm() {
return this.formBuilder.group({
fractionSize: [
2,
[
Validators.required,
Validators.min(this.limits.numberOfDecimalPlacesMin),
Validators.max(this.limits.numberOfDecimalPlacesMax)
]
],
datapointsLabels: this.formBuilder.control(new Array(), []),
datapointsGauge: this.formBuilder.control(new Array(), []),
gaugePresetId: [this.config.selectedPresetId || 'default']
}, {
validators: [
ensureAtLeastOneDatapointSelectedAndActive(['datapointsLabels', 'datapointsGauge'])
]
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: InfoGaugeWidgetConfigComponent, deps: [{ token: i1$3.FormBuilder }, { token: i1$3.NgForm }, { token: i2.WidgetConfigComponent }, { token: i2.WidgetConfigService }, { token: i1.DynamicComponentComponent, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: InfoGaugeWidgetConfigComponent, isStandalone: true, selector: "c8y-info-gauge-widget-config", inputs: { config: "config" }, providers: [MeasurementRealtimeService], viewQueries: [{ propertyName: "editorComponent", first: true, predicate: EditorComponent, descendants: true }, { propertyName: "previewMapSet", first: true, predicate: ["gaugePreview"], descendants: true }], ngImport: i0, template: "<form\n class=\"fit-h\"\n [formGroup]=\"formGroup\"\n>\n @if (isInfoGauge) {\n <div class=\"m-l-16 m-r-16\">\n <c8y-form-group class=\"p-t-8\">\n <label translate>Decimal places</label>\n <input\n class=\"form-control\"\n name=\"fractionSize\"\n type=\"number\"\n formControlName=\"fractionSize\"\n step=\"1\"\n />\n <c8y-messages [show]=\"formGroup.controls.fractionSize.errors\"></c8y-messages>\n </c8y-form-group>\n @if (formGroup.errors?.noActiveDatapoint) {\n <div\n class=\"alert alert-info\"\n role=\"alert\"\n translate\n >\n At least one data point for the labels or the gauge needs to be selected.\n </div>\n }\n <c8y-datapoint-selection-list\n class=\"bg-inherit separator-top p-t-16 d-block\"\n listTitle=\"{{ 'Multiple label and value pairs' | translate }}\"\n name=\"datapoints\"\n [defaultFormOptions]=\"defaultFormOptions\"\n [config]=\"datapointSelectionConfig\"\n [minActiveCount]=\"0\"\n formControlName=\"datapointsLabels\"\n ></c8y-datapoint-selection-list>\n\n <c8y-datapoint-selection-list\n class=\"bg-inherit separator-top p-t-16 d-block\"\n listTitle=\"{{ 'Gauge`display`' | translate }}\"\n name=\"datapoints\"\n [defaultFormOptions]=\"defaultFormOptions\"\n [config]=\"datapointSelectionConfig\"\n [minActiveCount]=\"0\"\n [maxActiveCount]=\"1\"\n formControlName=\"datapointsGauge\"\n ></c8y-datapoint-selection-list>\n </div>\n } @else {\n <c8y-datapoint-selection-list\n class=\"bg-inherit d-block\"\n listTitle=\"{{ 'Data points`display`' | translate }}\"\n name=\"datapoints\"\n [defaultFormOptions]=\"defaultFormOptions\"\n [config]=\"datapointSelectionConfig\"\n [minActiveCount]=\"0\"\n [maxActiveCount]=\"1\"\n formControlName=\"datapointsGauge\"\n ></c8y-datapoint-selection-list>\n\n <c8y-form-group class=\"p-t-8 p-r-16 p-l-16\">\n <label translate>Decimal places</label>\n <input\n class=\"form-control\"\n name=\"fractionSize\"\n type=\"number\"\n formControlName=\"fractionSize\"\n step=\"1\"\n />\n <c8y-messages [show]=\"formGroup.controls.fractionSize.errors\"></c8y-messages>\n </c8y-form-group>\n\n <div class=\"form-group p-r-16 p-l-16 m-b-0\">\n <legend>\n {{ 'Presets' | translate }}\n </legend>\n <c8y-preset-preview\n formControlName=\"gaugePresetId\"\n [ALL_GAUGE_PRESETS]=\"ALL_GAUGE_PRESETS\"\n (onPresetChange)=\"onRadioPresetChange($event)\"\n ></c8y-preset-preview>\n </div>\n\n <div class=\"p-16\">\n <button\n class=\"btn btn-default\"\n aria-controls=\"advancedCollapse\"\n [attr.aria-expanded]=\"showAdvancedOptions\"\n type=\"button\"\n (click)=\"showAdvancedOptions = !showAdvancedOptions\"\n >\n {{ showAdvancedOptions ? hideAdvancedOptionsLabel : showAdvancedOptionsLabel }}\n </button>\n </div>\n\n <div\n class=\"collapse\"\n id=\"advancedCollapse\"\n [collapse]=\"!showAdvancedOptions\"\n [isAnimated]=\"true\"\n >\n <div\n class=\"fit-h\"\n style=\"min-height: 400px\"\n >\n <c8y-editor\n [ngModel]=\"gaugeOptionsString\"\n (ngModelChange)=\"gaugeJSONChange($event)\"\n (editorInit)=\"assignSchema()\"\n [ngModelOptions]=\"{ standalone: true }\"\n monacoEditorMarkerValidator\n ></c8y-editor>\n </div>\n </div>\n }\n</form>\n\n<ng-template #gaugePreview>\n @if (\n (this.formGroup.value.datapointsGauge?.length > 0 && activeDatapointGauge) ||\n (this.formGroup.value.datapointsLabels?.length > 0 && activeDatapointLabel)\n ) {\n <div style=\"height: 300px\">\n <c8y-info-gauge-widget-view [config]=\"previewConfig\"></c8y-info-gauge-widget-view>\n </div>\n } @else {\n <div class=\"d-col a-i-start j-c-center\">\n <c8y-ui-empty-state\n [icon]=\"'c8y-data-points'\"\n [title]=\"'No data points selected' | translate\"\n [subtitle]=\"'Select data point to render content' | translate\"\n [horizontal]=\"false\"\n data-cy=\"info-gauge--empty-state-no-data-point-selected\"\n >\n <p c8y-guide-docs>\n <small translate>\n Find out more in the\n <a c8y-guide-href=\"/docs/cockpit/widgets-collection/#info-gauge\">user documentation</a>\n .\n </small>\n </p>\n </c8y-ui-empty-state>\n </div>\n }\n</ng-template>\n", dependencies: [{ kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "ngmodule", type: CommonModule }, { kind: "component", type: i1.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "ngmodule", type: CollapseModule }, { kind: "directive", type: i4.CollapseDirective, selector: "[collapse]", inputs: ["display", "isAnimated", "collapse"], outputs: ["collapsed", "collapses", "expanded", "expands"], exportAs: ["bs-collapse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: EditorComponent, selector: "c8y-editor", inputs: ["editorOptions", "theme"], outputs: ["editorInit"] }, { kind: "directive", type: MonacoEditorMarkerValidatorDirective, selector: "c8y-editor [monacoEditorMarkerValidator]" }, { kind: "ngmodule", type: DatapointSelectorModule }, { kind: "component", type: i5.DatapointSelectionListComponent, selector: "c8y-datapoint-selection-list", inputs: ["actions", "allowDragAndDrop", "config", "defaultFormOptions", "maxActiveCount", "minActiveCount", "resolveContext", "listTitle"], outputs: ["isValid", "change"] }, { kind: "component", type: PresetPreviewComponent, selector: "c8y-preset-preview", inputs: ["ALL_GAUGE_PRESETS"], outputs: ["onPresetChange"] }, { kind: "component", type: InfoGaugeWidgetViewComponent, selector: "c8y-info-gauge-widget-view", inputs: ["config"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }], viewProviders: [{ provide: ControlContainer, useExisting: NgForm }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: InfoGaugeWidgetConfigComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-info-gauge-widget-config', viewProviders: [{ provide: ControlContainer, useExisting: NgForm }], providers: [MeasurementRealtimeService], standalone: true, imports: [
FormGroupComponent,
MessagesComponent,
CommonModule,
FormsModule,
CollapseModule,
ReactiveFormsModule,
EditorComponent,
MonacoEditorMarkerValidatorDirective,
DatapointSelectorModule,
PresetPreviewComponent,
InfoGaugeWidgetViewComponent
], template: "<form\n class=\"fit-h\"\n [formGroup]=\"formGroup\"\n>\n @if (isInfoGauge) {\n <div class=\"m-l-16 m-r-16\">\n <c8y-form-group class=\"p-t-8\">\n <label translate>Decimal places</label>\n <input\n class=\"form-control\"\n name=\"fractionSize\"\n type=\"number\"\n formControlName=\"fractionSize\"\n step=\"1\"\n />\n <c8y-messages [show]=\"formGroup.controls.fractionSize.errors\"></c8y-messages>\n </c8y-form-group>\n @if (formGroup.errors?.noActiveDatapoint) {\n <div\n class=\"alert alert-info\"\n role=\"alert\"\n translate\n >\n At least one data point for the labels or the gauge needs to be selected.\n </div>\n }\n <c8y-datapoint-selection-list\n class=\"bg-inherit separator-top p-t-16 d-block\"\n listTitle=\"{{ 'Multiple label and value pairs' | translate }}\"\n name=\"datapoints\"\n [defaultFormOptions]=\"defaultFormOptions\"\n [config]=\"datapointSelectionConfig\"\n [minActiveCount]=\"0\"\n formControlName=\"datapointsLabels\"\n ></c8y-datapoint-selection-list>\n\n <c8y-datapoint-selection-list\n class=\"bg-inherit separator-top p-t-16 d-block\"\n listTitle=\"{{ 'Gauge`display`' | translate }}\"\n name=\"datapoints\"\n [defaultFormOptions]=\"defaultFormOptions\"\n [config]=\"datapointSelectionConfig\"\n [minActiveCount]=\"0\"\n [maxActiveCount]=\"1\"\n formControlName=\"datapointsGauge\"\n ></c8y-datapoint-selection-list>\n </div>\n } @else {\n <c8y-datapoint-selection-list\n class=\"bg-inherit d-block\"\n listTitle=\"{{ 'Data points`display`' | translate }}\"\n name=\"datapoints\"\n [defaultFormOptions]=\"defaultFormOptions\"\n [config]=\"datapointSelectionConfig\"\n [minActiveCount]=\"0\"\n [maxActiveCount]=\"1\"\n formControlName=\"datapointsGauge\"\n ></c8y-datapoint-selection-list>\n\n <c8y-form-group class=\"p-t-8 p-r-16 p-l-16\">\n <label translate>Decimal places</label>\n <input\n class=\"form-control\"\n name=\"fractionSize\"\n type=\"number\"\n formControlName=\"fractionSize\"\n step=\"1\"\n />\n <c8y-messages [show]=\"formGroup.controls.fractionSize.errors\"></c8y-messages>\n </c8y-form-group>\n\n <div class=\"form-group p-r-16 p-l-16 m-b-0\">\n <legend>\n {{ 'Presets' | translate }}\n </legend>\n <c8y-preset-preview\n formControlName=\"gaugePresetId\"\n [ALL_GAUGE_PRESETS]=\"ALL_GAUGE_PRESETS\"\n (onPresetChange)=\"onRadioPresetChange($event)\"\n ></c8y-preset-preview>\n </div>\n\n <div class=\"p-16\">\n <button\n class=\"btn btn-default\"\n aria-controls=\"advancedCollapse\"\n [attr.aria-expanded]=\"showAdvancedOptions\"\n type=\"button\"\n (click)=\"showAdvancedOptions = !showAdvancedOptions\"\n >\n {{ showAdvancedOptions ? hideAdvancedOptionsLabel : showAdvancedOptionsLabel }}\n </button>\n </div>\n\n <div\n class=\"collapse\"\n id=\"advancedCollapse\"\n [collapse]=\"!showAdvancedOptions\"\n [isAnimated]=\"true\"\n >\n <div\n class=\"fit-h\"\n style=\"min-height: 400px\"\n >\n <c8y-editor\n [ngModel]=\"gaugeOptionsString\"\n (ngModelChange)=\"gaugeJSONChange($event)\"\n (editorInit)=\"assignSchema()\"\n [ngModelOptions]=\"{ standalone: true }\"\n monacoEditorMarkerValidator\n ></c8y-editor>\n </div>\n </div>\n }\n</form>\n\n<ng-template #gaugePreview>\n @if (\n (this.formGroup.value.datapointsGauge?.length > 0 && activeDatapointGauge) ||\n (this.formGroup.value.datapointsLabels?.length > 0 && activeDatapointLabel)\n ) {\n <div style=\"height: 300px\">\n <c8y-info-gauge-widget-view [config]=\"previewConfig\"></c8y-info-gauge-widget-view>\n </div>\n } @else {\n <div class=\"d-col a-i-start j-c-center\">\n <c8y-ui-empty-state\n [icon]=\"'c8y-data-points'\"\n [title]=\"'No data points selected' | translate\"\n [subtitle]=\"'Select data point to render content' | translate\"\n [horizontal]=\"false\"\n data-cy=\"info-gauge--empty-state-no-data-point-selected\"\n >\n <p c8y-guide-docs>\n <small translate>\n Find out more in the\n <a c8y-guide-href=\"/docs/cockpit/widgets-collection/#info-gauge\">user documentation</a>\n .\n </small>\n </p>\n </c8y-ui-empty-state>\n </div>\n }\n</ng-template>\n" }]
}], ctorParameters: () => [{ type: i1$3.FormBuilder }, { type: i1$3.NgForm }, { type: i2.WidgetConfigComponent }, { type: i2.WidgetConfigService }, { type: i1.DynamicComponentComponent, decorators: [{
type: Optional
}] }], propDecorators: { config: [{
type: Input
}], editorComponent: [{
type: ViewChild,
args: [EditorComponent]
}], previewMapSet: [{
type: ViewChild,
args: ['gaugePreview']
}] } });
/**
* Generated bundle index. Do not edit.
*/
export { GAUGE_PRESETS, GAUGE_PRESET_NAMES, InfoGaugeWidgetConfigComponent, InfoGaugeWidgetViewComponent };
//# sourceMappingURL=c8y-ngx-components-widgets-implementations-info-gauge.mjs.map