You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by ri...@apache.org on 2024/08/11 20:42:32 UTC

(streampipes) branch 3090-add-gauge-chart-to-data-explorer created (now 8bd4ac21e1)

This is an automated email from the ASF dual-hosted git repository.

riemer pushed a change to branch 3090-add-gauge-chart-to-data-explorer
in repository https://gitbox.apache.org/repos/asf/streampipes.git


      at 8bd4ac21e1 feat(#3090): Add gauge chart to data explorer

This branch includes the following new commits:

     new 8bd4ac21e1 feat(#3090): Add gauge chart to data explorer

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(streampipes) 01/01: feat(#3090): Add gauge chart to data explorer

Posted by ri...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

riemer pushed a commit to branch 3090-add-gauge-chart-to-data-explorer
in repository https://gitbox.apache.org/repos/asf/streampipes.git

commit 8bd4ac21e1a8097337c377665084e0e1e0c68082
Author: Dominik Riemer <do...@gmail.com>
AuthorDate: Sun Aug 11 22:41:58 2024 +0200

    feat(#3090): Add gauge chart to data explorer
---
 .../src/lib/apis/datalake-rest.service.ts          |   8 +-
 .../data-explorer-dashboard-panel.component.ts     |   1 +
 .../base/base-data-explorer-widget.directive.ts    |   2 -
 .../config/gauge-widget-config.component.html      | 100 +++++++++++++++++
 .../gauge/config/gauge-widget-config.component.ts  |  60 +++++++++++
 .../widgets/gauge/gauge-renderer.service.ts        | 118 +++++++++++++++++++++
 .../widgets/gauge/model/gauge-widget.model.ts      |  38 +++++++
 ui/src/app/data-explorer/data-explorer.module.ts   |   2 +
 .../registry/data-explorer-widget-registry.ts      |  13 +++
 9 files changed, 339 insertions(+), 3 deletions(-)

diff --git a/ui/projects/streampipes/platform-services/src/lib/apis/datalake-rest.service.ts b/ui/projects/streampipes/platform-services/src/lib/apis/datalake-rest.service.ts
index 76f552ac3e..09535f38d3 100644
--- a/ui/projects/streampipes/platform-services/src/lib/apis/datalake-rest.service.ts
+++ b/ui/projects/streampipes/platform-services/src/lib/apis/datalake-rest.service.ts
@@ -17,11 +17,17 @@
  */
 
 import { Injectable } from '@angular/core';
-import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http';
+import {
+    HttpClient,
+    HttpContext,
+    HttpParams,
+    HttpRequest,
+} from '@angular/common/http';
 import { Observable, of } from 'rxjs';
 import { DataLakeMeasure, SpQueryResult } from '../model/gen/streampipes-model';
 import { map } from 'rxjs/operators';
 import { DatalakeQueryParameters } from '../model/datalake/DatalakeQueryParameters';
+import { NGX_LOADING_BAR_IGNORED } from '@ngx-loading-bar/http-client';
 
 @Injectable({
     providedIn: 'root',
diff --git a/ui/src/app/data-explorer/components/dashboard/data-explorer-dashboard-panel.component.ts b/ui/src/app/data-explorer/components/dashboard/data-explorer-dashboard-panel.component.ts
index e932e8945a..8f2c7ad649 100644
--- a/ui/src/app/data-explorer/components/dashboard/data-explorer-dashboard-panel.component.ts
+++ b/ui/src/app/data-explorer/components/dashboard/data-explorer-dashboard-panel.component.ts
@@ -216,6 +216,7 @@ export class DataExplorerDashboardPanelComponent implements OnInit, OnDestroy {
                     ? this.overrideTime(+startTime, +endTime)
                     : this.dashboard.dashboardTimeSettings;
             this.dashboardLoaded = true;
+            this.modifyRefreshInterval();
         });
     }
 
diff --git a/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts b/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts
index beaea66509..b8e86ffdb9 100644
--- a/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts
+++ b/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts
@@ -147,7 +147,6 @@ export abstract class BaseDataExplorerWidgetDirective<
                 this.timerCallback.emit(false);
                 setTimeout(() => {
                     this.validateReceivedData(results);
-                    this.refreshView();
                 });
             });
 
@@ -234,7 +233,6 @@ export abstract class BaseDataExplorerWidgetDirective<
 
     public updateData(includeTooMuchEventsParameter: boolean = true) {
         this.beforeDataFetched();
-
         this.loadData(includeTooMuchEventsParameter);
     }
 
diff --git a/ui/src/app/data-explorer/components/widgets/gauge/config/gauge-widget-config.component.html b/ui/src/app/data-explorer/components/widgets/gauge/config/gauge-widget-config.component.html
new file mode 100644
index 0000000000..f50603abd6
--- /dev/null
+++ b/ui/src/app/data-explorer/components/widgets/gauge/config/gauge-widget-config.component.html
@@ -0,0 +1,100 @@
+<!--
+  ~ 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.selectedProperty
+            "
+            (changeSelectedProperty)="setSelectedProperty($event)"
+        >
+        </sp-select-property>
+    </sp-configuration-box>
+    <sp-configuration-box
+        title="Settings"
+        *ngIf="
+            currentlyConfiguredWidget.visualizationConfig.selectedProperty
+                ?.fieldCharacteristics.numeric
+        "
+    >
+        <div fxLayout="column">
+            <div fxFlex fxLayoutAlign="start center" class="ml-10 mb-10">
+                <small>Min</small>
+                <span fxFlex></span>
+                <mat-form-field appearance="outline" color="accent" fxFlex="30">
+                    <input
+                        matInput
+                        type="number"
+                        [(ngModel)]="
+                            currentlyConfiguredWidget.visualizationConfig.min
+                        "
+                        (ngModelChange)="triggerViewRefresh()"
+                    />
+                </mat-form-field>
+            </div>
+            <div fxFlex fxLayoutAlign="start center" class="ml-10 mb-10">
+                <small>Max</small>
+                <span fxFlex></span>
+                <mat-form-field appearance="outline" color="accent" fxFlex="30">
+                    <input
+                        matInput
+                        type="number"
+                        [(ngModel)]="
+                            currentlyConfiguredWidget.visualizationConfig.max
+                        "
+                        (ngModelChange)="triggerViewRefresh()"
+                    />
+                </mat-form-field>
+            </div>
+        </div>
+        <!--    <div-->
+        <!--        fxFlex="100"-->
+        <!--        fxLayout="row"-->
+        <!--        fxLayoutAlign="start center"-->
+        <!--        fxLayoutGap="10px"-->
+        <!--    >-->
+        <!--      <small>Rounding</small>-->
+        <!--      <mat-form-field-->
+        <!--          appearance="outline"-->
+        <!--          class="marginColorField"-->
+        <!--          color="accent"-->
+        <!--          fxFlex-->
+        <!--      >-->
+        <!--        <mat-select-->
+        <!--            [(value)]="-->
+        <!--                        currentlyConfiguredWidget.visualizationConfig-->
+        <!--                            .roundingValue-->
+        <!--                    "-->
+        <!--            (selectionChange)="updateRoundingValue($event.value)"-->
+        <!--        >-->
+        <!--          <mat-option [value]="100">100</mat-option>-->
+        <!--          <mat-option [value]="10">10</mat-option>-->
+        <!--          <mat-option [value]="1">1</mat-option>-->
+        <!--          <mat-option [value]="0.1">0.1</mat-option>-->
+        <!--          <mat-option [value]="0.01">0.01</mat-option>-->
+        <!--        </mat-select>-->
+        <!--      </mat-form-field>-->
+        <!--    </div>-->
+    </sp-configuration-box>
+</sp-visualization-config-outer>
diff --git a/ui/src/app/data-explorer/components/widgets/gauge/config/gauge-widget-config.component.ts b/ui/src/app/data-explorer/components/widgets/gauge/config/gauge-widget-config.component.ts
new file mode 100644
index 0000000000..809b0f303b
--- /dev/null
+++ b/ui/src/app/data-explorer/components/widgets/gauge/config/gauge-widget-config.component.ts
@@ -0,0 +1,60 @@
+/*
+ * 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 { DataExplorerFieldProviderService } from '../../../../services/data-explorer-field-provider-service';
+import { GaugeVisConfig, GaugeWidgetModel } from '../model/gauge-widget.model';
+import { DataExplorerField } from '@streampipes/platform-services';
+
+@Component({
+    selector: 'sp-data-explorer-gauge-widget-config',
+    templateUrl: './gauge-widget-config.component.html',
+})
+export class GaugeWidgetConfigComponent extends BaseWidgetConfig<
+    GaugeWidgetModel,
+    GaugeVisConfig
+> {
+    constructor(
+        widgetConfigurationService: WidgetConfigurationService,
+        fieldService: DataExplorerFieldProviderService,
+    ) {
+        super(widgetConfigurationService, fieldService);
+    }
+
+    setSelectedProperty(field: DataExplorerField) {
+        this.currentlyConfiguredWidget.visualizationConfig.selectedProperty =
+            field;
+        this.triggerViewRefresh();
+    }
+
+    protected applyWidgetConfig(config: GaugeVisConfig): void {
+        config.selectedProperty = this.fieldService.getSelectedField(
+            config.selectedProperty,
+            this.fieldProvider.numericFields,
+            () => this.fieldProvider.numericFields[0],
+        );
+        config.min ??= 0;
+        config.max ??= 100;
+    }
+
+    protected requiredFieldsForChartPresent(): boolean {
+        return this.fieldProvider.numericFields.length > 0;
+    }
+}
diff --git a/ui/src/app/data-explorer/components/widgets/gauge/gauge-renderer.service.ts b/ui/src/app/data-explorer/components/widgets/gauge/gauge-renderer.service.ts
new file mode 100644
index 0000000000..e7e6e9d4af
--- /dev/null
+++ b/ui/src/app/data-explorer/components/widgets/gauge/gauge-renderer.service.ts
@@ -0,0 +1,118 @@
+/*
+ * 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 { inject, Injectable } from '@angular/core';
+import { GaugeWidgetModel } from './model/gauge-widget.model';
+import { EChartsOption, GaugeSeriesOption } from 'echarts';
+import { FieldUpdateInfo } from '../../../models/field-update.model';
+import {
+    DataExplorerField,
+    SpQueryResult,
+} from '@streampipes/platform-services';
+import {
+    SpEchartsRenderer,
+    WidgetEchartsAppearanceConfig,
+} from '../../../models/dataview-dashboard.model';
+import { WidgetSize } from '../../../models/dataset.model';
+import { EchartsBasicOptionsGeneratorService } from '../../../echarts-renderer/echarts-basic-options-generator.service';
+import { SpFieldUpdateService } from '../../../services/field-update.service';
+
+@Injectable({ providedIn: 'root' })
+export class SpGaugeRendererService
+    implements SpEchartsRenderer<GaugeWidgetModel>
+{
+    protected fieldUpdateService = inject(SpFieldUpdateService);
+    protected echartsBaseOptionsGenerator = inject(
+        EchartsBasicOptionsGeneratorService,
+    );
+
+    makeSeriesItem(
+        seriesName: string,
+        fieldName: string,
+        value: number,
+        widgetConfig: GaugeWidgetModel,
+    ): GaugeSeriesOption {
+        const visConfig = widgetConfig.visualizationConfig;
+        return {
+            name: seriesName,
+            type: 'gauge',
+            progress: {
+                show: true,
+            },
+            detail: {
+                show: true,
+                valueAnimation: false,
+                formatter: '{value}',
+            },
+            min: visConfig.min,
+            max: visConfig.max,
+            data: [
+                {
+                    value: value,
+                    name: fieldName,
+                },
+            ],
+        };
+    }
+
+    getSelectedField(widgetConfig: GaugeWidgetModel): DataExplorerField {
+        return widgetConfig.visualizationConfig.selectedProperty;
+    }
+
+    handleUpdatedFields(
+        fieldUpdateInfo: FieldUpdateInfo,
+        widgetConfig: GaugeWidgetModel,
+    ): void {
+        this.fieldUpdateService.updateAnyField(
+            this.getSelectedField(widgetConfig),
+            fieldUpdateInfo,
+        );
+    }
+
+    render(
+        queryResult: SpQueryResult[],
+        widgetConfig: GaugeWidgetModel,
+        _widgetSize: WidgetSize,
+    ): EChartsOption {
+        const option = this.echartsBaseOptionsGenerator.makeBaseConfig(
+            widgetConfig.baseAppearanceConfig as WidgetEchartsAppearanceConfig,
+            {},
+        );
+        const selectedField = this.getSelectedField(widgetConfig);
+        const sourceIndex = selectedField.sourceIndex;
+        const dataSeries = queryResult[sourceIndex].allDataSeries[0];
+        const columnIndex = dataSeries.headers.indexOf(
+            selectedField.fullDbName,
+        );
+        const data = parseFloat(dataSeries.rows[0][columnIndex].toFixed(2));
+        Object.assign(option, {
+            grid: {
+                width: '100%',
+                height: '100%',
+            },
+            series: this.makeSeriesItem(
+                '',
+                selectedField.fullDbName,
+                data,
+                widgetConfig,
+            ),
+        });
+
+        return option;
+    }
+}
diff --git a/ui/src/app/data-explorer/components/widgets/gauge/model/gauge-widget.model.ts b/ui/src/app/data-explorer/components/widgets/gauge/model/gauge-widget.model.ts
new file mode 100644
index 0000000000..ee76a6ed9c
--- /dev/null
+++ b/ui/src/app/data-explorer/components/widgets/gauge/model/gauge-widget.model.ts
@@ -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.
+ *
+ */
+
+import {
+    DataExplorerDataConfig,
+    DataExplorerField,
+    DataExplorerWidgetModel,
+} from '@streampipes/platform-services';
+import {
+    AxisConfig,
+    DataExplorerVisConfig,
+} from '../../../../models/dataview-dashboard.model';
+
+export interface GaugeVisConfig extends DataExplorerVisConfig {
+    selectedProperty: DataExplorerField;
+    min: number;
+    max: number;
+}
+
+export interface GaugeWidgetModel extends DataExplorerWidgetModel {
+    dataConfig: DataExplorerDataConfig;
+    visualizationConfig: GaugeVisConfig;
+}
diff --git a/ui/src/app/data-explorer/data-explorer.module.ts b/ui/src/app/data-explorer/data-explorer.module.ts
index 2fc83096f5..d3f42afa9a 100644
--- a/ui/src/app/data-explorer/data-explorer.module.ts
+++ b/ui/src/app/data-explorer/data-explorer.module.ts
@@ -129,6 +129,7 @@ import { TimeRangeSelectorMenuComponent } from './components/time-selector/time-
 import { CustomTimeRangeSelectionComponent } from './components/time-selector/time-selector-menu/custom-time-range-selection/custom-time-range-selection.component';
 import { DataExplorerRefreshIntervalSettingsComponent } from './components/dashboard/dashboard-toolbar/refresh-interval-settings/refresh-interval-settings.component';
 import { OrderSelectionPanelComponent } from './components/data-view/data-view-designer-panel/data-settings/order-selection-panel/order-selection-panel.component';
+import { GaugeWidgetConfigComponent } from './components/widgets/gauge/config/gauge-widget-config.component';
 
 @NgModule({
     imports: [
@@ -230,6 +231,7 @@ import { OrderSelectionPanelComponent } from './components/data-view/data-view-d
         FieldSelectionPanelComponent,
         FieldSelectionComponent,
         FilterSelectionPanelComponent,
+        GaugeWidgetConfigComponent,
         GroupConfigurationComponent,
         ImageWidgetComponent,
         ImageBarComponent,
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 c37eeb475d..4ef84d7dca 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
@@ -49,12 +49,16 @@ import { TimeSeriesChartWidgetModel } from '../components/widgets/time-series-ch
 import { SpTimeseriesRendererService } from '../components/widgets/time-series-chart/sp-timeseries-renderer.service';
 import { SpEchartsWidgetAppearanceConfigComponent } from '../components/widgets/utils/echarts-widget-appearance-config/echarts-widget-appearance-config.component';
 import { SpTimeSeriesAppearanceConfigComponent } from '../components/widgets/time-series-chart/appearance-config/time-series-appearance-config.component';
+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';
 
 @Injectable({ providedIn: 'root' })
 export class DataExplorerWidgetRegistry {
     widgetTypes: IWidget<any>[] = [];
 
     constructor(
+        private gaugeRenderer: SpGaugeRendererService,
         private heatmapRenderer: SpHeatmapRendererService,
         private histogramRenderer: SpHistogramRendererService,
         private pieRenderer: SpPieRendererService,
@@ -65,6 +69,15 @@ export class DataExplorerWidgetRegistry {
         private timeseriesRenderer: SpTimeseriesRendererService,
     ) {
         this.widgetTypes = [
+            {
+                id: 'gauge',
+                label: 'Gauge',
+                widgetAppearanceConfigurationComponent:
+                    SpEchartsWidgetAppearanceConfigComponent,
+                widgetConfigurationComponent: GaugeWidgetConfigComponent,
+                widgetComponent: SpEchartsWidgetComponent<GaugeWidgetModel>,
+                chartRenderer: this.gaugeRenderer,
+            },
             {
                 id: 'table',
                 label: 'Table',