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 2020/06/15 20:14:04 UTC

[incubator-streampipes] 02/02: [STREAMPIPES-145] Migrate matching error dialog

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

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

commit e00001ce2044afdbffbb486e8d85f53ec55824b0
Author: Dominik Riemer <ri...@fzi.de>
AuthorDate: Mon Jun 15 22:13:45 2020 +0200

    [STREAMPIPES-145] Migrate matching error dialog
---
 .../client/matching/MatchingResultMessage.java     |  3 +
 .../rest/impl/AbstractRestInterface.java           | 46 +++++++--------
 .../rest/impl/PipelineWithUserResource.java        |  2 +-
 .../app/core-model/gen/streampipes-model-client.ts | 57 +++++++++++++++++++
 .../standard-dialog/standard-dialog.component.scss |  3 +-
 .../components/pipeline/pipeline.component.ts      | 46 +++++++++------
 .../matching-error/matching-error.component.html   | 53 ++++++++++++++++++
 .../matching-error/matching-error.component.scss}  | 39 +------------
 .../matching-error/matching-error.component.ts}    | 65 ++++++++++------------
 ui/src/app/editor-v2/editor.module.ts              |  2 +
 10 files changed, 199 insertions(+), 117 deletions(-)

diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/matching/MatchingResultMessage.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/matching/MatchingResultMessage.java
index 7112406..c16ab9c 100644
--- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/matching/MatchingResultMessage.java
+++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/matching/MatchingResultMessage.java
@@ -18,6 +18,9 @@
 
 package org.apache.streampipes.model.client.matching;
 
