This is an automated email from the ASF dual-hosted git repository.
riemer pushed a commit to branch 2815-pipeline-validation-in-pipeline-editor
in repository https://gitbox.apache.org/repos/asf/streampipes.git
The following commit(s) were added to
refs/heads/2815-pipeline-validation-in-pipeline-editor by this push:
new 49b2f40bc7 fix(#2815): Fix pipeline validation in UI
49b2f40bc7 is described below
commit 49b2f40bc7771f4fd55f9c5a4a54d1b527690c30
Author: Dominik Riemer <[email protected]>
AuthorDate: Fri May 3 09:42:25 2024 +0200
fix(#2815): Fix pipeline validation in UI
---
.../pipeline-assembly.component.ts | 2 +-
.../pipeline-element-options.component.html | 200 +++++++++++----------
.../pipeline-element-options.component.ts | 1 -
.../components/pipeline/pipeline.component.ts | 49 ++---
ui/src/app/editor/model/editor.model.ts | 1 -
ui/src/app/editor/services/jsplumb.service.ts | 1 -
.../app/editor/services/object-provider.service.ts | 49 ++---
7 files changed, 151 insertions(+), 152 deletions(-)
diff --git
a/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.ts
b/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.ts
index 0cb54b1b7c..4f138e2694 100644
---
a/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.ts
+++
b/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.ts
@@ -246,7 +246,7 @@ export class PipelineAssemblyComponent implements OnInit,
AfterViewInit {
*/
submit() {
const pipelineModel = this.pipelineComponent.rawPipelineModel;
- const pipeline = this.objectProvider.makeFinalPipeline(pipelineModel);
+ const pipeline = this.objectProvider.makePipeline(pipelineModel);
this.pipelinePositioningService.collectPipelineElementPositions(
this.pipelineCanvasMetadata,
pipelineModel,
diff --git
a/ui/src/app/editor/components/pipeline-element-options/pipeline-element-options.component.html
b/ui/src/app/editor/components/pipeline-element-options/pipeline-element-options.component.html
index a879e6b374..e11765cd32 100644
---
a/ui/src/app/editor/components/pipeline-element-options/pipeline-element-options.component.html
+++
b/ui/src/app/editor/components/pipeline-element-options/pipeline-element-options.component.html
@@ -16,110 +16,114 @@
~
-->
<div>
- <div
- [ngStyle]="
- currentMouseOverElement === pipelineElement.payload.dom
- ? { opacity: 1 }
- : { opacity: 1 }
- "
- class="sp-fade-options"
- >
- <span
- class="options-button customize-button"
- *ngIf="pipelineElement.type !== 'stream'"
- style="z-index: 10"
+ <div>
+ <div
+ [ngStyle]="
+ currentMouseOverElement === pipelineElement.payload.dom
+ ? { opacity: 1 }
+ : { opacity: 0 }
+ "
+ class="sp-fade-options"
>
- <button
- class="options-icon-button"
- mat-icon-button
- matTooltip="Configure Element"
- [matTooltipPosition]="'above'"
- (click)="customizeElement(pipelineElement)"
- data-cy="settings-pipeline-element-button"
+ <span
+ class="options-button customize-button"
+ *ngIf="pipelineElement.type !== 'stream'"
+ style="z-index: 10"
>
- <i class="material-icons options-icon-size">settings</i>
- </button>
- </span>
- <span
- class="options-button customize-button"
- *ngIf="pipelineElement.type === 'stream' && isWildcardTopic()"
- style="z-index: 10"
- >
- <button
- class="options-icon-button"
- mat-icon-button
- matTooltip="Configure Element"
- [matTooltipPosition]="'above'"
- (click)="openCustomizeStreamDialog()"
+ <button
+ class="options-icon-button"
+ mat-icon-button
+ matTooltip="Configure Element"
+ [matTooltipPosition]="'above'"
+ (click)="customizeElement(pipelineElement)"
+ data-cy="settings-pipeline-element-button"
+ >
+ <i class="material-icons options-icon-size">settings</i>
+ </button>
+ </span>
+ <span
+ class="options-button customize-button"
+ *ngIf="pipelineElement.type === 'stream' && isWildcardTopic()"
+ style="z-index: 10"
>
- <i class="material-icons options-icon-size">settings</i>
- </button>
- </span>
- <span class="options-button delete-button" style="z-index: 10">
- <button
- class="options-icon-button"
- mat-icon-button
- matTooltip="Delete Element"
- [matTooltipPosition]="'above'"
- (click)="removeElement(pipelineElement)"
+ <button
+ class="options-icon-button"
+ mat-icon-button
+ matTooltip="Configure Element"
+ [matTooltipPosition]="'above'"
+ (click)="openCustomizeStreamDialog()"
+ >
+ <i class="material-icons options-icon-size">settings</i>
+ </button>
+ </span>
+ <span class="options-button delete-button" style="z-index: 10">
+ <button
+ class="options-icon-button"
+ mat-icon-button
+ matTooltip="Delete Element"
+ [matTooltipPosition]="'above'"
+ (click)="removeElement(pipelineElement)"
+ >
+ <i class="material-icons options-icon-size">clear</i>
+ </button>
+ </span>
+ <span
+ class="options-button possible-button"
+ *ngIf="pipelineElement.type !== 'action'"
+ style="z-index: 10"
>
- <i class="material-icons options-icon-size">clear</i>
- </button>
- </span>
- <span
- class="options-button possible-button"
- *ngIf="pipelineElement.type !== 'action'"
- style="z-index: 10"
- >
- <button
- class="options-icon-button"
- mat-icon-button
- matTooltip="Compatible Elements"
- [matTooltipPosition]="'below'"
- [disabled]="!possibleElements || possibleElements.length === 0"
- (click)="openPossibleElementsDialog()"
- [attr.data-cy]="
- 'sp-possible-elements-' +
- pipelineElement.payload.name
- .toLowerCase()
- .replaceAll(' ', '_')
+ <button
+ class="options-icon-button"
+ mat-icon-button
+ matTooltip="Compatible Elements"
+ [matTooltipPosition]="'below'"
+ [disabled]="
+ !possibleElements || possibleElements.length === 0
+ "
+ (click)="openPossibleElementsDialog()"
+ [attr.data-cy]="
+ 'sp-possible-elements-' +
+ pipelineElement.payload.name
+ .toLowerCase()
+ .replaceAll(' ', '_')
+ "
+ _
+ >
+ <i class="material-icons
options-icon-size">account_tree</i>
+ </button>
+ </span>
+ <span
+ class="options-button recommended-button"
+ *ngIf="
+ pipelineElement.type !== 'action' &&
+ recommendationsAvailable &&
+ recommendedElements.length > 0
"
- _
+ style="z-index: 10"
>
- <i class="material-icons options-icon-size">account_tree</i>
- </button>
- </span>
- <span
- class="options-button recommended-button"
- *ngIf="
- pipelineElement.type !== 'action' &&
- recommendationsAvailable &&
- recommendedElements.length > 0
- "
- style="z-index: 10"
- >
- <button
- class="options-icon-button"
- mat-icon-button
- matTooltip="Recommended Elements"
- [matTooltipPosition]="'below'"
- (click)="showRecommendations($event)"
- [disabled]="!recommendationsAvailable"
- >
- <i class="material-icons options-icon-size">add</i>
- </button>
- </span>
- <span class="options-button help-button" style="z-index: 10">
- <button
- class="options-icon-button"
- matTooltip="Help"
- [matTooltipPosition]="'below'"
- mat-icon-button
- (click)="openHelpDialog()"
- >
- <i class="material-icons options-icon-size">help</i>
- </button>
- </span>
+ <button
+ class="options-icon-button"
+ mat-icon-button
+ matTooltip="Recommended Elements"
+ [matTooltipPosition]="'below'"
+ (click)="showRecommendations($event)"
+ [disabled]="!recommendationsAvailable"
+ >
+ <i class="material-icons options-icon-size">add</i>
+ </button>
+ </span>
+ <span class="options-button help-button" style="z-index: 10">
+ <button
+ class="options-icon-button"
+ matTooltip="Help"
+ [matTooltipPosition]="'below'"
+ mat-icon-button
+ (click)="openHelpDialog()"
+ >
+ <i class="material-icons options-icon-size">help</i>
+ </button>
+ </span>
+ </div>
<div
class="editor-pe-info"
[ngClass]="'pe-info-' + pipelineElementCssType"
diff --git
a/ui/src/app/editor/components/pipeline-element-options/pipeline-element-options.component.ts
b/ui/src/app/editor/components/pipeline-element-options/pipeline-element-options.component.ts
index e6645f12cd..ea1e5dc40c 100644
---
a/ui/src/app/editor/components/pipeline-element-options/pipeline-element-options.component.ts
+++
b/ui/src/app/editor/components/pipeline-element-options/pipeline-element-options.component.ts
@@ -111,7 +111,6 @@ export class PipelineElementOptionsComponent implements
OnInit, OnDestroy {
this.pipelineElementConfiguredObservable =
this.editorService.pipelineElementConfigured$.subscribe(
pipelineElementDomId => {
- this.pipelineElement.settings.openCustomize = false;
this.restApi.updateCachedPipeline(this.rawPipelineModel);
if (
pipelineElementDomId ===
diff --git a/ui/src/app/editor/components/pipeline/pipeline.component.ts
b/ui/src/app/editor/components/pipeline/pipeline.component.ts
index 7fa75b3d7e..3bebff9f6f 100644
--- a/ui/src/app/editor/components/pipeline/pipeline.component.ts
+++ b/ui/src/app/editor/components/pipeline/pipeline.component.ts
@@ -118,6 +118,8 @@ export class PipelineComponent implements OnInit, OnDestroy
{
previewModeActive = false;
pipelinePreview: PipelinePreviewModel;
+ shouldOpenCustomizeSettings = false;
+
constructor(
private jsplumbService: JsplumbService,
private pipelineEditorService: PipelineEditorService,
@@ -168,11 +170,11 @@ export class PipelineComponent implements OnInit,
OnDestroy {
this.jsplumbFactoryService.destroy(this.preview);
}
- updateMouseover(elementId) {
+ updateMouseover(elementId: string) {
this.currentMouseOverElement = elementId;
}
- updateOptionsClick(elementId) {
+ updateOptionsClick(elementId: string) {
this.currentMouseOverElement =
this.currentMouseOverElement === elementId ? '' : elementId;
}
@@ -191,11 +193,10 @@ export class PipelineComponent implements OnInit,
OnDestroy {
);
}
- getElementCssClasses(currentPipelineElement) {
+ getElementCssClasses(currentPipelineElement: PipelineElementConfig) {
return (
currentPipelineElement.type +
' ' +
- (currentPipelineElement.settings.openCustomize ? '' : '') +
currentPipelineElement.settings.connectable +
' ' +
currentPipelineElement.settings.displaySettings
@@ -210,7 +211,7 @@ export class PipelineComponent implements OnInit, OnDestroy
{
return this.isInPipeline('set');
}
- isInPipeline(type) {
+ isInPipeline(type: string) {
return this.rawPipelineModel.some(
x => x.type === type && !x.settings.disabled,
);
@@ -336,6 +337,14 @@ export class PipelineComponent implements OnInit,
OnDestroy {
initPlumb() {
this.JsplumbBridge.unbind(EVENT_CONNECTION);
+ this.JsplumbBridge.bind(EVENT_CONNECTION_DRAG, () => {
+ this.shouldOpenCustomizeSettings = true;
+ });
+
+ this.JsplumbBridge.bind(EVENT_CONNECTION_ABORT, () => {
+ this.shouldOpenCustomizeSettings = false;
+ });
+
this.JsplumbBridge.bind(EVENT_CONNECTION_MOVED, info => {
const pe = this.objectProvider.findElement(
info.newTargetEndpoint.elementId,
@@ -355,7 +364,6 @@ export class PipelineComponent implements OnInit, OnDestroy
{
this.rawPipelineModel,
);
(pe.payload as InvocablePipelineElementUnion).configured = false;
- pe.settings.openCustomize = true;
info.targetEndpoint.setType('empty');
this.JsplumbBridge.repaintEverything();
this.validatePipeline();
@@ -383,10 +391,12 @@ export class PipelineComponent implements OnInit,
OnDestroy {
info.target.id,
this.rawPipelineModel,
);
- if (pe.settings.openCustomize) {
+
+ if (this.shouldOpenCustomizeSettings) {
this.currentPipelineModel = this.objectProvider.makePipeline(
this.rawPipelineModel,
);
+
pe.settings.loadingStatus = true;
this.objectProvider
.updatePipeline(this.currentPipelineModel)
@@ -399,10 +409,7 @@ export class PipelineComponent implements OnInit,
OnDestroy {
info.target.id,
);
const currentConnectionValid =
- this.currentConnectionValid(
- pe,
- edgeValidations,
- );
+ this.currentConnectionValid(edgeValidations);
if (currentConnectionValid) {
this.validatePipeline(
pipelineModificationMessage,
@@ -467,11 +474,7 @@ export class PipelineComponent implements OnInit,
OnDestroy {
};
}
- currentConnectionValid(
- pe: PipelineElementConfig,
- targetEdges: PipelineEdgeValidation[],
- ) {
- const entity = pe.payload as InvocablePipelineElementUnion;
+ currentConnectionValid(targetEdges: PipelineEdgeValidation[]) {
return targetEdges.every(
e => e.status.validationStatusType === 'COMPLETE',
);
@@ -511,11 +514,18 @@ export class PipelineComponent implements OnInit,
OnDestroy {
).outputStream = modification.outputStream;
}
}
- if (modification.inputStreams) {
+ if (
+ modification.inputStreams &&
+ modification.inputStreams.length > 0
+ ) {
(
pe.payload as InvocablePipelineElementUnion
).inputStreams = modification.inputStreams;
}
+ if (modification.pipelineElementValid) {
+ pe.settings.completed =
+ PipelineElementConfigurationStatus.OK;
+ }
if (modification.validationInfos.length > 0) {
this.pipelineStyleService.updatePeConfigurationStatus(
pe,
@@ -536,7 +546,7 @@ export class PipelineComponent implements OnInit, OnDestroy
{
}
}
- isCustomOutput(pe) {
+ isCustomOutput(pe: PipelineElementConfig) {
let custom = false;
if (pe.payload instanceof DataProcessorInvocation) {
pe.payload.outputStrategies.forEach(strategy => {
@@ -576,7 +586,7 @@ export class PipelineComponent implements OnInit, OnDestroy
{
});
}
- showErrorDialog(title, description) {
+ showErrorDialog(title: string, description: string) {
this.dialog.open(ConfirmDialogComponent, {
width: '500px',
data: {
@@ -610,7 +620,6 @@ export class PipelineComponent implements OnInit, OnDestroy
{
dialogRef.afterClosed().subscribe(c => {
if (c) {
- pipelineElementConfig.settings.openCustomize = false;
(
pipelineElementConfig.payload as
InvocablePipelineElementUnion
).configured = true;
diff --git a/ui/src/app/editor/model/editor.model.ts
b/ui/src/app/editor/model/editor.model.ts
index 57f939eba6..c92142950c 100644
--- a/ui/src/app/editor/model/editor.model.ts
+++ b/ui/src/app/editor/model/editor.model.ts
@@ -41,7 +41,6 @@ export enum PipelineElementConfigurationStatus {
export interface PipelineElementConfig {
type: string;
settings: {
- openCustomize: boolean;
preview: boolean;
displaySettings: string;
connectable: string;
diff --git a/ui/src/app/editor/services/jsplumb.service.ts
b/ui/src/app/editor/services/jsplumb.service.ts
index 6e6959aff4..ed2d051e5e 100644
--- a/ui/src/app/editor/services/jsplumb.service.ts
+++ b/ui/src/app/editor/services/jsplumb.service.ts
@@ -250,7 +250,6 @@ export class JsplumbService {
);
pipelineElementConfig.settings = {
connectable,
- openCustomize: !(pipelineElement as any).configured,
preview: isPreview,
completed:
pipelineElement instanceof SpDataStream ||
diff --git a/ui/src/app/editor/services/object-provider.service.ts
b/ui/src/app/editor/services/object-provider.service.ts
index b9cd55acc8..d020bd9d1e 100644
--- a/ui/src/app/editor/services/object-provider.service.ts
+++ b/ui/src/app/editor/services/object-provider.service.ts
@@ -17,11 +17,13 @@
*/
import { Injectable } from '@angular/core';
+import { PipelineElementConfig } from '../model/editor.model';
import {
- InvocablePipelineElementUnion,
- PipelineElementConfig,
-} from '../model/editor.model';
-import { DataSinkInvocation, Pipeline } from '@streampipes/platform-services';
+ DataProcessorInvocation,
+ DataSinkInvocation,
+ Pipeline,
+ SpDataStream,
+} from '@streampipes/platform-services';
import { EditorService } from './editor.service';
import { JsplumbFactoryService } from './jsplumb-factory.service';
@@ -32,11 +34,6 @@ export class ObjectProvider {
private jsplumbFactoryService: JsplumbFactoryService,
) {}
- prepareElement(pipelineElement: InvocablePipelineElementUnion) {
- pipelineElement.connectedTo = [];
- return pipelineElement;
- }
-
preparePipeline(): Pipeline {
const pipeline = new Pipeline();
pipeline.name = '';
@@ -48,16 +45,6 @@ export class ObjectProvider {
return pipeline;
}
- makeFinalPipeline(currentPipelineElements: PipelineElementConfig[]) {
- return this.makePipeline(currentPipelineElements);
- }
-
- makePipeline(currentPipelineElements: PipelineElementConfig[]): Pipeline {
- let pipeline = this.preparePipeline();
- pipeline = this.addElementNew(pipeline, currentPipelineElements);
- return pipeline;
- }
-
hasConnectedPipelineElement(
pipelineElementDomId: string,
rawPipelineModel: PipelineElementConfig[],
@@ -85,7 +72,7 @@ export class ObjectProvider {
}
findElement(
- elementId,
+ elementId: string,
rawPipelineModel: PipelineElementConfig[],
): PipelineElementConfig {
return (
@@ -94,10 +81,8 @@ export class ObjectProvider {
);
}
- addElementNew(
- pipeline,
- currentPipelineElements: PipelineElementConfig[],
- ): Pipeline {
+ makePipeline(currentPipelineElements: PipelineElementConfig[]): Pipeline {
+ const pipeline = this.preparePipeline();
const jsplumbBridge =
this.jsplumbFactoryService.getJsplumbBridge(false);
currentPipelineElements.forEach(pipelineElementConfig => {
@@ -110,9 +95,7 @@ export class ObjectProvider {
pipelineElementConfig.type === 'action'
) {
let payload = pipelineElementConfig.payload;
- payload = this.prepareElement(
- payload as InvocablePipelineElementUnion,
- );
+ payload.connectedTo = [];
const connections = jsplumbBridge.getConnections({
target: document.getElementById(payload.dom),
}) as any;
@@ -121,11 +104,17 @@ export class ObjectProvider {
}
if (payload.connectedTo && payload.connectedTo.length > 0)
{
pipelineElementConfig.type === 'action'
- ? pipeline.actions.push(payload)
- : pipeline.sepas.push(payload);
+ ? pipeline.actions.push(
+ payload as DataSinkInvocation,
+ )
+ : pipeline.sepas.push(
+ payload as DataProcessorInvocation,
+ );
}
} else {
- pipeline.streams.push(pipelineElementConfig.payload);
+ pipeline.streams.push(
+ pipelineElementConfig.payload as SpDataStream,
+ );
}
}
});