+
+
diff --git a/ui/src/app/data-explorer/components/widgets/status/config/status-widget-config.component.scss b/ui/src/app/data-explorer/components/widgets/status/config/status-widget-config.component.scss
new file mode 100644
index 0000000000..c3105ba0e4
--- /dev/null
+++ b/ui/src/app/data-explorer/components/widgets/status/config/status-widget-config.component.scss
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+.color-box {
+ display: inline-block;
+ width: 12px;
+ height: 12px;
+ margin-right: 5px;
+ border-radius: 50%;
+}
+.spacing {
+ margin-left: 15px;
+}
+.green-box {
+ background-color: green;
+}
+
+.red-box {
+ background-color: red;
+}
+
+.checkbox-container {
+ margin-top: 20px;
+}
diff --git a/ui/src/app/data-explorer/components/widgets/status/config/status-widget-config.component.ts b/ui/src/app/data-explorer/components/widgets/status/config/status-widget-config.component.ts
new file mode 100644
index 0000000000..f671616d16
--- /dev/null
+++ b/ui/src/app/data-explorer/components/widgets/status/config/status-widget-config.component.ts
@@ -0,0 +1,91 @@
+/*
+ * 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 {
+ StatusWidgetModel,
+ StatusVisConfig,
+} from '../model/status-widget.model';
+import { DataExplorerFieldProviderService } from '../../../../services/data-explorer-field-provider-service';
+import { DataExplorerField } from '@streampipes/platform-services';
+
+@Component({
+ selector: 'sp-data-explorer-status-widget-config',
+ templateUrl: './status-widget-config.component.html',
+ styleUrls: ['./status-widget-config.component.scss'],
+})
+export class StatusWidgetConfigComponent extends BaseWidgetConfig<
+ StatusWidgetModel,
+ StatusVisConfig
+> {
+ constructor(
+ widgetConfigurationService: WidgetConfigurationService,
+ fieldService: DataExplorerFieldProviderService,
+ ) {
+ super(widgetConfigurationService, fieldService);
+ }
+
+ selectDataType(selectedDataType: string): void {
+ this.currentlyConfiguredWidget.visualizationConfig.selectedDataType =
+ selectedDataType;
+ this.triggerViewRefresh();
+ }
+
+ selectInterval(selectedInterval: number): void {
+ this.currentlyConfiguredWidget.visualizationConfig.selectedInterval =
+ selectedInterval;
+ this.triggerViewRefresh();
+ }
+
+ showLastSeen(selectedLastSeen: boolean): void {
+ this.currentlyConfiguredWidget.visualizationConfig.showLastSeen =
+ selectedLastSeen;
+ this.triggerViewRefresh();
+ }
+
+ selectBooleanFieldToObserve(
+ selectedBooleanFieldToObserve: DataExplorerField,
+ ): void {
+ this.currentlyConfiguredWidget.visualizationConfig.selectedBooleanFieldToObserve =
+ selectedBooleanFieldToObserve;
+ this.triggerViewRefresh();
+ }
+
+ selectMappingGreenTrue(selectedMappingGreenTrue: boolean): void {
+ this.currentlyConfiguredWidget.visualizationConfig.selectedMappingGreenTrue =
+ selectedMappingGreenTrue;
+ this.triggerViewRefresh();
+ }
+
+ protected applyWidgetConfig(config: StatusVisConfig): void {
+ config.selectedBooleanFieldToObserve =
+ this.fieldService.getSelectedField(
+ config.selectedBooleanFieldToObserve,
+ this.fieldProvider.allFields,
+ () => this.fieldProvider.allFields[0],
+ );
+ this.currentlyConfiguredWidget.visualizationConfig.selectedInterval ??= 5;
+ this.currentlyConfiguredWidget.visualizationConfig.selectedMappingGreenTrue ??=
+ true;
+ }
+ protected requiredFieldsForChartPresent(): boolean {
+ return true;
+ }
+}
diff --git a/ui/src/app/data-explorer/components/widgets/status/model/status-widget.model.ts b/ui/src/app/data-explorer/components/widgets/status/model/status-widget.model.ts
new file mode 100644
index 0000000000..73bb53e69d
--- /dev/null
+++ b/ui/src/app/data-explorer/components/widgets/status/model/status-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 StatusVisConfig extends DataExplorerVisConfig {
+ selectedDataType: string;
+ selectedInterval: number;
+ showLastSeen: boolean;
+ selectedBooleanFieldToObserve: DataExplorerField;
+ selectedMappingGreenTrue: boolean;
+}
+
+export interface StatusWidgetModel extends DataExplorerWidgetModel {
+ dataConfig: DataExplorerDataConfig;
+ visualizationConfig: StatusVisConfig;
+}
diff --git a/ui/src/app/data-explorer/components/widgets/status/status-widget.component.html b/ui/src/app/data-explorer/components/widgets/status/status-widget.component.html
new file mode 100644
index 0000000000..ad01626a9f
--- /dev/null
+++ b/ui/src/app/data-explorer/components/widgets/status/status-widget.component.html
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Last seen: {{ lastTimestamp | date: 'short' }}
+
+
diff --git a/ui/src/app/data-explorer/components/widgets/status/status-widget.component.scss b/ui/src/app/data-explorer/components/widgets/status/status-widget.component.scss
new file mode 100644
index 0000000000..ac656663e5
--- /dev/null
+++ b/ui/src/app/data-explorer/components/widgets/status/status-widget.component.scss
@@ -0,0 +1,57 @@
+/*
+ * 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;
+ flex-direction: column;
+ padding: 20px;
+ border-radius: 10px;
+}
+
+.light {
+ border-radius: 50%;
+ background-color: #3d3535;
+ background: repeating-linear-gradient(#333, #443 5px);
+}
+
+.light-red,
+.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-green {
+ background: repeating-linear-gradient(#0d0, #0c0 5px);
+ box-shadow: 0 0 40px #0d0;
+}
+
+.title-panel {
+ font-size: 20px;
+ height: 30px;
+ margin: 10px 0;
+}
diff --git a/ui/src/app/data-explorer/components/widgets/status/status-widget.component.ts b/ui/src/app/data-explorer/components/widgets/status/status-widget.component.ts
new file mode 100644
index 0000000000..abb41e549c
--- /dev/null
+++ b/ui/src/app/data-explorer/components/widgets/status/status-widget.component.ts
@@ -0,0 +1,164 @@
+/*
+ * 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 { StatusWidgetModel } from './model/status-widget.model';
+import {
+ DataExplorerField,
+ SpQueryResult,
+} from '@streampipes/platform-services';
+
+@Component({
+ selector: 'sp-data-explorer-status-widget',
+ templateUrl: './status-widget.component.html',
+ styleUrls: ['./status-widget.component.scss'],
+})
+export class StatusWidgetComponent
+ extends BaseDataExplorerWidgetDirective
+ implements OnInit
+{
+ width: number;
+ height: number;
+
+ row: any[][];
+ header: string[];
+ fieldIndex = -1;
+
+ containerWidth: number;
+ containerHeight: number;
+
+ lightWidth: number;
+ lightHeight: number;
+
+ selectedDataType: string;
+ selectedInterval: number;
+ showLastSeen: boolean;
+ selectedBooleanFieldToObserve: DataExplorerField;
+ selectedMappingGreenTrue: boolean;
+
+ lastTimestamp = 0;
+ active: boolean;
+
+ ngOnInit(): void {
+ super.ngOnInit();
+ this.onResize(
+ this.gridsterItemComponent.width - this.widthOffset,
+ this.gridsterItemComponent.height - this.heightOffset,
+ );
+ this.updateSettings();
+ }
+
+ updateSettings(): void {
+ this.selectedDataType =
+ this.dataExplorerWidget.visualizationConfig.selectedDataType;
+ this.selectedInterval =
+ this.dataExplorerWidget.visualizationConfig.selectedInterval;
+ this.showLastSeen =
+ this.dataExplorerWidget.visualizationConfig.showLastSeen;
+ this.selectedBooleanFieldToObserve =
+ this.dataExplorerWidget.visualizationConfig.selectedBooleanFieldToObserve;
+ this.selectedMappingGreenTrue =
+ this.dataExplorerWidget.visualizationConfig.selectedMappingGreenTrue;
+ }
+
+ getNumericalStatus(): void {
+ const timestamp = new Date().getTime();
+ this.active =
+ this.lastTimestamp >= timestamp - this.selectedInterval * 1000;
+ }
+
+ getBooleanStatus(): void {
+ if (this.selectedMappingGreenTrue) {
+ this.active = this.row[0][this.fieldIndex];
+ } else {
+ this.active = !this.row[0][this.fieldIndex];
+ }
+ }
+
+ booleanFieldToObserve(): void {
+ this.fieldIndex = this.header.indexOf(
+ this.selectedBooleanFieldToObserve.runtimeName,
+ );
+ }
+
+ refreshView(): void {
+ this.updateSettings();
+ if (this.row !== undefined && this.row.length > 0) {
+ if (this.selectedDataType == 'boolean') {
+ this.getBooleanStatus();
+ } else {
+ this.getNumericalStatus();
+ }
+ }
+ }
+
+ beforeDataFetched(): void {
+ this.setShownComponents(false, false, true, false);
+ }
+
+ onDataReceived(spQueryResult: SpQueryResult[]): void {
+ if (
+ spQueryResult.length > 0 &&
+ spQueryResult[0].allDataSeries.length > 0
+ ) {
+ this.header = spQueryResult[0].allDataSeries[0].headers;
+ this.row = spQueryResult[0].allDataSeries[0].rows;
+ this.lastTimestamp = spQueryResult[0].allDataSeries[0].rows[0][0];
+
+ if (this.selectedDataType == 'number') {
+ this.getNumericalStatus();
+ } else if (this.selectedDataType == 'boolean') {
+ this.booleanFieldToObserve();
+ this.getBooleanStatus();
+ }
+ this.setShownComponents(false, true, false, false);
+ } else {
+ this.setShownComponents(true, false, false, false);
+ }
+ }
+
+ onResize(width: number, heigth: number): void {
+ this.containerHeight = heigth * 0.3;
+ this.containerWidth = this.containerHeight;
+ this.lightWidth = this.containerHeight;
+ this.lightHeight = this.lightWidth;
+ }
+
+ handleUpdatedFields(
+ addedFields: DataExplorerField[],
+ removedFields: DataExplorerField[],
+ ) {
+ const updatedFields = this.fieldUpdateService.updateFieldSelection(
+ [
+ this.dataExplorerWidget.visualizationConfig
+ .selectedBooleanFieldToObserve,
+ ],
+ {
+ addedFields,
+ removedFields,
+ fieldProvider: this.fieldProvider,
+ },
+ () => true,
+ );
+
+ this.selectedBooleanFieldToObserve = updatedFields[0];
+ this.booleanFieldToObserve();
+ this.refreshView();
+ }
+}
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
index 80e3490ddc..99df13f09f 100644
--- 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
@@ -110,8 +110,6 @@ export class TrafficLightWidgetComponent
(this.selectedWarningRange / 100)
);
} else {
- console.log(value);
-
return (
value <=
this.selectedThreshold +
@@ -125,13 +123,13 @@ export class TrafficLightWidgetComponent
return !this.exceedsThreshold(value) && !this.isInWarningRange(value);
}
- public refreshView(): void {
+ refreshView(): void {
this.updateSettings();
this.fieldToObserve();
this.getTrafficLightColor();
}
- public beforeDataFetched(): void {
+ beforeDataFetched(): void {
this.setShownComponents(false, false, true, false);
}
@@ -141,12 +139,19 @@ export class TrafficLightWidgetComponent
);
}
- 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);
+ onDataReceived(spQueryResult: SpQueryResult[]): void {
+ if (
+ spQueryResult.length > 0 &&
+ spQueryResult[0].allDataSeries.length > 0
+ ) {
+ this.header = spQueryResult[0].allDataSeries[0].headers;
+ this.row = spQueryResult[0].allDataSeries[0].rows;
+ this.fieldToObserve();
+ this.getTrafficLightColor();
+ this.setShownComponents(false, true, false, false);
+ } else {
+ this.setShownComponents(true, false, false, false);
+ }
}
onResize(width: number, heigth: number) {
diff --git a/ui/src/app/data-explorer/data-explorer.module.ts b/ui/src/app/data-explorer/data-explorer.module.ts
index 09b8f33e75..c3070b45b5 100644
--- a/ui/src/app/data-explorer/data-explorer.module.ts
+++ b/ui/src/app/data-explorer/data-explorer.module.ts
@@ -48,6 +48,8 @@ import { DataExplorerDashboardWidgetComponent } from './components/widget/data-e
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 { StatusWidgetComponent } from './components/widgets/status/status-widget.component';
+import { StatusWidgetConfigComponent } from './components/widgets/status/config/status-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';
@@ -251,6 +253,8 @@ import { GaugeWidgetConfigComponent } from './components/widgets/gauge/config/ga
TableWidgetConfigComponent,
TrafficLightWidgetComponent,
TrafficLightWidgetConfigComponent,
+ StatusWidgetComponent,
+ StatusWidgetConfigComponent,
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 c2d486bfd6..efb221b3b6 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
@@ -54,6 +54,8 @@ import { GaugeWidgetConfigComponent } from '../components/widgets/gauge/config/g
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';
+import { StatusWidgetConfigComponent } from '../components/widgets/status/config/status-widget-config.component';
+import { StatusWidgetComponent } from '../components/widgets/status/status-widget.component';
@Injectable({ providedIn: 'root' })
export class DataExplorerWidgetRegistry {
@@ -92,6 +94,12 @@ export class DataExplorerWidgetRegistry {
widgetConfigurationComponent: TrafficLightWidgetConfigComponent,
widgetComponent: TrafficLightWidgetComponent,
},
+ {
+ id: 'status',
+ label: 'Status',
+ widgetConfigurationComponent: StatusWidgetConfigComponent,
+ widgetComponent: StatusWidgetComponent,
+ },
{
id: 'map',
label: 'Map',