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 2021/01/20 14:13:57 UTC
[incubator-streampipes] branch STREAMPIPES-272 updated:
[STREAMPIPES-275] Add support for pipeline element templates in UI
This is an automated email from the ASF dual-hosted git repository.
riemer pushed a commit to branch STREAMPIPES-272
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git
The following commit(s) were added to refs/heads/STREAMPIPES-272 by this push:
new 6fcb15b [STREAMPIPES-275] Add support for pipeline element templates in UI
6fcb15b is described below
commit 6fcb15bcb9779d6d49f7df2da6165ccb2308b95b
Author: Dominik Riemer <ri...@fzi.de>
AuthorDate: Wed Jan 20 15:13:39 2021 +0100
[STREAMPIPES-275] Add support for pipeline element templates in UI
---
.../template/PipelineElementTemplateHandler.java | 8 ++
.../template/PipelineElementTemplateVisitor.java | 45 +++++++---
ui/src/app/core-model/gen/streampipes-model.ts | 39 +++++++--
...pipeline-element-template-config.component.html | 60 ++++++++++++++
...ipeline-element-template-config.component.scss} | 15 ++++
.../pipeline-element-template-config.component.ts | 79 ++++++++++++++++++
.../pipeline-element-template-generator.ts | 45 ++++++++++
.../dialog/customize/customize.component.html | 76 ++++++++++++-----
.../dialog/customize/customize.component.scss | 11 +++
.../editor/dialog/customize/customize.component.ts | 96 +++++++++++++++++++---
ui/src/app/editor/editor.module.ts | 4 +-
.../apis/pipeline-element-template.service.ts | 69 ++++++++++++++++
ui/src/app/platform-services/platform.module.ts | 2 +
ui/src/scss/sp/sp-dialog.scss | 2 +-
14 files changed, 497 insertions(+), 54 deletions(-)
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateHandler.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateHandler.java
index 4ae13de..1f74717 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateHandler.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateHandler.java
@@ -25,17 +25,25 @@ public abstract class PipelineElementTemplateHandler<T extends InvocableStreamPi
protected T pipelineElement;
protected PipelineElementTemplate template;
+ private boolean overwriteNameAndDescription;
+
public PipelineElementTemplateHandler(PipelineElementTemplate template,
T pipelineElement,
boolean overwriteNameAndDescription) {
this.template = template;
this.pipelineElement = pipelineElement;
+ this.overwriteNameAndDescription = overwriteNameAndDescription;
}
public T applyTemplateOnPipelineElement() {
PipelineElementTemplateVisitor visitor = new PipelineElementTemplateVisitor(template);
pipelineElement.getStaticProperties().forEach(config -> config.accept(visitor));
+ if (overwriteNameAndDescription) {
+ pipelineElement.setName(template.getTemplateName());
+ pipelineElement.setDescription(template.getTemplateDescription());
+ }
+
return pipelineElement;
}
}
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateVisitor.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateVisitor.java
index fc55d28..11c9583 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateVisitor.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateVisitor.java
@@ -21,6 +21,7 @@ import org.apache.streampipes.model.staticproperty.*;
import org.apache.streampipes.model.template.PipelineElementTemplate;
import org.apache.streampipes.model.template.PipelineElementTemplateConfig;
+import java.util.List;
import java.util.Map;
public class PipelineElementTemplateVisitor implements StaticPropertyVisitor {
@@ -33,7 +34,12 @@ public class PipelineElementTemplateVisitor implements StaticPropertyVisitor {
@Override
public void visit(AnyStaticProperty property) {
-
+ if (hasKey(property)) {
+ List<String> value = (List<String>) getValue(property);
+ property.getOptions().forEach(option -> {
+ option.setSelected(value.stream().anyMatch(v -> v.equals(option.getName())));
+ });
+ }
}
@Override
@@ -48,7 +54,9 @@ public class PipelineElementTemplateVisitor implements StaticPropertyVisitor {
@Override
public void visit(ColorPickerStaticProperty colorPickerStaticProperty) {
-
+ if (hasKey(colorPickerStaticProperty)) {
+ colorPickerStaticProperty.setSelectedColor(getStringValue(colorPickerStaticProperty));
+ }
}
@Override
@@ -58,34 +66,41 @@ public class PipelineElementTemplateVisitor implements StaticPropertyVisitor {
@Override
public void visit(FileStaticProperty fileStaticProperty) {
-
+ if (hasKey(fileStaticProperty)) {
+ fileStaticProperty.setLocationPath(getStringValue(fileStaticProperty));
+ }
}
@Override
public void visit(FreeTextStaticProperty freeTextStaticProperty) {
- if (hasKey(freeTextStaticProperty.getInternalName())) {
- freeTextStaticProperty.setValue(String.valueOf(getValue(freeTextStaticProperty.getInternalName())));
+ if (hasKey(freeTextStaticProperty)) {
+ freeTextStaticProperty.setValue(getStringValue(freeTextStaticProperty));
}
}
@Override
public void visit(MappingPropertyNary mappingPropertyNary) {
-
+ // Do nothing, not supported by pipeline element templates
}
@Override
public void visit(MappingPropertyUnary mappingPropertyUnary) {
-
+ // Do nothing, not supported by pipeline element templates
}
@Override
public void visit(MatchingStaticProperty matchingStaticProperty) {
-
+ // Do nothing, not supported by pipeline element templates
}
@Override
public void visit(OneOfStaticProperty oneOfStaticProperty) {
-
+ if (hasKey(oneOfStaticProperty)) {
+ String value = getStringValue(oneOfStaticProperty);
+ oneOfStaticProperty.getOptions().forEach(option -> {
+ option.setSelected(option.getName().equals(value));
+ });
+ }
}
@Override
@@ -113,11 +128,15 @@ public class PipelineElementTemplateVisitor implements StaticPropertyVisitor {
}
- private Object getValue(String internalName) {
- return configs.get(internalName).getValue();
+ private String getStringValue(StaticProperty sp) {
+ return String.valueOf(getValue(sp));
+ }
+
+ private Object getValue(StaticProperty sp) {
+ return configs.get(sp.getInternalName()).getValue();
}
- private boolean hasKey(String internalName) {
- return configs.containsKey(internalName);
+ private boolean hasKey(StaticProperty sp) {
+ return configs.containsKey(sp.getInternalName());
}
}
diff --git a/ui/src/app/core-model/gen/streampipes-model.ts b/ui/src/app/core-model/gen/streampipes-model.ts
index 716c1d7..835b465 100644
--- a/ui/src/app/core-model/gen/streampipes-model.ts
+++ b/ui/src/app/core-model/gen/streampipes-model.ts
@@ -19,7 +19,7 @@
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
-// Generated using typescript-generator version 2.27.744 on 2021-01-02 22:18:05.
+// Generated using typescript-generator version 2.27.744 on 2021-01-19 20:45:10.
export class AbstractStreamPipesEntity {
"@class": "org.apache.streampipes.model.base.AbstractStreamPipesEntity" | "org.apache.streampipes.model.base.NamedStreamPipesEntity" | "org.apache.streampipes.model.connect.adapter.AdapterDescription" | "org.apache.streampipes.model.connect.adapter.AdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.GenericAdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.SpecificAdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.AdapterStre [...]
@@ -151,8 +151,8 @@ export class NamedStreamPipesEntity extends AbstractStreamPipesEntity {
instance.applicationLinks = __getCopyArrayFn(ApplicationLink.fromData)(data.applicationLinks);
instance.internallyManaged = data.internallyManaged;
instance.connectedTo = __getCopyArrayFn(__identity<string>())(data.connectedTo);
- instance.dom = data.dom;
instance.uri = data.uri;
+ instance.dom = data.dom;
return instance;
}
}
@@ -187,9 +187,9 @@ export class AdapterDescription extends NamedStreamPipesEntity {
instance.config = __getCopyArrayFn(StaticProperty.fromDataUnion)(data.config);
instance.rules = __getCopyArrayFn(TransformationRuleDescription.fromDataUnion)(data.rules);
instance.category = __getCopyArrayFn(__identity<string>())(data.category);
+ instance.schemaRules = __getCopyArrayFn(__identity<any>())(data.schemaRules);
instance.valueRules = __getCopyArrayFn(__identity<any>())(data.valueRules);
instance.streamRules = __getCopyArrayFn(__identity<any>())(data.streamRules);
- instance.schemaRules = __getCopyArrayFn(__identity<any>())(data.schemaRules);
instance.couchDBId = data.couchDBId;
instance._rev = data._rev;
return instance;
@@ -1601,9 +1601,9 @@ export class GenericAdapterSetDescription extends AdapterSetDescription implemen
}
const instance = target || new GenericAdapterSetDescription();
super.fromData(data, instance);
- instance.eventSchema = EventSchema.fromData(data.eventSchema);
- instance.formatDescription = FormatDescription.fromData(data.formatDescription);
instance.protocolDescription = ProtocolDescription.fromData(data.protocolDescription);
+ instance.formatDescription = FormatDescription.fromData(data.formatDescription);
+ instance.eventSchema = EventSchema.fromData(data.eventSchema);
return instance;
}
}
@@ -1620,9 +1620,9 @@ export class GenericAdapterStreamDescription extends AdapterStreamDescription im
}
const instance = target || new GenericAdapterStreamDescription();
super.fromData(data, instance);
- instance.eventSchema = EventSchema.fromData(data.eventSchema);
- instance.formatDescription = FormatDescription.fromData(data.formatDescription);
instance.protocolDescription = ProtocolDescription.fromData(data.protocolDescription);
+ instance.formatDescription = FormatDescription.fromData(data.formatDescription);
+ instance.eventSchema = EventSchema.fromData(data.eventSchema);
return instance;
}
}
@@ -2118,8 +2118,10 @@ export class PipelineElementStatus {
}
export class PipelineElementTemplate {
+ _id: string;
+ _rev: string;
basePipelineElementAppId: string;
- templateConfigs: { [index: string]: any };
+ templateConfigs: { [index: string]: PipelineElementTemplateConfig };
templateDescription: string;
templateName: string;
@@ -2131,7 +2133,26 @@ export class PipelineElementTemplate {
instance.templateName = data.templateName;
instance.templateDescription = data.templateDescription;
instance.basePipelineElementAppId = data.basePipelineElementAppId;
- instance.templateConfigs = __getCopyObjectFn(__identity<any>())(data.templateConfigs);
+ instance.templateConfigs = __getCopyObjectFn(PipelineElementTemplateConfig.fromData)(data.templateConfigs);
+ instance._id = data._id;
+ instance._rev = data._rev;
+ return instance;
+ }
+}
+
+export class PipelineElementTemplateConfig {
+ displayed: boolean;
+ editable: boolean;
+ value: any;
+
+ static fromData(data: PipelineElementTemplateConfig, target?: PipelineElementTemplateConfig): PipelineElementTemplateConfig {
+ if (!data) {
+ return data;
+ }
+ const instance = target || new PipelineElementTemplateConfig();
+ instance.editable = data.editable;
+ instance.displayed = data.displayed;
+ instance.value = data.value;
return instance;
}
}
diff --git a/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.html b/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.html
new file mode 100644
index 0000000..ea93938
--- /dev/null
+++ b/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.html
@@ -0,0 +1,60 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~
+ -->
+
+<div class="p-15">
+ <div fxFlex="100" fxLayout="column">
+ <h4>Basics</h4>
+ <mat-form-field fxFlex>
+ <mat-label>Template name</mat-label>
+ <input [(ngModel)]="template.templateName" matInput name="templateName" class="sp" required/>
+ </mat-form-field>
+ <mat-form-field fxFlex>
+ <mat-label>Template description</mat-label>
+ <input [(ngModel)]="template.templateDescription" matInput name="templateDescription" class="sp"
+ required/>
+ </mat-form-field>
+ <mat-checkbox class="sp" color="primary">Make available as pipeline element</mat-checkbox>
+ <mat-divider class="divider"></mat-divider>
+ <h4>Configuration</h4>
+ <div fxLayout="column" *ngFor="let config of cachedPipelineElement.staticProperties"
+ class="static-property-panel static-property-panel-border">
+ <div fxLayout="row">
+ <div fxFlex="50">
+ {{config.label}}
+ </div>
+ <div fxFlex="50">
+ <div fxLayout="column">
+ <mat-checkbox [checked]="templateConfigs.has(config.internalName)"
+ (change)="handleSelection(config)" name="store" class="sp" color="primary">Store
+ as template
+ </mat-checkbox>
+ <mat-checkbox *ngIf="templateConfigs.has(config.internalName)"
+ (click)="toggleViewPermission(config)" name="displayed"
+ class="sp" color="primary">Users can view
+ </mat-checkbox>
+ <mat-checkbox *ngIf="templateConfigs.has(config.internalName)"
+ (click)="toggleEditPermission(config)" name="editable"
+ class="sp" color="primary">Users can modify
+ </mat-checkbox>
+ </div>
+ </div>
+ </div>
+
+ </div>
+ </div>
+</div>
diff --git a/ui/src/app/editor/dialog/customize/customize.component.scss b/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.scss
similarity index 79%
copy from ui/src/app/editor/dialog/customize/customize.component.scss
copy to ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.scss
index fddade7..2c1a70e 100644
--- a/ui/src/app/editor/dialog/customize/customize.component.scss
+++ b/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.scss
@@ -17,3 +17,18 @@
*/
@import '../../../../scss/sp/sp-dialog.scss';
+
+.divider {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+
+.static-property-panel {
+ padding-left: 10px;
+ margin-bottom: 10px;
+ margin-top: 10px;
+}
+
+.static-property-panel-border {
+ border-left:5px solid gray;
+}
diff --git a/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.ts b/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.ts
new file mode 100644
index 0000000..c402757
--- /dev/null
+++ b/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.ts
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import {Component, Input, OnInit} from "@angular/core";
+import {InvocablePipelineElementUnion} from "../../model/editor.model";
+import {
+ PipelineElementTemplate,
+ StaticPropertyUnion
+} from "../../../core-model/gen/streampipes-model";
+import {PipelineElementTemplateGenerator} from "./pipeline-element-template-generator";
+
+@Component({
+ selector: 'pipeline-element-template-config',
+ templateUrl: './pipeline-element-template-config.component.html',
+ styleUrls: ['./pipeline-element-template-config.component.scss']
+})
+export class PipelineElementTemplateConfigComponent implements OnInit {
+
+ @Input()
+ cachedPipelineElement: InvocablePipelineElementUnion;
+
+ @Input()
+ template: PipelineElementTemplate;
+
+ @Input()
+ templateConfigs: Map<string, any>;
+
+
+ ngOnInit(): void {
+ this.template.basePipelineElementAppId = this.cachedPipelineElement.appId;
+ this.cachedPipelineElement.staticProperties.forEach(sp => {
+ this.templateConfigs.set(sp.internalName, this.makeTemplateValue(sp));
+ })
+ }
+
+ handleSelection(sp: StaticPropertyUnion) {
+ if (this.templateConfigs.has(sp.internalName)) {
+ this.templateConfigs.delete(sp.internalName);
+ } else {
+ this.templateConfigs.set(sp.internalName, this.makeTemplateValue(sp));
+ }
+ }
+
+ makeTemplateValue(sp: StaticPropertyUnion) {
+ let config: any = {};
+ config.displayed = false;
+ config.editable = false;
+ config.value = new PipelineElementTemplateGenerator(sp).toTemplateValue();
+ return config;
+ }
+
+ toggleViewPermission(sp: StaticPropertyUnion) {
+ let config: any = this.templateConfigs.get(sp.internalName);
+ config.displayed = ! config.displayed;
+ this.templateConfigs.set(sp.internalName, config);
+ }
+
+ toggleEditPermission(sp: StaticPropertyUnion) {
+ let config: any = this.templateConfigs.get(sp.internalName);
+ config.editable = ! config.editable;
+ this.templateConfigs.set(sp.internalName, config);
+ }
+
+}
diff --git a/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-generator.ts b/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-generator.ts
new file mode 100644
index 0000000..f09a834
--- /dev/null
+++ b/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-generator.ts
@@ -0,0 +1,45 @@
+/*
+ * 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 {
+ AnyStaticProperty,
+ ColorPickerStaticProperty,
+ FreeTextStaticProperty, OneOfStaticProperty, SecretStaticProperty,
+ StaticPropertyUnion
+} from "../../../core-model/gen/streampipes-model";
+
+export class PipelineElementTemplateGenerator {
+
+ constructor(private sp: StaticPropertyUnion) {
+
+ }
+
+ public toTemplateValue(): any {
+ if (this.sp instanceof FreeTextStaticProperty) {
+ return this.sp.value;
+ } else if (this.sp instanceof OneOfStaticProperty) {
+ return this.sp.options.find(o => o.selected).name;
+ } else if (this.sp instanceof ColorPickerStaticProperty) {
+ return this.sp.selectedColor;
+ } else if (this.sp instanceof SecretStaticProperty) {
+ return undefined;
+ } else if (this.sp instanceof AnyStaticProperty) {
+ return this.sp.options.filter(o => o.selected).map(o => o.name);
+ }
+ }
+}
diff --git a/ui/src/app/editor/dialog/customize/customize.component.html b/ui/src/app/editor/dialog/customize/customize.component.html
index 1fa0c6d..28f82d8 100644
--- a/ui/src/app/editor/dialog/customize/customize.component.html
+++ b/ui/src/app/editor/dialog/customize/customize.component.html
@@ -19,8 +19,19 @@
<div class="sp-dialog-container">
<div class="sp-dialog-content">
<div fxFlex="100" fxLayout="column">
- <div style="border-bottom:1px solid #ccc;padding:10px;background-color:#f6f6f6">
- <div fxFlex="100" fxLayout="row" fxLayoutAlign="end end">
+ <div style="border-bottom:1px solid #ccc;padding:10px;background-color:#f6f6f6" fxLayout="row">
+ <div fxFlex fxLayoutAlign="start center" *ngIf="availableTemplates && availableTemplates.length > 0">
+ <mat-form-field class="form-field" floatLabel="never">
+ <mat-label>Use template</mat-label>
+ <mat-select (selectionChange)="loadTemplate($event)" [(value)]="selectedTemplate">
+ <mat-option>--</mat-option>
+ <mat-option [value]="template" *ngFor="let template of availableTemplates">
+ {{template.templateName}}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+ </div>
+ <div fxFlex fxLayout="row" fxLayoutAlign="end center">
<mat-slide-toggle [(ngModel)]="showDocumentation"
color="primary"
[disabled]="!pipelineElement.payload.includesAssets">
@@ -34,10 +45,11 @@
</div>
<div fxFlex="100" fxLayout="row">
<div fxFlex="{{_showDocumentation ? 50: 100}}">
- <div fxLayout="column">
+ <div fxLayout="column" *ngIf="!templateMode">
<div fxLayout="row" *ngIf="restrictedEditMode">
<div fxLayout="column">
- <div fxLayout="column" class="customize-item-main-help" style="border: 2px solid #ffc400">
+ <div fxLayout="column" class="customize-item-main-help"
+ style="border: 2px solid #ffc400">
<div class="customize-item-title-help" style="background: #ffc400;" fxFlex="100"
fxLayout="row">
You can only modify things that don't affect your pipeline structure. To fully
@@ -51,7 +63,7 @@
<form [formGroup]="parentForm" fxFlex="100">
<app-static-property *ngFor="let config of cachedPipelineElement.staticProperties"
[staticProperty]="config"
- [pipelineElement] = "cachedPipelineElement"
+ [pipelineElement]="cachedPipelineElement"
[displayRecommended]="displayRecommended"
[staticProperties]="cachedPipelineElement.staticProperties"
[eventSchemas]="eventSchemas"
@@ -62,31 +74,55 @@
(validateEmitter)="validConfiguration($event)">
</app-static-property>
<div *ngIf="isDataProcessor">
- <output-strategy *ngFor="let outputStrategy of cachedPipelineElement.outputStrategies"
- [parentForm]="parentForm"
- [outputStrategy]="outputStrategy"
- [selectedElement]="cachedPipelineElement"
- [restrictedEditMode]="restrictedEditMode">
+ <output-strategy
+ *ngFor="let outputStrategy of cachedPipelineElement.outputStrategies"
+ [parentForm]="parentForm"
+ [outputStrategy]="outputStrategy"
+ [selectedElement]="cachedPipelineElement"
+ [restrictedEditMode]="restrictedEditMode">
</output-strategy>
</div>
</form>
</div>
</div>
+ <div fxLayout="column" *ngIf="templateMode">
+ <pipeline-element-template-config [cachedPipelineElement]="cachedPipelineElement"
+ [template]="template" [templateConfigs]="templateConfigs">
+ </pipeline-element-template-config>
+ </div>
</div>
- <div fxFlex="50" *ngIf="showDocumentation" style="padding-left:10px;border-left: 2px solid rgb(204, 204, 204);">
- <pipeline-element-documentation [useStyling]="false" [appId]="pipelineElement.payload.appId"></pipeline-element-documentation>
+ <div fxFlex="50" *ngIf="showDocumentation"
+ style="padding-left:10px;border-left: 2px solid rgb(204, 204, 204);">
+ <pipeline-element-documentation [useStyling]="false"
+ [appId]="pipelineElement.payload.appId"></pipeline-element-documentation>
</div>
</div>
</div>
</div>
<mat-divider></mat-divider>
<div class="sp-dialog-actions">
- <button mat-button mat-raised-button color="primary" (click)="save()" style="margin-right:10px;"
- [disabled]="!(formValid)">
- Save
- </button>
- <button mat-button mat-raised-button class="mat-basic" (click)="close()">
- Cancel
- </button>
+ <div fxLayout="row" *ngIf="!templateMode">
+ <button mat-button mat-raised-button color="primary" (click)="save()" style="margin-right:10px;"
+ [disabled]="!(formValid)">
+ <i class="material-icons">save</i><span> Save</span>
+ </button>
+ <button mat-button mat-raised-button class="mat-basic" (click)="close()">
+ Cancel
+ </button>
+ <div fxFlex></div>
+ <button mat-button mat-raised-button color="primary" [disabled]="!(formValid)"
+ (click)="triggerTemplateMode()">
+ <i class="material-icons">add_circle_outline</i><span> Create template</span>
+ </button>
+ </div>
+ <div fxLayout="row" *ngIf="templateMode">
+ <button mat-button mat-raised-button color="primary" (click)="saveTemplate()" style="margin-right:10px;"
+ [disabled]="!(formValid)">
+ <i class="material-icons">save</i><span> Save template</span>
+ </button>
+ <button mat-button mat-raised-button class="mat-basic" (click)="cancelTemplateMode()">
+ Cancel
+ </button>
+ </div>
</div>
-</div>
\ No newline at end of file
+</div>
diff --git a/ui/src/app/editor/dialog/customize/customize.component.scss b/ui/src/app/editor/dialog/customize/customize.component.scss
index fddade7..d613b95 100644
--- a/ui/src/app/editor/dialog/customize/customize.component.scss
+++ b/ui/src/app/editor/dialog/customize/customize.component.scss
@@ -17,3 +17,14 @@
*/
@import '../../../../scss/sp/sp-dialog.scss';
+
+.form-field .mat-form-field-wrapper {
+ margin-bottom: -1.25em;
+}
+
+
+.form-field .mat-form-field-infix {
+ border-top: 0;
+}
+
+
diff --git a/ui/src/app/editor/dialog/customize/customize.component.ts b/ui/src/app/editor/dialog/customize/customize.component.ts
index 71ddda1..fc9c60c 100644
--- a/ui/src/app/editor/dialog/customize/customize.component.ts
+++ b/ui/src/app/editor/dialog/customize/customize.component.ts
@@ -16,19 +16,32 @@
*
*/
-import {AfterViewInit, ChangeDetectorRef, Component, Input, OnInit} from "@angular/core";
+import {
+ AfterViewInit,
+ ChangeDetectorRef,
+ Component,
+ Input,
+ OnInit,
+ ViewEncapsulation
+} from "@angular/core";
import {InvocablePipelineElementUnion, PipelineElementConfig} from "../../model/editor.model";
import {DialogRef} from "../../../core-ui/dialog/base-dialog/dialog-ref";
import {JsplumbService} from "../../services/jsplumb.service";
-import {DataProcessorInvocation, EventSchema} from "../../../core-model/gen/streampipes-model";
+import {
+ DataProcessorInvocation,
+ EventSchema,
+ 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";
@Component({
selector: 'customize-pipeline-element',
templateUrl: './customize.component.html',
- styleUrls: ['./customize.component.scss']
+ styleUrls: ['./customize.component.scss'],
+ encapsulation: ViewEncapsulation.None
})
export class CustomizeComponent implements OnInit, AfterViewInit {
@@ -64,11 +77,18 @@ export class CustomizeComponent implements OnInit, AfterViewInit {
originalDialogWidth: string | number;
completedStaticProperty: ConfigurationInfo;
+ availableTemplates: Array<PipelineElementTemplate>;
+ selectedTemplate: any = false;
+ templateMode: boolean = false;
+ template: PipelineElementTemplate;
+ templateConfigs: Map<string, any> = new Map();
+
constructor(private dialogRef: DialogRef<CustomizeComponent>,
private JsPlumbService: JsplumbService,
private ShepherdService: ShepherdService,
private fb: FormBuilder,
- private changeDetectorRef: ChangeDetectorRef) {
+ private changeDetectorRef: ChangeDetectorRef,
+ private pipelineElementTemplateService: PipelineElementTemplateService) {
}
@@ -81,18 +101,26 @@ export class CustomizeComponent implements OnInit, AfterViewInit {
});
this.formValid = this.pipelineElement.settings.completed;
- this.parentForm = this.fb.group({
- });
+ this.parentForm = this.fb.group({});
this.parentForm.valueChanges.subscribe(v => {
});
- this.parentForm.statusChanges.subscribe((status)=>{
+ this.parentForm.statusChanges.subscribe((status) => {
this.formValid = this.viewInitialized && this.parentForm.valid;
})
if (this.ShepherdService.isTourActive()) {
- this.ShepherdService.trigger("customize-" +this.pipelineElement.type);
+ this.ShepherdService.trigger("customize-" + this.pipelineElement.type);
}
+ this.loadPipelineElementTemplates();
+ }
+
+ loadPipelineElementTemplates() {
+ this.pipelineElementTemplateService
+ .getPipelineElementTemplates(this.cachedPipelineElement.appId)
+ .subscribe(templates => {
+ this.availableTemplates = templates;
+ });
}
close() {
@@ -104,7 +132,7 @@ export class CustomizeComponent implements OnInit, AfterViewInit {
this.pipelineElement.settings.completed = true;
this.pipelineElement.payload.configured = true;
if (this.ShepherdService.isTourActive()) {
- this.ShepherdService.trigger("save-" +this.pipelineElement.type);
+ this.ShepherdService.trigger("save-" + this.pipelineElement.type);
}
this.dialogRef.close(this.pipelineElement);
}
@@ -136,4 +164,52 @@ export class CustomizeComponent implements OnInit, AfterViewInit {
this.completedStaticProperty = {...configurationInfo};
}
-}
\ No newline at end of file
+ triggerTemplateMode() {
+ this.template = new PipelineElementTemplate();
+ this.templateMode = true;
+ }
+
+ saveTemplate() {
+ this.template.templateConfigs = this.convert(this.templateConfigs);
+ this.pipelineElementTemplateService.storePipelineElementTemplate(this.template).subscribe(result => {
+ this.loadPipelineElementTemplates();
+ this.templateMode = false;
+ });
+ }
+
+ convert(templateConfigs: Map<string, any>): any {
+ let configs: { [index: string]: PipelineElementTemplateConfig } = {};
+ templateConfigs.forEach((value, key) => {
+ configs[key] = new PipelineElementTemplateConfig();
+ configs[key].editable = value.editable;
+ configs[key].displayed = value.displayed;
+ configs[key].value = value.value;
+ });
+ return configs;
+ }
+
+ cancelTemplateMode() {
+ this.templateMode = false;
+ }
+
+ loadTemplate(event: any) {
+ if (!event.value) {
+ this.cachedPipelineElement = this.JsPlumbService.clone(this.pipelineElement.payload) as InvocablePipelineElementUnion;
+ this.selectedTemplate = false;
+ } else {
+ this.selectedTemplate = event.value;
+ if (this.cachedPipelineElement instanceof DataProcessorInvocation) {
+ this.pipelineElementTemplateService.getConfiguredDataProcessorForTemplate(event.value._id, this.cachedPipelineElement).subscribe(pe => {
+ this.cachedPipelineElement = pe as InvocablePipelineElementUnion;
+ })
+ } else {
+ this.pipelineElementTemplateService.getConfiguredDataSinkForTemplate(event.value._id, this.cachedPipelineElement).subscribe(pe => {
+ this.cachedPipelineElement = pe as InvocablePipelineElementUnion;
+ })
+ }
+
+ }
+ }
+
+
+}
diff --git a/ui/src/app/editor/editor.module.ts b/ui/src/app/editor/editor.module.ts
index db54354..511678d 100644
--- a/ui/src/app/editor/editor.module.ts
+++ b/ui/src/app/editor/editor.module.ts
@@ -59,6 +59,7 @@ import {CustomOutputStrategyComponent} from "./components/output-strategy/custom
import {PropertySelectionComponent} from "./components/output-strategy/property-selection/property-selection.component";
import {UserDefinedOutputStrategyComponent} from "./components/output-strategy/user-defined-output/user-defined-output.component";
import {ConnectModule} from "../connect/connect.module";
+import {PipelineElementTemplateConfigComponent} from "./components/pipeline-element-template-config/pipeline-element-template-config.component";
@NgModule({
imports: [
@@ -93,6 +94,7 @@ import {ConnectModule} from "../connect/connect.module";
PipelineElementIconStandComponent,
PipelineElementOptionsComponent,
PipelineElementRecommendationComponent,
+ PipelineElementTemplateConfigComponent,
PipelineComponent,
PropertySelectionComponent,
SavePipelineComponent,
@@ -127,4 +129,4 @@ export class EditorModule {
constructor() {
}
-}
\ No newline at end of file
+}
diff --git a/ui/src/app/platform-services/apis/pipeline-element-template.service.ts b/ui/src/app/platform-services/apis/pipeline-element-template.service.ts
new file mode 100644
index 0000000..25f6628
--- /dev/null
+++ b/ui/src/app/platform-services/apis/pipeline-element-template.service.ts
@@ -0,0 +1,69 @@
+/*
+ * 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 {HttpClient} from "@angular/common/http";
+import {Observable} from "rxjs";
+import {
+ DataProcessorInvocation,
+ DataSinkInvocation,
+ PipelineElementTemplate
+} from "../../core-model/gen/streampipes-model";
+import {PlatformServicesCommons} from "./commons.service";
+import {map} from "rxjs/operators";
+
+@Injectable()
+export class PipelineElementTemplateService {
+
+ constructor(private http: HttpClient,
+ private platformServicesCommons: PlatformServicesCommons) {
+
+ }
+
+ getPipelineElementTemplates(appId: string): Observable<Array<PipelineElementTemplate>> {
+ return this.http
+ .get(this.platformServicesCommons.authUserBasePath()
+ + "/pipeline-element-templates?appId=" + appId)
+ .pipe(map(data => {
+ console.log(data);
+ return (data as []).map(dpi => PipelineElementTemplate.fromData(dpi));
+ }));
+ }
+
+ getConfiguredDataProcessorForTemplate(templateId: string, invocation: DataProcessorInvocation): Observable<DataProcessorInvocation> {
+ return this.http.post(this.platformServicesCommons.authUserBasePath()
+ + "/pipeline-element-templates/" + templateId + "/processor", invocation)
+ .pipe(map(response => {
+ return DataProcessorInvocation.fromData(response as DataProcessorInvocation);
+ }));
+ }
+
+ getConfiguredDataSinkForTemplate(templateId: string, invocation: DataSinkInvocation): Observable<DataSinkInvocation> {
+ return this.http.post(this.platformServicesCommons.authUserBasePath()
+ + "/pipeline-element-templates/" + templateId + "/sink", invocation)
+ .pipe(map(response => {
+ return DataSinkInvocation.fromData(response as DataSinkInvocation);
+ }));
+ }
+
+ storePipelineElementTemplate(template: PipelineElementTemplate) {
+ return this.http.post(this.platformServicesCommons.authUserBasePath() + "/pipeline-element-templates", template);
+ }
+
+
+}
diff --git a/ui/src/app/platform-services/platform.module.ts b/ui/src/app/platform-services/platform.module.ts
index 85962e5..2e3cec5 100644
--- a/ui/src/app/platform-services/platform.module.ts
+++ b/ui/src/app/platform-services/platform.module.ts
@@ -23,6 +23,7 @@ import {PlatformServicesCommons} from "./apis/commons.service";
import {PipelineElementEndpointService} from "./apis/pipeline-element-endpoint.service";
import {FilesService} from "./apis/files.service";
import {MeasurementUnitsService} from "./apis/measurement-units.service";
+import {PipelineElementTemplateService} from "./apis/pipeline-element-template.service";
@NgModule({
imports: [],
@@ -32,6 +33,7 @@ import {MeasurementUnitsService} from "./apis/measurement-units.service";
MeasurementUnitsService,
PlatformServicesCommons,
PipelineElementEndpointService,
+ PipelineElementTemplateService,
//PipelineTemplateService,
PipelineElementService,
PipelineService
diff --git a/ui/src/scss/sp/sp-dialog.scss b/ui/src/scss/sp/sp-dialog.scss
index d0bdea3..e79a646 100644
--- a/ui/src/scss/sp/sp-dialog.scss
+++ b/ui/src/scss/sp/sp-dialog.scss
@@ -39,4 +39,4 @@
.p-15 {
padding: 15px;
-}
\ No newline at end of file
+}