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 2022/02/04 16:11:15 UTC
[incubator-streampipes] branch experimental-module-federation-494 updated: [hotfix] Show possible values of tags in data explorer query config
This is an automated email from the ASF dual-hosted git repository.
riemer pushed a commit to branch experimental-module-federation-494
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git
The following commit(s) were added to refs/heads/experimental-module-federation-494 by this push:
new 29612cb [hotfix] Show possible values of tags in data explorer query config
29612cb is described below
commit 29612cb4f57db521f0e84285be4541bdb873f836
Author: Dominik Riemer <do...@gmail.com>
AuthorDate: Fri Feb 4 17:10:58 2022 +0100
[hotfix] Show possible values of tags in data explorer query config
---
.../dataexplorer/DataLakeManagementV4.java | 42 +++++++++++++++++++---
.../apache/streampipes/ps/DataLakeResourceV4.java | 9 +++++
.../src/lib/apis/datalake-rest.service.ts | 6 ++++
.../filter-selection-panel.component.html | 22 ++++++++++--
.../filter-selection-panel.component.ts | 40 +++++++++++++++++----
5 files changed, 106 insertions(+), 13 deletions(-)
diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataLakeManagementV4.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataLakeManagementV4.java
index 11aff0a..9f659f1 100644
--- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataLakeManagementV4.java
+++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataLakeManagementV4.java
@@ -20,6 +20,7 @@ package org.apache.streampipes.dataexplorer;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
+import org.apache.streampipes.config.backend.BackendConfig;
import org.apache.streampipes.dataexplorer.param.RetentionPolicyQueryParams;
import org.apache.streampipes.dataexplorer.query.DeleteDataQuery;
import org.apache.streampipes.dataexplorer.query.EditRetentionPolicyQuery;
@@ -31,24 +32,32 @@ import org.apache.streampipes.dataexplorer.v4.SupportedDataLakeQueryParameters;
import org.apache.streampipes.dataexplorer.v4.params.QueryParamsV4;
import org.apache.streampipes.dataexplorer.v4.query.DataExplorerQueryV4;
import org.apache.streampipes.dataexplorer.v4.utils.DataLakeManagementUtils;
-import org.apache.streampipes.model.datalake.*;
+import org.apache.streampipes.model.datalake.DataLakeConfiguration;
+import org.apache.streampipes.model.datalake.DataLakeMeasure;
+import org.apache.streampipes.model.datalake.DataLakeRetentionPolicy;
+import org.apache.streampipes.model.datalake.SpQueryResult;
import org.apache.streampipes.storage.couchdb.utils.Utils;
+import org.influxdb.InfluxDB;
+import org.influxdb.dto.Query;
import org.influxdb.dto.QueryResult;
import org.lightcouch.CouchDbClient;
import java.io.IOException;
import java.io.OutputStream;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.time.*;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAccessor;
+import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.TimeZone;
+import java.util.stream.Collectors;
import static org.apache.streampipes.dataexplorer.v4.SupportedDataLakeQueryParameters.*;
@@ -294,4 +303,27 @@ public class DataLakeManagementV4 {
return Instant.EPOCH.until(instant, ChronoUnit.MILLIS);
}
+ public Map<String, Object> getTagValues(String measurementId,
+ String fields) {
+ InfluxDB influxDB = DataExplorerUtils.getInfluxDBClient();
+ Map<String, Object> tags = new HashMap<>();
+ List<String> fieldList = Arrays.asList(fields.split(","));
+ fieldList.forEach(f -> {
+ String q = "SHOW TAG VALUES ON \"" + BackendConfig.INSTANCE.getInfluxDatabaseName() + "\" FROM \"" +measurementId + "\" WITH KEY = \"" +f + "\"";
+ Query query = new Query(q);
+ QueryResult queryResult = influxDB.query(query);
+ queryResult.getResults().forEach(res -> {
+ res.getSeries().forEach(series -> {
+ if (series.getValues().size() > 0) {
+ String field = series.getValues().get(0).get(0).toString();
+ List<String> values = series.getValues().stream().map(v -> v.get(1).toString()).collect(Collectors.toList());
+ tags.put(field, values);
+ }
+ });
+ });
+ System.out.println(queryResult.getResults().size());
+ });
+
+ return tags;
+ }
}
diff --git a/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeResourceV4.java b/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeResourceV4.java
index 28350d1..4791b4c 100644
--- a/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeResourceV4.java
+++ b/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeResourceV4.java
@@ -120,6 +120,15 @@ public class DataLakeResourceV4 extends AbstractRestResource {
return ok(allMeasurements);
}
+ @GET
+ @Path("/measurements/{measurementId}/tags")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getTagValues(@PathParam("measurementId") String measurementId,
+ @QueryParam("fields") String fields) {
+ Map<String, Object> tagValues = dataLakeManagement.getTagValues(measurementId, fields);
+ return ok(tagValues);
+ }
+
@GET
@Path("/measurements/{measurementID}")
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 d4f1331..b1adceb 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
@@ -64,6 +64,12 @@ export class DatalakeRestService {
return this.http.get<PageResult>(url, { params: queryParams });
}
+ getTagValues(index: string,
+ fieldNames: string[]): Observable<Map<string, string[]>> {
+ return this.http.get(this.dataLakeUrl + '/measurements/' + index + '/tags?fields=' + fieldNames.toString())
+ .pipe(map(r => r as Map<string, string[]>));
+ }
+
// getGroupedData(index: string, groupingTags: string, aggregationFunction?: string, columns?: string, startDate?: number, endDate?:
// number, aggregationTimeUnit?: string, aggregationTimeValue?: number, order?: string, limit?: number):
// Observable<SpQueryResult> {
diff --git a/ui/src/app/data-explorer/components/designer-panel/data-settings/filter-selection-panel/filter-selection-panel.component.html b/ui/src/app/data-explorer/components/designer-panel/data-settings/filter-selection-panel/filter-selection-panel.component.html
index 8d360a4..236855a 100644
--- a/ui/src/app/data-explorer/components/designer-panel/data-settings/filter-selection-panel/filter-selection-panel.component.html
+++ b/ui/src/app/data-explorer/components/designer-panel/data-settings/filter-selection-panel/filter-selection-panel.component.html
@@ -65,13 +65,31 @@
</mat-option>
</mat-select>
</mat-form-field>
- <mat-form-field color="accent" class="w-140-px mr-5">
+ <mat-form-field color="accent" class="w-140-px mr-5" *ngIf="!filter.field || !tagValues.has(filter.field.runtimeName)">
<mat-label>Value</mat-label>
- <input matInput
+ <input type="text"
+ placeholder="Value"
+ aria-label="Number"
+ matInput
[(ngModel)]="filter.value"
(change)="updateWidget()"
data-cy="design-panel-data-settings-filter-value">
</mat-form-field>
+ <mat-form-field color="accent" class="w-140-px mr-5" *ngIf="filter.field && tagValues.has(filter.field.runtimeName)">
+ <input type="text"
+ placeholder="Value"
+ aria-label="Number"
+ matInput
+ [(ngModel)]="filter.value"
+ (change)="updateWidget()"
+ data-cy="design-panel-data-settings-filter-value"
+ [matAutocomplete]="auto">
+ <mat-autocomplete #auto="matAutocomplete" (optionSelected)="updateWidget()">
+ <mat-option *ngFor="let value of tagValues.get(filter.field.runtimeName)" [value]="value">
+ {{value}}
+ </mat-option>
+ </mat-autocomplete>
+ </mat-form-field>
<button mat-icon-button color="accent"
(click)="remove(sourceConfig, filter.index)"
data-cy="design-panel-data-settings-remove-filter">
diff --git a/ui/src/app/data-explorer/components/designer-panel/data-settings/filter-selection-panel/filter-selection-panel.component.ts b/ui/src/app/data-explorer/components/designer-panel/data-settings/filter-selection-panel/filter-selection-panel.component.ts
index 51162b6..7b6eff3 100644
--- a/ui/src/app/data-explorer/components/designer-panel/data-settings/filter-selection-panel/filter-selection-panel.component.ts
+++ b/ui/src/app/data-explorer/components/designer-panel/data-settings/filter-selection-panel/filter-selection-panel.component.ts
@@ -16,21 +16,47 @@
*
*/
-import { Component, Input } from '@angular/core';
-import { FieldConfig, SelectedFilter, SourceConfig } from '@streampipes/platform-services';
+import { Component, Input, OnInit } from '@angular/core';
+import { DatalakeRestService, FieldConfig, SelectedFilter, SourceConfig } from '@streampipes/platform-services';
import { WidgetConfigurationService } from '../../../../services/widget-configuration.service';
+import { DataExplorerFieldProviderService } from '../../../../services/data-explorer-field-provider-service';
@Component({
selector: 'sp-filter-selection-panel',
templateUrl: './filter-selection-panel.component.html',
styleUrls: ['./filter-selection-panel.component.scss']
})
-export class FilterSelectionPanelComponent {
+export class FilterSelectionPanelComponent implements OnInit {
@Input() sourceConfig: SourceConfig;
@Input() widgetId: string;
- constructor(private widgetConfigService: WidgetConfigurationService) {
+ tagValues: Map<string, string[]> = new Map<string, string[]>();
+
+ constructor(private widgetConfigService: WidgetConfigurationService,
+ private fieldProviderService: DataExplorerFieldProviderService,
+ private dataLakeRestService: DatalakeRestService) {
+ }
+
+ ngOnInit(): void {
+ this.sourceConfig.queryConfig.fields.forEach(f => {
+ this.tagValues.set(f.runtimeName, []);
+ });
+ const fieldProvider = this.fieldProviderService.generateFieldLists([this.sourceConfig]);
+ this.sourceConfig.queryConfig.fields
+ .filter(f => fieldProvider.booleanFields
+ .find(df => df.measure === this.sourceConfig.measureName && df.runtimeName === f.runtimeName))
+ .forEach(f => this.tagValues.set(f.runtimeName, ['true', 'false']));
+ const fields = this.sourceConfig.queryConfig.fields
+ .filter(f =>
+ fieldProvider.dimensionFields.find(df => (df.measure === this.sourceConfig.measureName && df.runtimeName === f.runtimeName)))
+ .map(f => f.runtimeName);
+ this.dataLakeRestService.getTagValues(this.sourceConfig.measureName, fields).subscribe(response => {
+ Object.keys(response).forEach(key => {
+ this.tagValues.set(key, response[key]);
+ });
+ });
+
}
addFilter() {
@@ -40,7 +66,7 @@ export class FilterSelectionPanelComponent {
value: ''
};
this.sourceConfig.queryConfig.selectedFilters.push(newFilter);
- this.widgetConfigService.notify({ widgetId: this.widgetId, refreshData: true, refreshView: true });
+ this.widgetConfigService.notify({widgetId: this.widgetId, refreshData: true, refreshView: true});
this.updateWidget();
}
@@ -58,11 +84,13 @@ export class FilterSelectionPanelComponent {
});
if (update) {
- this.widgetConfigService.notify({ widgetId: this.widgetId, refreshData: true, refreshView: true });
+ this.widgetConfigService.notify({widgetId: this.widgetId, refreshData: true, refreshView: true});
}
}
compare(available: FieldConfig, selected: FieldConfig) {
return (available.runtimeName === selected.runtimeName);
}
+
+
}