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

dominikriemer pushed a commit to branch improve-dataset-selection-charts
in repository https://gitbox.apache.org/repos/asf/streampipes.git

commit 741ec9d89d1b48dc5421deaaa61d57ee64fc1a90
Author: Dominik Riemer <[email protected]>
AuthorDate: Sat Jun 13 13:21:21 2026 +0200

    feat: Add search feature to dataset selection in chart view
---
 ui/deployment/i18n/de.json                         |   2 +
 ui/deployment/i18n/en.json                         |   2 +
 ui/deployment/i18n/pl.json                         |   2 +
 .../chart-data-settings.component.html             |  56 +++++--
 .../data-settings/chart-data-settings.component.ts | 164 +++++++++++++++++----
 5 files changed, 189 insertions(+), 37 deletions(-)

diff --git a/ui/deployment/i18n/de.json b/ui/deployment/i18n/de.json
index 27fccbbc08..2eea78a5da 100644
--- a/ui/deployment/i18n/de.json
+++ b/ui/deployment/i18n/de.json
@@ -705,6 +705,7 @@
   "No charts match your search.": "Keine Diagramme entsprechen deiner Suche.",
   "No data available.": "Keine Daten verfügbar",
   "No datasets available": "Keine Datensätze verfügbar",
+  "No datasets match your search.": "Keine Datensätze entsprechen deiner 
Suche.",
   "No entries available.": "Keine Einträge vorhanden.",
   "No export providers found": "Keine Exportanbieter gefunden",
   "No fields selected.": "Keine Felder ausgewählt.",
@@ -898,6 +899,7 @@
   "Schema fields": "Schemafelder",
   "Script": "Skript",
   "Search": "Suche",
+  "Search datasets": "Datensätze suchen",
   "Search charts": "Diagramme suchen",
   "Searching for available extensions, please wait...": "Nach verfügbaren 
Extensions suchen, bitte warten...",
   "Second": "Sekunde",
diff --git a/ui/deployment/i18n/en.json b/ui/deployment/i18n/en.json
index 86d7ca4e3f..0c4193aaa4 100644
--- a/ui/deployment/i18n/en.json
+++ b/ui/deployment/i18n/en.json
@@ -705,6 +705,7 @@
   "No charts match your search.": null,
   "No data available.": null,
   "No datasets available": null,
+  "No datasets match your search.": null,
   "No entries available.": null,
   "No export providers found": null,
   "No fields selected.": null,
@@ -898,6 +899,7 @@
   "Schema fields": null,
   "Script": null,
   "Search": null,
+  "Search datasets": null,
   "Search charts": null,
   "Searching for available extensions, please wait...": null,
   "Second": null,
diff --git a/ui/deployment/i18n/pl.json b/ui/deployment/i18n/pl.json
index d17c3bcc58..a53abc89a1 100644
--- a/ui/deployment/i18n/pl.json
+++ b/ui/deployment/i18n/pl.json
@@ -705,6 +705,7 @@
   "No charts match your search.": "Żadne wykresy nie pasują do wyszukiwania.",
   "No data available.": "Brak dostępnych danych.",
   "No datasets available": "Brak dostępnych zbiorów danych",
+  "No datasets match your search.": "Żadne zbiory danych nie pasują do 
wyszukiwania.",
   "No entries available.": "Brak dostępnych wpisów.",
   "No export providers found": "Nie znaleziono exportera",
   "No fields selected.": "Nie wybrano żadnych pól.",
@@ -898,6 +899,7 @@
   "Schema fields": "Pola schematu",
   "Script": "Skrypt",
   "Search": "Szukaj",
+  "Search datasets": "Szukaj zbiorów danych",
   "Search charts": "Szukaj wykresów",
   "Searching for available extensions, please wait...": "Wyszukiwanie 
