This is an automated email from the ASF dual-hosted git repository. dominikriemer pushed a commit to branch improve-influx-query-builder in repository https://gitbox.apache.org/repos/asf/streampipes.git
commit 494fc24ec7dc2328faa491bb9dbe1cb3858f8959 Author: Dominik Riemer <[email protected]> AuthorDate: Sun Jun 14 15:51:09 2026 +0200 Add fill mode to aggregations --- .../dataexplorer/influx/SelectQueryParamsTest.java | 72 +++++++++++++ .../utils/ProvidedQueryParameterBuilder.java | 6 ++ .../param/ProvidedRestQueryParamConverter.java | 2 +- .../dataexplorer/param/model/FillClauseParams.java | 15 ++- .../param/model/InfluxQueryParameterValidator.java | 22 ++++ .../datalake/param/SupportedRestQueryParams.java | 2 + .../lib/model/datalake/DatalakeQueryParameters.ts | 1 + .../model/datalake/data-lake-query-config.model.ts | 1 + .../src/lib/query/DatalakeQueryParameterBuilder.ts | 6 ++ .../lib/query/data-view-query-generator.service.ts | 4 + .../aggregate-configuration.component.html | 15 ++- .../aggregate-configuration.component.ts | 10 +- .../chart-data-settings.component.html | 8 ++ .../data-settings/chart-data-settings.component.ts | 3 + .../fill-configuration.component.html | 68 ++++++++++++ .../fill-configuration.component.scss | 21 ---- .../fill-configuration.component.ts | 115 +++++++++++++++++++++ 17 files changed, 334 insertions(+), 37 deletions(-) diff --git a/streampipes-data-explorer-influx/src/test/java/org/apache/streampipes/dataexplorer/influx/SelectQueryParamsTest.java b/streampipes-data-explorer-influx/src/test/java/org/apache/streampipes/dataexplorer/influx/SelectQueryParamsTest.java index b79f55d98d..6513f2a7c3 100644 --- a/streampipes-data-explorer-influx/src/test/java/org/apache/streampipes/dataexplorer/influx/SelectQueryParamsTest.java +++ b/streampipes-data-explorer-influx/src/test/java/org/apache/streampipes/dataexplorer/influx/SelectQueryParamsTest.java @@ -236,6 +236,66 @@ public class SelectQueryParamsTest { assertEquals("SELECT value FROM \"abc\" GROUP BY time(1ms),\"sensorId\" fill(none);", query); } + @Test + public void testGroupByTimeWithPreviousFill() { + var params = ProvidedQueryParameterBuilder.create("abc") + .withSimpleColumns(List.of("value")) + .withTimeInterval("1h") + .withFill("previous") + .build(); + + SelectQueryParams qp = ProvidedRestQueryParamConverter.getSelectQueryParams(params); + + String query = qp.toQuery(DataLakeInfluxQueryBuilder.create("abc")).getCommand(); + + assertEquals("SELECT value FROM \"abc\" GROUP BY time(1h) fill(previous);", query); + } + + @Test + public void testGroupByTimeWithLinearFill() { + var params = ProvidedQueryParameterBuilder.create("abc") + .withSimpleColumns(List.of("value")) + .withTimeInterval("1h") + .withFill("linear") + .build(); + + SelectQueryParams qp = ProvidedRestQueryParamConverter.getSelectQueryParams(params); + + String query = qp.toQuery(DataLakeInfluxQueryBuilder.create("abc")).getCommand(); + + assertEquals("SELECT value FROM \"abc\" GROUP BY time(1h) fill(linear);", query); + } + + @Test + public void testGroupByTimeWithNullFill() { + var params = ProvidedQueryParameterBuilder.create("abc") + .withSimpleColumns(List.of("value")) + .withTimeInterval("1h") + .withFill("null") + .build(); + + SelectQueryParams qp = ProvidedRestQueryParamConverter.getSelectQueryParams(params); + + String query = qp.toQuery(DataLakeInfluxQueryBuilder.create("abc")).getCommand(); + + assertEquals("SELECT value FROM \"abc\" GROUP BY time(1h) fill(null);", query); + } + + @Test + public void testGroupByTimeWithNumericFill() { + var params = ProvidedQueryParameterBuilder.create("abc") + .withSimpleColumns(List.of("value")) + .withTimeInterval("1h") + .withFill("12.5") + .build(); + + SelectQueryParams qp = ProvidedRestQueryParamConverter.getSelectQueryParams(params); + + String query = qp.toQuery(DataLakeInfluxQueryBuilder.create("abc")).getCommand(); + + assertEquals("SELECT value FROM \"abc\" GROUP BY time(1h) fill(12.5);", query); + } + @Test public void testGroupByTimeRejectsUnsafeInterval() { var params = ProvidedQueryParameterBuilder.create("abc") @@ -247,6 +307,18 @@ public class SelectQueryParamsTest { () -> ProvidedRestQueryParamConverter.getSelectQueryParams(params)); } + @Test + public void testGroupByTimeRejectsUnsafeFill() { + var params = ProvidedQueryParameterBuilder.create("abc") + .withSimpleColumns(List.of("value")) + .withTimeInterval("1h") + .withFill("previous); DROP MEASUREMENT foo --") + .build(); + + assertThrows(IllegalArgumentException.class, + () -> ProvidedRestQueryParamConverter.getSelectQueryParams(params)); + } + @Test public void testGroupByRejectsUnsafeIdentifier() { var params = ProvidedQueryParameterBuilder.create("abc") diff --git a/streampipes-data-explorer-influx/src/test/java/org/apache/streampipes/dataexplorer/influx/utils/ProvidedQueryParameterBuilder.java b/streampipes-data-explorer-influx/src/test/java/org/apache/streampipes/dataexplorer/influx/utils/ProvidedQueryParameterBuilder.java index 944b4f6a66..3b28051000 100644 --- a/streampipes-data-explorer-influx/src/test/java/org/apache/streampipes/dataexplorer/influx/utils/ProvidedQueryParameterBuilder.java +++ b/streampipes-data-explorer-influx/src/test/java/org/apache/streampipes/dataexplorer/influx/utils/ProvidedQueryParameterBuilder.java @@ -74,6 +74,12 @@ public class ProvidedQueryParameterBuilder { return this; } + public ProvidedQueryParameterBuilder withFill(String fill) { + this.queryParams.put(SupportedRestQueryParams.QP_FILL, fill); + + return this; + } + public ProvidedQueryParameterBuilder withFilter(String filter) { this.queryParams.put(SupportedRestQueryParams.QP_FILTER, filter); diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/param/ProvidedRestQueryParamConverter.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/param/ProvidedRestQueryParamConverter.java index 90569a26d2..e6926308c2 100644 --- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/param/ProvidedRestQueryParamConverter.java +++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/param/ProvidedRestQueryParamConverter.java @@ -78,7 +78,7 @@ public class ProvidedRestQueryParamConverter { if (params.has(SupportedRestQueryParams.QP_TIME_INTERVAL)) { String timeInterval = params.getAsString(SupportedRestQueryParams.QP_TIME_INTERVAL); queryParameters.withGroupByTimeParams(GroupByTimeClauseParams.from(timeInterval)); - queryParameters.withFillParams(FillClauseParams.from()); + queryParameters.withFillParams(FillClauseParams.from(params.getAsString(SupportedRestQueryParams.QP_FILL))); } if (params.has(SupportedRestQueryParams.QP_GROUP_BY)) { diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/param/model/FillClauseParams.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/param/model/FillClauseParams.java index ccece054ba..f4d133d4b9 100644 --- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/param/model/FillClauseParams.java +++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/param/model/FillClauseParams.java @@ -22,15 +22,28 @@ import org.apache.streampipes.dataexplorer.api.IDataLakeQueryBuilder; import org.apache.streampipes.dataexplorer.api.IQueryStatement; public class FillClauseParams implements IQueryStatement { - String fill = "none"; + private final Object fill; protected FillClauseParams() { + this.fill = "none"; } public static FillClauseParams from() { return new FillClauseParams(); } + protected FillClauseParams(String fill) { + this.fill = InfluxQueryParameterValidator.requireValidFill(fill); + } + + public static FillClauseParams from(String fill) { + if (fill == null || fill.isBlank()) { + return from(); + } + + return new FillClauseParams(fill); + } + @Override public void buildStatement(IDataLakeQueryBuilder<?> builder) { builder.withFill(fill); diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/param/model/InfluxQueryParameterValidator.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/param/model/InfluxQueryParameterValidator.java index 750d1b3ac8..6eaaba1bd1 100644 --- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/param/model/InfluxQueryParameterValidator.java +++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/param/model/InfluxQueryParameterValidator.java @@ -26,6 +26,7 @@ final class InfluxQueryParameterValidator { private static final Pattern SAFE_TIME_INTERVAL = Pattern.compile("^\\d+(ms|s|m|h|d|w)$"); private static final Pattern SAFE_IDENTIFIER = Pattern.compile("^[^\\s,;()\"']+$"); + private static final Pattern NUMERIC_FILL = Pattern.compile("^-?\\d+(\\.\\d+)?$"); private InfluxQueryParameterValidator() { } @@ -47,4 +48,25 @@ final class InfluxQueryParameterValidator { return identifier; } + + static Object requireValidFill(String fill) { + if (fill == null || fill.isBlank()) { + return "none"; + } + + String normalized = fill.trim().toLowerCase(); + + if (normalized.equals("none") + || normalized.equals("null") + || normalized.equals("previous") + || normalized.equals("linear")) { + return normalized; + } + + if (NUMERIC_FILL.matcher(normalized).matches()) { + return Double.parseDouble(normalized); + } + + throw new IllegalArgumentException("Invalid fill parameter: " + fill); + } } diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/param/SupportedRestQueryParams.java b/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/param/SupportedRestQueryParams.java index 667d02291f..2eea5c1877 100644 --- a/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/param/SupportedRestQueryParams.java +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/param/SupportedRestQueryParams.java @@ -32,6 +32,7 @@ public class SupportedRestQueryParams { public static final String QP_ORDER = "order"; public static final String QP_AGGREGATION_FUNCTION = "aggregationFunction"; public static final String QP_TIME_INTERVAL = "timeInterval"; + public static final String QP_FILL = "fill"; public static final String QP_FORMAT = "format"; public static final String QP_CSV_DELIMITER = "delimiter"; @@ -57,6 +58,7 @@ public class SupportedRestQueryParams { QP_ORDER, QP_AGGREGATION_FUNCTION, QP_TIME_INTERVAL, + QP_FILL, QP_FORMAT, QP_CSV_DELIMITER, QP_COUNT_ONLY, diff --git a/ui/projects/streampipes/platform-services/src/lib/model/datalake/DatalakeQueryParameters.ts b/ui/projects/streampipes/platform-services/src/lib/model/datalake/DatalakeQueryParameters.ts index eaf8627e11..e288b47fe5 100644 --- a/ui/projects/streampipes/platform-services/src/lib/model/datalake/DatalakeQueryParameters.ts +++ b/ui/projects/streampipes/platform-services/src/lib/model/datalake/DatalakeQueryParameters.ts @@ -29,6 +29,7 @@ export interface DatalakeQueryParameters { order?: string; aggregationFunction?: string; timeInterval?: string; + fill?: string | number; countOnly?: boolean; autoAggregate?: boolean; filter?: string; diff --git a/ui/projects/streampipes/platform-services/src/lib/model/datalake/data-lake-query-config.model.ts b/ui/projects/streampipes/platform-services/src/lib/model/datalake/data-lake-query-config.model.ts index 6b648c48f8..60a3957286 100644 --- a/ui/projects/streampipes/platform-services/src/lib/model/datalake/data-lake-query-config.model.ts +++ b/ui/projects/streampipes/platform-services/src/lib/model/datalake/data-lake-query-config.model.ts @@ -77,6 +77,7 @@ export interface QueryConfig { aggregationValue?: number; aggregationTimeUnit?: string; aggregationFunction?: string; + fill?: string | number; } export interface SourceConfig { diff --git a/ui/projects/streampipes/platform-services/src/lib/query/DatalakeQueryParameterBuilder.ts b/ui/projects/streampipes/platform-services/src/lib/query/DatalakeQueryParameterBuilder.ts index f8ab65e7c9..1c7d78b2bf 100644 --- a/ui/projects/streampipes/platform-services/src/lib/query/DatalakeQueryParameterBuilder.ts +++ b/ui/projects/streampipes/platform-services/src/lib/query/DatalakeQueryParameterBuilder.ts @@ -80,6 +80,12 @@ export class DatalakeQueryParameterBuilder { return this; } + public withFill(fill: string | number): DatalakeQueryParameterBuilder { + this.queryParams.fill = fill; + + return this; + } + public withGrouping(groupBy: FieldConfig[]): DatalakeQueryParameterBuilder { const groupByRuntimeNames = groupBy.map( property => property.runtimeName, diff --git a/ui/projects/streampipes/platform-services/src/lib/query/data-view-query-generator.service.ts b/ui/projects/streampipes/platform-services/src/lib/query/data-view-query-generator.service.ts index ccb3e33bcc..ef1c5cf9f4 100644 --- a/ui/projects/streampipes/platform-services/src/lib/query/data-view-query-generator.service.ts +++ b/ui/projects/streampipes/platform-services/src/lib/query/data-view-query-generator.service.ts @@ -138,6 +138,10 @@ export class DataViewQueryGeneratorService { queryConfig.aggregationValue, ); } + + if (queryConfig.fill !== undefined) { + queryBuilder.withFill(queryConfig.fill); + } } if (ignoreEventsWithMissingValues) { diff --git a/ui/src/app/chart/components/chart-view/designer-panel/data-settings/aggregate-configuration/aggregate-configuration.component.html b/ui/src/app/chart/components/chart-view/designer-panel/data-settings/aggregate-configuration/aggregate-configuration.component.html index 9fd6a3014f..706df8aba1 100644 --- a/ui/src/app/chart/components/chart-view/designer-panel/data-settings/aggregate-configuration/aggregate-configuration.component.html +++ b/ui/src/app/chart/components/chart-view/designer-panel/data-settings/aggregate-configuration/aggregate-configuration.component.html @@ -16,7 +16,7 @@ ~ --> -<div fxLayout="column" fxLayoutAlign="stretch" fxFlex="100"> +<div fxLayout="column" fxFlex="100"> <div fxFlex="100" fxLayout="column" @@ -24,12 +24,7 @@ class="ml-0 mr-5 form-field-small" > <sp-form-field [level]="3" [label]="'Unit' | translate" class="w-100"> - <mat-form-field - appearance="outline" - fxFlex="100" - class="w-100" - color="accent" - > + <mat-form-field appearance="outline" fxFlex="100" class="w-100"> <mat-select [(value)]="queryConfig.aggregationTimeUnit" class="w-100" @@ -43,7 +38,11 @@ </mat-select> </mat-form-field> </sp-form-field> - <sp-form-field [level]="3" [label]="'Value' | translate" class="w-100"> + <sp-form-field + [level]="3" + [label]="'Value' | translate" + class="w-100 mb-10" + > <mat-form-field appearance="outline" fxFlex="100" diff --git a/ui/src/app/chart/components/chart-view/designer-panel/data-settings/aggregate-configuration/aggregate-configuration.component.ts b/ui/src/app/chart/components/chart-view/designer-panel/data-settings/aggregate-configuration/aggregate-configuration.component.ts index 77ee49957f..c8514ddaf3 100644 --- a/ui/src/app/chart/components/chart-view/designer-panel/data-settings/aggregate-configuration/aggregate-configuration.component.ts +++ b/ui/src/app/chart/components/chart-view/designer-panel/data-settings/aggregate-configuration/aggregate-configuration.component.ts @@ -66,11 +66,9 @@ export class AggregateConfigurationComponent { ]; triggerDataRefresh() { - if (this.widgetId) { - this.widgetConfigService.notify({ - refreshData: true, - refreshView: true, - }); - } + this.widgetConfigService.notify({ + refreshData: true, + refreshView: true, + }); } } diff --git a/ui/src/app/chart/components/chart-view/designer-panel/data-settings/chart-data-settings.component.html b/ui/src/app/chart/components/chart-view/designer-panel/data-settings/chart-data-settings.component.html index dc988a4145..af89a9f414 100644 --- a/ui/src/app/chart/components/chart-view/designer-panel/data-settings/chart-data-settings.component.html +++ b/ui/src/app/chart/components/chart-view/designer-panel/data-settings/chart-data-settings.component.html @@ -351,6 +351,14 @@ > </sp-aggregate-configuration> } + <sp-fill-configuration + class="mt-10" + [queryConfig]=" + sourceConfig.queryConfig + " + [widgetId]="widgetId" + > + </sp-fill-configuration> </div> } </div> diff --git a/ui/src/app/chart/components/chart-view/designer-panel/data-settings/chart-data-settings.component.ts b/ui/src/app/chart/components/chart-view/designer-panel/data-settings/chart-data-settings.component.ts index 71477ca0ac..5502cff7be 100644 --- a/ui/src/app/chart/components/chart-view/designer-panel/data-settings/chart-data-settings.component.ts +++ b/ui/src/app/chart/components/chart-view/designer-panel/data-settings/chart-data-settings.component.ts @@ -74,6 +74,7 @@ import { ClassDirective } from '@ngbracket/ngx-layout/extended'; import { MatInput } from '@angular/material/input'; import { MatCheckbox } from '@angular/material/checkbox'; import { AggregateConfigurationComponent } from './aggregate-configuration/aggregate-configuration.component'; +import { FillConfigurationComponent } from './fill-configuration/fill-configuration.component'; import { FilterSelectionPanelComponent } from './filter-selection-panel/filter-selection-panel.component'; import { OrderSelectionPanelComponent } from './order-selection-panel/order-selection-panel.component'; import { TranslatePipe } from '@ngx-translate/core'; @@ -116,6 +117,7 @@ import { MatAutocomplete, MatAutocompleteTrigger, AggregateConfigurationComponent, + FillConfigurationComponent, FieldSelectionPanelComponent, FilterSelectionPanelComponent, GroupSelectionPanelComponent, @@ -332,6 +334,7 @@ export class ChartDataSettingsComponent implements OnInit { page: 1, aggregationTimeUnit: 'd', aggregationValue: 1, + fill: 'none', }, queryType: 'raw', }; diff --git a/ui/src/app/chart/components/chart-view/designer-panel/data-settings/fill-configuration/fill-configuration.component.html b/ui/src/app/chart/components/chart-view/designer-panel/data-settings/fill-configuration/fill-configuration.component.html new file mode 100644 index 0000000000..43b4750a6f --- /dev/null +++ b/ui/src/app/chart/components/chart-view/designer-panel/data-settings/fill-configuration/fill-configuration.component.html @@ -0,0 +1,68 @@ +<!-- +~ 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 fxLayout="column" fxFlex="100"> + <div + fxFlex="100" + fxLayout="column" + fxLayoutAlign="start center" + class="ml-0 mr-5 form-field-small" + > + <sp-form-field + [level]="3" + [label]="'Fill' | translate" + class="w-100" + [description]="'Handle empty values' | translate" + > + <mat-form-field appearance="outline" fxFlex="100" class="w-100"> + <mat-select + [(ngModel)]="fillMode" + class="w-100" + (selectionChange)="updateFillMode(fillMode)" + > + @for (option of fillOptions; track option.value) { + <mat-option [value]="option.value">{{ + option.label | translate + }}</mat-option> + } + </mat-select> + </mat-form-field> + </sp-form-field> + @if (fillMode === 'number') { + <sp-form-field + [level]="3" + [label]="'Fill Value' | translate" + class="w-100" + > + <mat-form-field + appearance="outline" + fxFlex="100" + class="w-100" + color="accent" + > + <input + matInput + type="number" + [(ngModel)]="customFillValue" + (ngModelChange)="updateCustomFillValue()" + /> + </mat-form-field> + </sp-form-field> + } + </div> +</div> diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/param/model/FillClauseParams.java b/ui/src/app/chart/components/chart-view/designer-panel/data-settings/fill-configuration/fill-configuration.component.scss similarity index 61% copy from streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/param/model/FillClauseParams.java copy to ui/src/app/chart/components/chart-view/designer-panel/data-settings/fill-configuration/fill-configuration.component.scss index ccece054ba..13cbc4aacb 100644 --- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/param/model/FillClauseParams.java +++ b/ui/src/app/chart/components/chart-view/designer-panel/data-settings/fill-configuration/fill-configuration.component.scss @@ -15,24 +15,3 @@ * limitations under the License. * */ - -package org.apache.streampipes.dataexplorer.param.model; - -import org.apache.streampipes.dataexplorer.api.IDataLakeQueryBuilder; -import org.apache.streampipes.dataexplorer.api.IQueryStatement; - -public class FillClauseParams implements IQueryStatement { - String fill = "none"; - - protected FillClauseParams() { - } - - public static FillClauseParams from() { - return new FillClauseParams(); - } - - @Override - public void buildStatement(IDataLakeQueryBuilder<?> builder) { - builder.withFill(fill); - } -} diff --git a/ui/src/app/chart/components/chart-view/designer-panel/data-settings/fill-configuration/fill-configuration.component.ts b/ui/src/app/chart/components/chart-view/designer-panel/data-settings/fill-configuration/fill-configuration.component.ts new file mode 100644 index 0000000000..9b0ab2a203 --- /dev/null +++ b/ui/src/app/chart/components/chart-view/designer-panel/data-settings/fill-configuration/fill-configuration.component.ts @@ -0,0 +1,115 @@ +/* + * 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, Input, OnInit, inject } from '@angular/core'; +import { QueryConfig } from '@streampipes/platform-services'; +import { ChartConfigurationService } from '../../../../../../chart-shared/services/chart-configuration.service'; +import { TranslatePipe, TranslateService } from '@ngx-translate/core'; +import { + FlexDirective, + LayoutAlignDirective, + LayoutDirective, +} from '@ngbracket/ngx-layout/flex'; +import { FormFieldComponent } from '@streampipes/shared-ui'; +import { MatFormField } from '@angular/material/form-field'; +import { MatOption, MatSelect } from '@angular/material/select'; +import { MatInput } from '@angular/material/input'; +import { FormsModule } from '@angular/forms'; + +type FillMode = 'none' | 'previous' | 'linear' | 'null' | 'number'; + +@Component({ + selector: 'sp-fill-configuration', + templateUrl: './fill-configuration.component.html', + styleUrls: ['./fill-configuration.component.scss'], + imports: [ + LayoutDirective, + LayoutAlignDirective, + FlexDirective, + FormFieldComponent, + MatFormField, + MatSelect, + MatOption, + MatInput, + FormsModule, + TranslatePipe, + ], +}) +export class FillConfigurationComponent implements OnInit { + private widgetConfigService = inject(ChartConfigurationService); + private translate = inject(TranslateService); + + @Input() queryConfig: QueryConfig; + @Input() widgetId: string; + + fillMode: FillMode = 'none'; + customFillValue = 0; + + fillOptions: Array<{ value: FillMode; label: string }> = [ + { value: 'none', label: this.translate.instant('None') }, + { value: 'previous', label: this.translate.instant('Previous Value') }, + { + value: 'linear', + label: this.translate.instant('Linear Interpolation'), + }, + { value: 'null', label: 'Null' }, + { value: 'number', label: this.translate.instant('Custom Value') }, + ]; + + ngOnInit(): void { + if ( + typeof this.queryConfig.fill === 'number' && + !Number.isNaN(this.queryConfig.fill) + ) { + this.fillMode = 'number'; + this.customFillValue = this.queryConfig.fill; + return; + } + + const configuredMode = this.queryConfig.fill; + if ( + configuredMode === 'none' || + configuredMode === 'previous' || + configuredMode === 'linear' || + configuredMode === 'null' + ) { + this.fillMode = configuredMode; + return; + } + + this.queryConfig.fill = 'none'; + } + + updateFillMode(mode: FillMode): void { + this.fillMode = mode; + this.queryConfig.fill = mode === 'number' ? this.customFillValue : mode; + this.triggerDataRefresh(); + } + + updateCustomFillValue(): void { + this.queryConfig.fill = this.customFillValue; + this.triggerDataRefresh(); + } + + triggerDataRefresh(): void { + this.widgetConfigService.notify({ + refreshData: true, + refreshView: true, + }); + } +}
