This is an automated email from the ASF dual-hosted git repository. riemer pushed a commit to branch 3292-show-adapter-and-pipeline-configuration-in-ui in repository https://gitbox.apache.org/repos/asf/streampipes.git
commit de921e539a69fe88c657b0d60beb9a9f7224c67f Author: Dominik Riemer <[email protected]> AuthorDate: Wed Oct 9 09:27:38 2024 +0200 Show pipeline code in UI --- .../connect/adapter/compact/CreateOptions.java | 7 +- .../pipeline/compact/CompactPipelineElement.java | 3 + .../compact/CompactPipelineManagement.java | 14 ++++ .../generation/CompactPipelineConverter.java | 85 ++++++++++++++++++++++ .../PipelineElementConfigurationStep.java | 12 +-- .../streampipes/rest/impl/PipelineResource.java | 22 ++++++ .../src/lib/apis/pipeline.service.ts | 8 ++ .../adapter-code-panel.component.html | 21 ++---- ui/src/app/connect/connect.module.ts | 4 - .../configuration-code-panel.component.html} | 34 ++++----- .../configuration-code-panel.component.scss | 17 +++-- .../configuration-code-panel.component.ts} | 20 ++--- ui/src/app/core-ui/core-ui.module.ts | 9 +++ .../pipes}/json-pretty-print.pipe.ts | 0 .../pipes}/yaml-pretty-print.pipe.ts | 0 .../save-pipeline-settings.component.html | 22 ++++-- .../save-pipeline-settings.component.scss | 4 + .../save-pipeline-settings.component.ts | 16 +++- .../pipeline-details-toolbar.component.html | 12 +++ .../pipeline-details-toolbar.component.ts | 3 + .../pipeline-code-dialog.component.html} | 38 +++++----- .../pipeline-code-dialog.component.ts} | 37 ++++++---- .../pipeline-details.component.html | 1 + .../pipeline-details/pipeline-details.component.ts | 15 ++++ .../pipeline-details/pipeline-details.module.ts | 2 + 25 files changed, 308 insertions(+), 98 deletions(-) diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CreateOptions.java b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CreateOptions.java index 6fc266ff21..ee8ea06f61 100644 --- a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CreateOptions.java +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CreateOptions.java @@ -18,6 +18,9 @@ package org.apache.streampipes.model.connect.adapter.compact; -public record CreateOptions(boolean persist, - boolean start) { +import com.fasterxml.jackson.annotation.JsonInclude; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public record CreateOptions(Boolean persist, + Boolean start) { } diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/pipeline/compact/CompactPipelineElement.java b/streampipes-model/src/main/java/org/apache/streampipes/model/pipeline/compact/CompactPipelineElement.java index 0f976c8145..b145c2aad3 100644 --- a/streampipes-model/src/main/java/org/apache/streampipes/model/pipeline/compact/CompactPipelineElement.java +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/pipeline/compact/CompactPipelineElement.java @@ -18,9 +18,12 @@ package org.apache.streampipes.model.pipeline.compact; +import com.fasterxml.jackson.annotation.JsonInclude; + import java.util.List; import java.util.Map; +@JsonInclude(JsonInclude.Include.NON_NULL) public record CompactPipelineElement(String type, String ref, String id, diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/pipeline/compact/CompactPipelineManagement.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/pipeline/compact/CompactPipelineManagement.java index 1a0a1cd44e..e0137e13b4 100644 --- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/pipeline/compact/CompactPipelineManagement.java +++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/pipeline/compact/CompactPipelineManagement.java @@ -19,12 +19,16 @@ package org.apache.streampipes.manager.pipeline.compact; import org.apache.streampipes.manager.matching.PipelineVerificationHandlerV2; +import org.apache.streampipes.manager.pipeline.compact.generation.CompactPipelineConverter; import org.apache.streampipes.manager.pipeline.compact.generation.PipelineElementConfigurationStep; +import org.apache.streampipes.model.connect.adapter.compact.CreateOptions; import org.apache.streampipes.model.pipeline.Pipeline; import org.apache.streampipes.model.pipeline.PipelineModificationResult; import org.apache.streampipes.model.pipeline.compact.CompactPipeline; import org.apache.streampipes.storage.api.IPipelineElementDescriptionStorage; +import java.util.UUID; + public class CompactPipelineManagement { private final IPipelineElementDescriptionStorage storage; @@ -42,6 +46,16 @@ public class CompactPipelineManagement { return new PipelineVerificationHandlerV2(pipeline).makeModifiedPipeline(); } + public CompactPipeline convertPipeline(Pipeline pipeline) { + return new CompactPipeline( + pipeline.getElementId() != null ? pipeline.getElementId() : UUID.randomUUID().toString(), + pipeline.getName(), + pipeline.getDescription(), + new CompactPipelineConverter().convert(pipeline), + new CreateOptions(null, false) + ); + } + private void applyPipelineBasics(CompactPipeline compactPipeline, Pipeline pipeline) { pipeline.setElementId(compactPipeline.id()); diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/pipeline/compact/generation/CompactPipelineConverter.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/pipeline/compact/generation/CompactPipelineConverter.java new file mode 100644 index 0000000000..bebc3b9286 --- /dev/null +++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/pipeline/compact/generation/CompactPipelineConverter.java @@ -0,0 +1,85 @@ +/* + * 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. + * + */ + +package org.apache.streampipes.manager.pipeline.compact.generation; + +import org.apache.streampipes.manager.template.CompactConfigGenerator; +import org.apache.streampipes.model.pipeline.Pipeline; +import org.apache.streampipes.model.pipeline.compact.CompactPipelineElement; +import org.apache.streampipes.model.staticproperty.StaticProperty; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class CompactPipelineConverter { + + public List<CompactPipelineElement> convert(Pipeline pipeline) { + var pipelineElements = new ArrayList<CompactPipelineElement>(); + + pipeline.getStreams().stream() + .map(stream -> createElement( + PipelineElementConfigurationStep.STREAM_TYPE, + stream.getDom(), + stream.getElementId(), + null, + null)) + .forEach(pipelineElements::add); + + pipeline.getSepas().stream() + .map(processor -> createElement( + PipelineElementConfigurationStep.PROCESSOR_TYPE, + processor.getDom(), + processor.getAppId(), + processor.getConnectedTo(), + getConfig(processor.getStaticProperties()))) + .forEach(pipelineElements::add); + + pipeline.getActions().stream() + .map(sink -> createElement( + PipelineElementConfigurationStep.SINK_TYPE, + sink.getDom(), + sink.getAppId(), + sink.getConnectedTo(), + getConfig(sink.getStaticProperties()))) + .forEach(pipelineElements::add); + + return pipelineElements; + } + + private CompactPipelineElement createElement(String type, + String ref, + String elementId, + List<String> connectedTo, + List<Map<String, Object>> config) { + var connections = connectedTo != null ? connectedTo.stream() + .map(this::replaceId) + .toList() : null; + return new CompactPipelineElement(type, replaceId(ref), elementId, connections, config); + } + + public List<Map<String, Object>> getConfig(List<StaticProperty> staticProperties) { + var configs = new ArrayList<Map<String, Object>>(); + staticProperties.forEach(c -> configs.add(new CompactConfigGenerator(c).toTemplateValue())); + return configs; + } + + private String replaceId(String id) { + return id.replaceAll(InvocablePipelineElementGenerator.ID_PREFIX, ""); + } +} diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/pipeline/compact/generation/PipelineElementConfigurationStep.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/pipeline/compact/generation/PipelineElementConfigurationStep.java index ec5539414c..ec61f414be 100644 --- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/pipeline/compact/generation/PipelineElementConfigurationStep.java +++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/pipeline/compact/generation/PipelineElementConfigurationStep.java @@ -28,9 +28,9 @@ import org.apache.streampipes.storage.api.IPipelineElementDescriptionStorage; public class PipelineElementConfigurationStep implements CompactPipelineGenerator { - private static final String StreamType = "stream"; - private static final String ProcessorType = "processor"; - private static final String SinkType = "sink"; + public static final String STREAM_TYPE = "stream"; + public static final String PROCESSOR_TYPE = "processor"; + public static final String SINK_TYPE = "sink"; private final IPipelineElementDescriptionStorage storage; @@ -42,11 +42,11 @@ public class PipelineElementConfigurationStep implements CompactPipelineGenerato public void apply(Pipeline pipeline, CompactPipeline compactPipeline) throws Exception { compactPipeline.pipelineElements().forEach(pe -> { - if (pe.type().equalsIgnoreCase(StreamType)) { + if (pe.type().equalsIgnoreCase(STREAM_TYPE)) { pipeline.getStreams().add(makeStream(pe)); - } else if (pe.type().equalsIgnoreCase(ProcessorType)) { + } else if (pe.type().equalsIgnoreCase(PROCESSOR_TYPE)) { pipeline.getSepas().add(makeProcessor(pe)); - } else if (pe.type().equalsIgnoreCase(SinkType)) { + } else if (pe.type().equalsIgnoreCase(SINK_TYPE)) { pipeline.getActions().add(makeSink(pe)); } }); diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineResource.java index aa362aba16..a04ac7b2ca 100644 --- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineResource.java +++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineResource.java @@ -22,6 +22,7 @@ import org.apache.streampipes.commons.exceptions.NoSuitableSepasAvailableExcepti import org.apache.streampipes.manager.execution.status.PipelineStatusManager; import org.apache.streampipes.manager.matching.PipelineVerificationHandlerV2; import org.apache.streampipes.manager.pipeline.PipelineManager; +import org.apache.streampipes.manager.pipeline.compact.CompactPipelineManagement; import org.apache.streampipes.manager.recommender.ElementRecommender; import org.apache.streampipes.manager.storage.PipelineStorageService; import org.apache.streampipes.model.message.ErrorMessage; @@ -34,10 +35,12 @@ import org.apache.streampipes.model.message.SuccessMessage; import org.apache.streampipes.model.pipeline.Pipeline; import org.apache.streampipes.model.pipeline.PipelineElementRecommendationMessage; import org.apache.streampipes.model.pipeline.PipelineOperationStatus; +import org.apache.streampipes.model.pipeline.compact.CompactPipeline; import org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource; import org.apache.streampipes.rest.security.AuthConstants; import org.apache.streampipes.rest.shared.exception.SpMessageException; import org.apache.streampipes.rest.shared.exception.SpNotificationException; +import org.apache.streampipes.storage.management.StorageDispatcher; import com.google.gson.JsonSyntaxException; import io.swagger.v3.oas.annotations.Hidden; @@ -48,6 +51,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -77,6 +81,14 @@ public class PipelineResource extends AbstractAuthGuardedRestResource { private static final Logger LOG = LoggerFactory.getLogger(PipelineResource.class); + private final CompactPipelineManagement compactPipelineManagement; + + public PipelineResource() { + this.compactPipelineManagement = new CompactPipelineManagement( + StorageDispatcher.INSTANCE.getNoSqlStore().getPipelineElementDescriptionStorage() + ); + } + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Get all pipelines of the current user", tags = {"Pipeline"}, responses = { @ApiResponse(content = { @@ -164,6 +176,16 @@ public class PipelineResource extends AbstractAuthGuardedRestResource { return ok(message); } + @PostMapping( + path = "compact", + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "Convert a pipeline to the compact model", tags = {"Pipeline"}) + @PreAuthorize(AuthConstants.HAS_WRITE_PIPELINE_PRIVILEGE) + public ResponseEntity<CompactPipeline> convertToCompactPipeline(@RequestBody Pipeline pipeline) { + return ok(compactPipelineManagement.convertPipeline(pipeline)); + } + @PostMapping( path = "/recommend/{recId}", consumes = MediaType.APPLICATION_JSON_VALUE, diff --git a/ui/projects/streampipes/platform-services/src/lib/apis/pipeline.service.ts b/ui/projects/streampipes/platform-services/src/lib/apis/pipeline.service.ts index d4e084424c..de5c37517e 100644 --- a/ui/projects/streampipes/platform-services/src/lib/apis/pipeline.service.ts +++ b/ui/projects/streampipes/platform-services/src/lib/apis/pipeline.service.ts @@ -21,6 +21,7 @@ import { HttpClient } from '@angular/common/http'; import { PlatformServicesCommons } from './commons.service'; import { Observable } from 'rxjs'; import { + CompactPipeline, Message, Pipeline, PipelineElementRecommendationMessage, @@ -75,6 +76,13 @@ export class PipelineService { .pipe(map(response => Pipeline.fromData(response as Pipeline))); } + convertToCompactPipeline(pipeline: Pipeline): Observable<CompactPipeline> { + return this.http.post<CompactPipeline>( + `${this.apiBasePath}/pipelines/compact`, + pipeline, + ); + } + storePipeline(pipeline: Pipeline): Observable<Message> { return this.http.post(`${this.apiBasePath}/pipelines`, pipeline).pipe( map(response => { diff --git a/ui/src/app/connect/components/adapter-code-panel/adapter-code-panel.component.html b/ui/src/app/connect/components/adapter-code-panel/adapter-code-panel.component.html index 52b5d4e5f4..8a05afabd3 100644 --- a/ui/src/app/connect/components/adapter-code-panel/adapter-code-panel.component.html +++ b/ui/src/app/connect/components/adapter-code-panel/adapter-code-panel.component.html @@ -17,20 +17,9 @@ --> <div fxFlex="100" *ngIf="compactAdapter" class="mt-10"> - <mat-tab-group color="accent" [mat-stretch-tabs]="false"> - <mat-tab label="YAML"> - <pre - [innerHTML]="compactAdapter | yamlpretty" - class="preview-text" - [ngStyle]="{ maxHeight: maxHeight }" - ></pre> - </mat-tab> - <mat-tab label="JSON"> - <pre - [innerHTML]="compactAdapter | jsonpretty" - class="preview-text" - [ngStyle]="{ maxHeight: maxHeight }" - ></pre> - </mat-tab> - </mat-tab-group> + <sp-configuration-code-panel + [configuration]="compactAdapter" + [maxHeight]="maxHeight" + > + </sp-configuration-code-panel> </div> diff --git a/ui/src/app/connect/connect.module.ts b/ui/src/app/connect/connect.module.ts index 5d2e8b4756..a244a4b217 100644 --- a/ui/src/app/connect/connect.module.ts +++ b/ui/src/app/connect/connect.module.ts @@ -62,7 +62,6 @@ import { EditValueTransformationComponent } from './dialog/edit-event-property/c import { SpEpSettingsSectionComponent } from './dialog/edit-event-property/components/ep-settings-section/ep-settings-section.component'; import { SpAdapterOptionsPanelComponent } from './components/adapter-configuration/start-adapter-configuration/adapter-options-panel/adapter-options-panel.component'; import { SpAdapterTemplateDialogComponent } from './dialog/adapter-template/adapter-template-dialog.component'; -import { JsonPrettyPrintPipe } from './filter/json-pretty-print.pipe'; import { MatSnackBarModule } from '@angular/material/snack-bar'; import { AdapterConfigurationHeaderComponent } from './components/adapter-configuration/adapter-configuration-header/adapter-configuration-header.component'; import { NewAdapterComponent } from './components/new-adapter/new-adapter.component'; @@ -105,7 +104,6 @@ import { SpAdapterDeploymentSettingsComponent } from './components/adapter-confi import { SpAdapterDocumentationDialogComponent } from './dialog/adapter-documentation/adapter-documentation-dialog.component'; import { AdapterDetailsDataComponent } from './components/adapter-details/adapter-details-data/adapter-details-data.component'; import { AdapterCodePanelComponent } from './components/adapter-code-panel/adapter-code-panel.component'; -import { YamlPrettyPrintPipe } from './filter/yaml-pretty-print.pipe'; import { AdapterDetailsCodeComponent } from './components/adapter-details/adapter-details-code/adapter-details-code.component'; @NgModule({ @@ -222,8 +220,6 @@ import { AdapterDetailsCodeComponent } from './components/adapter-details/adapte EventSchemaPreviewComponent, ExistingAdaptersComponent, AdapterFilterPipe, - JsonPrettyPrintPipe, - YamlPrettyPrintPipe, AdapterConfigurationComponent, TimestampPipe, EditCorrectionValueComponent, diff --git a/ui/src/app/connect/components/adapter-code-panel/adapter-code-panel.component.html b/ui/src/app/core-ui/configuration-code-panel/configuration-code-panel.component.html similarity index 57% copy from ui/src/app/connect/components/adapter-code-panel/adapter-code-panel.component.html copy to ui/src/app/core-ui/configuration-code-panel/configuration-code-panel.component.html index 52b5d4e5f4..083d9291c7 100644 --- a/ui/src/app/connect/components/adapter-code-panel/adapter-code-panel.component.html +++ b/ui/src/app/core-ui/configuration-code-panel/configuration-code-panel.component.html @@ -16,21 +16,19 @@ ~ --> -<div fxFlex="100" *ngIf="compactAdapter" class="mt-10"> - <mat-tab-group color="accent" [mat-stretch-tabs]="false"> - <mat-tab label="YAML"> - <pre - [innerHTML]="compactAdapter | yamlpretty" - class="preview-text" - [ngStyle]="{ maxHeight: maxHeight }" - ></pre> - </mat-tab> - <mat-tab label="JSON"> - <pre - [innerHTML]="compactAdapter | jsonpretty" - class="preview-text" - [ngStyle]="{ maxHeight: maxHeight }" - ></pre> - </mat-tab> - </mat-tab-group> -</div> +<mat-tab-group color="accent" [mat-stretch-tabs]="false"> + <mat-tab label="YAML"> + <pre + [innerHTML]="configuration | yamlpretty" + class="preview-text" + [ngStyle]="{ maxHeight: maxHeight }" + ></pre> + </mat-tab> + <mat-tab label="JSON"> + <pre + [innerHTML]="configuration | jsonpretty" + class="preview-text" + [ngStyle]="{ maxHeight: maxHeight }" + ></pre> + </mat-tab> +</mat-tab-group> diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CreateOptions.java b/ui/src/app/core-ui/configuration-code-panel/configuration-code-panel.component.scss similarity index 76% copy from streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CreateOptions.java copy to ui/src/app/core-ui/configuration-code-panel/configuration-code-panel.component.scss index 6fc266ff21..c02ba8acc6 100644 --- a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CreateOptions.java +++ b/ui/src/app/core-ui/configuration-code-panel/configuration-code-panel.component.scss @@ -1,4 +1,4 @@ -/* +/*! * 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. @@ -16,8 +16,15 @@ * */ -package org.apache.streampipes.model.connect.adapter.compact; - -public record CreateOptions(boolean persist, - boolean start) { +.preview-text { + background-color: black; + font: + 9pt Inconsolata, + monospace; + text-shadow: 0 0 5px #c8c8c8; + color: white; + padding: 10px; + max-width: 100%; + overflow-y: scroll; + white-space: pre-wrap; } diff --git a/ui/src/app/connect/filter/yaml-pretty-print.pipe.ts b/ui/src/app/core-ui/configuration-code-panel/configuration-code-panel.component.ts similarity index 69% copy from ui/src/app/connect/filter/yaml-pretty-print.pipe.ts copy to ui/src/app/core-ui/configuration-code-panel/configuration-code-panel.component.ts index 88f8b4b459..bf8deb6418 100644 --- a/ui/src/app/connect/filter/yaml-pretty-print.pipe.ts +++ b/ui/src/app/core-ui/configuration-code-panel/configuration-code-panel.component.ts @@ -16,15 +16,17 @@ * */ -import { Injectable, Pipe, PipeTransform } from '@angular/core'; -import { parse, stringify } from 'yaml'; +import { Component, Input, OnInit } from '@angular/core'; -@Pipe({ - name: 'yamlpretty', +@Component({ + selector: 'sp-configuration-code-panel', + templateUrl: './configuration-code-panel.component.html', + styleUrls: ['./configuration-code-panel.component.scss'], }) -@Injectable({ providedIn: 'root' }) -export class YamlPrettyPrintPipe implements PipeTransform { - transform(obj: any) { - return stringify(obj).replace(/ /g, ' ').replace(/\n/g, '<br/>'); - } +export class ConfigurationCodePanelComponent { + @Input() + configuration: any; + + @Input() + maxHeight = '300px'; } diff --git a/ui/src/app/core-ui/core-ui.module.ts b/ui/src/app/core-ui/core-ui.module.ts index dc2337b5d1..5a8815dce0 100644 --- a/ui/src/app/core-ui/core-ui.module.ts +++ b/ui/src/app/core-ui/core-ui.module.ts @@ -116,6 +116,9 @@ import { SingleMarkerMapComponent } from './single-marker-map/single-marker-map. import { LeafletModule } from '@asymmetrik/ngx-leaflet'; import { StaticTreeInputTextEditorComponent } from './static-properties/static-runtime-resolvable-tree-input/static-tree-input-text-editor/static-tree-input-text-editor.component'; import { PipelineElementTemplateConfigItemComponent } from './pipeline-element-template-config/pipeline-element-template-config-item/pipeline-element-template-config-item.component'; +import { ConfigurationCodePanelComponent } from './configuration-code-panel/configuration-code-panel.component'; +import { JsonPrettyPrintPipe } from './pipes/json-pretty-print.pipe'; +import { YamlPrettyPrintPipe } from './pipes/yaml-pretty-print.pipe'; @NgModule({ imports: [ @@ -168,6 +171,7 @@ import { PipelineElementTemplateConfigItemComponent } from './pipeline-element-t LeafletModule, ], declarations: [ + ConfigurationCodePanelComponent, DataDownloadDialogComponent, DateInputComponent, DisplayRecommendedPipe, @@ -220,9 +224,12 @@ import { PipelineElementTemplateConfigItemComponent } from './pipeline-element-t StatusIndicatorComponent, MultiStepStatusIndicatorComponent, PipelineOperationStatusComponent, + JsonPrettyPrintPipe, + YamlPrettyPrintPipe, ], providers: [MatDatepickerModule, DisplayRecommendedPipe], exports: [ + ConfigurationCodePanelComponent, DataDownloadDialogComponent, DateInputComponent, PipelineElementTemplateConfigComponent, @@ -255,6 +262,8 @@ import { PipelineElementTemplateConfigItemComponent } from './pipeline-element-t MultiStepStatusIndicatorComponent, PipelineOperationStatusComponent, SingleMarkerMapComponent, + JsonPrettyPrintPipe, + YamlPrettyPrintPipe, ], }) export class CoreUiModule {} diff --git a/ui/src/app/connect/filter/json-pretty-print.pipe.ts b/ui/src/app/core-ui/pipes/json-pretty-print.pipe.ts similarity index 100% rename from ui/src/app/connect/filter/json-pretty-print.pipe.ts rename to ui/src/app/core-ui/pipes/json-pretty-print.pipe.ts diff --git a/ui/src/app/connect/filter/yaml-pretty-print.pipe.ts b/ui/src/app/core-ui/pipes/yaml-pretty-print.pipe.ts similarity index 100% rename from ui/src/app/connect/filter/yaml-pretty-print.pipe.ts rename to ui/src/app/core-ui/pipes/yaml-pretty-print.pipe.ts diff --git a/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.html b/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.html index 6ff8ea6a14..18f221cbfc 100644 --- a/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.html +++ b/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.html @@ -63,17 +63,15 @@ (blur)="triggerTutorial()" /> <mat-error - >Pipeline name must have between 3 and 40 - characters.</mat-error - > + >Pipeline name must have between 3 and 40 characters. + </mat-error> </mat-form-field> <mat-form-field fxFlex color="accent"> <mat-label>Description</mat-label> <input [formControlName]="'pipelineDescription'" matInput /> <mat-error - >Pipeline description must not have more than 80 - characters.</mat-error - > + >Pipeline description must not have more than 80 characters. + </mat-error> </mat-form-field> </div> </form> @@ -91,4 +89,16 @@ > Navigate to pipeline overview afterwards </mat-checkbox> + <div class="mt-10"> + <mat-expansion-panel class="mat-elevation-z0 border-1"> + <mat-expansion-panel-header + >Show pipeline configuration as code</mat-expansion-panel-header + > + <sp-configuration-code-panel + [configuration]="compactPipeline" + maxHeight="none" + > + </sp-configuration-code-panel> + </mat-expansion-panel> + </div> </div> diff --git a/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.scss b/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.scss index 13cbc4aacb..e22ed79985 100644 --- a/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.scss +++ b/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.scss @@ -15,3 +15,7 @@ * limitations under the License. * */ + +.border-1 { + border: 1px solid var(--color-bg-2); +} diff --git a/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.ts b/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.ts index d75b2c1aed..fb0daa47bb 100644 --- a/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.ts +++ b/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.ts @@ -23,7 +23,11 @@ import { UntypedFormGroup, Validators, } from '@angular/forms'; -import { Pipeline } from '@streampipes/platform-services'; +import { + CompactPipeline, + Pipeline, + PipelineService, +} from '@streampipes/platform-services'; import { PipelineStorageOptions } from '../../../model/editor.model'; @Component({ @@ -44,7 +48,12 @@ export class SavePipelineSettingsComponent implements OnInit { @Input() currentPipelineName: string; - constructor(private shepherdService: ShepherdService) {} + compactPipeline: CompactPipeline; + + constructor( + private shepherdService: ShepherdService, + private pipelineService: PipelineService, + ) {} ngOnInit() { this.submitPipelineForm.addControl( @@ -73,6 +82,9 @@ export class SavePipelineSettingsComponent implements OnInit { ].valueChanges.subscribe(value => { this.pipeline.description = value; }); + this.pipelineService + .convertToCompactPipeline(this.pipeline) + .subscribe(p => (this.compactPipeline = p)); } triggerTutorial() { diff --git a/ui/src/app/pipeline-details/components/pipeline-details-toolbar/pipeline-details-toolbar.component.html b/ui/src/app/pipeline-details/components/pipeline-details-toolbar/pipeline-details-toolbar.component.html index 4a6192901c..01e230ab4a 100644 --- a/ui/src/app/pipeline-details/components/pipeline-details-toolbar/pipeline-details-toolbar.component.html +++ b/ui/src/app/pipeline-details/components/pipeline-details-toolbar/pipeline-details-toolbar.component.html @@ -30,6 +30,18 @@ <span *ngIf="previewModeActive"> Disable live preview</span> </div> </button> + <button + mat-button + color="accent" + matTooltip="Pipeline as code" + [matTooltipPosition]="'above'" + (click)="openCodeDialogEmitter.emit()" + > + <div fxLayoutAlign="start center" fxLayout="row"> + <i class="material-icons">code</i> + <span> View pipeline as code</span> + </div> + </button> <div fxFlex></div> <div fxLayoutAlign="end center"> <button diff --git a/ui/src/app/pipeline-details/components/pipeline-details-toolbar/pipeline-details-toolbar.component.ts b/ui/src/app/pipeline-details/components/pipeline-details-toolbar/pipeline-details-toolbar.component.ts index 9b8417ecc7..32d8aef9c5 100644 --- a/ui/src/app/pipeline-details/components/pipeline-details-toolbar/pipeline-details-toolbar.component.ts +++ b/ui/src/app/pipeline-details/components/pipeline-details-toolbar/pipeline-details-toolbar.component.ts @@ -37,4 +37,7 @@ export class PipelineDetailsToolbarComponent { @Output() togglePreviewEmitter: EventEmitter<void> = new EventEmitter(); + + @Output() + openCodeDialogEmitter: EventEmitter<void> = new EventEmitter(); } diff --git a/ui/src/app/connect/components/adapter-code-panel/adapter-code-panel.component.html b/ui/src/app/pipeline-details/dialogs/pipeline-code/pipeline-code-dialog.component.html similarity index 57% copy from ui/src/app/connect/components/adapter-code-panel/adapter-code-panel.component.html copy to ui/src/app/pipeline-details/dialogs/pipeline-code/pipeline-code-dialog.component.html index 52b5d4e5f4..2b89fa567e 100644 --- a/ui/src/app/connect/components/adapter-code-panel/adapter-code-panel.component.html +++ b/ui/src/app/pipeline-details/dialogs/pipeline-code/pipeline-code-dialog.component.html @@ -16,21 +16,25 @@ ~ --> -<div fxFlex="100" *ngIf="compactAdapter" class="mt-10"> - <mat-tab-group color="accent" [mat-stretch-tabs]="false"> - <mat-tab label="YAML"> - <pre - [innerHTML]="compactAdapter | yamlpretty" - class="preview-text" - [ngStyle]="{ maxHeight: maxHeight }" - ></pre> - </mat-tab> - <mat-tab label="JSON"> - <pre - [innerHTML]="compactAdapter | jsonpretty" - class="preview-text" - [ngStyle]="{ maxHeight: maxHeight }" - ></pre> - </mat-tab> - </mat-tab-group> +<div class="sp-dialog-container"> + <div class="sp-dialog-content"> + <div fxFlex="100" fxLayout="column" class="p-10"> + <sp-configuration-code-panel + [configuration]="compactPipeline" + maxHeight="none" + > + </sp-configuration-code-panel> + </div> + </div> + <mat-divider></mat-divider> + <div class="sp-dialog-actions"> + <button + mat-button + mat-raised-button + class="mat-basic" + (click)="close()" + > + Close + </button> + </div> </div> diff --git a/ui/src/app/pipeline-details/components/pipeline-details-toolbar/pipeline-details-toolbar.component.ts b/ui/src/app/pipeline-details/dialogs/pipeline-code/pipeline-code-dialog.component.ts similarity index 51% copy from ui/src/app/pipeline-details/components/pipeline-details-toolbar/pipeline-details-toolbar.component.ts copy to ui/src/app/pipeline-details/dialogs/pipeline-code/pipeline-code-dialog.component.ts index 9b8417ecc7..f7c96f031e 100644 --- a/ui/src/app/pipeline-details/components/pipeline-details-toolbar/pipeline-details-toolbar.component.ts +++ b/ui/src/app/pipeline-details/dialogs/pipeline-code/pipeline-code-dialog.component.ts @@ -16,25 +16,36 @@ * */ -import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; +import { + CompactPipeline, + Pipeline, + PipelineService, +} from '@streampipes/platform-services'; +import { DialogRef } from '@streampipes/shared-ui'; @Component({ - selector: 'sp-pipeline-details-toolbar', - templateUrl: './pipeline-details-toolbar.component.html', + selector: 'sp-pipeline-code-dialog', + templateUrl: './pipeline-code-dialog.component.html', }) -export class PipelineDetailsToolbarComponent { +export class PipelineCodeDialogComponent implements OnInit { @Input() - autoRefresh: boolean; + pipeline: Pipeline; - @Input() - previewModeActive: boolean; + compactPipeline: CompactPipeline; - @Output() - autoRefreshChange = new EventEmitter<boolean>(); + constructor( + private pipelineService: PipelineService, + private dialogRef: DialogRef<PipelineCodeDialogComponent>, + ) {} - @Output() - reloadMetricsEmitter: EventEmitter<void> = new EventEmitter(); + ngOnInit() { + this.pipelineService + .convertToCompactPipeline(this.pipeline) + .subscribe(p => (this.compactPipeline = p)); + } - @Output() - togglePreviewEmitter: EventEmitter<void> = new EventEmitter(); + close() { + this.dialogRef.close(); + } } diff --git a/ui/src/app/pipeline-details/pipeline-details.component.html b/ui/src/app/pipeline-details/pipeline-details.component.html index 500885bccd..e012942490 100644 --- a/ui/src/app/pipeline-details/pipeline-details.component.html +++ b/ui/src/app/pipeline-details/pipeline-details.component.html @@ -29,6 +29,7 @@ (togglePreviewEmitter)="toggleLivePreview()" (autoRefreshChange)="autoRefresh = $event" (reloadMetricsEmitter)="triggerReload()" + (openCodeDialogEmitter)="openPipelineAsCodeDialog()" > </sp-pipeline-details-toolbar> </div> diff --git a/ui/src/app/pipeline-details/pipeline-details.component.ts b/ui/src/app/pipeline-details/pipeline-details.component.ts index 97c070b1b9..19ec1c45ac 100644 --- a/ui/src/app/pipeline-details/pipeline-details.component.ts +++ b/ui/src/app/pipeline-details/pipeline-details.component.ts @@ -31,6 +31,8 @@ import { import { PipelineElementUnion } from '../editor/model/editor.model'; import { CurrentUserService, + DialogService, + PanelType, SpBreadcrumbService, } from '@streampipes/shared-ui'; import { SpPipelineRoutes } from '../pipelines/pipelines.routes'; @@ -40,6 +42,7 @@ import { catchError, filter, switchMap } from 'rxjs/operators'; import { PipelinePreviewComponent } from './components/preview/pipeline-preview.component'; import { HttpContext } from '@angular/common/http'; import { NGX_LOADING_BAR_IGNORED } from '@ngx-loading-bar/http-client'; +import { PipelineCodeDialogComponent } from './dialogs/pipeline-code/pipeline-code-dialog.component'; @Component({ selector: 'sp-pipeline-details-overview-component', @@ -75,6 +78,7 @@ export class SpPipelineDetailsComponent implements OnInit, OnDestroy { private currentUserService: CurrentUserService, private breadcrumbService: SpBreadcrumbService, private pipelineMonitoringService: PipelineMonitoringService, + private dialogService: DialogService, ) {} ngOnInit(): void { @@ -176,6 +180,17 @@ export class SpPipelineDetailsComponent implements OnInit, OnDestroy { this.pipelinePreviewComponent?.toggleLivePreview(); } + openPipelineAsCodeDialog(): void { + this.dialogService.open(PipelineCodeDialogComponent, { + panelType: PanelType.SLIDE_IN_PANEL, + width: '50vw', + title: 'Pipeline code', + data: { + pipeline: this.pipeline, + }, + }); + } + ngOnDestroy() { this.currentUserSub?.unsubscribe(); this.autoRefreshSub?.unsubscribe(); diff --git a/ui/src/app/pipeline-details/pipeline-details.module.ts b/ui/src/app/pipeline-details/pipeline-details.module.ts index 8b15a1fca6..f05009a578 100644 --- a/ui/src/app/pipeline-details/pipeline-details.module.ts +++ b/ui/src/app/pipeline-details/pipeline-details.module.ts @@ -41,6 +41,7 @@ import { MatTooltipModule } from '@angular/material/tooltip'; import { PipelineDetailsToolbarComponent } from './components/pipeline-details-toolbar/pipeline-details-toolbar.component'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; import { MatDivider } from '@angular/material/divider'; +import { PipelineCodeDialogComponent } from './dialogs/pipeline-code/pipeline-code-dialog.component'; @NgModule({ imports: [ @@ -64,6 +65,7 @@ import { MatDivider } from '@angular/material/divider'; ], declarations: [ PipelineActionsComponent, + PipelineCodeDialogComponent, PipelineElementsRowComponent, PipelineLogsDialogComponent, PipelineStatusComponent,
