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

SvenO3 pushed a commit to branch 
4367-warn-on-incompatible-dataset-schema-changes-affecting-measurements-in-pipelines
in repository https://gitbox.apache.org/repos/asf/streampipes.git


The following commit(s) were added to 
refs/heads/4367-warn-on-incompatible-dataset-schema-changes-affecting-measurements-in-pipelines
 by this push:
     new d31e4208ea Add measurement update dialog
d31e4208ea is described below

commit d31e4208ea530e0208ee6456b6ad068cb3613f2f
Author: Sven Oehler <[email protected]>
AuthorDate: Wed May 6 16:13:56 2026 +0200

    Add measurement update dialog
---
 .../src/lib/model/gen/streampipes-model.ts         |   8 +-
 .../pipeline-details/pipeline-details.component.ts |  40 ++++++
 .../pipeline-preview-meta.component.ts             |   5 +-
 .../pipeline-overview.component.html               |   4 +-
 .../measurement-update-dialog.component.html       | 150 +++++++++++++++++++++
 .../measurement-update-dialog.component.scss       |  16 +++
 .../measurement-update-dialog.component.ts         |  60 +++++++++
 7 files changed, 280 insertions(+), 3 deletions(-)

diff --git 
a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
 
b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
index 397faf0f6b..1c09e3e189 100644
--- 
a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
+++ 
b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
@@ -4632,7 +4632,13 @@ export type OutputStrategyUnion =
     | TransformOutputStrategy
     | UserDefinedOutputStrategy;
 