dostępnych rozszerzeń, proszę czekać...",
   "Second": "Sekunda",
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 b4a7dcd331..dc988a4145 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
@@ -85,24 +85,51 @@
                         }
                         @if (availableMeasurements.length !== 0) {
                             <mat-form-field
-                                color="accent"
                                 fxFlex="100"
                                 appearance="outline"
                                 subscriptSizing="dynamic"
                             >
-                                <mat-select
+                                <mat-icon matPrefix>search</mat-icon>
+                                <input
+                                    matInput
+                                    [placeholder]="
+                                        'Search datasets' | translate
+                                    "
+                                    [value]="measurementInputValue"
+                                    (input)="
+                                        onMeasurementSearchChange(
+                                            $any($event.target).value
+                                        )
+                                    "
+                                    [matAutocomplete]="datasetAutocomplete"
                                     data-cy="data-explorer-select-data-set"
-                                    [(value)]="sourceConfig.measureName"
-                                    (selectionChange)="
-                                        updateMeasure(
+                                />
+                                @if (hasActiveMeasurementSearch()) {
+                                    <button
+                                        mat-icon-button
+                                        matSuffix
+                                        type="button"
+                                        [attr.aria-label]="
+                                            'Clear search' | translate
+                                        "
+                                        (click)="clearMeasurementSearch()"
+                                    >
+                                        <mat-icon>close</mat-icon>
+                                    </button>
+                                }
+                                <mat-autocomplete
+                                    #datasetAutocomplete="matAutocomplete"
+                                    autoActiveFirstOption
+                                    (optionSelected)="
+                                        onMeasurementSelected(
                                             sourceConfig,
-                                            $event.value
+                                            $event
                                         )
                                     "
                                 >
                                     @for (
-                                        measurement of availableMeasurements;
-                                        track measurement
+                                        measurement of filteredMeasurements;
+                                        track measurement.elementId
                                     ) {
                                         <mat-option
                                             [value]="measurement.measureName"
@@ -112,7 +139,18 @@
                                             }}</span>
                                         </mat-option>
                                     }
-                                </mat-select>
+                                    @if (
+                                        filteredMeasurements.length === 0 &&
+                                        hasActiveMeasurementSearch()
+                                    ) {
+                                        <mat-option disabled>
+                                            {{
+                                                'No datasets match your 
search.'
+                                                    | translate
+                                            }}
+                                        </mat-option>
+                                    }
+                                </mat-autocomplete>
                             </mat-form-field>
                         }
                     </sp-split-section>
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 478d92561b..71477ca0ac 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
@@ -29,6 +29,7 @@ import {
     DataExplorerDataConfig,
     DataExplorerWidgetModel,
     DataLakeMeasure,
+    DatasetSummaryDto,
     DatalakeRestService,
     SourceConfig,
 } from '@streampipes/platform-services';
@@ -59,8 +60,12 @@ import {
     SpAlertBannerComponent,
     SplitSectionComponent,
 } from '@streampipes/shared-ui';
-import { MatFormField } from '@angular/material/form-field';
-import { MatOption, MatSelect } from '@angular/material/select';
+import {
+    MatFormField,
+    MatPrefix,
+    MatSuffix,
+} from '@angular/material/form-field';
+import { MatOption } from '@angular/material/core';
 import { MatIcon } from '@angular/material/icon';
 import { MatRadioButton, MatRadioGroup } from '@angular/material/radio';
 import { FormsModule } from '@angular/forms';
@@ -72,6 +77,11 @@ import { AggregateConfigurationComponent } from 
'./aggregate-configuration/aggre
 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';
