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);
+ }
+}