-export type PipelineHealthStatus = 'OK' | 'REQUIRES_ATTENTION' | 'FAILURE';
+export type PipelineHealthStatus =
+    | 'OK'
+    | 'REQUIRES_ATTENTION'
+    | 'HANDLE_MEASUREMENT_UPDATE'
+    | 'FAILURE';
+
+export type MeasurementUpdateAction = 'edit-pipeline' | 'manage-datasets';
 
 export type PropertyScope =
     | 'HEADER_PROPERTY'
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.ts 
b/ui/src/app/pipeline-details/pipeline-details.component.ts
index 7a2448ede8..eb63b3e913 100644
--- a/ui/src/app/pipeline-details/pipeline-details.component.ts
+++ b/ui/src/app/pipeline-details/pipeline-details.component.ts
@@ -20,6 +20,7 @@ import { Component, OnDestroy, OnInit, ViewChild, inject } 
from '@angular/core';
 import { ActivatedRoute, Router } from '@angular/router';
 import { AuthService } from '../services/auth.service';
 import {
+    MeasurementUpdateAction,
     Pipeline,
     PipelineCanvasMetadata,
     PipelineCanvasMetadataService,
@@ -55,6 +56,7 @@ import { PipelineDetailsToolbarComponent } from 
'./components/pipeline-details-t
 import { PipelineDetailsExpansionPanelComponent } from 
'./components/pipeline-details-expansion-panel/pipeline-details-expansion-panel.component';
 import { TranslatePipe } from '@ngx-translate/core';
 import { PipelineOperationsService } from 
'../pipelines/services/pipeline-operations.service';
+import { MeasurementUpdateDialogComponent } from 
'../pipelines/dialog/measurement-update/measurement-update-dialog.component';
 
 @Component({
     selector: 'sp-pipeline-details-overview-component',
@@ -102,6 +104,7 @@ export class SpPipelineDetailsComponent implements OnInit, 
OnDestroy {
     currentUser$: Subscription;
     autoRefresh$: Subscription;
     private shortcutReg: ShortcutRegistration;
+    private measurementUpdateDialogOpened = false;
 
     @ViewChild('pipelinePreviewComponent')
     pipelinePreviewComponent: PipelinePreviewComponent;
@@ -171,6 +174,43 @@ export class SpPipelineDetailsComponent implements OnInit, 
OnDestroy {
             { label: this.pipeline.name },
             { label: 'Overview' },
         ]);
+        this.openMeasurementUpdateDialogIfRequired();
+    }
+
+    openMeasurementUpdateDialogIfRequired(): void {
+        if (
+            this.measurementUpdateDialogOpened ||
+            this.pipeline.healthStatus !== 'HANDLE_MEASUREMENT_UPDATE'
+        ) {
+            return;
+        }
+
+        this.measurementUpdateDialogOpened = true;
+        const dialogRef = this.dialogService.open(
+            MeasurementUpdateDialogComponent,
+            {
+                panelType: PanelType.STANDARD_PANEL,
+                title: 'Measurement update required',
+                width: '50vw',
+                data: {
+                    pipeline: this.pipeline,
+                },
+            },
+        );
+
+        dialogRef.afterClosed().subscribe(action => {
+            this.handleMeasurementUpdateAction(action);
+        });
+    }
+
+    handleMeasurementUpdateAction(action?: MeasurementUpdateAction): void {
+        if (action === 'edit-pipeline') {
+            this.pipelineOperationsService.showPipelineInEditor(
+                this.pipeline._id,
+            );
+        } else if (action === 'manage-datasets') {
+            this.router.navigate(['datasets']);
+        }
     }
 
     setupAutoRefresh(): void {
diff --git 
a/ui/src/app/pipelines/components/pipeline-feature-card/pipeline-preview-meta/pipeline-preview-meta.component.ts
 
b/ui/src/app/pipelines/components/pipeline-feature-card/pipeline-preview-meta/pipeline-preview-meta.component.ts
index 77ea3b5929..1649099ab2 100644
--- 
a/ui/src/app/pipelines/components/pipeline-feature-card/pipeline-preview-meta/pipeline-preview-meta.component.ts
+++ 
b/ui/src/app/pipelines/components/pipeline-feature-card/pipeline-preview-meta/pipeline-preview-meta.component.ts
@@ -73,7 +73,10 @@ export class PipelinePreviewMetaComponent implements OnInit {
 
         if (this.healthStatus === 'OK') {
             this.healthStatusTone = 'success';
-        } else if (this.healthStatus === 'REQUIRES_ATTENTION') {
+        } else if (
+            this.healthStatus === 'REQUIRES_ATTENTION' ||
+            this.healthStatus === 'HANDLE_MEASUREMENT_UPDATE'
+        ) {
             this.healthStatusTone = 'warning';
         } else if (this.healthStatus === 'FAILURE') {
             this.healthStatusTone = 'error';
diff --git 
a/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.html
 
b/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.html
index cb78aaa817..cee5e86ca3 100644
--- 
a/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.html
+++ 
b/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.html
@@ -51,7 +51,9 @@
                     }
                     @if (
                         pipeline.running &&
-                        pipeline.healthStatus === 'REQUIRES_ATTENTION'
+                        (pipeline.healthStatus === 'REQUIRES_ATTENTION' ||
+                            pipeline.healthStatus ===
+                                'HANDLE_MEASUREMENT_UPDATE')
                     ) {
                         <div class="light light-yellow"></div>
                     }
diff --git 
a/ui/src/app/pipelines/dialog/measurement-update/measurement-update-dialog.component.html
 
b/ui/src/app/pipelines/dialog/measurement-update/measurement-update-dialog.component.html
new file mode 100644
index 0000000000..cc9064c75f
--- /dev/null
+++ 
b/ui/src/app/pipelines/dialog/measurement-update/measurement-update-dialog.component.html
@@ -0,0 +1,150 @@
+<!--
+~ 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 class="sp-dialog-container">
+    <div
+        class="sp-dialog-content p-md"
+        data-cy="measurement-update-dialog"
+        fxLayout="column"
+        fxLayoutGap="var(--space-lg)"
+    >
+        <div fxLayout="column" fxLayoutGap="var(--space-xs)">
+            @if (pipeline?.pipelineNotifications?.length > 0) {
+                <div
+                    class="measurement-update-notifications mt-sm"
+                    fxLayout="column"
+                    fxLayoutGap="0.75rem"
+                >
+                    @for (
+                        notification of pipeline.pipelineNotifications;
+                        track notification
+                    ) {
+                        <sp-alert-banner
+                            type="warning"
+                            title="Pipeline Notification"
+                            [description]="notification"
+                        ></sp-alert-banner>
+                    }
+                </div>
+            }
+            <p class="measurement-update-description">
+                {{
+                    'A measurement field changed to a data type that conflicts 
with existing data. This needs manual adjustments. You can handle this error by 
following one of the given instructions:'
+                        | translate
+                }}
+            </p>
+        </div>
+
+        <div
+            class="measurement-update-options"
+            fxLayout="column"
+            fxLayoutGap="0.75rem"
+        >
+            <div
+                class="measurement-update-option"
+                fxLayout="row"
+                fxLayoutAlign="start center"
+                fxLayoutGap="0.75rem"
+            >
+                <mat-icon>add_chart</mat-icon>
+                <span
+                    class="measurement-update-option-text"
+                    fxLayout="column"
+                    fxLayoutGap="0.5rem"
+                >
+                    <span class="font-bold">
+                        {{ 'Save in a new data lake' | translate }}
+                    </span>
+                    <span class="text-small">
+                        {{
+                            'Change the identifier of the "Data Lake" by 
opening the pipeline element configuration to save the data in a new "Data 
Lake".'
+                                | translate
+                        }}
+                    </span>
+                </span>
+            </div>
+            <div
+                class="measurement-update-option"
+                fxLayout="row"
+                fxLayoutAlign="start center"
+                fxLayoutGap="0.75rem"
+            >
+                <mat-icon>drive_file_rename_outline</mat-icon>
+                <span
+                    class="measurement-update-option-text"
+                    fxLayout="column"
+                    fxLayoutGap="0.5rem"
+                >
+                    <span class="font-bold">
+                        {{ 'Rename the changed fields' | translate }}
+                    </span>
+                    <span class="text-small">
+                        {{
+                            'Rename the fields with changed data types by 
using the "Field Renamer" data processor'
+                                | translate
+                        }}
+                    </span>
+                </span>
+            </div>
+            <div
+                class="measurement-update-option"
+                fxLayout="row"
+                fxLayoutAlign="start center"
+                fxLayoutGap="0.75rem"
+            >
+                <mat-icon>delete_forever</mat-icon>
+                <span
+                    class="measurement-update-option-text"
+                    fxLayout="column"
+                    fxLayoutGap="0.5rem"
+                >
+                    <span class="font-bold">
+                        {{ 'Delete historical data' | translate }}
+                    </span>
+                    <span class="text-small">
+                        {{
+                            'Truncate the data of the dataset or delete it 
completely. All historical data is lost!'
+                                | translate
+                        }}
+                    </span>
+                </span>
+            </div>
+        </div>
+    </div>
+    <mat-divider></mat-divider>
+    <div
+        class="sp-dialog-actions actions-align-right"
+        fxLayout="row"
+        fxLayoutAlign="end center"
+        fxLayoutGap="0.5rem"
+    >
+        <button mat-flat-button class="mat-basic" (click)="close()">
+            {{ 'Close' | translate }}
+        </button>
+        <button mat-flat-button color="accent" 
(click)="close('edit-pipeline')">
+            {{ 'Edit pipeline' | translate }}
+        </button>
+        <button
+            mat-flat-button
+            color="accent"
+            (click)="close('manage-datasets')"
+        >
+            {{ 'Manage datasets' | translate }}
+        </button>
+    </div>
+</div>
diff --git 
a/ui/src/app/pipelines/dialog/measurement-update/measurement-update-dialog.component.scss
 
b/ui/src/app/pipelines/dialog/measurement-update/measurement-update-dialog.component.scss
new file mode 100644
index 0000000000..f6d0eb5bf0
--- /dev/null
+++ 
b/ui/src/app/pipelines/dialog/measurement-update/measurement-update-dialog.component.scss
@@ -0,0 +1,16 @@
+.measurement-update-description {
+    margin: 0;
+}
+
+.measurement-update-option {
+    height: auto;
+    min-height: calc(var(--space-xl) * 3.5);
+    padding: var(--space-md);
+    text-align: left;
+    border: 1px solid var(--color-border-subtle);
+    border-radius: var(--button-border-radius);
+}
+
+.measurement-update-option-text {
+    white-space: normal;
+}
diff --git 
a/ui/src/app/pipelines/dialog/measurement-update/measurement-update-dialog.component.ts
 
b/ui/src/app/pipelines/dialog/measurement-update/measurement-update-dialog.component.ts
new file mode 100644
index 0000000000..8201e57699
--- /dev/null
+++ 
b/ui/src/app/pipelines/dialog/measurement-update/measurement-update-dialog.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, Input, inject } from '@angular/core';
+import {
+    MeasurementUpdateAction,
+    Pipeline,
+} from '@streampipes/platform-services';
+import { DialogRef, SpAlertBannerComponent } from '@streampipes/shared-ui';
+import { MatButton } from '@angular/material/button';
+import { MatDivider } from '@angular/material/divider';
+import { MatIcon } from '@angular/material/icon';
+import { TranslatePipe } from '@ngx-translate/core';
+import {
+    LayoutAlignDirective,
+    LayoutDirective,
+    LayoutGapDirective,
+} from '@ngbracket/ngx-layout/flex';
+
+@Component({
+    selector: 'sp-measurement-update-dialog',
+    templateUrl: './measurement-update-dialog.component.html',
+    styleUrls: ['./measurement-update-dialog.component.scss'],
+    imports: [
+        LayoutAlignDirective,
+        LayoutDirective,
+        LayoutGapDirective,
+        MatButton,
+        MatDivider,
+        MatIcon,
+        SpAlertBannerComponent,
+        TranslatePipe,
+    ],
+})
+export class MeasurementUpdateDialogComponent {
+    private dialogRef =
+        inject<DialogRef<MeasurementUpdateDialogComponent>>(DialogRef);
+
+    @Input()
+    pipeline: Pipeline;
+
+    close(action?: MeasurementUpdateAction): void {
+        this.dialogRef.close(action);
+    }
+}

Reply via email to