+import {
+    MatAutocomplete,
+    MatAutocompleteSelectedEvent,
+    MatAutocompleteTrigger,
+} from '@angular/material/autocomplete';
 
 @Component({
     selector: 'sp-chart-data-settings',
@@ -91,7 +101,8 @@ import { TranslatePipe } from '@ngx-translate/core';
         LayoutGapDirective,
         MatButton,
         MatFormField,
-        MatSelect,
+        MatPrefix,
+        MatSuffix,
         MatOption,
         MatIcon,
         MatRadioGroup,
@@ -102,6 +113,8 @@ import { TranslatePipe } from '@ngx-translate/core';
         FormFieldComponent,
         MatInput,
         MatCheckbox,
+        MatAutocomplete,
+        MatAutocompleteTrigger,
         AggregateConfigurationComponent,
         FieldSelectionPanelComponent,
         FilterSelectionPanelComponent,
@@ -137,7 +150,9 @@ export class ChartDataSettingsComponent implements OnInit {
     @ViewChild('groupSelectionPanel')
     groupSelectionPanel: GroupSelectionPanelComponent;
 
-    availableMeasurements: DataLakeMeasure[] = [];
+    availableMeasurements: DatasetSummaryDto[] = [];
+    filteredMeasurements: DatasetSummaryDto[] = [];
+    measurementInputValue = '';
 
     step = 0;
 
@@ -149,33 +164,42 @@ export class ChartDataSettingsComponent implements OnInit 
{
     }
 
     ngOnInit(): void {
+        this.syncCurrentMeasure();
         this.loadPipelinesAndMeasurements();
     }
 
     loadPipelinesAndMeasurements() {
-        this.datalakeRestService
-            .getAllMeasurementSeries()
-            .subscribe(response => {
-                this.availableMeasurements = response;
-                this.availableMeasurements.sort((a, b) =>
-                    a.measureName.localeCompare(b.measureName),
-                );
+        this.datalakeRestService.getMeasurementSummary().subscribe(response => 
{
+            this.availableMeasurements = response.resources.sort((a, b) =>
+                a.measureName.localeCompare(b.measureName),
+            );
+            this.applyMeasurementSearch();
 
-                if (!this.sourceConfig) {
-                    const defaultConfigs = this.findDefaultConfig();
-                    this.initializeSourceConfig(defaultConfigs.measureName);
-                    if (defaultConfigs.measureName !== undefined) {
-                        this.updateMeasure(
-                            this.sourceConfig,
-                            defaultConfigs.measureName,
-                        );
-                    }
+            if (!this.sourceConfig) {
+                const defaultConfigs = this.findDefaultConfig();
+                this.initializeSourceConfig(defaultConfigs.measureName);
+                if (defaultConfigs.measureName !== undefined) {
+                    this.loadMeasurement(
+                        defaultConfigs.measureName,
+                        true,
+                        true,
+                    );
                 }
-            });
+            } else if (
+                !this.sourceConfig.measure &&
+                this.sourceConfig.measureName
+            ) {
+                this.loadMeasurement(
+                    this.sourceConfig.measureName,
+                    false,
+                    false,
+                );
+            }
+        });
     }
 
     findDefaultConfig(): {
-        measureName: string;
+        measureName: string | undefined;
     } {
         if (this.availableMeasurements.length > 0) {
             return {
@@ -187,7 +211,84 @@ export class ChartDataSettingsComponent implements OnInit {
     }
 
     updateMeasure(sourceConfig: SourceConfig, measureName: string) {
-        sourceConfig.measure = this.findMeasure(measureName);
+        sourceConfig.measureName = measureName;
+        this.measurementInputValue = measureName;
+        this.loadMeasurement(measureName, true, true);
+    }
+
+    onMeasurementSearchChange(value: string): void {
+        this.measurementInputValue = value;
+        this.applyMeasurementSearch();
+    }
+
+    clearMeasurementSearch(): void {
+        this.measurementInputValue = '';
+        this.applyMeasurementSearch();
+    }
+
+    hasActiveMeasurementSearch(): boolean {
+        return this.measurementInputValue.trim().length > 0;
+    }
+
+    onMeasurementSelected(
+        sourceConfig: SourceConfig,
+        event: MatAutocompleteSelectedEvent,
+    ): void {
+        this.updateMeasure(sourceConfig, event.option.value);
+    }
+
+    private applyMeasurementSearch(): void {
+        const query = this.measurementInputValue.trim().toLowerCase();
+        if (!query) {
+            this.filteredMeasurements = this.availableMeasurements;
+            return;
+        }
+
+        this.filteredMeasurements = this.availableMeasurements.filter(
+            measurement =>
+                measurement.measureName.toLowerCase().includes(query) ||
+                measurement.pipelines.some(pipeline =>
+                    pipeline.toLowerCase().includes(query),
+                ),
+        );
+    }
+
+    private loadMeasurement(
+        measureName: string,
+        resetQueryConfig: boolean,
+        refreshData: boolean,
+    ): void {
+        this.datalakeRestService
+            .getMeasurementByName(measureName)
+            .subscribe(measure =>
+                this.applySelectedMeasurement(
+                    measure,
+                    resetQueryConfig,
+                    refreshData,
+                ),
+            );
+    }
+
+    private applySelectedMeasurement(
+        measure: DataLakeMeasure,
+        resetQueryConfig: boolean,
+        refreshData: boolean,
+    ): void {
+        const sourceConfig = this.sourceConfig;
+        if (!sourceConfig) {
+            return;
+        }
+
+        this.dataLakeMeasure = measure;
+        this.dataLakeMeasureChange.emit(measure);
+        sourceConfig.measureName = measure.measureName;
+        sourceConfig.measure = measure;
+        this.measurementInputValue = measure.measureName;
+
+        if (!resetQueryConfig) {
+            return;
+        }
+
         sourceConfig.queryConfig.fields = [];
         if (this.fieldSelectionPanel) {
             this.fieldSelectionPanel.applyDefaultFields();
@@ -197,13 +298,20 @@ export class ChartDataSettingsComponent implements OnInit 
{
         if (this.groupSelectionPanel) {
             this.groupSelectionPanel.applyDefaultFields();
         }
-        this.triggerDataRefresh();
+
+        if (refreshData) {
+            this.triggerDataRefresh();
+        }
     }
 
-    findMeasure(measureName: string) {
-        return this.availableMeasurements.find(
-            m => m.measureName === measureName,
-        );
+    private syncCurrentMeasure(): void {
+        if (this.sourceConfig?.measure) {
+            this.dataLakeMeasure = this.sourceConfig.measure;
+            this.dataLakeMeasureChange.emit(this.sourceConfig.measure);
+            this.measurementInputValue = this.sourceConfig.measure.measureName;
+        } else if (this.sourceConfig?.measureName) {
+            this.measurementInputValue = this.sourceConfig.measureName;
+        }
     }
 
     changeDataAggregation() {

Reply via email to