This is an automated email from the ASF dual-hosted git repository.
riemer pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/streampipes.git
The following commit(s) were added to refs/heads/dev by this push:
new c16cf41d6f Add new traffic light widget to data explorer (#3223)
c16cf41d6f is described below
commit c16cf41d6f1fd1932ead00c70f6ca1453881fd36
Author: Marcelfrueh <[email protected]>
AuthorDate: Thu Sep 12 08:56:34 2024 +0200
Add new traffic light widget to data explorer (#3223)
---
.../data-explorer-data-view-toolbar.component.html | 4 +-
.../traffic-light-widget-config.component.html | 130 +++++++++++++++
.../traffic-light-widget-config.component.scss | 27 +++
.../traffic-light-widget-config.component.ts | 183 +++++++++++++++++++++
.../model/traffic-light-widget.model.ts | 37 +++++
.../traffic-light-widget.component.html | 79 +++++++++
.../traffic-light-widget.component.scss | 89 ++++++++++
.../traffic-light-widget.component.ts | 180 ++++++++++++++++++++
ui/src/app/data-explorer/data-explorer.module.ts | 4 +
.../registry/data-explorer-widget-registry.ts | 8 +
10 files changed, 739 insertions(+), 2 deletions(-)
diff --git
a/ui/src/app/data-explorer/components/data-view/data-view-toolbar/data-explorer-data-view-toolbar.component.html
b/ui/src/app/data-explorer/components/data-view/data-view-toolbar/data-explorer-data-view-toolbar.component.html
index 96aea25dff..de4394dc7e 100644
---
a/ui/src/app/data-explorer/components/data-view/data-view-toolbar/data-explorer-data-view-toolbar.component.html
+++
b/ui/src/app/data-explorer/components/data-view/data-view-toolbar/data-explorer-data-view-toolbar.component.html
@@ -24,10 +24,10 @@
fxFlex="100"
>
<div
- fxFlex="15"
+ fxFlex="25"
fxLayout="row"
fxLayoutAlign="start center"
- class="widget-header-text mr-10"
+ class="widget-header-text mr-15"
>
<div
fxFlex="100"
diff --git
a/ui/src/app/data-explorer/components/widgets/traffic-light/config/traffic-light-widget-config.component.html
b/ui/src/app/data-explorer/components/widgets/traffic-light/config/traffic-light-widget-config.component.html
new file mode 100644
index 0000000000..7c8d7c941c
--- /dev/null
+++
b/ui/src/app/data-explorer/components/widgets/traffic-light/config/traffic-light-widget-config.component.html
@@ -0,0 +1,130 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~
+ -->
+
+<sp-visualization-config-outer
+ [configurationValid]="
+ currentlyConfiguredWidget.visualizationConfig.configurationValid
+ "
+>
+ <sp-configuration-box title="Field">
+ <sp-select-property
+ [availableProperties]="fieldProvider.numericFields"
+ [selectedProperty]="
+ currentlyConfiguredWidget.visualizationConfig
+ .selectedFieldToObserve
+ "
+ (changeSelectedProperty)="selectFieldToObserve($event)"
+ >
+ </sp-select-property>
+ </sp-configuration-box>
+
+ <sp-configuration-box title="Settings">
+ <div fxLayout="column" fxLayoutGap="10px">
+ <div
+ fxLayout="row"
+ fxLayoutGap="10px"
+ fxLayoutAlign="start center"
+ fxFlex="100"
+ >
+ <small fxFlex="30">Threshold</small>
+ <mat-form-field color="accent" appearance="outline" fxFlex>
+ <input
+ type="text"
+ [(ngModel)]="
+ currentlyConfiguredWidget.visualizationConfig
+ .selectedThreshold
+ "
+ matInput
+ (input)="selectThreshold($event.target.value)"
+ [pattern]="'[0-9.,]*'"
+ (keydown)="restrictInput($event)"
+ />
+ </mat-form-field>
+ </div>
+
+ <div
+ fxLayout="row"
+ fxLayoutGap="10px"
+ fxLayoutAlign="start center"
+ fxFlex="100"
+ >
+ <small fxFlex="30">With Threshold being</small>
+ <mat-radio-group
+ [(ngModel)]="
+ currentlyConfiguredWidget.visualizationConfig
+ .selectedUpperLimit
+ "
+ (change)="selectUpperLimit($event.source.value)"
+ >
+ <mat-radio-button [value]="true"
+ >Upper Limit</mat-radio-button
+ >
+ <mat-radio-button [value]="false"
+ >Lower Limit</mat-radio-button
+ >
+ </mat-radio-group>
+ </div>
+
+ <div
+ fxLayout="row"
+ fxLayoutGap="10px"
+ fxLayoutAlign="start center"
+ fxFlex="100"
+ >
+ <small fxFlex="30">Warning Range (%)</small>
+ <mat-form-field color="accent" appearance="outline" fxFlex>
+ <input
+ [(ngModel)]="
+ currentlyConfiguredWidget.visualizationConfig
+ .selectedWarningRange
+ "
+ matInput
+ type="text"
+ (input)="selectWarningRange($event.target.value)"
+ [pattern]="'[0-9.,]*'"
+ (keydown)="restrictInput($event)"
+ />
+ <div
+ *ngIf="warningRangeInterval"
+ class="warning-range-info"
+ >
+ <small>{{ warningRangeInterval }}</small>
+ </div>
+ </mat-form-field>
+ </div>
+ <div
+ fxLayout="row"
+ fxLayoutGap="10px"
+ fxLayoutAlign="start center"
+ fxFlex="100"
+ class="checkbox-container"
+ >
+ <small>Show Value in Traffic Light</small>
+ <mat-checkbox
+ color="accent"
+ [(ngModel)]="
+ currentlyConfiguredWidget.visualizationConfig
+ .selectedToShowValue
+ "
+ (ngModelChange)="selectToShowValue($event)"
+ >
+ </mat-checkbox>
+ </div>
+ </div>
+ </sp-configuration-box>
+</sp-visualization-config-outer>
diff --git
a/ui/src/app/data-explorer/components/widgets/traffic-light/config/traffic-light-widget-config.component.scss
b/ui/src/app/data-explorer/components/widgets/traffic-light/config/traffic-light-widget-config.component.scss
new file mode 100644
index 0000000000..159b9f5901
--- /dev/null
+++
b/ui/src/app/data-explorer/components/widgets/traffic-light/config/traffic-light-widget-config.component.scss
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.warning-range-info {
+ font-size: 0.9rem;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.checkbox-container {
+ margin-top: 20px;
+}
diff --git
a/ui/src/app/data-explorer/components/widgets/traffic-light/config/traffic-light-widget-config.component.ts
b/ui/src/app/data-explorer/components/widgets/traffic-light/config/traffic-light-widget-config.component.ts
new file mode 100644
index 0000000000..7ca8a535c6
--- /dev/null
+++
b/ui/src/app/data-explorer/components/widgets/traffic-light/config/traffic-light-widget-config.component.ts
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { Component } from '@angular/core';
+import { BaseWidgetConfig } from '../../base/base-widget-config';
+import { WidgetConfigurationService } from
'../../../../services/widget-configuration.service';
+import {
+ TrafficLightVisConfig,
+ TrafficLightWidgetModel,
+} from '../model/traffic-light-widget.model';
+import { DataExplorerFieldProviderService } from
'../../../../services/data-explorer-field-provider-service';
+import { DataExplorerField } from '@streampipes/platform-services';
+
+@Component({
+ selector: 'sp-data-explorer-traffic-light-widget-config',
+ templateUrl: './traffic-light-widget-config.component.html',
+ styleUrls: ['./traffic-light-widget-config.component.scss'],
+})
+export class TrafficLightWidgetConfigComponent extends BaseWidgetConfig<
+ TrafficLightWidgetModel,
+ TrafficLightVisConfig
+> {
+ constructor(
+ widgetConfigurationService: WidgetConfigurationService,
+ fieldService: DataExplorerFieldProviderService,
+ ) {
+ super(widgetConfigurationService, fieldService);
+ }
+ warningRangeInterval: string;
+
+ selectWarningRange(selectedWarningRange: string): void {
+ const formattedValue = selectedWarningRange?.replace(',', '.');
+ const numericValue = parseFloat(formattedValue);
+ if (!isNaN(numericValue)) {
+
this.currentlyConfiguredWidget.visualizationConfig.selectedWarningRange =
+ numericValue;
+ } else {
+
this.currentlyConfiguredWidget.visualizationConfig.selectedWarningRange =
+ null;
+ }
+ this.updateWarningRangeInterval();
+ this.triggerViewRefresh();
+ }
+
+ selectFieldToObserve(selectedFieldToObserve: DataExplorerField): void {
+
this.currentlyConfiguredWidget.visualizationConfig.selectedFieldToObserve =
+ selectedFieldToObserve;
+ this.triggerViewRefresh();
+ }
+
+ selectUpperLimit(selectedUpperLimit: boolean): void {
+ this.currentlyConfiguredWidget.visualizationConfig.selectedUpperLimit =
+ selectedUpperLimit;
+ this.triggerViewRefresh();
+ }
+
+ selectToShowValue(selectedToShowValue: boolean): void {
+ this.currentlyConfiguredWidget.visualizationConfig.selectedToShowValue
=
+ selectedToShowValue;
+ this.triggerViewRefresh();
+ }
+
+ selectThreshold(selectedThreshold: string): void {
+ const formattedValue = selectedThreshold?.replace(',', '.');
+ const numericValue = parseFloat(formattedValue);
+ if (!isNaN(numericValue)) {
+
this.currentlyConfiguredWidget.visualizationConfig.selectedThreshold =
+ numericValue;
+ } else {
+
this.currentlyConfiguredWidget.visualizationConfig.selectedThreshold =
+ null;
+ }
+ this.updateWarningRangeInterval();
+ this.triggerViewRefresh();
+ }
+
+ protected applyWidgetConfig(config: TrafficLightVisConfig): void {
+ config.selectedFieldToObserve = this.fieldService.getSelectedField(
+ config.selectedFieldToObserve,
+ this.fieldProvider.allFields,
+ () => this.fieldProvider.allFields[0],
+ );
+ this.currentlyConfiguredWidget.visualizationConfig.selectedUpperLimit
??=
+ true;
+ this.updateWarningRangeInterval();
+ }
+ protected requiredFieldsForChartPresent(): boolean {
+ return true;
+ }
+
+ restrictInput(event: KeyboardEvent): void {
+ const inputValue = (event.target as HTMLInputElement).value;
+ const allowedKeys = [
+ '0',
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ 'Backspace',
+ 'ArrowLeft',
+ 'ArrowRight',
+ 'Delete',
+ ];
+
+ const pointOrComma = ['.', ','];
+ if (pointOrComma.includes(event.key)) {
+ if (inputValue.includes('.') || inputValue.includes(',')) {
+ event.preventDefault();
+ return;
+ }
+ }
+
+ if (
+ !allowedKeys.includes(event.key) &&
+ !pointOrComma.includes(event.key) &&
+ !(event.ctrlKey || event.metaKey)
+ ) {
+ event.preventDefault();
+ }
+ }
+
+ updateWarningRangeInterval(): void {
+ if (
+ this.currentlyConfiguredWidget.visualizationConfig
+ .selectedThreshold != null &&
+ this.currentlyConfiguredWidget.visualizationConfig
+ .selectedWarningRange != null
+ ) {
+ const rangeValue =
+ this.currentlyConfiguredWidget.visualizationConfig
+ .selectedThreshold *
+ (this.currentlyConfiguredWidget.visualizationConfig
+ .selectedWarningRange /
+ 100);
+
+ if (
+ this.currentlyConfiguredWidget.visualizationConfig
+ .selectedWarningRange === 0
+ ) {
+ this.warningRangeInterval = 'No Warning Range defined';
+ } else if (
+ this.currentlyConfiguredWidget.visualizationConfig
+ .selectedUpperLimit
+ ) {
+ const lowerBound =
+ this.currentlyConfiguredWidget.visualizationConfig
+ .selectedThreshold - rangeValue;
+ this.warningRangeInterval =
+ 'Current Warning Range: ' +
+ `${lowerBound} to
${this.currentlyConfiguredWidget.visualizationConfig.selectedThreshold}`;
+ } else {
+ const upperBound =
+ this.currentlyConfiguredWidget.visualizationConfig
+ .selectedThreshold + rangeValue;
+ this.warningRangeInterval =
+ 'Current Warning Range: ' +
+
`${this.currentlyConfiguredWidget.visualizationConfig.selectedThreshold} to
${upperBound}`;
+ }
+ } else {
+ this.warningRangeInterval = '';
+ }
+ }
+}
diff --git
a/ui/src/app/data-explorer/components/widgets/traffic-light/model/traffic-light-widget.model.ts
b/ui/src/app/data-explorer/components/widgets/traffic-light/model/traffic-light-widget.model.ts
new file mode 100644
index 0000000000..43fe5d6beb
--- /dev/null
+++
b/ui/src/app/data-explorer/components/widgets/traffic-light/model/traffic-light-widget.model.ts
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import {
+ DataExplorerDataConfig,
+ DataExplorerWidgetModel,
+ DataExplorerField,
+} from '@streampipes/platform-services';
+import { DataExplorerVisConfig } from
'../../../../models/dataview-dashboard.model';
+
+export interface TrafficLightVisConfig extends DataExplorerVisConfig {
+ selectedWarningRange: number;
+ selectedFieldToObserve: DataExplorerField;
+ selectedUpperLimit: boolean;
+ selectedThreshold: number;
+ selectedToShowValue: boolean;
+}
+
+export interface TrafficLightWidgetModel extends DataExplorerWidgetModel {
+ dataConfig: DataExplorerDataConfig;
+ visualizationConfig: TrafficLightVisConfig;
+}
diff --git
a/ui/src/app/data-explorer/components/widgets/traffic-light/traffic-light-widget.component.html
b/ui/src/app/data-explorer/components/widgets/traffic-light/traffic-light-widget.component.html
new file mode 100644
index 0000000000..72b5a90aa2
--- /dev/null
+++
b/ui/src/app/data-explorer/components/widgets/traffic-light/traffic-light-widget.component.html
@@ -0,0 +1,79 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<div
+ fxFlex="100"
+ fxLayoutAlign="center center"
+ fxLayout="column"
+ class="main-panel"
+ [ngStyle]="{
+ background: dataExplorerWidget.baseAppearanceConfig.backgroundColor,
+ color: dataExplorerWidget.baseAppearanceConfig.textColor,
+ overflowX: 'auto'
+ }"
+>
+ <sp-no-data-in-date-range
+ *ngIf="showNoDataInDateRange"
+ [viewDateRange]="timeSettings"
+ class="h-100"
+ >
+ </sp-no-data-in-date-range>
+
+ <div fxLayoutAlign="center center">
+ <div
+ class="tl-container"
+ [ngClass]="selectedToShowValue ? 'no-border-container' : ''"
+ [ngStyle]="{
+ width: containerWidth + 'px',
+ height: containerHeight + 'px'
+ }"
+ >
+ <div
+ class="light"
+ [ngClass]="{ 'light-red': activeClass === 'red' }"
+ [ngStyle]="{
+ width: lightWidth + 'px',
+ height: lightHeight + 'px'
+ }"
+ ></div>
+ <div
+ class="light"
+ [ngClass]="{ 'light-yellow': activeClass === 'yellow' }"
+ [ngStyle]="{
+ width: lightWidth + 'px',
+ height: lightHeight + 'px'
+ }"
+ ></div>
+ <div
+ class="light"
+ [ngClass]="{ 'light-green': activeClass === 'green' }"
+ [ngStyle]="{
+ width: lightWidth + 'px',
+ height: lightHeight + 'px'
+ }"
+ ></div>
+ </div>
+ </div>
+ <div class="light-value-container">
+ <div
+ *ngIf="selectedToShowValue"
+ class="light-value"
+ [ngStyle]="{ width: containerWidth + 'px' }"
+ >
+ {{ displayed_value }}
+ </div>
+ </div>
+</div>
diff --git
a/ui/src/app/data-explorer/components/widgets/traffic-light/traffic-light-widget.component.scss
b/ui/src/app/data-explorer/components/widgets/traffic-light/traffic-light-widget.component.scss
new file mode 100644
index 0000000000..cc13ba4625
--- /dev/null
+++
b/ui/src/app/data-explorer/components/widgets/traffic-light/traffic-light-widget.component.scss
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.h-100 {
+ height: 100%;
+}
+
+.tl-container {
+ background-color: #222;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ flex-direction: column;
+ padding: 10px;
+ border-radius: 10px;
+}
+
+.no-border-container {
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+ border-top-left-radius: 10px;
+ border-top-right-radius: 10px;
+}
+
+.light {
+ border-radius: 50%;
+ background-color: #3d3535;
+ background: repeating-linear-gradient(#333, #443 5px);
+}
+
+.light-red,
+.light-yellow,
+.light-green {
+ box-shadow: 0 0 40px;
+ z-index: 1;
+}
+
+.light-red {
+ background: repeating-linear-gradient(#f00, #e00 5px);
+ box-shadow: 0 0 40px #f00;
+}
+
+.light-yellow {
+ background: repeating-linear-gradient(#fd0, #ec0 5px);
+ box-shadow: 0 0 40px #fd0;
+}
+
+.light-green {
+ background: repeating-linear-gradient(#0d0, #0c0 5px);
+ box-shadow: 0 0 40px #0d0;
+}
+
+.title-panel {
+ font-size: 20px;
+ height: 30px;
+ margin: 10px 0;
+}
+
+.light-value-container {
+ background-color: #222;
+ border-radius: 10px;
+}
+
+.light-value {
+ color: #fff;
+ font-weight: bold;
+ font-size: 16px;
+ text-align: center;
+ background-color: #222;
+ padding: 10px;
+ border-bottom-left-radius: 10px;
+ border-bottom-right-radius: 10px;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
diff --git
a/ui/src/app/data-explorer/components/widgets/traffic-light/traffic-light-widget.component.ts
b/ui/src/app/data-explorer/components/widgets/traffic-light/traffic-light-widget.component.ts
new file mode 100644
index 0000000000..80e3490ddc
--- /dev/null
+++
b/ui/src/app/data-explorer/components/widgets/traffic-light/traffic-light-widget.component.ts
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { Component, OnInit } from '@angular/core';
+import { BaseDataExplorerWidgetDirective } from
'../base/base-data-explorer-widget.directive';
+import { TrafficLightWidgetModel } from './model/traffic-light-widget.model';
+import {
+ DataExplorerField,
+ SpQueryResult,
+} from '@streampipes/platform-services';
+
+@Component({
+ selector: 'sp-data-explorer-traffic-light-widget',
+ templateUrl: './traffic-light-widget.component.html',
+ styleUrls: ['./traffic-light-widget.component.scss'],
+})
+export class TrafficLightWidgetComponent
+ extends BaseDataExplorerWidgetDirective<TrafficLightWidgetModel>
+ implements OnInit
+{
+ row: any[][];
+ header: string[];
+ fieldIndex: number;
+
+ width: number;
+ height: number;
+
+ containerWidth: number;
+ containerHeight: number;
+
+ lightWidth: number;
+ lightHeight: number;
+
+ selectedWarningRange: number;
+ selectedFieldToObserve: DataExplorerField;
+ selectedUpperLimit: boolean;
+ selectedThreshold: number;
+ selectedToShowValue: boolean;
+
+ activeClass = 'red';
+ displayed_value: string;
+
+ ngOnInit(): void {
+ super.ngOnInit();
+ this.onResize(
+ this.gridsterItemComponent.width - this.widthOffset,
+ this.gridsterItemComponent.height - this.heightOffset,
+ );
+ this.updateSettings();
+ }
+
+ updateSettings(): void {
+ this.selectedFieldToObserve =
+ this.dataExplorerWidget.visualizationConfig.selectedFieldToObserve;
+ this.selectedWarningRange =
+ this.dataExplorerWidget.visualizationConfig.selectedWarningRange;
+ this.selectedUpperLimit =
+ this.dataExplorerWidget.visualizationConfig.selectedUpperLimit;
+ this.selectedThreshold =
+ this.dataExplorerWidget.visualizationConfig.selectedThreshold;
+ this.selectedToShowValue =
+ this.dataExplorerWidget.visualizationConfig.selectedToShowValue;
+ }
+
+ getTrafficLightColor(): void {
+ const value = this.row[0][this.fieldIndex];
+ this.displayed_value = value.toFixed(2);
+
+ if (this.isInOkRange(value)) {
+ this.activeClass = 'green';
+ } else if (this.isInWarningRange(value)) {
+ this.activeClass = 'yellow';
+ } else {
+ this.activeClass = 'red';
+ }
+ }
+
+ exceedsThreshold(value) {
+ if (this.selectedUpperLimit) {
+ return value >= this.selectedThreshold;
+ } else {
+ return value <= this.selectedThreshold;
+ }
+ }
+
+ isInWarningRange(value) {
+ if (this.exceedsThreshold(value)) {
+ return false;
+ } else {
+ if (this.selectedUpperLimit) {
+ return (
+ value >=
+ this.selectedThreshold -
+ this.selectedThreshold *
+ (this.selectedWarningRange / 100)
+ );
+ } else {
+ console.log(value);
+
+ return (
+ value <=
+ this.selectedThreshold +
+ this.selectedThreshold *
+ (this.selectedWarningRange / 100)
+ );
+ }
+ }
+ }
+ isInOkRange(value) {
+ return !this.exceedsThreshold(value) && !this.isInWarningRange(value);
+ }
+
+ public refreshView(): void {
+ this.updateSettings();
+ this.fieldToObserve();
+ this.getTrafficLightColor();
+ }
+
+ public beforeDataFetched(): void {
+ this.setShownComponents(false, false, true, false);
+ }
+
+ fieldToObserve(): void {
+ this.fieldIndex = this.header.indexOf(
+ this.selectedFieldToObserve.runtimeName,
+ );
+ }
+
+ public onDataReceived(spQueryResult: SpQueryResult[]): void {
+ this.header = spQueryResult[0].allDataSeries[0].headers;
+ this.row = spQueryResult[0].allDataSeries[0].rows;
+ this.fieldToObserve();
+ this.getTrafficLightColor();
+ this.setShownComponents(false, true, false, false);
+ }
+
+ onResize(width: number, heigth: number) {
+ this.containerHeight = heigth * 0.8;
+ this.containerWidth = this.containerHeight / 3;
+ this.lightWidth = (this.containerHeight * 0.9) / 3;
+ this.lightHeight = this.lightWidth;
+ }
+
+ handleUpdatedFields(
+ addedFields: DataExplorerField[],
+ removedFields: DataExplorerField[],
+ ) {
+ const updatedFields = this.fieldUpdateService.updateFieldSelection(
+ [
+ this.dataExplorerWidget.visualizationConfig
+ .selectedFieldToObserve,
+ ],
+ {
+ addedFields,
+ removedFields,
+ fieldProvider: this.fieldProvider,
+ },
+ () => true,
+ );
+
+ this.selectedFieldToObserve = updatedFields[0];
+ this.fieldToObserve();
+ this.refreshView();
+ }
+}
diff --git a/ui/src/app/data-explorer/data-explorer.module.ts
b/ui/src/app/data-explorer/data-explorer.module.ts
index 81be2dc5fb..09b8f33e75 100644
--- a/ui/src/app/data-explorer/data-explorer.module.ts
+++ b/ui/src/app/data-explorer/data-explorer.module.ts
@@ -46,6 +46,8 @@ import { DataExplorerDashboardPanelComponent } from
'./components/dashboard/data
import { TimeRangeSelectorComponent } from
'./components/time-selector/time-range-selector.component';
import { DataExplorerDashboardWidgetComponent } from
'./components/widget/data-explorer-dashboard-widget.component';
import { ImageWidgetComponent } from
'./components/widgets/image/image-widget.component';
+import { TrafficLightWidgetComponent } from
'./components/widgets/traffic-light/traffic-light-widget.component';
+import { TrafficLightWidgetConfigComponent } from
'./components/widgets/traffic-light/config/traffic-light-widget-config.component';
import { TableWidgetComponent } from
'./components/widgets/table/table-widget.component';
import { AggregateConfigurationComponent } from
'./components/widgets/utils/aggregate-configuration/aggregate-configuration.component';
import { LoadDataSpinnerComponent } from
'./components/widgets/utils/load-data-spinner/load-data-spinner.component';
@@ -247,6 +249,8 @@ import { GaugeWidgetConfigComponent } from
'./components/widgets/gauge/config/ga
SelectPropertyComponent,
TableWidgetComponent,
TableWidgetConfigComponent,
+ TrafficLightWidgetComponent,
+ TrafficLightWidgetConfigComponent,
MapWidgetConfigComponent,
MapWidgetComponent,
HeatmapWidgetConfigComponent,
diff --git a/ui/src/app/data-explorer/registry/data-explorer-widget-registry.ts
b/ui/src/app/data-explorer/registry/data-explorer-widget-registry.ts
index 4ef84d7dca..c2d486bfd6 100644
--- a/ui/src/app/data-explorer/registry/data-explorer-widget-registry.ts
+++ b/ui/src/app/data-explorer/registry/data-explorer-widget-registry.ts
@@ -52,6 +52,8 @@ import { SpTimeSeriesAppearanceConfigComponent } from
'../components/widgets/tim
import { SpGaugeRendererService } from
'../components/widgets/gauge/gauge-renderer.service';
import { GaugeWidgetConfigComponent } from
'../components/widgets/gauge/config/gauge-widget-config.component';
import { GaugeWidgetModel } from
'../components/widgets/gauge/model/gauge-widget.model';
+import { TrafficLightWidgetConfigComponent } from
'../components/widgets/traffic-light/config/traffic-light-widget-config.component';
+import { TrafficLightWidgetComponent } from
'../components/widgets/traffic-light/traffic-light-widget.component';
@Injectable({ providedIn: 'root' })
export class DataExplorerWidgetRegistry {
@@ -84,6 +86,12 @@ export class DataExplorerWidgetRegistry {
widgetConfigurationComponent: TableWidgetConfigComponent,
widgetComponent: TableWidgetComponent,
},
+ {
+ id: 'traffic-Light',
+ label: 'Traffic Light',
+ widgetConfigurationComponent:
TrafficLightWidgetConfigComponent,
+ widgetComponent: TrafficLightWidgetComponent,
+ },
{
id: 'map',
label: 'Map',