You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by ri...@apache.org on 2022/01/15 20:05:58 UTC

[incubator-streampipes] branch STREAMPIPES-494 updated (3e84f20 -> 0e45db0)

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

riemer pushed a change to branch STREAMPIPES-494
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git.


    from 3e84f20  Merge branch 'dev' into STREAMPIPES-494
     new c53d2f2  [STREAMPIPES-494] Update endpoint styles
     new bc84714  [STREAMPIPES-494] Support edge validation for nodes with multiple inputs
     new 0e45db0  [STREAMPIPES-494] Improve auto-update of pipeline element configurations

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../matching/PipelineModificationGenerator.java    |  37 ++-
 .../matching/v2/pipeline/ApplyGroundingStep.java   |   4 +-
 .../v2/pipeline/CheckCompletedVisitor.java         |  38 ++-
 .../matching/v2/pipeline/SchemaValidationStep.java |   4 +-
 .../v2/pipeline/UpdateOutputStrategiesStep.java    |  16 +-
 .../v2/pipeline/UpdateStaticPropertiesVisitor.java |  10 +
 .../pipeline-assembly.component.ts                 |   1 +
 .../pipeline-element-options.component.ts          |  16 +-
 .../components/pipeline/pipeline.component.html    |  14 +-
 .../components/pipeline/pipeline.component.ts      |  66 +++--
 .../editor/dialog/customize/customize.component.ts |  42 ++--
 ui/src/app/editor/editor.module.ts                 | 128 +++++-----
 ui/src/app/editor/model/editor.model.ts            |   8 +-
 .../app/editor/services/jsplumb-bridge.service.ts  |   4 +-
 .../app/editor/services/jsplumb-config.service.ts  | 270 ++++++++++++---------
 ui/src/app/editor/services/jsplumb.service.ts      |   9 +-
 .../app/editor/services/pipeline-style.service.ts  |  88 +++++++
 .../editor/services/pipeline-validation.service.ts |   4 +-
 ui/src/scss/sp/pipeline-element.scss               |  20 +-
 19 files changed, 508 insertions(+), 271 deletions(-)
 create mode 100644 ui/src/app/editor/services/pipeline-style.service.ts

[incubator-streampipes] 01/03: [STREAMPIPES-494] Update endpoint styles

Posted by ri...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

riemer pushed a commit to branch STREAMPIPES-494
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git

commit c53d2f233f87c84d389b0a8401e193e2d164eef5
Author: Dominik Riemer <do...@gmail.com>
AuthorDate: Fri Jan 14 09:52:26 2022 +0100

    [STREAMPIPES-494] Update endpoint styles
---
 .../v2/pipeline/CheckCompletedVisitor.java         |  10 +
 .../v2/pipeline/UpdateStaticPropertiesVisitor.java |  10 +
 .../pipeline-assembly.component.ts                 |   1 +
 .../components/pipeline/pipeline.component.ts      |  32 ++-
 ui/src/app/editor/editor.module.ts                 | 128 +++++-----
 .../app/editor/services/jsplumb-bridge.service.ts  |   4 +-
 .../app/editor/services/jsplumb-config.service.ts  | 270 ++++++++++++---------
 .../app/editor/services/pipeline-style.service.ts  |  82 +++++++
 8 files changed, 343 insertions(+), 194 deletions(-)

diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/CheckCompletedVisitor.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/CheckCompletedVisitor.java
index 885ab77..113c8c6 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/CheckCompletedVisitor.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/CheckCompletedVisitor.java
@@ -107,6 +107,16 @@ public class CheckCompletedVisitor extends DefaultStaticPropertyVisitor {
 
   }
 
+  @Override
+  public void visit(SlideToggleStaticProperty slideToggleStaticProperty) {
+
+  }
+
+  @Override
+  public void visit(RuntimeResolvableTreeInputStaticProperty treeInputStaticProperty) {
+
+  }
+
   public List<PipelineElementValidationInfo> getValidationInfos() {
     return this.validationInfos;
   }
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/UpdateStaticPropertiesVisitor.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/UpdateStaticPropertiesVisitor.java
index 18cb7a2..4787a69 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/UpdateStaticPropertiesVisitor.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/UpdateStaticPropertiesVisitor.java
@@ -96,6 +96,16 @@ public class UpdateStaticPropertiesVisitor extends DefaultStaticPropertyVisitor
 
   }
 
+  @Override
+  public void visit(SlideToggleStaticProperty slideToggleStaticProperty) {
+
+  }
+
+  @Override
+  public void visit(RuntimeResolvableTreeInputStaticProperty treeInputStaticProperty) {
+
+  }
+
   private void updateMappingProperty(MappingProperty mappingProperty) {
     AbstractRequirementsSelectorGenerator generator = RequirementsSelectorGeneratorFactory
             .getRequirementsSelector(
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 28f6b40..bc137ba 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
@@ -282,6 +282,7 @@ export class PipelineAssemblyComponent implements OnInit, AfterViewInit {
                 this.pipelineValid = this.pipelineValidationService
                     .isValidPipeline(this.rawPipelineModel.filter(pe => !(pe.settings.disabled)), false);
             });
+            this.pipelineComponent.triggerPipelineModification();
         });
     }
 
diff --git a/ui/src/app/editor/components/pipeline/pipeline.component.ts b/ui/src/app/editor/components/pipeline/pipeline.component.ts
index de159ca..05d860d 100644
--- a/ui/src/app/editor/components/pipeline/pipeline.component.ts
+++ b/ui/src/app/editor/components/pipeline/pipeline.component.ts
@@ -46,6 +46,7 @@ import { JsplumbFactoryService } from '../../services/jsplumb-factory.service';
 import { PipelinePositioningService } from '../../services/pipeline-positioning.service';
 import { EVENT_CONNECTION_ABORT, EVENT_CONNECTION_DRAG } from '@jsplumb/browser-ui';
 import { EVENT_CONNECTION, EVENT_CONNECTION_DETACHED, EVENT_CONNECTION_MOVED } from '@jsplumb/core';
