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 8a5d4ec587f77234e5357b56bc351c03d26bc4f8 Author: Dominik Riemer <[email protected]> AuthorDate: Tue Oct 8 22:33:08 2024 +0200 feat(#3292): Add code tab to adapter view --- .../generator/AdapterEnrichmentRuleGenerator.java | 4 +- .../compact/generator/CompactAdapterGenerator.java | 123 ++++++++++++ .../management/CompactAdapterManagement.java | 17 ++ .../connect/adapter/compact/CompactAdapter.java | 3 + .../adapter/compact/CompactEventProperty.java | 3 + .../manager/template/CompactConfigGenerator.java | 211 +++++++++++++++++++++ .../template/PipelineElementTemplateVisitor.java | 33 +--- .../rest/impl/connect/AdapterResource.java | 58 ++++-- .../rest/impl/connect/CompactAdapterResource.java | 5 +- .../src/lib/apis/adapter.service.ts | 10 + .../src/lib/model/gen/streampipes-model.ts | 176 +++++++++-------- .../adapter-code-panel.component.html | 36 ++++ .../adapter-code-panel.component.scss | 21 +- .../adapter-code-panel.component.ts} | 48 +++-- .../adapter-options-panel.component.html | 22 +-- .../start-adapter-configuration.component.html | 15 ++ .../start-adapter-configuration.component.ts | 1 + .../abstract-adapter-details.directive.ts | 2 + .../adapter-details-code.component.html | 38 ++++ .../adapter-details-code.component.ts | 17 ++ .../adapter-details/adapter-details-tabs.ts | 5 + ui/src/app/connect/connect.module.ts | 10 + .../app/connect/filter/yaml-pretty-print.pipe.ts | 17 +- 23 files changed, 701 insertions(+), 174 deletions(-) diff --git a/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/compact/generator/AdapterEnrichmentRuleGenerator.java b/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/compact/generator/AdapterEnrichmentRuleGenerator.java index 5abb7a99ce..9c19b30791 100644 --- a/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/compact/generator/AdapterEnrichmentRuleGenerator.java +++ b/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/compact/generator/AdapterEnrichmentRuleGenerator.java @@ -25,6 +25,8 @@ import org.apache.streampipes.sdk.helpers.EpProperties; public class AdapterEnrichmentRuleGenerator implements AdapterModelGenerator { + public static final String TIMESTAMP_FIELD = "timestamp"; + @Override public void apply(AdapterDescription adapterDescription, CompactAdapter compactAdapter) throws Exception { @@ -33,7 +35,7 @@ public class AdapterEnrichmentRuleGenerator implements AdapterModelGenerator { var timestampRule = new AddTimestampRuleDescription(compactAdapter.enrich().timestamp()); adapterDescription.getRules().add(timestampRule); adapterDescription.getEventSchema().addEventProperty( - EpProperties.timestampProperty("timestamp") + EpProperties.timestampProperty(TIMESTAMP_FIELD) ); } } diff --git a/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/compact/generator/CompactAdapterGenerator.java b/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/compact/generator/CompactAdapterGenerator.java new file mode 100644 index 0000000000..6857d0c4ef --- /dev/null +++ b/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/compact/generator/CompactAdapterGenerator.java @@ -0,0 +1,123 @@ +/* + * 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.connect.management.compact.generator; + +import org.apache.streampipes.connect.shared.preprocessing.convert.ToOriginalSchemaConverter; +import org.apache.streampipes.manager.template.CompactConfigGenerator; +import org.apache.streampipes.model.connect.adapter.AdapterDescription; +import org.apache.streampipes.model.connect.adapter.compact.CompactEventProperty; +import org.apache.streampipes.model.connect.adapter.compact.CreateOptions; +import org.apache.streampipes.model.connect.adapter.compact.EnrichmentConfig; +import org.apache.streampipes.model.connect.adapter.compact.TransformationConfig; +import org.apache.streampipes.model.connect.rules.TransformationRuleDescription; +import org.apache.streampipes.model.connect.rules.schema.RenameRuleDescription; +import org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescription; +import org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CompactAdapterGenerator { + + private final AdapterDescription adapterDescription; + + public CompactAdapterGenerator(AdapterDescription adapterDescription) { + this.adapterDescription = adapterDescription; + } + + public List<Map<String, Object>> getConfig() { + var configs = new ArrayList<Map<String, Object>>(); + adapterDescription.getConfig().forEach(c -> { + configs.add(new CompactConfigGenerator(c).toTemplateValue()); + }); + return configs; + } + + public Map<String, CompactEventProperty> getSchema() { + var map = new HashMap<String, CompactEventProperty>(); + var originalProperties = new ToOriginalSchemaConverter( + adapterDescription.getEventSchema().getEventProperties() + ).getTransformedProperties(); + originalProperties + .forEach(ep -> map.put(ep.getRuntimeName(), new CompactEventProperty( + ep.getLabel(), + ep.getDescription(), + ep.getPropertyScope(), + ep.getSemanticType() + ))); + return map; + } + + public EnrichmentConfig getEnrichmentConfig() { + if (hasTimestampEnrichmentRule()) { + return new EnrichmentConfig(AdapterEnrichmentRuleGenerator.TIMESTAMP_FIELD); + } else { + return null; + } + } + + public TransformationConfig getTransformationConfig() { + var renameRules = new HashMap<String, String>(); + var unitTransformRules = new HashMap<String, String>(); + if (hasTransformationRule()) { + if (hasRule(RenameRuleDescription.class)) { + var rules = getRules(RenameRuleDescription.class); + rules.forEach(rule -> { + renameRules.put(rule.getOldRuntimeKey(), rule.getNewRuntimeKey()); + }); + } else if (hasRule(UnitTransformRuleDescription.class)) { + var rules = getRules(UnitTransformRuleDescription.class); + rules.forEach(rule -> { + unitTransformRules.put(rule.getRuntimeKey(), rule.getToUnitRessourceURL()); + }); + } + } + return new TransformationConfig(renameRules, unitTransformRules); + } + + public CreateOptions getCreateOptions() { + return new CreateOptions( + true, + true + ); + } + + private boolean hasTimestampEnrichmentRule() { + return hasRule(AddTimestampRuleDescription.class); + } + + private boolean hasTransformationRule() { + return adapterDescription.getRules().stream() + .anyMatch(r -> hasRule(RenameRuleDescription.class) || hasRule(UnitTransformRuleDescription.class)); + } + + private boolean hasRule(Class<? extends TransformationRuleDescription> rule) { + return adapterDescription.getRules().stream().anyMatch(r -> r.getClass().equals(rule)); + } + + private <T extends TransformationRuleDescription> List<T> getRules(Class<T> rule) { + return adapterDescription.getRules() + .stream() + .filter(rule::isInstance) + .map(rule::cast) + .toList(); + } +} diff --git a/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/management/CompactAdapterManagement.java b/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/management/CompactAdapterManagement.java index a973a22d85..12db048447 100644 --- a/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/management/CompactAdapterManagement.java +++ b/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/management/CompactAdapterManagement.java @@ -19,6 +19,7 @@ package org.apache.streampipes.connect.management.management; import org.apache.streampipes.connect.management.compact.generator.AdapterModelGenerator; +import org.apache.streampipes.connect.management.compact.generator.CompactAdapterGenerator; import org.apache.streampipes.model.connect.adapter.AdapterDescription; import org.apache.streampipes.model.connect.adapter.compact.CompactAdapter; import org.apache.streampipes.storage.api.IAdapterStorage; @@ -45,6 +46,22 @@ public class CompactAdapterManagement { return adapterDescription; } + public CompactAdapter convertToCompactAdapter(AdapterDescription adapterDescription) throws Exception { + var generator = new CompactAdapterGenerator(adapterDescription); + + return new CompactAdapter( + adapterDescription.getElementId(), + adapterDescription.getName(), + adapterDescription.getDescription(), + adapterDescription.getAppId(), + generator.getConfig(), + generator.getSchema(), + generator.getEnrichmentConfig(), + generator.getTransformationConfig(), + generator.getCreateOptions() + ); + } + public AdapterDescription convertToAdapterDescription(CompactAdapter compactAdapter, AdapterDescription existingAdapter) throws Exception { var adapterDescription = convertToAdapterDescription(compactAdapter); diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CompactAdapter.java b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CompactAdapter.java index d8a0a93f29..1129736376 100644 --- a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CompactAdapter.java +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CompactAdapter.java @@ -36,9 +36,12 @@ package org.apache.streampipes.model.connect.adapter.compact; +import org.apache.streampipes.model.shared.annotation.TsModel; + import java.util.List; import java.util.Map; +@TsModel public record CompactAdapter( String id, String name, diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CompactEventProperty.java b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CompactEventProperty.java index c0cdd7e6af..479b42b0dc 100644 --- a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CompactEventProperty.java +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CompactEventProperty.java @@ -18,6 +18,9 @@ package org.apache.streampipes.model.connect.adapter.compact; +import com.fasterxml.jackson.annotation.JsonInclude; + +@JsonInclude(JsonInclude.Include.NON_NULL) public record CompactEventProperty( String label, String description, diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/CompactConfigGenerator.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/CompactConfigGenerator.java new file mode 100644 index 0000000000..3ec54266b7 --- /dev/null +++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/CompactConfigGenerator.java @@ -0,0 +1,211 @@ +/* + * 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.template; + +import org.apache.streampipes.model.staticproperty.AnyStaticProperty; +import org.apache.streampipes.model.staticproperty.CodeInputStaticProperty; +import org.apache.streampipes.model.staticproperty.CollectionStaticProperty; +import org.apache.streampipes.model.staticproperty.ColorPickerStaticProperty; +import org.apache.streampipes.model.staticproperty.FileStaticProperty; +import org.apache.streampipes.model.staticproperty.FreeTextStaticProperty; +import org.apache.streampipes.model.staticproperty.MappingPropertyNary; +import org.apache.streampipes.model.staticproperty.MappingPropertyUnary; +import org.apache.streampipes.model.staticproperty.MatchingStaticProperty; +import org.apache.streampipes.model.staticproperty.OneOfStaticProperty; +import org.apache.streampipes.model.staticproperty.Option; +import org.apache.streampipes.model.staticproperty.RuntimeResolvableGroupStaticProperty; +import org.apache.streampipes.model.staticproperty.RuntimeResolvableTreeInputStaticProperty; +import org.apache.streampipes.model.staticproperty.SecretStaticProperty; +import org.apache.streampipes.model.staticproperty.SlideToggleStaticProperty; +import org.apache.streampipes.model.staticproperty.StaticProperty; +import org.apache.streampipes.model.staticproperty.StaticPropertyAlternative; +import org.apache.streampipes.model.staticproperty.StaticPropertyAlternatives; +import org.apache.streampipes.model.staticproperty.StaticPropertyGroup; +import org.apache.streampipes.model.staticproperty.StaticPropertyVisitor; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CompactConfigGenerator implements StaticPropertyVisitor { + + private final Map<String, Object> config; + private final StaticProperty staticProperty; + + public CompactConfigGenerator(StaticProperty staticProperty) { + this.config = new HashMap<>(); + this.staticProperty = staticProperty; + } + + public Map<String, Object> toTemplateValue() { + staticProperty.accept(this); + return config; + } + + @Override + public void visit(AnyStaticProperty property) { + addConfig( + property, + property.getOptions().stream().filter(Option::isSelected).map(Option::getName).toList() + ); + } + + @Override + public void visit(CodeInputStaticProperty codeInputStaticProperty) { + addConfig( + codeInputStaticProperty, + codeInputStaticProperty.getValue() + ); + } + + @Override + public void visit(CollectionStaticProperty collectionStaticProperty) { + config.put( + collectionStaticProperty.getInternalName(), + addListEntry(collectionStaticProperty.getMembers()) + ); + } + + @Override + public void visit(ColorPickerStaticProperty colorPickerStaticProperty) { + addConfig( + colorPickerStaticProperty, + colorPickerStaticProperty.getSelectedColor() + ); + } + + @Override + public void visit(FileStaticProperty fileStaticProperty) { + addConfig( + fileStaticProperty, + fileStaticProperty.getLocationPath() + ); + } + + @Override + public void visit(FreeTextStaticProperty freeTextStaticProperty) { + addConfig( + freeTextStaticProperty, + freeTextStaticProperty.getValue() + ); + } + + @Override + public void visit(MappingPropertyNary mappingPropertyNary) { + addConfig( + mappingPropertyNary, + mappingPropertyNary.getSelectedProperties() + ); + } + + @Override + public void visit(MappingPropertyUnary mappingPropertyUnary) { + addConfig( + mappingPropertyUnary, + mappingPropertyUnary.getSelectedProperty() + ); + } + + @Override + public void visit(MatchingStaticProperty matchingStaticProperty) { + // not supported + } + + @Override + public void visit(OneOfStaticProperty oneOfStaticProperty) { + addConfig( + oneOfStaticProperty, + oneOfStaticProperty.getOptions().stream().filter(Option::isSelected).findFirst().map(Option::getName) + ); + } + + @Override + public void visit(SecretStaticProperty secretStaticProperty) { + config.put(secretStaticProperty.getInternalName(), secretStaticProperty.getValue()); + config.put("encrypted", secretStaticProperty.getEncrypted()); + } + + @Override + public void visit(StaticPropertyAlternative staticPropertyAlternative) { + + } + + @Override + public void visit(StaticPropertyAlternatives staticPropertyAlternatives) { + var selectedAlternativeOpt = staticPropertyAlternatives.getAlternatives() + .stream() + .filter(StaticPropertyAlternative::getSelected) + .findFirst(); + if (selectedAlternativeOpt.isPresent()) { + var selectedAlternative = selectedAlternativeOpt.get(); + config.put(staticPropertyAlternatives.getInternalName(), selectedAlternative.getInternalName()); + if (selectedAlternative.getStaticProperty() != null) { + var alternative = new CompactConfigGenerator(selectedAlternative.getStaticProperty()).toTemplateValue(); + config.putAll(alternative); + } + } + } + + @Override + public void visit(StaticPropertyGroup staticPropertyGroup) { + config.putAll(addNestedEntry(staticPropertyGroup.getStaticProperties())); + } + + @Override + public void visit(SlideToggleStaticProperty slideToggleStaticProperty) { + addConfig( + slideToggleStaticProperty, + slideToggleStaticProperty.isSelected() + ); + } + + @Override + public void visit(RuntimeResolvableTreeInputStaticProperty treeInputStaticProperty) { + addConfig( + treeInputStaticProperty, + treeInputStaticProperty.getSelectedNodesInternalNames() + ); + } + + @Override + public void visit(RuntimeResolvableGroupStaticProperty groupStaticProperty) { + + } + + private void addConfig(StaticProperty staticProperty, Object value) { + config.put(staticProperty.getInternalName(), value); + } + + public List<Map<String, Object>> addListEntry(List<StaticProperty> staticProperties) { + return staticProperties.stream() + .map(sp -> new CompactConfigGenerator(sp).toTemplateValue()) + .toList(); + } + + public Map<String, Object> addNestedEntry(List<StaticProperty> staticProperties) { + Map<String, Object> entry = new HashMap<>(); + + staticProperties.forEach(sp -> { + Map<String, Object> groupEntries = new CompactConfigGenerator(sp).toTemplateValue(); + entry.putAll(groupEntries); + }); + + return entry; + } +} 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 11ec281927..fbcd30907a 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 @@ -27,7 +27,9 @@ import org.apache.streampipes.model.staticproperty.MappingPropertyNary; import org.apache.streampipes.model.staticproperty.MappingPropertyUnary; import org.apache.streampipes.model.staticproperty.MatchingStaticProperty; import org.apache.streampipes.model.staticproperty.OneOfStaticProperty; +import org.apache.streampipes.model.staticproperty.Option; import org.apache.streampipes.model.staticproperty.RuntimeResolvableGroupStaticProperty; +import org.apache.streampipes.model.staticproperty.RuntimeResolvableOneOfStaticProperty; import org.apache.streampipes.model.staticproperty.RuntimeResolvableTreeInputStaticProperty; import org.apache.streampipes.model.staticproperty.SecretStaticProperty; import org.apache.streampipes.model.staticproperty.SlideToggleStaticProperty; @@ -132,6 +134,10 @@ public class PipelineElementTemplateVisitor implements StaticPropertyVisitor { String value = getConfigValueAsString(oneOfStaticProperty); oneOfStaticProperty.getOptions().forEach(option -> option.setSelected(option.getName().equals(value))); + if (oneOfStaticProperty instanceof RuntimeResolvableOneOfStaticProperty + && oneOfStaticProperty.getOptions().isEmpty()) { + oneOfStaticProperty.setOptions(List.of(new Option(value, true))); + } } } @@ -204,7 +210,7 @@ public class PipelineElementTemplateVisitor implements StaticPropertyVisitor { @Override public void visit(RuntimeResolvableGroupStaticProperty groupStaticProperty) { - // TODO not yet supported + // TODO } @@ -289,29 +295,4 @@ public class PipelineElementTemplateVisitor implements StaticPropertyVisitor { } throw new IllegalArgumentException("Key '" + key + "' not found"); } - - -// private String getAsString(StaticProperty sp) { -// return configs.get(sp.getInternalName()).toString(); -// } -// -// private boolean getAsBoolean(StaticProperty sp) { -// return Boolean.parseBoolean(configs.get(sp.getInternalName()).toString()); -// } -// -// private Map<String, Object> getAsMap(StaticProperty sp) { -// return (Map<String, Object>) configs.get(sp.getInternalName()); -// } -// -// private Map<String, Object> getAsMap(StaticProperty sp, String subkey) { -// return (Map<String, Object>) getAsMap(sp).get(subkey); -// } -// -// private Map<String, Object> getAsMap(Map<String, Object> map, String key) { -// return (Map<String, Object>) map.get(key); -// } -// -// private List<Map<String, Object>> getAsList(StaticProperty sp, String key) { -// return (List<Map<String, Object>>) getAsMap(sp).get(key); -// } } diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AdapterResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AdapterResource.java index 0961a8c5c4..3ca4465d29 100644 --- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AdapterResource.java +++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AdapterResource.java @@ -22,11 +22,13 @@ import org.apache.streampipes.commons.exceptions.connect.AdapterException; import org.apache.streampipes.commons.prometheus.adapter.AdapterMetricsManager; import org.apache.streampipes.connect.management.management.AdapterMasterManagement; import org.apache.streampipes.connect.management.management.AdapterUpdateManagement; +import org.apache.streampipes.connect.management.management.CompactAdapterManagement; import org.apache.streampipes.manager.pipeline.PipelineManager; import org.apache.streampipes.model.client.user.DefaultRole; import org.apache.streampipes.model.client.user.Permission; import org.apache.streampipes.model.connect.adapter.AdapterDescription; import org.apache.streampipes.model.connect.adapter.PipelineUpdateInfo; +import org.apache.streampipes.model.connect.adapter.compact.CompactAdapter; import org.apache.streampipes.model.message.Message; import org.apache.streampipes.model.message.Notifications; import org.apache.streampipes.model.monitoring.SpLogMessage; @@ -34,6 +36,7 @@ import org.apache.streampipes.model.util.ElementIdGenerator; import org.apache.streampipes.resource.management.PermissionResourceManager; import org.apache.streampipes.resource.management.SpResourceManager; import org.apache.streampipes.rest.security.AuthConstants; +import org.apache.streampipes.rest.shared.constants.SpMediaType; import org.apache.streampipes.storage.api.IPipelineStorage; import org.apache.streampipes.storage.management.StorageDispatcher; @@ -66,7 +69,7 @@ public class AdapterResource extends AbstractAdapterResource<AdapterMasterManage public AdapterResource() { super(() -> new AdapterMasterManagement( StorageDispatcher.INSTANCE.getNoSqlStore() - .getAdapterInstanceStorage(), + .getAdapterInstanceStorage(), new SpResourceManager().manageAdapters(), new SpResourceManager().manageDataStreams(), AdapterMetricsManager.INSTANCE.getAdapterMetrics() @@ -93,6 +96,16 @@ public class AdapterResource extends AbstractAdapterResource<AdapterMasterManage return ok(Notifications.success(adapterId)); } + @PostMapping(path = "compact", consumes = {MediaType.APPLICATION_JSON_VALUE}, produces = { + MediaType.APPLICATION_JSON_VALUE, + SpMediaType.YAML, + SpMediaType.YML + }) + @PreAuthorize(AuthConstants.HAS_WRITE_ADAPTER_PRIVILEGE) + public ResponseEntity<?> convertToCompactAdapter(@RequestBody AdapterDescription adapterDescription) throws Exception { + return ok(new CompactAdapterManagement(List.of()).convertToCompactAdapter(adapterDescription)); + } + @PutMapping(produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize(AuthConstants.HAS_WRITE_ADAPTER_PRIVILEGE) public ResponseEntity<? extends Message> updateAdapter(@RequestBody AdapterDescription adapterDescription) { @@ -108,7 +121,7 @@ public class AdapterResource extends AbstractAdapterResource<AdapterMasterManage } @PutMapping(path = "pipeline-migration-preflight", consumes = MediaType.APPLICATION_JSON_VALUE, - produces = MediaType.APPLICATION_JSON_VALUE) + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize(AuthConstants.HAS_WRITE_ADAPTER_PRIVILEGE) public ResponseEntity<List<PipelineUpdateInfo>> performPipelineMigrationPreflight( @RequestBody AdapterDescription adapterDescription @@ -119,17 +132,26 @@ public class AdapterResource extends AbstractAdapterResource<AdapterMasterManage return ok(migrations); } - @GetMapping(path = "/{id}", produces = { MediaType.APPLICATION_JSON_VALUE, "application/yaml" }) + @GetMapping(path = "/{id}", produces = {MediaType.APPLICATION_JSON_VALUE, SpMediaType.YAML, SpMediaType.YML}) @PreAuthorize(AuthConstants.HAS_READ_ADAPTER_PRIVILEGE) - public ResponseEntity<?> getAdapter(@PathVariable("id") String adapterId) { + public ResponseEntity<?> getAdapter(@PathVariable("id") String adapterId, + @RequestParam(value = "output", + defaultValue = "full", + required = false) String outputMode) { try { AdapterDescription adapterDescription = getAdapterDescription(adapterId); - - return ok(adapterDescription); + if (outputMode.equalsIgnoreCase("compact")) { + return ok(toCompactAdapterDescription(adapterDescription)); + } else { + return ok(adapterDescription); + } } catch (AdapterException e) { LOG.error("Error while getting adapter with id {}", adapterId, e); return fail(); + } catch (Exception e) { + LOG.error("Error while transforming adapter {}", adapterId, e); + return fail(); } } @@ -164,7 +186,7 @@ public class AdapterResource extends AbstractAdapterResource<AdapterMasterManage boolean deleteAssociatedPipelines) { List<String> pipelinesUsingAdapter = getPipelinesUsingAdapter(elementId); IPipelineStorage pipelineStorageAPI = StorageDispatcher.INSTANCE.getNoSqlStore() - .getPipelineStorageAPI(); + .getPipelineStorageAPI(); if (pipelinesUsingAdapter.isEmpty()) { try { @@ -178,11 +200,11 @@ public class AdapterResource extends AbstractAdapterResource<AdapterMasterManage List<String> namesOfPipelinesUsingAdapter = pipelinesUsingAdapter .stream() .map(pipelineId -> pipelineStorageAPI.getElementById( - pipelineId) - .getName()) + pipelineId) + .getName()) .collect(Collectors.toList()); return ResponseEntity.status(HttpStatus.SC_CONFLICT) - .body(String.join(", ", namesOfPipelinesUsingAdapter)); + .body(String.join(", ", namesOfPipelinesUsingAdapter)); } else { PermissionResourceManager permissionResourceManager = new PermissionResourceManager(); // find out the names of pipelines that have an owner and the owner is not the current user @@ -204,16 +226,16 @@ public class AdapterResource extends AbstractAdapterResource<AdapterMasterManage } managementService.deleteAdapter(elementId); return ok(Notifications.success("Adapter with id: " + elementId - + " and all pipelines using the adapter are deleted.")); + + " and all pipelines using the adapter are deleted.")); } catch (Exception e) { LOG.error("Error while deleting adapter with id " - + elementId + " and all pipelines using the adapter", e); + + elementId + " and all pipelines using the adapter", e); return ok(Notifications.error(e.getMessage())); } } else { // otherwise, hint the user the names of pipelines using the adapter but not owned by the user return ResponseEntity.status(HttpStatus.SC_CONFLICT) - .body(String.join(", ", namesOfPipelinesNotOwnedByUser)); + .body(String.join(", ", namesOfPipelinesNotOwnedByUser)); } } } @@ -226,7 +248,7 @@ public class AdapterResource extends AbstractAdapterResource<AdapterMasterManage } catch (AdapterException e) { LOG.error("Error while getting all adapters", e); return ResponseEntity.status(500) - .build(); + .build(); } } @@ -234,10 +256,14 @@ public class AdapterResource extends AbstractAdapterResource<AdapterMasterManage return managementService.getAdapter(adapterId); } + private CompactAdapter toCompactAdapterDescription(AdapterDescription adapterDescription) throws Exception { + return new CompactAdapterManagement(List.of()).convertToCompactAdapter(adapterDescription); + } + private List<String> getPipelinesUsingAdapter(String adapterId) { return StorageDispatcher.INSTANCE.getNoSqlStore() - .getPipelineStorageAPI() - .getPipelinesUsingAdapter(adapterId); + .getPipelineStorageAPI() + .getPipelinesUsingAdapter(adapterId); } } diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/CompactAdapterResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/CompactAdapterResource.java index 97dbb7912a..88424c2256 100644 --- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/CompactAdapterResource.java +++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/CompactAdapterResource.java @@ -31,6 +31,7 @@ import org.apache.streampipes.model.connect.adapter.compact.CompactAdapter; import org.apache.streampipes.model.message.Notifications; import org.apache.streampipes.resource.management.SpResourceManager; import org.apache.streampipes.rest.security.AuthConstants; +import org.apache.streampipes.rest.shared.constants.SpMediaType; import org.apache.streampipes.rest.shared.exception.BadRequestException; import org.apache.streampipes.storage.management.StorageDispatcher; @@ -69,8 +70,8 @@ public class CompactAdapterResource extends AbstractAdapterResource<AdapterMaste @PostMapping( consumes = { MediaType.APPLICATION_JSON_VALUE, - "application/yaml", - "application/yml" + SpMediaType.YML, + SpMediaType.YAML } ) @PreAuthorize(AuthConstants.HAS_WRITE_ADAPTER_PRIVILEGE) diff --git a/ui/projects/streampipes/platform-services/src/lib/apis/adapter.service.ts b/ui/projects/streampipes/platform-services/src/lib/apis/adapter.service.ts index a18160a427..ff32b390f4 100644 --- a/ui/projects/streampipes/platform-services/src/lib/apis/adapter.service.ts +++ b/ui/projects/streampipes/platform-services/src/lib/apis/adapter.service.ts @@ -24,6 +24,7 @@ import { Observable } from 'rxjs'; import { PlatformServicesCommons } from './commons.service'; import { AdapterDescription, + CompactAdapter, Message, PipelineUpdateInfo, } from '../model/gen/streampipes-model'; @@ -55,6 +56,15 @@ export class AdapterService { ); } + convertToCompactAdapter( + adapterDescription: AdapterDescription, + ): Observable<CompactAdapter> { + return this.http.post<CompactAdapter>( + this.connectPath + `/master/adapters/compact`, + adapterDescription, + ); + } + requestAdapterDescriptions(path: string): Observable<AdapterDescription[]> { return this.http.get(this.connectPath + path).pipe( map(response => { diff --git a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts index 235a32498e..8840666969 100644 --- a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts +++ b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts @@ -20,11 +20,10 @@ /* tslint:disable */ /* eslint-disable */ // @ts-nocheck -// Generated using typescript-generator version 3.2.1263 on 2024-10-02 14:54:56. +// Generated using typescript-generator version 3.2.1263 on 2024-10-08 10:25:48. export class NamedStreamPipesEntity implements Storable { '@class': - | 'org.apache.streampipes.model.template.PipelineTemplateDescription' | 'org.apache.streampipes.model.SpDataStream' | 'org.apache.streampipes.model.base.VersionedNamedStreamPipesEntity' | 'org.apache.streampipes.model.connect.adapter.AdapterDescription' @@ -644,28 +643,6 @@ export class AssetExportConfiguration { } } -export class BoundPipelineElement { - connectedTo: BoundPipelineElement[]; - pipelineElementTemplate: InvocableStreamPipesEntity; - - static fromData( - data: BoundPipelineElement, - target?: BoundPipelineElement, - ): BoundPipelineElement { - if (!data) { - return data; - } - const instance = target || new BoundPipelineElement(); - instance.connectedTo = __getCopyArrayFn(BoundPipelineElement.fromData)( - data.connectedTo, - ); - instance.pipelineElementTemplate = InvocableStreamPipesEntity.fromData( - data.pipelineElementTemplate, - ); - return instance; - } -} - export class CanvasPosition { x: number; y: number; @@ -773,6 +750,64 @@ export class ColorPickerStaticProperty extends StaticProperty { } } +export class CompactAdapter { + appId: string; + configuration: { [index: string]: any }[]; + createOptions: CreateOptions; + description: string; + enrich: EnrichmentConfig; + id: string; + name: string; + schema: { [index: string]: CompactEventProperty }; + transform: TransformationConfig; + + static fromData( + data: CompactAdapter, + target?: CompactAdapter, + ): CompactAdapter { + if (!data) { + return data; + } + const instance = target || new CompactAdapter(); + instance.appId = data.appId; + instance.configuration = __getCopyArrayFn( + __getCopyObjectFn(__identity<any>()), + )(data.configuration); + instance.createOptions = CreateOptions.fromData(data.createOptions); + instance.description = data.description; + instance.enrich = EnrichmentConfig.fromData(data.enrich); + instance.id = data.id; + instance.name = data.name; + instance.schema = __getCopyObjectFn(CompactEventProperty.fromData)( + data.schema, + ); + instance.transform = TransformationConfig.fromData(data.transform); + return instance; + } +} + +export class CompactEventProperty { + description: string; + label: string; + propertyScope: string; + semanticType: string; + + static fromData( + data: CompactEventProperty, + target?: CompactEventProperty, + ): CompactEventProperty { + if (!data) { + return data; + } + const instance = target || new CompactEventProperty(); + instance.description = data.description; + instance.label = data.label; + instance.propertyScope = data.propertyScope; + instance.semanticType = data.semanticType; + return instance; + } +} + export class CompactPipeline { createOptions: CreateOptions; description: string; @@ -1478,6 +1513,22 @@ export interface EndpointSelectable { selectedEndpointUrl: string; } +export class EnrichmentConfig { + timestamp: string; + + static fromData( + data: EnrichmentConfig, + target?: EnrichmentConfig, + ): EnrichmentConfig { + if (!data) { + return data; + } + const instance = target || new EnrichmentConfig(); + instance.timestamp = data.timestamp; + return instance; + } +} + export class ValueSpecification { '@class': | 'org.apache.streampipes.model.schema.QuantitativeValue' @@ -3024,32 +3075,6 @@ export class PipelineStatusMessage { } } -export class PipelineTemplateDescription extends NamedStreamPipesEntity { - '@class': 'org.apache.streampipes.model.template.PipelineTemplateDescription'; - 'boundTo': BoundPipelineElement[]; - 'pipelineTemplateDescription': string; - 'pipelineTemplateId': string; - 'pipelineTemplateName': string; - - static 'fromData'( - data: PipelineTemplateDescription, - target?: PipelineTemplateDescription, - ): PipelineTemplateDescription { - if (!data) { - return data; - } - const instance = target || new PipelineTemplateDescription(); - super.fromData(data, instance); - instance.boundTo = __getCopyArrayFn(BoundPipelineElement.fromData)( - data.boundTo, - ); - instance.pipelineTemplateDescription = data.pipelineTemplateDescription; - instance.pipelineTemplateId = data.pipelineTemplateId; - instance.pipelineTemplateName = data.pipelineTemplateName; - return instance; - } -} - export class PipelineTemplateGenerationRequest { pipelineDescription: string; pipelineName: string; @@ -3074,37 +3099,6 @@ export class PipelineTemplateGenerationRequest { } } -export class PipelineTemplateInvocation { - '@class': 'org.apache.streampipes.model.template.PipelineTemplateInvocation'; - 'dataStreamId': string; - 'kviName': string; - 'pipelineTemplateDescription': PipelineTemplateDescription; - 'pipelineTemplateId': string; - 'staticProperties': StaticPropertyUnion[]; - - static 'fromData'( - data: PipelineTemplateInvocation, - target?: PipelineTemplateInvocation, - ): PipelineTemplateInvocation { - if (!data) { - return data; - } - const instance = target || new PipelineTemplateInvocation(); - instance['@class'] = data['@class']; - instance.dataStreamId = data.dataStreamId; - instance.kviName = data.kviName; - instance.pipelineTemplateDescription = - PipelineTemplateDescription.fromData( - data.pipelineTemplateDescription, - ); - instance.pipelineTemplateId = data.pipelineTemplateId; - instance.staticProperties = __getCopyArrayFn( - StaticProperty.fromDataUnion, - )(data.staticProperties); - return instance; - } -} - export class PipelineUpdateInfo { canAutoMigrate: boolean; migrationInfo: string; @@ -3960,6 +3954,26 @@ export class TransformOutputStrategy extends OutputStrategy { } } +export class TransformationConfig { + measurementUnit: { [index: string]: string }; + rename: { [index: string]: string }; + + static fromData( + data: TransformationConfig, + target?: TransformationConfig, + ): TransformationConfig { + if (!data) { + return data; + } + const instance = target || new TransformationConfig(); + instance.measurementUnit = __getCopyObjectFn(__identity<string>())( + data.measurementUnit, + ); + instance.rename = __getCopyObjectFn(__identity<string>())(data.rename); + return instance; + } +} + export class TreeInputNode { children: TreeInputNode[]; dataNode: boolean; 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 new file mode 100644 index 0000000000..52b5d4e5f4 --- /dev/null +++ b/ui/src/app/connect/components/adapter-code-panel/adapter-code-panel.component.html @@ -0,0 +1,36 @@ +<!-- + ~ 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 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> diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CompactEventProperty.java b/ui/src/app/connect/components/adapter-code-panel/adapter-code-panel.component.scss similarity index 76% copy from streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CompactEventProperty.java copy to ui/src/app/connect/components/adapter-code-panel/adapter-code-panel.component.scss index c0cdd7e6af..c02ba8acc6 100644 --- a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CompactEventProperty.java +++ b/ui/src/app/connect/components/adapter-code-panel/adapter-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,12 +16,15 @@ * */ -package org.apache.streampipes.model.connect.adapter.compact; - -public record CompactEventProperty( - String label, - String description, - String propertyScope, - String semanticType -) { +.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/components/adapter-details/adapter-details-tabs.ts b/ui/src/app/connect/components/adapter-code-panel/adapter-code-panel.component.ts similarity index 50% copy from ui/src/app/connect/components/adapter-details/adapter-details-tabs.ts copy to ui/src/app/connect/components/adapter-code-panel/adapter-code-panel.component.ts index c4633a0fb4..5c742add6f 100644 --- a/ui/src/app/connect/components/adapter-details/adapter-details-tabs.ts +++ b/ui/src/app/connect/components/adapter-code-panel/adapter-code-panel.component.ts @@ -16,26 +16,34 @@ * */ -import { SpNavigationItem } from '@streampipes/shared-ui'; +import { Component, Input, OnInit } from '@angular/core'; +import { + AdapterDescription, + AdapterService, + CompactAdapter, +} from '@streampipes/platform-services'; -export class SpAdapterDetailsTabs { - public getTabs(elementId: string): SpNavigationItem[] { - return [ - { - itemId: 'data', - itemTitle: 'Data', - itemLink: ['connect', 'details', elementId, 'data'], - }, - { - itemId: 'metrics', - itemTitle: 'Metrics', - itemLink: ['connect', 'details', elementId, 'metrics'], - }, - { - itemId: 'logs', - itemTitle: 'Logs', - itemLink: ['connect', 'details', elementId, 'logs'], - }, - ]; +@Component({ + selector: 'sp-adapter-code-panel', + templateUrl: './adapter-code-panel.component.html', + styleUrls: ['./adapter-code-panel.component.scss'], +}) +export class AdapterCodePanelComponent implements OnInit { + @Input() + adapterDescription: AdapterDescription; + + @Input() + maxHeight = '300px'; + + compactAdapter: CompactAdapter; + + constructor(private adapterService: AdapterService) {} + + ngOnInit(): void { + this.adapterService + .convertToCompactAdapter(this.adapterDescription) + .subscribe(res => { + this.compactAdapter = res; + }); } } diff --git a/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/adapter-options-panel/adapter-options-panel.component.html b/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/adapter-options-panel/adapter-options-panel.component.html index 2bcfd840d1..b3afa5c944 100644 --- a/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/adapter-options-panel/adapter-options-panel.component.html +++ b/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/adapter-options-panel/adapter-options-panel.component.html @@ -18,17 +18,16 @@ <div fxFlex="100" fxLayout="column" class="options-panel"> <div fxLayout="row" fxFlex="100" fxLayoutAlign="start center"> - <div class="mr-15" fxLayoutAlign="start center"> - <mat-icon class="icon">{{ optionIcon }}</mat-icon> - </div> <div fxFlex fxLayout="column" fxLayoutAlign="center start"> <div fxFlex="100" - class="title" + class="title w-100" fxLayout="row" - fxLayoutAlign="start center" + fxLayoutAlign="start start" + fxLayoutGap="15px" > - <div fxLayoutAlign="start center" class="mr-15"> + <div class="mr-15" fxLayoutAlign="start center"> + <mat-icon class="icon mr-15">{{ optionIcon }}</mat-icon> <mat-checkbox (change)="optionSelectedEmitter.emit($event.checked)" [checked]="isChecked" @@ -37,15 +36,14 @@ > </mat-checkbox> </div> - <div fxFlex fxLayout="column"> + <div fxFlex fxLayout="column" class="w-100"> <div>{{ optionTitle }}</div> - <mat-hint class="description">{{ - optionDescription - }}</mat-hint> + <mat-hint class="description" + >{{ optionDescription }} + </mat-hint> + <ng-content class="w-100 mt-10"></ng-content> </div> </div> - - <ng-content></ng-content> </div> </div> </div> diff --git a/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.html b/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.html index 66cbbed55f..f7ff5b8c7b 100644 --- a/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.html +++ b/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.html @@ -145,6 +145,21 @@ </mat-select> </mat-form-field> </sp-adapter-options-panel> + + <sp-adapter-options-panel + optionTitle="Show code" + optionDescription="Show code to programmatically deploy this adapter over the API" + optionIcon="code" + (optionSelectedEmitter)="showCode = $event" + > + @if (showCode) { + <sp-adapter-code-panel + [adapterDescription]="adapterDescription" + class="w-100" + > + </sp-adapter-code-panel> + } + </sp-adapter-options-panel> </div> <div fxLayoutAlign="end" style="margin-top: 10px"> diff --git a/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.ts b/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.ts index e6b97f915a..e8fc266424 100644 --- a/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.ts +++ b/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.ts @@ -89,6 +89,7 @@ export class StartAdapterConfigurationComponent implements OnInit { dataLakeTimestampField: string; startAdapterNow = true; + showCode = false; constructor( private dialogService: DialogService, diff --git a/ui/src/app/connect/components/adapter-details/abstract-adapter-details.directive.ts b/ui/src/app/connect/components/adapter-details/abstract-adapter-details.directive.ts index 394274eb12..1298c1dea9 100644 --- a/ui/src/app/connect/components/adapter-details/abstract-adapter-details.directive.ts +++ b/ui/src/app/connect/components/adapter-details/abstract-adapter-details.directive.ts @@ -28,7 +28,9 @@ import { SpBreadcrumbService, } from '@streampipes/shared-ui'; import { SpAdapterDetailsTabs } from './adapter-details-tabs'; +import { Directive } from '@angular/core'; +@Directive() export abstract class SpAbstractAdapterDetailsDirective { currentAdapterId: string; tabs: SpNavigationItem[] = []; diff --git a/ui/src/app/connect/components/adapter-details/adapter-details-code/adapter-details-code.component.html b/ui/src/app/connect/components/adapter-details/adapter-details-code/adapter-details-code.component.html new file mode 100644 index 0000000000..6a93d34e7f --- /dev/null +++ b/ui/src/app/connect/components/adapter-details/adapter-details-code/adapter-details-code.component.html @@ -0,0 +1,38 @@ +<!-- + ~ 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. + ~ + --> + +<sp-basic-nav-tabs + [spNavigationItems]="tabs" + [activeLink]="'code'" + [showBackLink]="true" + [backLinkTarget]="['connect']" +> + <div fxLayout="column"> + @if (adapter) { + <div fxLayout="column"> + <sp-basic-header-title-component + [title]="adapter.name + ' - Data'" + ></sp-basic-header-title-component> + <sp-adapter-code-panel + [adapterDescription]="adapter" + maxHeight="none" + ></sp-adapter-code-panel> + </div> + } + </div> +</sp-basic-nav-tabs> diff --git a/ui/src/app/connect/components/adapter-details/adapter-details-code/adapter-details-code.component.ts b/ui/src/app/connect/components/adapter-details/adapter-details-code/adapter-details-code.component.ts new file mode 100644 index 0000000000..07dfacae09 --- /dev/null +++ b/ui/src/app/connect/components/adapter-details/adapter-details-code/adapter-details-code.component.ts @@ -0,0 +1,17 @@ +import { Component, OnInit } from '@angular/core'; +import { SpAbstractAdapterDetailsDirective } from '../abstract-adapter-details.directive'; + +@Component({ + selector: 'sp-adapter-details-code', + templateUrl: './adapter-details-code.component.html', +}) +export class AdapterDetailsCodeComponent + extends SpAbstractAdapterDetailsDirective + implements OnInit +{ + ngOnInit() { + super.onInit(); + } + + onAdapterLoaded(): void {} +} diff --git a/ui/src/app/connect/components/adapter-details/adapter-details-tabs.ts b/ui/src/app/connect/components/adapter-details/adapter-details-tabs.ts index c4633a0fb4..8d3bf34714 100644 --- a/ui/src/app/connect/components/adapter-details/adapter-details-tabs.ts +++ b/ui/src/app/connect/components/adapter-details/adapter-details-tabs.ts @@ -36,6 +36,11 @@ export class SpAdapterDetailsTabs { itemTitle: 'Logs', itemLink: ['connect', 'details', elementId, 'logs'], }, + { + itemId: 'code', + itemTitle: 'Code', + itemLink: ['connect', 'details', elementId, 'code'], + }, ]; } } diff --git a/ui/src/app/connect/connect.module.ts b/ui/src/app/connect/connect.module.ts index 0d0e598a31..5d2e8b4756 100644 --- a/ui/src/app/connect/connect.module.ts +++ b/ui/src/app/connect/connect.module.ts @@ -104,6 +104,9 @@ import { AdapterStatusLightComponent } from './components/existing-adapters/adap import { SpAdapterDeploymentSettingsComponent } from './components/adapter-configuration/adapter-settings/adapter-deployment-settings/adapter-deployment-settings.component'; 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({ imports: [ @@ -184,6 +187,10 @@ import { AdapterDetailsDataComponent } from './components/adapter-details/adapte path: 'logs', component: SpAdapterDetailsLogsComponent, }, + { + path: 'code', + component: AdapterDetailsCodeComponent, + }, ], }, ], @@ -193,9 +200,11 @@ import { AdapterDetailsDataComponent } from './components/adapter-details/adapte ], exports: [ErrorMessageComponent], declarations: [ + AdapterCodePanelComponent, AdapterConfigurationHeaderComponent, AdapterConfigurationComponent, AdapterDescriptionComponent, + AdapterDetailsCodeComponent, AdapterDetailsDataComponent, AdapterStartedDialog, AdapterStatusLightComponent, @@ -214,6 +223,7 @@ import { AdapterDetailsDataComponent } from './components/adapter-details/adapte ExistingAdaptersComponent, AdapterFilterPipe, JsonPrettyPrintPipe, + YamlPrettyPrintPipe, AdapterConfigurationComponent, TimestampPipe, EditCorrectionValueComponent, diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CompactEventProperty.java b/ui/src/app/connect/filter/yaml-pretty-print.pipe.ts similarity index 69% copy from streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CompactEventProperty.java copy to ui/src/app/connect/filter/yaml-pretty-print.pipe.ts index c0cdd7e6af..88f8b4b459 100644 --- a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/compact/CompactEventProperty.java +++ b/ui/src/app/connect/filter/yaml-pretty-print.pipe.ts @@ -16,12 +16,15 @@ * */ -package org.apache.streampipes.model.connect.adapter.compact; +import { Injectable, Pipe, PipeTransform } from '@angular/core'; +import { parse, stringify } from 'yaml'; -public record CompactEventProperty( - String label, - String description, - String propertyScope, - String semanticType -) { +@Pipe({ + name: 'yamlpretty', +}) +@Injectable({ providedIn: 'root' }) +export class YamlPrettyPrintPipe implements PipeTransform { + transform(obj: any) { + return stringify(obj).replace(/ /g, ' ').replace(/\n/g, '<br/>'); + } }
