This is an automated email from the ASF dual-hosted git repository.
riemer pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/streampipes.git
The following commit(s) were added to refs/heads/dev by this push:
new cd5a7b46e3 fix(#2815): Fix pipeline validation in UI (#2816)
cd5a7b46e3 is described below
commit cd5a7b46e3383573f0f2b51da4b7306d4936aa3f
Author: Dominik Riemer <[email protected]>
AuthorDate: Tue May 7 08:18:25 2024 +0200
fix(#2815): Fix pipeline validation in UI (#2816)
* fix(#2815): Fix pipeline validation in UI
* Fix formatting
* Fix formatting
* fix(#2815): Fix linting
* Fix e2e tests
---------
Co-authored-by: Philipp Zehnder <[email protected]>
---
.../adapter-deployment-settings.component.ts | 4 +-
.../pipeline-assembly.component.ts | 2 +-
.../pipeline-element-options.component.html | 200 +++++++++++----------
.../pipeline-element-options.component.ts | 1 -
.../components/pipeline/pipeline.component.ts | 52 +++---
.../compatible-elements.component.ts | 8 +-
ui/src/app/editor/model/editor.model.ts | 1 -
ui/src/app/editor/services/jsplumb.service.ts | 21 ++-
.../app/editor/services/object-provider.service.ts | 51 +++---
9 files changed, 177 insertions(+), 163 deletions(-)
diff --git
a/ui/src/app/connect/components/adapter-configuration/adapter-settings/adapter-deployment-settings/adapter-deployment-settings.component.ts
b/ui/src/app/connect/components/adapter-configuration/adapter-settings/adapter-deployment-settings/adapter-deployment-settings.component.ts
index c019e9c369..6355ab4c17 100644
---
a/ui/src/app/connect/components/adapter-configuration/adapter-settings/adapter-deployment-settings/adapter-deployment-settings.component.ts
+++
b/ui/src/app/connect/components/adapter-configuration/adapter-settings/adapter-deployment-settings/adapter-deployment-settings.component.ts
@@ -79,7 +79,9 @@ export class SpAdapterDeploymentSettingsComponent implements
OnInit {
);
}
- event.chipInput!.clear();
+ if (event.chipInput) {
+ event.chipInput.clear();
+ }
this.serviceTagCtrl.setValue(null);
}
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..22b03f6b1b 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: 1 }
+ "
+ 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..a06b6ba9a1 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,15 @@ export class PipelineComponent implements OnInit,
OnDestroy {
info.target.id,
this.rawPipelineModel,
);
- if (pe.settings.openCustomize) {
+
+ if (
+ this.shouldOpenCustomizeSettings ||
+ info.connection.data.openCustomize
+ ) {
this.currentPipelineModel = this.objectProvider.makePipeline(
this.rawPipelineModel,
);
+
pe.settings.loadingStatus = true;
this.objectProvider
.updatePipeline(this.currentPipelineModel)
@@ -399,10 +412,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 +477,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 +517,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 +549,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 +589,7 @@ export class PipelineComponent implements OnInit, OnDestroy
{
});
}
- showErrorDialog(title, description) {
+ showErrorDialog(title: string, description: string) {
this.dialog.open(ConfirmDialogComponent, {
width: '500px',
data: {
@@ -610,7 +623,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/dialog/compatible-elements/compatible-elements.component.ts
b/ui/src/app/editor/dialog/compatible-elements/compatible-elements.component.ts
index b9651c0327..3b23c6add6 100644
---
a/ui/src/app/editor/dialog/compatible-elements/compatible-elements.component.ts
+++
b/ui/src/app/editor/dialog/compatible-elements/compatible-elements.component.ts
@@ -45,9 +45,7 @@ export class CompatibleElementsComponent implements OnInit {
constructor(
private dialogRef: DialogRef<CompatibleElementsComponent>,
private JsPlumbService: JsplumbService,
- ) {
- // this.ElementIconText = ElementIconText;
- }
+ ) {}
ngOnInit() {
this.possibleElements.sort((a, b) => a.name.localeCompare(b.name));
@@ -65,10 +63,6 @@ export class CompatibleElementsComponent implements OnInit {
this.hide();
}
- iconText(elementId) {
- // return this.ElementIconText.getElementIconText(elementId);
- }
-
hide() {
// this.$mdDialog.hide();
this.dialogRef.close();
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..f0a61813a2 100644
--- a/ui/src/app/editor/services/jsplumb.service.ts
+++ b/ui/src/app/editor/services/jsplumb.service.ts
@@ -132,6 +132,7 @@ export class JsplumbService {
pipelineElementConfig.payload as InvocablePipelineElementUnion,
sourceElement,
false,
+ true,
);
});
}
@@ -141,6 +142,7 @@ export class JsplumbService {
pipelineElement: InvocablePipelineElementUnion,
sourceElement,
previewConfig: boolean,
+ openCustomize = false,
) {
let targetElementId;
if (pipelineElement instanceof DataProcessorInvocation) {
@@ -150,7 +152,12 @@ export class JsplumbService {
true,
false,
);
- this.connectNodes(sourceElement, targetElementId, previewConfig);
+ this.connectNodes(
+ sourceElement,
+ targetElementId,
+ previewConfig,
+ openCustomize,
+ );
} else {
targetElementId = this.dataSinkDropped(
pipelineElementDomId,
@@ -158,7 +165,12 @@ export class JsplumbService {
true,
false,
);
- this.connectNodes(sourceElement, targetElementId, previewConfig);
+ this.connectNodes(
+ sourceElement,
+ targetElementId,
+ previewConfig,
+ openCustomize,
+ );
}
}
@@ -166,6 +178,7 @@ export class JsplumbService {
sourceElementSelector,
targetElementId,
previewConfig: boolean,
+ openCustomize = false,
) {
const sourceElement = sourceElementSelector.get()[0];
const jsplumbBridge = this.getBridge(previewConfig);
@@ -195,6 +208,9 @@ export class JsplumbService {
source: sourceEndPoint,
target: targetEndPoint,
detachable: true,
+ data: {
+ openCustomize,
+ },
});
jsplumbBridge.repaintEverything();
}
@@ -250,7 +266,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..6557e58398 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 => {
@@ -109,10 +94,8 @@ export class ObjectProvider {
pipelineElementConfig.type === 'sepa' ||
pipelineElementConfig.type === 'action'
) {
- let payload = pipelineElementConfig.payload;
- payload = this.prepareElement(
- payload as InvocablePipelineElementUnion,
- );
+ const payload = pipelineElementConfig.payload;
+ 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,
+ );
}
}
});