+import org.apache.streampipes.model.shared.annotation.TsModel;
+
+@TsModel
 public class MatchingResultMessage {
 
 	private boolean matchingSuccessful;
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AbstractRestInterface.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AbstractRestInterface.java
index 3463064..cdc7913 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AbstractRestInterface.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AbstractRestInterface.java
@@ -18,41 +18,31 @@
 
 package org.apache.streampipes.rest.impl;
 
+import io.fogsy.empire.core.empire.annotation.InvalidRdfException;
 import org.apache.http.client.ClientProtocolException;
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.authc.AuthenticationException;
-import org.apache.streampipes.model.base.AbstractStreamPipesEntity;
-import org.apache.streampipes.model.base.StreamPipesJsonLdContainer;
-import org.eclipse.rdf4j.repository.RepositoryException;
-import org.eclipse.rdf4j.rio.RDFHandlerException;
-import org.eclipse.rdf4j.rio.RDFParseException;
-import org.eclipse.rdf4j.rio.UnsupportedRDFormatException;
 import org.apache.streampipes.commons.Utils;
-import io.fogsy.empire.core.empire.annotation.InvalidRdfException;
 import org.apache.streampipes.manager.endpoint.HttpJsonParser;
 import org.apache.streampipes.manager.storage.UserManagementService;
 import org.apache.streampipes.manager.storage.UserService;
+import org.apache.streampipes.model.base.AbstractStreamPipesEntity;
 import org.apache.streampipes.model.base.NamedStreamPipesEntity;
-import org.apache.streampipes.model.message.ErrorMessage;
-import org.apache.streampipes.model.message.Message;
+import org.apache.streampipes.model.base.StreamPipesJsonLdContainer;
 import org.apache.streampipes.model.message.Notification;
-import org.apache.streampipes.model.message.NotificationType;
-import org.apache.streampipes.model.message.SuccessMessage;
+import org.apache.streampipes.model.message.*;
 import org.apache.streampipes.serializers.json.GsonSerializer;
 import org.apache.streampipes.serializers.jsonld.JsonLdTransformer;
-import org.apache.streampipes.storage.api.IDataLakeStorage;
-import org.apache.streampipes.storage.api.IFileMetadataStorage;
-import org.apache.streampipes.storage.api.INoSqlStorage;
-import org.apache.streampipes.storage.api.INotificationStorage;
-import org.apache.streampipes.storage.api.IPipelineElementDescriptionStorageCache;
-import org.apache.streampipes.storage.api.IPipelineStorage;
-import org.apache.streampipes.storage.api.ITripleStorage;
-import org.apache.streampipes.storage.api.IUserStorage;
-import org.apache.streampipes.storage.api.IVisualizationStorage;
+import org.apache.streampipes.storage.api.*;
 import org.apache.streampipes.storage.management.StorageDispatcher;
 import org.apache.streampipes.storage.management.StorageManager;
 import org.apache.streampipes.storage.rdf4j.util.Transformer;
+import org.eclipse.rdf4j.repository.RepositoryException;
+import org.eclipse.rdf4j.rio.RDFHandlerException;
+import org.eclipse.rdf4j.rio.RDFParseException;
+import org.eclipse.rdf4j.rio.UnsupportedRDFormatException;
 
+import javax.ws.rs.core.Response;
 import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
 import java.net.URI;
@@ -60,8 +50,6 @@ import java.net.URISyntaxException;
 import java.net.URLDecoder;
 import java.util.List;
 
-import javax.ws.rs.core.Response;
-
 public abstract class AbstractRestInterface {
 
   protected <T> String toJsonLd(T object) {
@@ -150,7 +138,6 @@ public abstract class AbstractRestInterface {
     return statusMessage(new ErrorMessage(notifications));
   }
 
-
   protected String getCurrentUsername() throws AuthenticationException {
     if (SecurityUtils.getSubject().isAuthenticated()) {
       return SecurityUtils.getSubject().getPrincipal().toString();
@@ -178,12 +165,25 @@ public abstract class AbstractRestInterface {
             .build();
   }
 
+  protected Response statusMessage(Message message, Response.ResponseBuilder builder) {
+    return builder
+            .entity(message)
+            .build();
+  }
+
   protected <T> Response ok(T entity) {
     return Response
             .ok(entity)
             .build();
   }
 
+  protected <T> Response badRequest(T entity) {
+    return Response
+            .status(400)
+            .entity(entity)
+            .build();
+  }
+
   protected StreamPipesJsonLdContainer asContainer(List<? extends AbstractStreamPipesEntity> elements) {
     return new StreamPipesJsonLdContainer(elements);
   }
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineWithUserResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineWithUserResource.java
index 4854c69..41ad641 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineWithUserResource.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineWithUserResource.java
@@ -220,7 +220,7 @@ public class PipelineWithUserResource extends AbstractRestInterface implements I
             return constructErrorMessage(new Notification(NotificationType.REMOTE_SERVER_NOT_ACCESSIBLE
                     , e.getMessage()));
         } catch (InvalidConnectionException e) {
-            return ok(e.getErrorLog());
+            return badRequest(e.getErrorLog());
         } catch (Exception e) {
             e.printStackTrace();
             return constructErrorMessage(new Notification(NotificationType.UNKNOWN_ERROR,
diff --git a/ui/src/app/core-model/gen/streampipes-model-client.ts b/ui/src/app/core-model/gen/streampipes-model-client.ts
new file mode 100644
index 0000000..f36247b
--- /dev/null
+++ b/ui/src/app/core-model/gen/streampipes-model-client.ts
@@ -0,0 +1,57 @@
+/* tslint:disable */
+/* eslint-disable */
+// @ts-nocheck
+// Generated using typescript-generator version 2.23.603 on 2020-06-15 21:49:32.
+
+export class MatchingResultMessage {
+    description: string;
+    matchingSuccessful: boolean;
+    offerSubject: string;
+    reasonText: string;
+    requirementSubject: string;
+    title: string;
+
+    static fromData(data: MatchingResultMessage, target?: MatchingResultMessage): MatchingResultMessage {
+        if (!data) {
+            return data;
+        }
+        const instance = target || new MatchingResultMessage();
+        instance.matchingSuccessful = data.matchingSuccessful;
+        instance.title = data.title;
+        instance.description = data.description;
+        instance.offerSubject = data.offerSubject;
+        instance.requirementSubject = data.requirementSubject;
+        instance.reasonText = data.reasonText;
+        return instance;
+    }
+}
+
+function __getCopyArrayFn<T>(itemCopyFn: (item: T) => T): (array: T[]) => T[] {
+    return (array: T[]) => __copyArray(array, itemCopyFn);
+}
+
+function __copyArray<T>(array: T[], itemCopyFn: (item: T) => T): T[] {
+    return array && array.map(item => item && itemCopyFn(item));
+}
+
+function __getCopyObjectFn<T>(itemCopyFn: (item: T) => T): (object: { [index: string]: T }) => { [index: string]: T } {
+    return (object: { [index: string]: T }) => __copyObject(object, itemCopyFn);
+}
+
+function __copyObject<T>(object: { [index: string]: T }, itemCopyFn: (item: T) => T): { [index: string]: T } {
+    if (!object) {
+        return object;
+    }
+    const result: any = {};
+    for (const key in object) {
+        if (object.hasOwnProperty(key)) {
+            const value = object[key];
+            result[key] = value && itemCopyFn(value);
+        }
+    }
+    return result;
+}
+
+function __identity<T>(): (value: T) => T {
+    return value => value;
+}
diff --git a/ui/src/app/core-ui/dialog/standard-dialog/standard-dialog.component.scss b/ui/src/app/core-ui/dialog/standard-dialog/standard-dialog.component.scss
index 3fe1d06..060041e 100644
--- a/ui/src/app/core-ui/dialog/standard-dialog/standard-dialog.component.scss
+++ b/ui/src/app/core-ui/dialog/standard-dialog/standard-dialog.component.scss
@@ -25,7 +25,8 @@ standard-dialog-container {
 }
 
 .dialog-panel {
-  height: 80vh;
+  max-height: 80vh;
+  height: 100%;
   display: grid;
   grid-template-rows: 50px auto;
 }
diff --git a/ui/src/app/editor-v2/components/pipeline/pipeline.component.ts b/ui/src/app/editor-v2/components/pipeline/pipeline.component.ts
index e6dd360..edc77ee 100644
--- a/ui/src/app/editor-v2/components/pipeline/pipeline.component.ts
+++ b/ui/src/app/editor-v2/components/pipeline/pipeline.component.ts
@@ -41,6 +41,8 @@ import {CustomizeComponent} from "../../dialog/customize/customize.component";
 import {PanelType} from "../../../core-ui/dialog/base-dialog/base-dialog.model";
 import {DialogService} from "../../../core-ui/dialog/base-dialog/base-dialog.service";
 import {EditorService} from "../../services/editor.service";
+import {MatchingResultMessage} from "../../../core-model/gen/streampipes-model-client";
+import {MatchingErrorComponent} from "../../dialog/matching-error/matching-error.component";
 
 @Component({
   selector: 'pipeline',
@@ -296,25 +298,25 @@ export class PipelineComponent implements OnInit {
         this.ObjectProvider.updatePipeline(this.currentPipelineModel)
             .subscribe(pipelineModificationMessage => {
               pe.settings.loadingStatus = false;
-              if (pipelineModificationMessage.success) {
-                info.targetEndpoint.setType("token");
-                this.validatePipeline();
-                this.modifyPipeline(pipelineModificationMessage.pipelineModifications);
-                var sourceEndpoint = this.JsplumbBridge.selectEndpoints({element: info.targetEndpoint.elementId});
-                if (this.PipelineEditorService.isFullyConnected(pe)) {
-                  let payload = pe.payload as InvocablePipelineElementUnion;
-                  if ((payload.staticProperties && payload.staticProperties.length > 0) || this.isCustomOutput(pe)) {
-                    this.showCustomizeDialog(pe);
-                  } else {
-                    this.announceConfiguredElement(pe);
-                    //this.$rootScope.$broadcast("SepaElementConfigured", pe.payload.DOM);
-                    (pe.payload as InvocablePipelineElementUnion).configured = true;
-                  }
+              info.targetEndpoint.setType("token");
+              this.validatePipeline();
+              this.modifyPipeline(pipelineModificationMessage.pipelineModifications);
+              var sourceEndpoint = this.JsplumbBridge.selectEndpoints({element: info.targetEndpoint.elementId});
+              if (this.PipelineEditorService.isFullyConnected(pe)) {
+                let payload = pe.payload as InvocablePipelineElementUnion;
+                if ((payload.staticProperties && payload.staticProperties.length > 0) || this.isCustomOutput(pe)) {
+                  this.showCustomizeDialog(pe);
+                } else {
+                  this.announceConfiguredElement(pe);
+                  //this.$rootScope.$broadcast("SepaElementConfigured", pe.payload.DOM);
+                  (pe.payload as InvocablePipelineElementUnion).configured = true;
                 }
-              } else {
-                this.JsplumbBridge.detach(info.connection);
-                this.EditorDialogManager.showMatchingErrorDialog(pipelineModificationMessage);
               }
+            }, status => {
+              pe.settings.loadingStatus = false;
+              this.JsplumbBridge.detach(info.connection);
+              let matchingResultMessage = (status.error as any[]).map(e => MatchingResultMessage.fromData(e as MatchingResultMessage));
+              this.showMatchingErrorDialog(matchingResultMessage);
             });
       }
     });
@@ -361,6 +363,16 @@ export class PipelineComponent implements OnInit {
     });
   }
 
+  showMatchingErrorDialog(matchingResultMessage: MatchingResultMessage[]) {
+    this.dialogService.open(MatchingErrorComponent, {
+      panelType: PanelType.STANDARD_PANEL,
+      title: "Invalid Connection",
+      data: {
+        "matchingResultMessage": matchingResultMessage
+      }
+    });
+  }
+
   showCustomizeDialog(pipelineElement: PipelineElementConfig) {
     const dialogRef = this.dialogService.open(CustomizeComponent,{
       panelType: PanelType.SLIDE_IN_PANEL,
diff --git a/ui/src/app/editor-v2/dialog/matching-error/matching-error.component.html b/ui/src/app/editor-v2/dialog/matching-error/matching-error.component.html
new file mode 100644
index 0000000..5303852
--- /dev/null
+++ b/ui/src/app/editor-v2/dialog/matching-error/matching-error.component.html
@@ -0,0 +1,53 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<div class="sp-dialog-container">
+    <div class="sp-dialog-content p-15">
+        <div>
+            <h4>These elements can't be connected.</h4>
+            <h4>The input data stream does not satisfy the requirements specified by the data processor.</h4>
+            <button mat-button (click)="toggleStatusDetailsVisible()" type="button" class="md-accent">
+                <div *ngIf="!statusDetailsVisible">Show Details</div>
+                <div *ngIf="statusDetailsVisible">Hide Details</div>
+            </button>
+            <div *ngIf="statusDetailsVisible">
+                <div *ngFor="let entry of matchingResultMessage">
+                    <div fxFlex="100" class="md-whiteframe-z1" style="margin-bottom:10px;">
+                        <div fxFlex fxLayout="column" class="md-padding">
+                            <div>
+                                <i class="material-icons" *ngIf="entry.matchingResultMessage">done</i>
+                                <i class="material-icons" *ngIf="entry.matchingSuccessful">warning</i>
+                                <b>{{entry.title}} </b>
+                            </div>
+                            <div fxFlex="column">
+                                {{entry.requirementSubject}}<br/>
+                                {{entry.reasonText}}
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    <mat-divider></mat-divider>
+    <div class="sp-dialog-actions actions-align-right">
+        <button mat-button mat-raised-button class="mat-basic" (click)="close()">
+            Close
+        </button>
+    </div>
+</div>
\ No newline at end of file
diff --git a/ui/src/app/core-ui/dialog/standard-dialog/standard-dialog.component.scss b/ui/src/app/editor-v2/dialog/matching-error/matching-error.component.scss
similarity index 58%
copy from ui/src/app/core-ui/dialog/standard-dialog/standard-dialog.component.scss
copy to ui/src/app/editor-v2/dialog/matching-error/matching-error.component.scss
index 3fe1d06..0a776e5 100644
--- a/ui/src/app/core-ui/dialog/standard-dialog/standard-dialog.component.scss
+++ b/ui/src/app/editor-v2/dialog/matching-error/matching-error.component.scss
@@ -16,41 +16,4 @@
  *
  */
 
-@import 'src/scss/sp/colors';
-
-standard-dialog-container {
-  width: 100%;
-  background-color: #fff;
-  box-shadow: -7px 0px 5px -5px #5d5d5d;
-}
-
-.dialog-panel {
-  height: 80vh;
-  display: grid;
-  grid-template-rows: 50px auto;
-}
-
-.dialog-panel-header {
-  display: flex;
-  justify-content: space-between;
-  height: 50px;
-  min-height: 50px;
-  width: 100%;
-  background: $sp-color-accent;
-  align-items: center;
-}
-
-.dialog-panel-content {
-  height: 100%;
-  overflow-y:auto;
-}
-
-.dialog-title {
-  padding: 5px 5px 5px 15px;
-  font-size:25px;
-  color: white;
-}
-
-#portal {
-  width:100%;
-}
\ No newline at end of file
+@import '../../../../scss/sp/sp-dialog.scss';
\ No newline at end of file
diff --git a/ui/src/app/core-ui/dialog/standard-dialog/standard-dialog.component.scss b/ui/src/app/editor-v2/dialog/matching-error/matching-error.component.ts
similarity index 53%
copy from ui/src/app/core-ui/dialog/standard-dialog/standard-dialog.component.scss
copy to ui/src/app/editor-v2/dialog/matching-error/matching-error.component.ts
index 3fe1d06..ac21a03 100644
--- a/ui/src/app/core-ui/dialog/standard-dialog/standard-dialog.component.scss
+++ b/ui/src/app/editor-v2/dialog/matching-error/matching-error.component.ts
@@ -16,41 +16,32 @@
  *
  */
 
-@import 'src/scss/sp/colors';
-
-standard-dialog-container {
-  width: 100%;
-  background-color: #fff;
-  box-shadow: -7px 0px 5px -5px #5d5d5d;
-}
-
-.dialog-panel {
-  height: 80vh;
-  display: grid;
-  grid-template-rows: 50px auto;
-}
-
-.dialog-panel-header {
-  display: flex;
-  justify-content: space-between;
-  height: 50px;
-  min-height: 50px;
-  width: 100%;
-  background: $sp-color-accent;
-  align-items: center;
-}
-
-.dialog-panel-content {
-  height: 100%;
-  overflow-y:auto;
-}
-
-.dialog-title {
-  padding: 5px 5px 5px 15px;
-  font-size:25px;
-  color: white;
-}
-
-#portal {
-  width:100%;
+import {Component, Input} from "@angular/core";
+import {DialogRef} from "../../../core-ui/dialog/base-dialog/dialog-ref";
+import {MatchingResultMessage} from "../../../core-model/gen/streampipes-model-client";
+
+@Component({
+  selector: 'matching-error',
+  templateUrl: './matching-error.component.html',
+  styleUrls: ['./matching-error.component.scss']
+})
+export class MatchingErrorComponent {
+
+  @Input()
+  matchingResultMessage: MatchingResultMessage[];
+
+  msg: any;
+  statusDetailsVisible: any;
+
+  constructor(private DialogRef: DialogRef<MatchingErrorComponent>) {
+
+  }
+
+  close() {
+    this.DialogRef.close();
+  };
+
+  toggleStatusDetailsVisible() {
+    this.statusDetailsVisible = !(this.statusDetailsVisible);
+  }
 }
\ No newline at end of file
diff --git a/ui/src/app/editor-v2/editor.module.ts b/ui/src/app/editor-v2/editor.module.ts
index d363f43..9d82380 100644
--- a/ui/src/app/editor-v2/editor.module.ts
+++ b/ui/src/app/editor-v2/editor.module.ts
@@ -56,6 +56,7 @@ import {HelpComponent} from "./dialog/help/help.component";
 import {PipelineElementDocumentationComponent} from "./components/pipeline-element-documentation/pipeline-element-documentation.component";
 import { ShowdownModule } from 'ngx-showdown';
 import {SafeCss} from "./utils/style-sanitizer";
+import {MatchingErrorComponent} from "./dialog/matching-error/matching-error.component";
 
 @NgModule({
     imports: [
@@ -78,6 +79,7 @@ import {SafeCss} from "./utils/style-sanitizer";
         CustomizeComponent,
         EditorComponent,
         HelpComponent,
+        MatchingErrorComponent,
         PipelineAssemblyComponent,
         PipelineElementComponent,
         PipelineElementDocumentationComponent,