+import { PipelineStyleService } from "../../services/pipeline-style.service";
 
 @Component({
   selector: 'pipeline',
@@ -104,6 +105,7 @@ export class PipelineComponent implements OnInit, OnDestroy {
               private objectProvider: ObjectProvider,
               private editorService: EditorService,
               private shepherdService: ShepherdService,
+              private pipelineStyleService: PipelineStyleService,
               private pipelineValidationService: PipelineValidationService,
               private dialogService: DialogService,
               private dialog: MatDialog,
@@ -325,9 +327,7 @@ export class PipelineComponent implements OnInit, OnDestroy {
             pe.settings.loadingStatus = false;
             const edgeValidations = this.getTargetEdgeValidations(pipelineModificationMessage, info.target.id);
             const currentConnectionValid = this.currentConnectionValid(pe, edgeValidations);
-            this.processEdgeValidations(pipelineModificationMessage, info.target.id);
             if (currentConnectionValid) {
-              info.targetEndpoint.setType('token');
               this.validatePipeline();
               this.modifyPipeline(pipelineModificationMessage);
               if (this.jsplumbService.isFullyConnected(pe, this.preview)) {
@@ -343,12 +343,12 @@ export class PipelineComponent implements OnInit, OnDestroy {
             } else {
               this.JsplumbBridge.detach(info.connection);
               const invalidEdgeValidation = edgeValidations.find(e => e.sourceId === info.source.id);
-              console.log(invalidEdgeValidation);
               if (invalidEdgeValidation) {
                 this.showMatchingErrorDialog(invalidEdgeValidation.status.notifications);
               }
             }
           }, status => {
+            pe.settings.loadingStatus = false;
             this.showErrorDialog(status.error.title, status.error.description);
           });
       }
@@ -371,25 +371,29 @@ export class PipelineComponent implements OnInit, OnDestroy {
     return edgeValidations.filter(ev => ev.targetId === targetDomId);
   }
 
-  processEdgeValidations(pipelineModificationMessage: PipelineModificationMessage,
-                         targetDomId: string) {
-
-  }
-
   modifyPipeline(pm: PipelineModificationMessage) {
     if (pm.pipelineModifications) {
       pm.pipelineModifications.forEach(modification => {
         const id = modification.domId;
         if (id !== 'undefined') {
           const pe = this.objectProvider.findElement(id, this.rawPipelineModel);
-          (pe.payload as InvocablePipelineElementUnion).staticProperties = modification.staticProperties;
-          if (pe.payload instanceof DataProcessorInvocation) {
+          if (modification.staticProperties) {
+            (pe.payload as InvocablePipelineElementUnion).staticProperties = modification.staticProperties;
+          }
+          if (pe.payload instanceof DataProcessorInvocation && modification.outputStrategies) {
             (pe.payload as DataProcessorInvocation).outputStrategies = modification.outputStrategies;
           }
-          (pe.payload as InvocablePipelineElementUnion).inputStreams = modification.inputStreams;
+          if (modification.inputStreams) {
+            (pe.payload as InvocablePipelineElementUnion).inputStreams = modification.inputStreams;
+          }
         }
       });
     }
+    if (pm.edgeValidations) {
+      this.pipelineStyleService.updateAllConnectorStyles(pm.edgeValidations);
+      this.pipelineStyleService.updateAllEndpointStyles(pm.edgeValidations);
+      this.JsplumbBridge.repaintEverything();
+    }
   }
 
   isCustomOutput(pe) {
@@ -460,7 +464,6 @@ export class PipelineComponent implements OnInit, OnDestroy {
           if (!(pipelineElementConfig.payload instanceof DataSinkInvocation)) {
             this.JsplumbBridge.activateEndpoint('out-' + pipelineElementConfig.payload.dom, pipelineElementConfig.settings.completed);
           }
-          this.JsplumbBridge.getSourceEndpoint(pipelineElementConfig.payload.dom).toggleType('token');
           this.triggerPipelineCacheUpdate();
           this.announceConfiguredElement(pipelineElementConfig);
           if (this.previewModeActive) {
@@ -500,4 +503,9 @@ export class PipelineComponent implements OnInit, OnDestroy {
       });
     }
   }
+
+  triggerPipelineModification() {
+    this.currentPipelineModel = this.objectProvider.makePipeline(this.rawPipelineModel);
+    this.objectProvider.updatePipeline(this.currentPipelineModel).subscribe(pm => this.modifyPipeline(pm));
+  }
 }
diff --git a/ui/src/app/editor/editor.module.ts b/ui/src/app/editor/editor.module.ts
index 3ff9973..8725e3a 100644
--- a/ui/src/app/editor/editor.module.ts
+++ b/ui/src/app/editor/editor.module.ts
@@ -65,78 +65,80 @@ import { JsplumbEndpointService } from './services/jsplumb-endpoint.service';
 import { JsplumbFactoryService } from './services/jsplumb-factory.service';
 import { PipelineElementPreviewComponent } from './components/pipeline-element-preview/pipeline-element-preview.component';
 import { PipelineElementDiscoveryComponent } from './dialog/pipeline-element-discovery/pipeline-element-discovery.component';
+import { PipelineStyleService } from './services/pipeline-style.service';
 
 @NgModule({
-    imports: [
-        CoreUiModule,
-        CommonModule,
-        ConnectModule,
-        MatTabsModule,
-        MatListModule,
-        FlexLayoutModule,
-        GridsterModule,
-        CommonModule,
-        FlexLayoutModule,
-        CustomMaterialModule,
-        FormsModule,
-        MatProgressSpinnerModule,
-        ShowdownModule,
-        ReactiveFormsModule,
-    ],
-    declarations: [
-        CompatibleElementsComponent,
-        CustomizeComponent,
-        CustomOutputStrategyComponent,
-        EditorComponent,
-        EnabledPipelineElementFilter,
-        HelpComponent,
-        MatchingErrorComponent,
-        MissingElementsForTutorialComponent,
-        OutputStrategyComponent,
-        UserDefinedOutputStrategyComponent,
-        PipelineAssemblyComponent,
-        PipelineElementComponent,
-        PipelineElementDiscoveryComponent,
-        PipelineElementDocumentationComponent,
-        PipelineElementIconStandComponent,
-        PipelineElementOptionsComponent,
-        PipelineElementPreviewComponent,
-        PipelineElementRecommendationComponent,
-        PipelineElementTemplateConfigComponent,
-        PipelineComponent,
-        PropertySelectionComponent,
-        SavePipelineComponent,
-        SafeCss,
-        WelcomeTourComponent
-    ],
-    providers: [
-        EditorService,
-        SemanticTypeUtilsService,
-        JsplumbFactoryService,
-        JsplumbEndpointService,
-        JsplumbService,
-        JsplumbConfigService,
-        ObjectProvider,
-        PipelineCanvasScrollingService,
-        PipelineElementDraggedService,
-        PipelineEditorService,
-        PipelinePositioningService,
-        PipelineValidationService,
-        PipelineElementRecommendationService,
-        SafeCss,
-    ],
+  imports: [
+    CoreUiModule,
+    CommonModule,
+    ConnectModule,
+    MatTabsModule,
+    MatListModule,
+    FlexLayoutModule,
+    GridsterModule,
+    CommonModule,
+    FlexLayoutModule,
+    CustomMaterialModule,
+    FormsModule,
+    MatProgressSpinnerModule,
+    ShowdownModule,
+    ReactiveFormsModule,
+  ],
+  declarations: [
+    CompatibleElementsComponent,
+    CustomizeComponent,
+    CustomOutputStrategyComponent,
+    EditorComponent,
+    EnabledPipelineElementFilter,
+    HelpComponent,
+    MatchingErrorComponent,
+    MissingElementsForTutorialComponent,
+    OutputStrategyComponent,
+    UserDefinedOutputStrategyComponent,
+    PipelineAssemblyComponent,
+    PipelineElementComponent,
+    PipelineElementDiscoveryComponent,
+    PipelineElementDocumentationComponent,
+    PipelineElementIconStandComponent,
+    PipelineElementOptionsComponent,
+    PipelineElementPreviewComponent,
+    PipelineElementRecommendationComponent,
+    PipelineElementTemplateConfigComponent,
+    PipelineComponent,
+    PropertySelectionComponent,
+    SavePipelineComponent,
+    SafeCss,
+    WelcomeTourComponent
+  ],
+  providers: [
+    EditorService,
+    SemanticTypeUtilsService,
+    JsplumbFactoryService,
+    JsplumbEndpointService,
+    JsplumbService,
+    JsplumbConfigService,
+    ObjectProvider,
+    PipelineCanvasScrollingService,
+    PipelineElementDraggedService,
+    PipelineEditorService,
+    PipelinePositioningService,
+    PipelineStyleService,
+    PipelineValidationService,
+    PipelineElementRecommendationService,
+    SafeCss,
+  ],
   exports: [
     EditorComponent,
     PipelineComponent,
     PipelineElementComponent
   ],
-    entryComponents: [
-        EditorComponent
-    ]
+  entryComponents: [
+    EditorComponent
+  ]
 })
 export class EditorModule {
 
-    constructor() {
-    }
+  constructor() {
+  }
 
 }
diff --git a/ui/src/app/editor/services/jsplumb-bridge.service.ts b/ui/src/app/editor/services/jsplumb-bridge.service.ts
index cc607c0..d0a63f8 100644
--- a/ui/src/app/editor/services/jsplumb-bridge.service.ts
+++ b/ui/src/app/editor/services/jsplumb-bridge.service.ts
@@ -30,11 +30,13 @@ export class JsplumbBridge {
     }
 
     activateEndpointWithType(endpointId: string, endpointEnabled: boolean, endpointType: string) {
+        console.log("activate endpoint");
         this.activateEndpoint(endpointId, endpointEnabled);
         this.setEndpointType(endpointId, endpointType);
     }
 
     setEndpointType(endpointId: string, endpointType: string) {
+        console.log("set endpoint type");
         const endpoint = this.getEndpointById(endpointId);
         // @ts-ignore
         endpoint.setType(endpointType);
@@ -91,7 +93,7 @@ export class JsplumbBridge {
 
     getTargetEndpoint(id) {
         // @ts-ignore
-        return this.jsPlumbInstance.selectEndpoints({target: id});
+        return this.jsPlumbInstance.selectEndpoints({target: document.getElementById(id)});
     }
 
     getEndpointCount(id) {
diff --git a/ui/src/app/editor/services/jsplumb-config.service.ts b/ui/src/app/editor/services/jsplumb-config.service.ts
index 77735a7..d6a2c16 100644
--- a/ui/src/app/editor/services/jsplumb-config.service.ts
+++ b/ui/src/app/editor/services/jsplumb-config.service.ts
@@ -19,127 +19,161 @@
 import { Injectable } from '@angular/core';
 import { JsplumbSettings } from '../model/jsplumb.model';
 import { BezierConnector } from '@jsplumb/connector-bezier';
-import { EndpointTypeDescriptor } from '@jsplumb/core';
+import { ArrowOverlay, EndpointTypeDescriptor } from '@jsplumb/core';
+import { ArrowOverlayOptions } from "@jsplumb/common";
 
 @Injectable()
 export class JsplumbConfigService {
 
-    constructor() {
-    }
-
-    getEditorConfig() {
-        return this.makeConfig(this.makeSettings(12, 5, 30, 30, 2, 80));
-    }
-
-    getPreviewConfig() {
-        return this.makeConfig(this.makeSettings(6, 2, 15, 15, 1, 40));
-    }
-
-    getEndpointTypeConfig(): Record<string, EndpointTypeDescriptor> {
-        return {
-            'empty': {
-                paintStyle: {
-                    fill: 'white',
-                    stroke: '#9E9E9E',
-                    strokeWidth: 2,
-                }
-            },
-            'token': {
-                paintStyle: {
-                    fill: '#BDBDBD',
-                    stroke: '#9E9E9E',
-                    strokeWidth: 2
-                },
-                hoverPaintStyle: {
-                    fill: '#BDBDBD',
-                    stroke: '#4CAF50',
-                    strokeWidth: 4,
-                }
-            },
-            'highlight': {
-                paintStyle: {
-                    fill: 'white',
-                    stroke: '#4CAF50',
-                    strokeWidth: 4
-                }
-            }
-        };
-    }
-
-    makeConfig(settings) {
-        const config = {} as any;
-        config.streamEndpointOptions = this.makeStreamEndpointOptions(settings);
-        config.sepaEndpointOptions = this.makeSepaEndpointOptions(settings);
-        config.leftTargetPointOptions = this.makeLeftTargetPointOptions(settings);
-        return config;
-    }
-
-    makeSettings(dotRadius: number,
-                 lineWidth: number,
-                 arrowWidth: number,
-                 arrowLength: number,
-                 arrowLineWidth: number,
-                 curviness: number) {
-        const settings = {} as JsplumbSettings;
-        settings.dotRadius = dotRadius;
-        settings.lineWidth = lineWidth;
-        settings.arrowWidth = arrowWidth;
-        settings.arrowLength = arrowLength;
-        settings.arrowLineWidth = arrowLineWidth;
-        settings.curviness = curviness;
-        return settings;
-    }
-
-    makeStreamEndpointOptions(settings: JsplumbSettings) {
-        return {
-            endpoint: {type: 'Dot', options: {radius: settings.dotRadius}},
-            connectorStyle: {stroke: '#BDBDBD', outlineStroke: '#BDBDBD', strokeWidth: settings.lineWidth},
-            connector: {type: BezierConnector.type, options: {curviness: settings.curviness}},
-            source: true,
-            type: 'token',
-            maxConnections: -1,
-            anchor: 'Right',
-            connectorOverlays: this.defaultConnectorOverlay(settings)
-        };
-    }
-
-    makeSepaEndpointOptions(settings) {
-        return {
-            endpoint: {type: 'Dot', options: {radius: settings.dotRadius}},
-            connectorStyle: {
-                stroke: '#BDBDBD', outlineStroke: '#9E9E9E', strokeWidth: settings.lineWidth
-            },
-            connector: {type: BezierConnector.type, options: {curviness: settings.curviness}},
-            source: true,
-            maxConnections: -1,
-            anchor: 'Right',
-            type: 'empty',
-            connectorOverlays: this.defaultConnectorOverlay(settings),
-            parameters: {
-                endpointType: 'output'
-            }
-        };
-    }
-
-    makeLeftTargetPointOptions(settings) {
-        return {
-            endpoint: {type: 'Dot', options: {radius: settings.dotRadius}},
-            type: 'empty',
-            anchor: 'Left',
-            target: true
-        };
-    }
-
-    defaultConnectorOverlay(settings) {
-        return [{
-            type: 'Arrow', options: {
-                width: settings.arrowWidth, length: settings.arrowLength, location: 0.5, id: 'arrow', paintStyle: {
-                    fillStyle: '#BDBDBD',
-                    stroke: '#9E9E9E',
-                    strokeWidth: settings.arrowLineWidth
-                }
-            }
-        }];
-    }
+  constructor() {
+  }
+
+  getEditorConfig() {
+    return this.makeConfig(this.makeSettings(12, 5, 30, 30, 2, 80));
+  }
+
+  getPreviewConfig() {
+    return this.makeConfig(this.makeSettings(6, 2, 15, 15, 1, 40));
+  }
+
+  getEndpointTypeConfig(): Record<string, EndpointTypeDescriptor> {
+    return {
+      'empty': {
+        paintStyle: {
+          fill: 'white',
+          stroke: '#9E9E9E',
+          strokeWidth: 1,
+        }
+      },
+      'token': {
+        paintStyle: {
+          fill: '#BDBDBD',
+          stroke: '#9E9E9E',
+          strokeWidth: 1
+        },
+        hoverPaintStyle: {
+          fill: '#9E9E9E',
+          stroke: '#9E9E9E',
+          strokeWidth: 2,
+        }
+      },
+      'highlight': {
+        paintStyle: {
+          fill: 'white',
+          stroke: '#4CAF50',
+          strokeWidth: 2
+        }
+      }
+    };
+  }
+
+  getConnectorStyleSuccess() {
+    return {
+      stroke: '#6ab26c',
+      outlineStroke: '#6ab26c',
+      strokeWidth: 5
+    };
+  }
+
+  getConnectorStyleError() {
+    return {
+      stroke: '#b74e4e',
+      outlineStroke: '#b74e4e',
+      strokeWidth: 5
+    };
+  }
+
+  getConnectorStyleWarning() {
+    return {
+      outlineStroke: '#d3c545',
+      stroke: '#d3c545',
+      strokeWidth: 5
+    };
+  }
+
+  getDefaultConnectorStyle(settings) {
+    return {stroke: '#BDBDBD', outlineStroke: '#BDBDBD', strokeWidth: settings.lineWidth};
+  }
+
+  getDefaultConnector(settings) {
+    return {type: BezierConnector.type, options: {curviness: settings.curviness}};
+  }
+
+  getDefaultEndpoint(settings) {
+    return {type: 'Dot', options: {radius: settings.dotRadius}};
+  }
+
+  makeConfig(settings: JsplumbSettings) {
+    const config = {} as any;
+    config.streamEndpointOptions = this.makeStreamEndpointOptions(settings);
+    config.sepaEndpointOptions = this.makeSepaEndpointOptions(settings);
+    config.leftTargetPointOptions = this.makeLeftTargetPointOptions(settings);
+    return config;
+  }
+
+  makeSettings(dotRadius: number,
+               lineWidth: number,
+               arrowWidth: number,
+               arrowLength: number,
+               arrowLineWidth: number,
+               curviness: number) {
+    const settings = {} as JsplumbSettings;
+    settings.dotRadius = dotRadius;
+    settings.lineWidth = lineWidth;
+    settings.arrowWidth = arrowWidth;
+    settings.arrowLength = arrowLength;
+    settings.arrowLineWidth = arrowLineWidth;
+    settings.curviness = curviness;
+    return settings;
+  }
+
+  makeStreamEndpointOptions(settings: JsplumbSettings) {
+    return {
+      ...this.makeDefaultOutputPortOptions(settings),
+      type: 'token',
+    };
+  }
+
+  makeSepaEndpointOptions(settings) {
+    return {
+      ...this.makeDefaultOutputPortOptions(settings),
+      type: 'token',
+      parameters: {
+        endpointType: 'output'
+      }
+    };
+  }
+
+  makeDefaultOutputPortOptions(settings) {
+    return {
+      endpoint: this.getDefaultEndpoint(settings),
+      connectorStyle: this.getDefaultConnectorStyle(settings),
+      connector: this.getDefaultConnector(settings),
+      source: true,
+      maxConnections: -1,
+      anchor: 'Right',
+      connectorOverlays: [this.defaultConnectorOverlay(settings)],
+    };
+  }
+
+  makeLeftTargetPointOptions(settings) {
+    return {
+      endpoint: {type: 'Dot', options: {radius: settings.dotRadius}},
+      type: 'empty',
+      anchor: 'Left',
+      target: true
+    };
+  }
+
+  defaultConnectorOverlay(settings): ArrowOverlayOptions {
+    return {
+      type: 'Arrow', options: {
+        width: settings.arrowWidth,
+        length: settings.arrowLength,
+        location: 0.5,
+        id: 'arrow'
+      }
+    };
+  }
 
 }
diff --git a/ui/src/app/editor/services/pipeline-style.service.ts b/ui/src/app/editor/services/pipeline-style.service.ts
new file mode 100644
index 0000000..a949f54
--- /dev/null
+++ b/ui/src/app/editor/services/pipeline-style.service.ts
@@ -0,0 +1,82 @@
+/*
+ * 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 { Injectable } from '@angular/core';
+import { JsplumbConfigService } from './jsplumb-config.service';
+import { EdgeValidationStatus, PipelineEdgeValidation } from '../../core-model/gen/streampipes-model';
+import { ArrowOverlay, Endpoint } from '@jsplumb/core';
+import { JsplumbFactoryService } from './jsplumb-factory.service';
+
+@Injectable()
+export class PipelineStyleService {
+
+  constructor(private jsPlumbConfigService: JsplumbConfigService,
+              private jsplumbFactoryService: JsplumbFactoryService) {
+
+  }
+
+  updateAllConnectorStyles(edgeValidations: PipelineEdgeValidation[]) {
+    edgeValidations.forEach(edgeValidation => this.updateConnectorStyle(edgeValidation));
+  }
+
+  updateAllEndpointStyles(edgeValidations: PipelineEdgeValidation[]) {
+    const jsplumbBridge = this.jsplumbFactoryService.getJsplumbBridge(false);
+    edgeValidations.forEach(value => {
+      const endpoints = jsplumbBridge.getTargetEndpoint(value.targetId);
+      endpoints.each(endpoint => {
+        if (endpoint.connections.length > 0) {
+          endpoint.setType('token');
+        }
+      });
+    });
+  }
+
+  updateConnectorStyle(validation: PipelineEdgeValidation) {
+    const jsplumbBridge = this.jsplumbFactoryService.getJsplumbBridge(false);
+    const connections = jsplumbBridge.getConnections({
+      source: this.byId(validation.sourceId),
+      target: this.byId(validation.targetId)
+    });
+    const connectorStyle = this.getConnectorStyleConfig(validation.status);
+
+    if (Array.isArray(connections)) {
+      connections.forEach(connection => {
+        connection.setPaintStyle(connectorStyle);
+      });
+    }
+  }
+
+  getConnectorStyleConfig(status: EdgeValidationStatus) {
+    if (status.validationStatusType === 'COMPLETE') {
+      return this.jsPlumbConfigService.getConnectorStyleSuccess();
+    } else if (status.validationStatusType === 'INCOMPLETE') {
+      return this.jsPlumbConfigService.getConnectorStyleWarning();
+    } else {
+      return this.jsPlumbConfigService.getConnectorStyleError();
+    }
+  }
+
+  updateEndpointStyle(endpoint: Endpoint,
+                      endpointType: string) {
+    endpoint.setType(endpointType);
+  }
+
+  byId(id: string) {
+    return document.getElementById(id);
+  }
+}

[incubator-streampipes] 03/03: [STREAMPIPES-494] Improve auto-update of pipeline element configurations

Posted by ri...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

riemer pushed a commit to branch STREAMPIPES-494
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git

commit 0e45db0a9ac82b25e270e32dde2dd2554beba8fe
Author: Dominik Riemer <do...@gmail.com>
AuthorDate: Sat Jan 15 21:05:43 2022 +0100

    [STREAMPIPES-494] Improve auto-update of pipeline element configurations
---
 .../matching/PipelineModificationGenerator.java    | 25 ++++++++-----
 .../v2/pipeline/CheckCompletedVisitor.java         | 28 +++++++++++----
 .../v2/pipeline/UpdateOutputStrategiesStep.java    | 16 ++++++---
 .../pipeline-element-options.component.ts          | 16 ++++++---
 .../components/pipeline/pipeline.component.html    | 11 ++++--
 .../components/pipeline/pipeline.component.ts      | 31 +++++++++-------
 .../editor/dialog/customize/customize.component.ts | 42 +++++++++++-----------
 ui/src/app/editor/model/editor.model.ts            |  8 ++++-
 ui/src/app/editor/services/jsplumb.service.ts      |  9 +++--
 .../app/editor/services/pipeline-style.service.ts  |  6 ++++
 .../editor/services/pipeline-validation.service.ts |  4 +--
 ui/src/scss/sp/pipeline-element.scss               | 20 ++++++++---
 12 files changed, 144 insertions(+), 72 deletions(-)

diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/PipelineModificationGenerator.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/PipelineModificationGenerator.java
index e43d535..78ec367 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/PipelineModificationGenerator.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/PipelineModificationGenerator.java
@@ -41,11 +41,23 @@ public class PipelineModificationGenerator {
     }
 
     PipelineModificationMessage message = new PipelineModificationMessage();
-    message.setPipelineModifications(getModifications());
-    message.setEdgeValidations(toList(this.edgeValidations));
+    List<PipelineModification> modifications = toList(this.pipelineModifications);
+    message.setPipelineModifications(modifications);
+
+    List<PipelineEdgeValidation> edgeValidations = toList(this.edgeValidations);
+    List<PipelineEdgeValidation> edgesWithoutConnectedStream = collectEdgesWithoutStream(modifications);
+    edgeValidations.addAll(edgesWithoutConnectedStream);
+    message.setEdgeValidations(edgeValidations);
     return message;
   }
 
+  private List<PipelineEdgeValidation> collectEdgesWithoutStream(List<PipelineModification> modifications) {
+    List<PipelineEdgeValidation> edgeValidations = new ArrayList<>();
+    Set<String> edges = pipelineGraph.edgeSet();
+
+    return edgeValidations;
+  }
+
   private void addModification(NamedStreamPipesEntity source,
                                Set<InvocableStreamPipesEntity> targets) {
 
@@ -75,9 +87,8 @@ public class PipelineModificationGenerator {
     return source.getDOM() + "-" + t.getDOM();
   }
 
-  private List<PipelineEdgeValidation> toList(Map<String,
-          PipelineEdgeValidation> edgeValidations) {
-    return new ArrayList<>(edgeValidations.values());
+  private <T> List<T> toList(Map<String,T> map) {
+    return new ArrayList<>(map.values());
   }
 
   private void buildModification(PipelineModification modification,
@@ -99,10 +110,6 @@ public class PipelineModificationGenerator {
             .collect(Collectors.toSet());
   }
 
-  private List<PipelineModification> getModifications() {
-    return new ArrayList<>(this.pipelineModifications.values());
-  }
-
   private List<Notification> toNotifications(List<MatchingResultMessage> matchingResultMessages) {
     return matchingResultMessages
             .stream()
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/CheckCompletedVisitor.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/CheckCompletedVisitor.java
index 113c8c6..7e4c4b4 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/CheckCompletedVisitor.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/CheckCompletedVisitor.java
@@ -40,7 +40,6 @@ public class CheckCompletedVisitor extends DefaultStaticPropertyVisitor {
 
   @Override
   public void visit(CodeInputStaticProperty codeInputStaticProperty) {
-
   }
 
   @Override
@@ -65,7 +64,7 @@ public class CheckCompletedVisitor extends DefaultStaticPropertyVisitor {
 
   @Override
   public void visit(MappingPropertyNary mappingPropertyNary) {
-    if (mappingPropertyNary
+    if (existsSelection(mappingPropertyNary) && mappingPropertyNary
             .getSelectedProperties()
             .stream()
             .noneMatch((p -> mappingPropertyNary.getMapsFromOptions().contains(p)))) {
@@ -74,16 +73,23 @@ public class CheckCompletedVisitor extends DefaultStaticPropertyVisitor {
               .stream()
               .filter(p -> mappingPropertyNary.getMapsFromOptions().contains(p))
               .collect(Collectors.toList()));
-      validationInfos.add(PipelineElementValidationInfo.info("Error in mapping property nary - removed invalid selection"));
+      validationInfos.add(PipelineElementValidationInfo.info("Auto-updated invalid field selection"));
     }
   }
 
   @Override
   public void visit(MappingPropertyUnary mappingPropertyUnary) {
-    if (!(mappingPropertyUnary.getMapsFromOptions().contains(mappingPropertyUnary.getSelectedProperty()))) {
-      // TODO only if element touched
-      mappingPropertyUnary.setSelectedProperty("");
-      validationInfos.add(PipelineElementValidationInfo.info("Error in mapping property unary - removed invalid selection"));
+    if (existsSelection(mappingPropertyUnary)) {
+      if (!(mappingPropertyUnary.getMapsFromOptions().contains(mappingPropertyUnary.getSelectedProperty()))) {
+        if (mappingPropertyUnary.getMapsFromOptions().size() > 0) {
+          String firstSelector = mappingPropertyUnary.getMapsFromOptions().get(0);
+          mappingPropertyUnary.setSelectedProperty(firstSelector);
+          validationInfos.add(PipelineElementValidationInfo.info("Auto-updated invalid field selection"));
+        }
+      }
+    } else {
+      String firstSelector = mappingPropertyUnary.getMapsFromOptions().get(0);
+      mappingPropertyUnary.setSelectedProperty(firstSelector);
     }
   }
 
@@ -120,4 +126,12 @@ public class CheckCompletedVisitor extends DefaultStaticPropertyVisitor {
   public List<PipelineElementValidationInfo> getValidationInfos() {
     return this.validationInfos;
   }
+
+  private boolean existsSelection(MappingPropertyUnary mappingProperty) {
+    return !(mappingProperty.getSelectedProperty() == null || mappingProperty.getSelectedProperty().equals(""));
+  }
+
+  private boolean existsSelection(MappingPropertyNary mappingProperty) {
+    return !(mappingProperty.getSelectedProperties() == null || mappingProperty.getSelectedProperties().size() == 0);
+  }
 }
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/UpdateOutputStrategiesStep.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/UpdateOutputStrategiesStep.java
index 1818e3a..d236759 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/UpdateOutputStrategiesStep.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/UpdateOutputStrategiesStep.java
@@ -43,19 +43,23 @@ public class UpdateOutputStrategiesStep extends AbstractPipelineValidationStep {
         .getOutputStrategies()
         .forEach(strategy -> {
           if (strategy instanceof CustomOutputStrategy) {
-            handleCustomOutputStrategy(inputStreams, (CustomOutputStrategy) strategy);
+            handleCustomOutputStrategy(inputStreams, (CustomOutputStrategy) strategy, validationInfos);
           }
         });
     }
   }
 
   private void handleCustomOutputStrategy(List<SpDataStream> inputStreams,
-                                          CustomOutputStrategy strategy) {
+                                          CustomOutputStrategy strategy,
+                                          List<PipelineElementValidationInfo> validationInfos) {
     PropertySelectorGenerator generator = getGenerator(inputStreams, strategy);
     strategy.setAvailablePropertyKeys(generator.generateSelectors());
     // delete selected keys that are not present as available keys
-    List<String> selected = getValidSelectedPropertyKeys(strategy);
-    strategy.setSelectedPropertyKeys(selected);
+    if (invalidPropertyKeysSelected(strategy)) {
+      List<String> selected = getValidSelectedPropertyKeys(strategy);
+      strategy.setSelectedPropertyKeys(selected);
+      validationInfos.add(PipelineElementValidationInfo.info("Auto-updated list of available fields"));
+    }
   }
 
   private PropertySelectorGenerator getGenerator(List<SpDataStream> inputStreams,
@@ -74,6 +78,10 @@ public class UpdateOutputStrategiesStep extends AbstractPipelineValidationStep {
     }
   }
 
+  private boolean invalidPropertyKeysSelected(CustomOutputStrategy strategy) {
+    return !strategy.getAvailablePropertyKeys().containsAll(strategy.getSelectedPropertyKeys());
+  }
+
   private List<String> getValidSelectedPropertyKeys(CustomOutputStrategy strategy) {
     return strategy
             .getSelectedPropertyKeys()
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 c49156c..b26b2b5 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
@@ -23,16 +23,21 @@ import { RestApi } from '../../../services/rest-api.service';
 import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
 import { PipelineElementRecommendationService } from '../../services/pipeline-element-recommendation.service';
 import { ObjectProvider } from '../../services/object-provider.service';
-import { InvocablePipelineElementUnion, PipelineElementConfig, PipelineElementUnion } from '../../model/editor.model';
+import {
+  InvocablePipelineElementUnion,
+  PipelineElementConfig,
+  PipelineElementConfigurationStatus,
+  PipelineElementUnion
+} from '../../model/editor.model';
 import { SpDataStream, WildcardTopicDefinition } from '../../../core-model/gen/streampipes-model';
 import { EditorService } from '../../services/editor.service';
 import { PanelType } from '../../../core-ui/dialog/base-dialog/base-dialog.model';
 import { DialogService } from '../../../core-ui/dialog/base-dialog/base-dialog.service';
 import { CompatibleElementsComponent } from '../../dialog/compatible-elements/compatible-elements.component';
-import { Tuple2 } from '../../../core-model/base/Tuple2';
 import { cloneDeep } from 'lodash';
 import { Subscription } from 'rxjs';
 import { JsplumbFactoryService } from '../../services/jsplumb-factory.service';
+import { PipelineStyleService } from "../../services/pipeline-style.service";
 
 @Component({
   selector: 'pipeline-element-options',
@@ -86,7 +91,8 @@ export class PipelineElementOptionsComponent implements OnInit, OnDestroy {
               private jsplumbFactoryService: JsplumbFactoryService,
               private jsplumbService: JsplumbService,
               private pipelineValidationService: PipelineValidationService,
-              private restApi: RestApi) {
+              private restApi: RestApi,
+              private pipelineStyleService: PipelineStyleService) {
     this.recommendationsAvailable = false;
     this.possibleElements = [];
     this.recommendedElements = [];
@@ -106,7 +112,7 @@ export class PipelineElementOptionsComponent implements OnInit, OnDestroy {
 
     this.isDataSource = this.pipelineElement.type === 'stream' || this.pipelineElement.type === 'set';
 
-    if (this.isDataSource || this.pipelineElement.settings.completed) {
+    if (this.isDataSource || this.pipelineElement.settings.completed === PipelineElementConfigurationStatus.OK) {
       this.initRecs(this.pipelineElement.payload.dom);
     }
   }
@@ -131,7 +137,7 @@ export class PipelineElementOptionsComponent implements OnInit, OnDestroy {
     const clonedModel: PipelineElementConfig[] = cloneDeep(this.rawPipelineModel);
     clonedModel.forEach(pe => {
       if (pe.payload.dom === pipelineElementDomId && (pe.type !== 'stream'  && pe.type !== 'set')) {
-        pe.settings.completed = false;
+        this.pipelineStyleService.updatePeConfigurationStatus(pe, PipelineElementConfigurationStatus.INCOMPLETE);
         (pe.payload as InvocablePipelineElementUnion).configured = false;
       }
     });
diff --git a/ui/src/app/editor/components/pipeline/pipeline.component.html b/ui/src/app/editor/components/pipeline/pipeline.component.html
index 206b322..39911fb 100644
--- a/ui/src/app/editor/components/pipeline/pipeline.component.html
+++ b/ui/src/app/editor/components/pipeline/pipeline.component.html
@@ -31,11 +31,16 @@
         </div>
         <div class="pipeline-element-loading-container sp-fade-opacity"
              *ngIf="pipelineElement.settings.loadingStatus"></div>
-        <div class="pipeline-element-configuration-invalid {{pipelineElement.type === 'stream' ? 'pi-stream' : 'pi-processor'}}"
-             *ngIf="!pipelineElement.settings.completed">
-            <i class="material-icons pipeline-element-configuration-invalid-icon">
+        <div class="pipeline-element-configuration-status {{pipelineElement.type === 'stream' ? 'pi-stream' : 'pi-processor'}}">
+            <i class="material-icons pipeline-element-configuration-invalid-icon" *ngIf="pipelineElement.settings.completed === 3">
                 warning
             </i>
+            <i class="material-icons pipeline-element-configuration-modified-icon" *ngIf="pipelineElement.settings.completed === 2">
+                warning
+            </i>
+            <i class="material-icons pipeline-element-configuration-ok-icon" *ngIf="pipelineElement.settings.completed === 1">
+                check_circle
+            </i>
         </div>
         <pipeline-element [pipelineElement]="pipelineElement.payload" [preview]="preview"></pipeline-element>
     </div>
diff --git a/ui/src/app/editor/components/pipeline/pipeline.component.ts b/ui/src/app/editor/components/pipeline/pipeline.component.ts
index ac82c26..534fe8a 100644
--- a/ui/src/app/editor/components/pipeline/pipeline.component.ts
+++ b/ui/src/app/editor/components/pipeline/pipeline.component.ts
@@ -22,13 +22,21 @@ import { PipelineEditorService } from '../../services/pipeline-editor.service';
 import { JsplumbBridge } from '../../services/jsplumb-bridge.service';
 import { ShepherdService } from '../../../services/tour/shepherd.service';
 import { Component, EventEmitter, Input, NgZone, OnDestroy, OnInit, Output } from '@angular/core';
-import { InvocablePipelineElementUnion, PipelineElementConfig, PipelineElementUnion } from '../../model/editor.model';
+import {
+  InvocablePipelineElementUnion,
+  PipelineElementConfig,
+  PipelineElementConfigurationStatus,
+  PipelineElementUnion
+} from '../../model/editor.model';
 import {
   CustomOutputStrategy,
   DataProcessorInvocation,
-  DataSinkInvocation, Notification,
+  DataSinkInvocation,
+  Notification,
   Pipeline,
-  PipelineCanvasMetadata, PipelineEdgeValidation, PipelineModification, PipelineModificationMessage,
+  PipelineCanvasMetadata,
+  PipelineEdgeValidation,
+  PipelineModificationMessage,
   PipelinePreviewModel,
   SpDataSet,
   SpDataStream
@@ -268,11 +276,7 @@ export class PipelineComponent implements OnInit, OnDestroy {
 
   handleDeleteOption(pipelineElement: PipelineElementConfig) {
     this.JsplumbBridge.removeAllEndpoints(pipelineElement.payload.dom);
-    this.rawPipelineModel.forEach(pe => {
-      if (pe.payload.dom === pipelineElement.payload.dom) {
-        pe.settings.disabled = true;
-      }
-    });
+    this.rawPipelineModel = this.rawPipelineModel.filter(pe => !(pe.payload.dom === pipelineElement.payload.dom));
     if (this.rawPipelineModel.every(pe => pe.settings.disabled)) {
       this.editorService.makePipelineAssemblyEmpty(true);
     }
@@ -336,7 +340,7 @@ export class PipelineComponent implements OnInit, OnDestroy {
                   this.showCustomizeDialog(pe);
                 } else {
                   (pe.payload as InvocablePipelineElementUnion).configured = true;
-                  pe.settings.completed = true;
+                  this.pipelineStyleService.updatePeConfigurationStatus(pe, PipelineElementConfigurationStatus.INCOMPLETE);
                   this.announceConfiguredElement(pe);
                 }
               }
@@ -387,6 +391,9 @@ export class PipelineComponent implements OnInit, OnDestroy {
           if (modification.inputStreams) {
             (pe.payload as InvocablePipelineElementUnion).inputStreams = modification.inputStreams;
           }
+          if (modification.validationInfos.length > 0) {
+            this.pipelineStyleService.updatePeConfigurationStatus(pe, PipelineElementConfigurationStatus.MODIFIED);
+          }
         }
       });
     }
@@ -462,9 +469,9 @@ export class PipelineComponent implements OnInit, OnDestroy {
         this.currentPipelineModel = this.objectProvider.makePipeline(this.rawPipelineModel);
         this.objectProvider.updatePipeline(this.currentPipelineModel).subscribe(pm => {
           this.modifyPipeline(pm);
-          if (!(pipelineElementConfig.payload instanceof DataSinkInvocation)) {
-            this.JsplumbBridge.activateEndpoint('out-' + pipelineElementConfig.payload.dom, pipelineElementConfig.settings.completed);
-          }
+          // if (!(pipelineElementConfig.payload instanceof DataSinkInvocation)) {
+          //   this.JsplumbBridge.activateEndpoint('out-' + pipelineElementConfig.payload.dom, pipelineElementConfig.settings.completed);
+          // }
           this.triggerPipelineCacheUpdate();
           this.announceConfiguredElement(pipelineElementConfig);
           if (this.previewModeActive) {
diff --git a/ui/src/app/editor/dialog/customize/customize.component.ts b/ui/src/app/editor/dialog/customize/customize.component.ts
index 11fd154..708adac 100644
--- a/ui/src/app/editor/dialog/customize/customize.component.ts
+++ b/ui/src/app/editor/dialog/customize/customize.component.ts
@@ -16,26 +16,25 @@
  *
  */
 
+import { AfterViewInit, ChangeDetectorRef, Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
 import {
-  AfterViewInit,
-  ChangeDetectorRef,
-  Component,
-  Input,
-  OnInit,
-  ViewEncapsulation
-} from '@angular/core';
-import { InvocablePipelineElementUnion, PipelineElementConfig } from '../../model/editor.model';
+  InvocablePipelineElementUnion,
+  PipelineElementConfig,
+  PipelineElementConfigurationStatus
+} from '../../model/editor.model';
 import { DialogRef } from '../../../core-ui/dialog/base-dialog/dialog-ref';
 import { JsplumbService } from '../../services/jsplumb.service';
 import {
   DataProcessorInvocation,
   EventSchema,
-  PipelineElementTemplate, PipelineElementTemplateConfig
+  PipelineElementTemplate,
+  PipelineElementTemplateConfig
 } from '../../../core-model/gen/streampipes-model';
 import { FormBuilder, FormGroup } from '@angular/forms';
 import { ShepherdService } from '../../../services/tour/shepherd.service';
 import { ConfigurationInfo } from '../../../connect/model/ConfigurationInfo';
 import { PipelineElementTemplateService } from '../../../platform-services/apis/pipeline-element-template.service';
+import { PipelineStyleService } from "../../services/pipeline-style.service";
 
 @Component({
   selector: 'customize-pipeline-element',
@@ -59,9 +58,7 @@ export class CustomizeComponent implements OnInit, AfterViewInit {
   matchingSelectionRight: any;
   invalid: any;
   helpDialogVisible: any;
-  currentStaticProperty: any;
   validationErrors: any;
-  configVisible: any;
 
   sourceEndpoint: any;
   sepa: any;
@@ -81,22 +78,23 @@ export class CustomizeComponent implements OnInit, AfterViewInit {
   templateConfigs: Map<string, any> = new Map();
 
   constructor(private dialogRef: DialogRef<CustomizeComponent>,
-              private JsPlumbService: JsplumbService,
-              private ShepherdService: ShepherdService,
+              private jsPlumbService: JsplumbService,
+              private shepherdService: ShepherdService,
               private fb: FormBuilder,
               private changeDetectorRef: ChangeDetectorRef,
-              private pipelineElementTemplateService: PipelineElementTemplateService) {
+              private pipelineElementTemplateService: PipelineElementTemplateService,
+              private pipelineStyleService: PipelineStyleService) {
 
   }
 
   ngOnInit(): void {
     this.originalDialogWidth = this.dialogRef.currentConfig().width;
-    this.cachedPipelineElement = this.JsPlumbService.clone(this.pipelineElement.payload) as InvocablePipelineElementUnion;
+    this.cachedPipelineElement = this.jsPlumbService.clone(this.pipelineElement.payload) as InvocablePipelineElementUnion;
     this.isDataProcessor = this.cachedPipelineElement instanceof DataProcessorInvocation;
     this.cachedPipelineElement.inputStreams.forEach(is => {
       this.eventSchemas = this.eventSchemas.concat(is.eventSchema);
     });
-    this.formValid = this.pipelineElement.settings.completed;
+    this.formValid = this.pipelineElement.settings.completed === PipelineElementConfigurationStatus.OK;
 
     this.parentForm = this.fb.group({});
 
@@ -106,8 +104,8 @@ export class CustomizeComponent implements OnInit, AfterViewInit {
     this.parentForm.statusChanges.subscribe((status) => {
       this.formValid = this.viewInitialized && this.parentForm.valid;
     });
-    if (this.ShepherdService.isTourActive()) {
-      this.ShepherdService.trigger('customize-' + this.pipelineElement.type);
+    if (this.shepherdService.isTourActive()) {
+      this.shepherdService.trigger('customize-' + this.pipelineElement.type);
     }
     this.loadPipelineElementTemplates();
   }
@@ -126,10 +124,10 @@ export class CustomizeComponent implements OnInit, AfterViewInit {
 
   save() {
     this.pipelineElement.payload = this.cachedPipelineElement;
-    this.pipelineElement.settings.completed = true;
+    this.pipelineStyleService.updatePeConfigurationStatus(this.pipelineElement, PipelineElementConfigurationStatus.OK);
     this.pipelineElement.payload.configured = true;
-    if (this.ShepherdService.isTourActive()) {
-      this.ShepherdService.trigger('save-' + this.pipelineElement.type);
+    if (this.shepherdService.isTourActive()) {
+      this.shepherdService.trigger('save-' + this.pipelineElement.type);
     }
     this.dialogRef.close(this.pipelineElement);
   }
@@ -191,7 +189,7 @@ export class CustomizeComponent implements OnInit, AfterViewInit {
 
   loadTemplate(event: any) {
     if (!event.value) {
-      this.cachedPipelineElement = this.JsPlumbService.clone(this.pipelineElement.payload) as InvocablePipelineElementUnion;
+      this.cachedPipelineElement = this.jsPlumbService.clone(this.pipelineElement.payload) as InvocablePipelineElementUnion;
       this.selectedTemplate = false;
     } else {
       this.selectedTemplate = event.value;
diff --git a/ui/src/app/editor/model/editor.model.ts b/ui/src/app/editor/model/editor.model.ts
index ab103db..d10a942 100644
--- a/ui/src/app/editor/model/editor.model.ts
+++ b/ui/src/app/editor/model/editor.model.ts
@@ -34,6 +34,12 @@ export interface PipelineElementPosition {
   y: number;
 }
 
+export enum PipelineElementConfigurationStatus {
+  OK = 1,
+  MODIFIED,
+  INCOMPLETE,
+}
+
 export interface PipelineElementConfig {
   type: string,
   settings: {
@@ -43,7 +49,7 @@ export interface PipelineElementConfig {
     connectable: string,
     disabled: boolean,
     loadingStatus: boolean,
-    completed: boolean
+    completed: PipelineElementConfigurationStatus
     position: {
       x: number,
       y: number
diff --git a/ui/src/app/editor/services/jsplumb.service.ts b/ui/src/app/editor/services/jsplumb.service.ts
index e36d669..47d180f 100644
--- a/ui/src/app/editor/services/jsplumb.service.ts
+++ b/ui/src/app/editor/services/jsplumb.service.ts
@@ -19,7 +19,12 @@
 import { JsplumbConfigService } from './jsplumb-config.service';
 import { JsplumbBridge } from './jsplumb-bridge.service';
 import { Injectable } from '@angular/core';
-import { InvocablePipelineElementUnion, PipelineElementConfig, PipelineElementUnion } from '../model/editor.model';
+import {
+    InvocablePipelineElementUnion,
+    PipelineElementConfig,
+    PipelineElementConfigurationStatus,
+    PipelineElementUnion
+} from '../model/editor.model';
 import { PipelineElementTypeUtils } from '../utils/editor.utils';
 import {
     DataProcessorInvocation,
@@ -181,7 +186,7 @@ export class JsplumbService {
         pipelineElementConfig.settings = {connectable,
             openCustomize: !(pipelineElement as any).configured,
             preview: isPreview,
-            completed: (pipelineElement instanceof SpDataStream || pipelineElement instanceof SpDataSet || isPreview || isCompleted),
+            completed: (pipelineElement instanceof SpDataStream || pipelineElement instanceof SpDataSet || isPreview || isCompleted) ? PipelineElementConfigurationStatus.OK : PipelineElementConfigurationStatus.INCOMPLETE,
             disabled: false,
             loadingStatus: false,
             displaySettings,
diff --git a/ui/src/app/editor/services/pipeline-style.service.ts b/ui/src/app/editor/services/pipeline-style.service.ts
index a949f54..895d577 100644
--- a/ui/src/app/editor/services/pipeline-style.service.ts
+++ b/ui/src/app/editor/services/pipeline-style.service.ts
@@ -21,6 +21,7 @@ import { JsplumbConfigService } from './jsplumb-config.service';
 import { EdgeValidationStatus, PipelineEdgeValidation } from '../../core-model/gen/streampipes-model';
 import { ArrowOverlay, Endpoint } from '@jsplumb/core';
 import { JsplumbFactoryService } from './jsplumb-factory.service';
+import { PipelineElementConfig, PipelineElementConfigurationStatus } from "../model/editor.model";
 
 @Injectable()
 export class PipelineStyleService {
@@ -76,6 +77,11 @@ export class PipelineStyleService {
     endpoint.setType(endpointType);
   }
 
+  updatePeConfigurationStatus(pe: PipelineElementConfig,
+                              status: PipelineElementConfigurationStatus) {
+    pe.settings.completed = status;
+  }
+
   byId(id: string) {
     return document.getElementById(id);
   }
diff --git a/ui/src/app/editor/services/pipeline-validation.service.ts b/ui/src/app/editor/services/pipeline-validation.service.ts
index 3233509..9fc1e14 100644
--- a/ui/src/app/editor/services/pipeline-validation.service.ts
+++ b/ui/src/app/editor/services/pipeline-validation.service.ts
@@ -19,7 +19,7 @@
 import * as dagre from 'dagre';
 import { JsplumbBridge } from './jsplumb-bridge.service';
 import { Injectable } from '@angular/core';
-import { PipelineElementConfig } from '../model/editor.model';
+import { PipelineElementConfig, PipelineElementConfigurationStatus } from '../model/editor.model';
 import { DataProcessorInvocation, DataSinkInvocation } from '../../core-model/gen/streampipes-model';
 import { JsplumbFactoryService } from './jsplumb-factory.service';
 import { UserErrorMessage } from '../../core-model/base/UserErrorMessage';
@@ -102,7 +102,7 @@ export class PipelineValidationService {
     allElementsConfigured(rawPipelineModel: PipelineElementConfig[]): boolean {
         return rawPipelineModel
             .filter(config => ((config.payload instanceof DataProcessorInvocation) || (config.payload instanceof DataSinkInvocation)))
-            .every(config => config.settings.completed);
+            .every(config => (config.settings.completed === PipelineElementConfigurationStatus.OK));
     }
 
     allElementsConnected(rawPipelineModel, jsplumbBridge) {
diff --git a/ui/src/scss/sp/pipeline-element.scss b/ui/src/scss/sp/pipeline-element.scss
index f939d9a..f817c56 100644
--- a/ui/src/scss/sp/pipeline-element.scss
+++ b/ui/src/scss/sp/pipeline-element.scss
@@ -16,16 +16,16 @@
  *
  */
 
-.pipeline-element-configuration-invalid {
+.pipeline-element-configuration-status {
   position: absolute;
   left: 20px;
-  top: 40px;
+  top: -37px;
   width: 100%;
   height: 100%;
 }
 
 .pi-processor {
-  left: 20px;
+  left: 0px;
 }
 
 .pi-stream {
@@ -33,6 +33,16 @@
 }
 
 .pipeline-element-configuration-invalid-icon {
-  font-size:30pt;
+  font-size:20pt;
   color: red;
-}
\ No newline at end of file
+}
+
+.pipeline-element-configuration-modified-icon {
+  font-size:20pt;
+  color: #d3c545;
+}
+
+.pipeline-element-configuration-ok-icon {
+  font-size:20pt;
+  color: #6ab26c;
+}

[incubator-streampipes] 02/03: [STREAMPIPES-494] Support edge validation for nodes with multiple inputs

Posted by ri...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

riemer pushed a commit to branch STREAMPIPES-494
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git

commit bc8471432c8ea18031020794d6349f49131f82cc
Author: Dominik Riemer <do...@gmail.com>
AuthorDate: Fri Jan 14 23:24:57 2022 +0100

    [STREAMPIPES-494] Support edge validation for nodes with multiple inputs
---
 .../matching/PipelineModificationGenerator.java      | 20 +++++++++++++++-----
 .../matching/v2/pipeline/ApplyGroundingStep.java     |  4 +++-
 .../matching/v2/pipeline/SchemaValidationStep.java   |  4 +++-
 .../components/pipeline/pipeline.component.html      |  3 ++-
 .../editor/components/pipeline/pipeline.component.ts |  3 ++-
 5 files changed, 25 insertions(+), 9 deletions(-)

diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/PipelineModificationGenerator.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/PipelineModificationGenerator.java
index 41f720c..e43d535 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/PipelineModificationGenerator.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/PipelineModificationGenerator.java
@@ -22,14 +22,14 @@ public class PipelineModificationGenerator {
 
   private final PipelineGraph pipelineGraph;
   private final Map<String, PipelineModification> pipelineModifications;
-  private List<PipelineEdgeValidation> edgeValidations;
+  private Map<String, PipelineEdgeValidation> edgeValidations;
   private final PipelineValidator pipelineValidator;
 
   public PipelineModificationGenerator(PipelineGraph pipelineGraph) {
     this.pipelineGraph = pipelineGraph;
     this.pipelineModifications = new HashMap<>();
     this.pipelineValidator = new PipelineValidator();
-    this.edgeValidations = new ArrayList<>();
+    this.edgeValidations = new HashMap<>();
   }
 
   public PipelineModificationMessage buildPipelineModificationMessage() {
@@ -42,7 +42,7 @@ public class PipelineModificationGenerator {
 
     PipelineModificationMessage message = new PipelineModificationMessage();
     message.setPipelineModifications(getModifications());
-    message.setEdgeValidations(this.edgeValidations);
+    message.setEdgeValidations(toList(this.edgeValidations));
     return message;
   }
 
@@ -57,10 +57,10 @@ public class PipelineModificationGenerator {
       try {
         pipelineValidator.apply(source, t, targets, validationInfos);
         buildModification(modification, t);
-        edgeValidations.add(PipelineEdgeValidation.complete(source.getDOM(), t.getDOM()));
+        edgeValidations.put(makeKey(source, t), PipelineEdgeValidation.complete(source.getDOM(), t.getDOM()));
       } catch (SpValidationException e) {
         //e.getErrorLog().forEach(log -> validationInfos.add(PipelineElementValidationInfo.error(log.toString())));
-        edgeValidations.add(PipelineEdgeValidation.invalid(source.getDOM(), t.getDOM(), toNotifications(e.getErrorLog())));
+        edgeValidations.put(makeKey(source, t), PipelineEdgeValidation.invalid(source.getDOM(), t.getDOM(), toNotifications(e.getErrorLog())));
         modification.setPipelineElementValid(false);
       }
       modification.setValidationInfos(validationInfos);
@@ -70,6 +70,16 @@ public class PipelineModificationGenerator {
     });
   }
 
+  private String makeKey(NamedStreamPipesEntity source,
+                         InvocableStreamPipesEntity t) {
+    return source.getDOM() + "-" + t.getDOM();
+  }
+
+  private List<PipelineEdgeValidation> toList(Map<String,
+          PipelineEdgeValidation> edgeValidations) {
+    return new ArrayList<>(edgeValidations.values());
+  }
+
   private void buildModification(PipelineModification modification,
                                  InvocableStreamPipesEntity t) {
     if (t instanceof DataProcessorInvocation) {
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/ApplyGroundingStep.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/ApplyGroundingStep.java
index cc5e54e..21a84f1 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/ApplyGroundingStep.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/ApplyGroundingStep.java
@@ -62,7 +62,9 @@ public class ApplyGroundingStep extends AbstractPipelineValidationStep {
               .get(getIndex(target))
               .setEventGrounding(selectedGrounding);
 
-      this.visitorHistory.put(target.getDOM(), 1);
+      if (target.getInputStreams().size() > 1) {
+        this.visitorHistory.put(target.getDOM(), 1);
+      }
     }
   }
 
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/SchemaValidationStep.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/SchemaValidationStep.java
index a306383..23fd614 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/SchemaValidationStep.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/pipeline/SchemaValidationStep.java
@@ -47,7 +47,9 @@ public class SchemaValidationStep extends AbstractPipelineValidationStep {
       target.getInputStreams().get(getIndex(target)).setEventSchema(getSourceSchema(source));
     }
 
-    this.visitorHistory.put(target.getDOM(), 1);
+    if (target.getInputStreams().size() > 1) {
+      this.visitorHistory.put(target.getDOM(), 1);
+    }
   }
 
   private EventSchema getSourceSchema(NamedStreamPipesEntity source) {
diff --git a/ui/src/app/editor/components/pipeline/pipeline.component.html b/ui/src/app/editor/components/pipeline/pipeline.component.html
index 571ddc9..206b322 100644
--- a/ui/src/app/editor/components/pipeline/pipeline.component.html
+++ b/ui/src/app/editor/components/pipeline/pipeline.component.html
@@ -39,7 +39,8 @@
         </div>
         <pipeline-element [pipelineElement]="pipelineElement.payload" [preview]="preview"></pipeline-element>
     </div>
-    <pipeline-element-options *ngIf="!preview" (delete)="handleDeleteOption($event)"
+    <pipeline-element-options *ngIf="!preview && currentMouseOverElement==pipelineElement.payload.dom"
+                              (delete)="handleDeleteOption($event)"
                               (customize)="showCustomizeDialog($event)"
                               [currentMouseOverElement]="currentMouseOverElement"
                               [pipelineValid]="pipelineValid"
diff --git a/ui/src/app/editor/components/pipeline/pipeline.component.ts b/ui/src/app/editor/components/pipeline/pipeline.component.ts
index 05d860d..ac82c26 100644
--- a/ui/src/app/editor/components/pipeline/pipeline.component.ts
+++ b/ui/src/app/editor/components/pipeline/pipeline.component.ts
@@ -362,7 +362,8 @@ export class PipelineComponent implements OnInit, OnDestroy {
   currentConnectionValid(pe: PipelineElementConfig,
                          targetEdges: PipelineEdgeValidation[]) {
     const entity = pe.payload as InvocablePipelineElementUnion;
-    return entity.streamRequirements.length === targetEdges.length && targetEdges.every(e => e.status.validationStatusType === 'COMPLETE');
+    //return entity.streamRequirements.length === targetEdges.length && targetEdges.every(e => e.status.validationStatusType === 'COMPLETE');
+    return targetEdges.every(e => e.status.validationStatusType === 'COMPLETE');
   }
 
   getTargetEdgeValidations(pipelineModificationMessage: PipelineModificationMessage,