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

riemer pushed a commit to branch 
3525-extend-capabilities-of-asset-export-feature
in repository https://gitbox.apache.org/repos/asf/streampipes.git


The following commit(s) were added to 
refs/heads/3525-extend-capabilities-of-asset-export-feature by this push:
     new 5617775376 feat(#3525): Extend capabilities of asset export
5617775376 is described below

commit 5617775376793c151cea0f8e4bf2f1ed7ad47dc8
Author: Dominik Riemer <[email protected]>
AuthorDate: Tue Mar 11 08:32:18 2025 +0100

    feat(#3525): Extend capabilities of asset export
---
 streampipes-data-export/pom.xml                    |  5 ++
 .../export/dataimport/ImportGenerator.java         | 11 +++
 .../export/dataimport/PerformImportGenerator.java  | 53 ++++++++----
 .../export/dataimport/PreviewImportGenerator.java  |  9 +-
 .../export/generator/ExportPackageGenerator.java   |  5 ++
 .../export/resolver/AbstractResolver.java          | 21 ++---
 .../export/resolver/AdapterResolver.java           | 44 ++++++++--
 .../streampipes/export/resolver/ChartResolver.java | 12 ++-
 .../export/resolver/DashboardResolver.java         | 12 ++-
 .../export/resolver/DataSourceResolver.java        | 18 ++--
 .../export/resolver/DocumentResolver.java          | 29 ++++---
 .../streampipes/export/resolver/FileResolver.java  | 12 ++-
 .../resolver/GenericStorageDocumentResolver.java   | 97 ++++++++++++++++++++++
 .../export/resolver/MeasurementResolver.java       | 12 ++-
 .../export/resolver/PipelineResolver.java          | 33 +++++---
 .../export/utils/ImportAdapterMigrationUtils.java  | 55 ------------
 .../model/export/AssetExportConfiguration.java     | 23 +++++
 .../export/StreamPipesApplicationPackage.java      | 14 ++++
 .../streampipes/storage/api/CRUDStorage.java       |  4 +-
 .../src/lib/model/gen/streampipes-model.ts         | 13 ++-
 ui/src/app/configuration/configuration.module.ts   |  4 +
 .../data-export-dialog.component.html              |  4 +
 .../generic-storage-item.component.html            | 39 +++++++++
 .../generic-storage-item.component.ts              | 31 +++----
 .../generic-storage-items.component.html           | 54 ++++++++++++
 .../generic-storage-items.component.ts             | 36 ++++++++
 .../data-import-dialog.component.html              | 46 ++++++++--
 .../data-import-dialog.component.scss              |  5 ++
 .../import-dialog/data-import-dialog.component.ts  | 30 ++++++-
 29 files changed, 569 insertions(+), 162 deletions(-)

diff --git a/streampipes-data-export/pom.xml b/streampipes-data-export/pom.xml
index 46e1b7837b..5bbf50542a 100644
--- a/streampipes-data-export/pom.xml
+++ b/streampipes-data-export/pom.xml
@@ -37,6 +37,11 @@
             <artifactId>streampipes-pipeline-management</artifactId>
             <version>0.98.0-SNAPSHOT</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.streampipes</groupId>
+            <artifactId>streampipes-connect-management</artifactId>
+            <version>0.98.0-SNAPSHOT</version>
+        </dependency>
         <dependency>
             <groupId>org.apache.streampipes</groupId>
             <artifactId>streampipes-resource-management</artifactId>
diff --git 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/ImportGenerator.java
 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/ImportGenerator.java
index 11e3340148..8ca45ff1f0 100644
--- 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/ImportGenerator.java
+++ 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/ImportGenerator.java
@@ -115,6 +115,14 @@ public abstract class ImportGenerator<T> {
       }
     }
 
+    for (String documentId : manifest.getGenericStorageDocuments()) {
+      try {
+        handleGenericStorageDocument(asString(previewFiles.get(documentId)), 
documentId);
+      } catch (DocumentConflictException e) {
+        LOG.warn("Skipping import of generic storage doc {} (already present 
with the same id)", documentId);
+      }
+    }
+
     afterResourcesCreated();
 
     return getReturnObject();
@@ -147,6 +155,9 @@ public abstract class ImportGenerator<T> {
   protected abstract void handleFile(String document, String fileMetadataId, 
Map<String, byte[]> zipContent)
       throws IOException;
 
+  protected abstract void handleGenericStorageDocument(String document, String 
dataLakeMeasureId)
+      throws JsonProcessingException;
+
   protected abstract T getReturnObject();
 
   protected abstract void afterResourcesCreated();
diff --git 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/PerformImportGenerator.java
 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/PerformImportGenerator.java
index 580341c996..674d9b287e 100644
--- 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/PerformImportGenerator.java
+++ 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/PerformImportGenerator.java
@@ -19,14 +19,15 @@
 package org.apache.streampipes.export.dataimport;
 
 import org.apache.streampipes.export.model.PermissionInfo;
+import org.apache.streampipes.export.resolver.AbstractResolver;
 import org.apache.streampipes.export.resolver.AdapterResolver;
 import org.apache.streampipes.export.resolver.ChartResolver;
 import org.apache.streampipes.export.resolver.DashboardResolver;
 import org.apache.streampipes.export.resolver.DataSourceResolver;
 import org.apache.streampipes.export.resolver.FileResolver;
+import org.apache.streampipes.export.resolver.GenericStorageDocumentResolver;
 import org.apache.streampipes.export.resolver.MeasurementResolver;
 import org.apache.streampipes.export.resolver.PipelineResolver;
-import org.apache.streampipes.export.utils.ImportAdapterMigrationUtils;
 import org.apache.streampipes.manager.file.FileHandler;
 import org.apache.streampipes.model.SpDataStream;
 import org.apache.streampipes.model.connect.adapter.AdapterDescription;
@@ -64,14 +65,22 @@ public class PerformImportGenerator extends 
ImportGenerator<Void> {
 
   @Override
   protected void handleAsset(Map<String, byte[]> previewFiles, String assetId) 
throws IOException {
-    storage.getGenericStorage().create(asString(previewFiles.get(assetId)));
+    var document = asString(previewFiles.get(assetId));
+    try {
+      var existing = storage.getGenericStorage().findOne(assetId);
+      if (config.isOverwriteExistingDocuments()) {
+        storage.getGenericStorage().delete(assetId, 
existing.get("_rev").toString());
+      }
+    } catch (IOException e) {
+      // Document not found, do nothing
+    }
+    storage.getGenericStorage().create(document);
   }
 
   @Override
   protected void handleAdapter(String document, String adapterId) throws 
JsonProcessingException {
     if (shouldStore(adapterId, config.getAdapters())) {
-      var convertedDoc = 
ImportAdapterMigrationUtils.checkAndPerformMigration(document);
-      new AdapterResolver().writeDocument(convertedDoc, 
config.isOverrideBrokerSettings());
+      writeDocument(document, new AdapterResolver());
       permissionsToStore.add(new PermissionInfo(adapterId, 
AdapterDescription.class));
     }
   }
@@ -79,7 +88,7 @@ public class PerformImportGenerator extends 
ImportGenerator<Void> {
   @Override
   protected void handleChart(String document, String chartId) throws 
JsonProcessingException {
     if (shouldStore(chartId, config.getDataViews())) {
-      new ChartResolver().writeDocument(document);
+      writeDocument(document, new ChartResolver());
       permissionsToStore.add(new PermissionInfo(chartId, 
DataExplorerWidgetModel.class));
     }
   }
@@ -87,7 +96,7 @@ public class PerformImportGenerator extends 
ImportGenerator<Void> {
   @Override
   protected void handleDashboard(String document, String dashboardId) throws 
JsonProcessingException {
     if (shouldStore(dashboardId, config.getDashboards())) {
-      new DashboardResolver().writeDocument(document);
+      writeDocument(document, new DashboardResolver());
       permissionsToStore.add(new PermissionInfo(dashboardId, 
DashboardModel.class));
     }
   }
@@ -95,7 +104,7 @@ public class PerformImportGenerator extends 
ImportGenerator<Void> {
   @Override
   protected void handleDataSource(String document, String dataSourceId) throws 
JsonProcessingException {
     if (shouldStore(dataSourceId, config.getDataSources())) {
-      new DataSourceResolver().writeDocument(document, 
config.isOverrideBrokerSettings());
+      writeDocument(document, new DataSourceResolver());
       permissionsToStore.add(new PermissionInfo(dataSourceId, 
SpDataStream.class));
     }
   }
@@ -103,7 +112,7 @@ public class PerformImportGenerator extends 
ImportGenerator<Void> {
   @Override
   protected void handlePipeline(String document, String pipelineId) throws 
JsonProcessingException {
     if (shouldStore(pipelineId, config.getPipelines())) {
-      new PipelineResolver().writeDocument(document, 
config.isOverrideBrokerSettings());
+      writeDocument(document, new PipelineResolver());
       permissionsToStore.add(new PermissionInfo(pipelineId, Pipeline.class));
     }
   }
@@ -111,7 +120,7 @@ public class PerformImportGenerator extends 
ImportGenerator<Void> {
   @Override
   protected void handleDataLakeMeasure(String document, String 
dataLakeMeasureId) throws JsonProcessingException {
     if (shouldStore(dataLakeMeasureId, config.getDataLakeMeasures())) {
-      new MeasurementResolver().writeDocument(document);
+      writeDocument(document, new MeasurementResolver());
       permissionsToStore.add(new PermissionInfo(dataLakeMeasureId, 
DataLakeMeasure.class));
     }
   }
@@ -122,12 +131,27 @@ public class PerformImportGenerator extends 
ImportGenerator<Void> {
                             Map<String, byte[]> zipContent) throws IOException 
{
     var resolver = new FileResolver();
     var fileMetadata = resolver.readDocument(document);
-    resolver.writeDocument(document);
+    writeDocument(document, resolver);
     byte[] file = zipContent.get(
         fileMetadata.getFilename().substring(0, 
fileMetadata.getFilename().lastIndexOf(".")));
     new FileHandler().storeFile(fileMetadata.getFilename(), new 
ByteArrayInputStream(file));
   }
 
+  @Override
+  protected void handleGenericStorageDocument(String document, String 
documentId) throws JsonProcessingException {
+    if (shouldStore(documentId, config.getGenericStorageDocuments())) {
+      writeDocument(document, new GenericStorageDocumentResolver());
+    }
+  }
+
+  private void writeDocument(String document,
+                             AbstractResolver<?> resolver) throws 
JsonProcessingException {
+    if (config.isOverwriteExistingDocuments()) {
+      resolver.deleteDocument(document);
+    }
+    resolver.writeDocument(document, config);
+  }
+
   @Override
   protected Void getReturnObject() {
     return null;
@@ -144,12 +168,11 @@ public class PerformImportGenerator extends 
ImportGenerator<Void> {
             true));
   }
 
-  private boolean shouldStore(String adapterId,
-                              Set<ExportItem> adapters) {
-    return adapters
+  private boolean shouldStore(String documentId,
+                              Set<ExportItem> exportItems) {
+    return exportItems
         .stream()
-        .filter(item -> item.getResourceId().equals(adapterId))
+        .filter(item -> item.getResourceId().equals(documentId))
         .allMatch(ExportItem::isSelected);
   }
-
 }
diff --git 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/PreviewImportGenerator.java
 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/PreviewImportGenerator.java
index 6d7383a9d5..40297b265c 100644
--- 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/PreviewImportGenerator.java
+++ 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/PreviewImportGenerator.java
@@ -26,7 +26,6 @@ import 
org.apache.streampipes.export.resolver.DataSourceResolver;
 import org.apache.streampipes.export.resolver.FileResolver;
 import org.apache.streampipes.export.resolver.MeasurementResolver;
 import org.apache.streampipes.export.resolver.PipelineResolver;
-import org.apache.streampipes.export.utils.ImportAdapterMigrationUtils;
 import org.apache.streampipes.model.export.AssetExportConfiguration;
 import org.apache.streampipes.model.export.ExportItem;
 
@@ -69,8 +68,7 @@ public class PreviewImportGenerator extends 
ImportGenerator<AssetExportConfigura
   protected void handleAdapter(String document,
                                String adapterId) throws 
JsonProcessingException {
     try {
-      var convertedDoc = 
ImportAdapterMigrationUtils.checkAndPerformMigration(document);
-      addExportItem(adapterId, new 
AdapterResolver().readDocument(convertedDoc).getName(), 
importConfig::addAdapter);
+      addExportItem(adapterId, new 
AdapterResolver().readDocument(document).getName(), importConfig::addAdapter);
     } catch (IllegalArgumentException e) {
       LOG.warn("Skipping import of data set adapter {}", adapterId);
     }
@@ -114,6 +112,11 @@ public class PreviewImportGenerator extends 
ImportGenerator<AssetExportConfigura
         importConfig::addFile);
   }
 
+  @Override
+  protected void handleGenericStorageDocument(String document, String 
genericDocId) throws JsonProcessingException {
+    addExportItem(genericDocId, genericDocId, 
importConfig::addGenericStorageDocument);
+  }
+
   @Override
   protected AssetExportConfiguration getReturnObject() {
     return this.importConfig;
diff --git 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/generator/ExportPackageGenerator.java
 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/generator/ExportPackageGenerator.java
index 752ce4209b..a5b6b1e926 100644
--- 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/generator/ExportPackageGenerator.java
+++ 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/generator/ExportPackageGenerator.java
@@ -25,6 +25,7 @@ import org.apache.streampipes.export.resolver.ChartResolver;
 import org.apache.streampipes.export.resolver.DashboardResolver;
 import org.apache.streampipes.export.resolver.DataSourceResolver;
 import org.apache.streampipes.export.resolver.FileResolver;
+import org.apache.streampipes.export.resolver.GenericStorageDocumentResolver;
 import org.apache.streampipes.export.resolver.MeasurementResolver;
 import org.apache.streampipes.export.resolver.PipelineResolver;
 import org.apache.streampipes.export.utils.SerializationUtils;
@@ -108,6 +109,10 @@ public class ExportPackageGenerator {
             manifest::addDataView);
       });
 
+      config.getGenericStorageDocuments().forEach(item -> {
+        addDoc(builder, item, new GenericStorageDocumentResolver(), 
manifest::addGenericStorageDocument);
+      });
+
       config.getFiles().forEach(item -> {
         var fileResolver = new FileResolver();
         String filename = 
fileResolver.findDocument(item.getResourceId()).getFilename();
diff --git 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AbstractResolver.java
 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AbstractResolver.java
index d86acdba29..1b59196125 100644
--- 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AbstractResolver.java
+++ 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AbstractResolver.java
@@ -29,13 +29,12 @@ import 
org.apache.streampipes.storage.management.StorageDispatcher;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import org.lightcouch.DocumentConflictException;
 
 import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
 
-public abstract class AbstractResolver<T> {
+public abstract class AbstractResolver<T> implements DocumentResolver<T> {
 
   protected ObjectMapper spMapper;
   protected ObjectMapper defaultMapper;
@@ -61,7 +60,7 @@ public abstract class AbstractResolver<T> {
   public String getSerializedDocument(String resourceId) throws 
JsonProcessingException, ElementNotFoundException {
     var document = findDocument(resourceId);
     if (document != null) {
-      return 
SerializationUtils.getSpObjectMapper().writeValueAsString(modifyDocumentForExport(document));
+      return 
getObjectMapper().writeValueAsString(modifyDocumentForExport(document));
     } else {
       throw new ElementNotFoundException("Could not find element with resource 
id " + resourceId);
     }
@@ -71,20 +70,12 @@ public abstract class AbstractResolver<T> {
     return StorageDispatcher.INSTANCE.getNoSqlStore();
   }
 
-  public abstract T findDocument(String resourceId);
-
-  public abstract T modifyDocumentForExport(T doc);
-
-  public abstract T readDocument(String serializedDoc) throws 
JsonProcessingException;
-
-  public abstract ExportItem convert(T document);
-
-  public abstract void writeDocument(String document) throws 
JsonProcessingException, DocumentConflictException;
-
-  protected abstract T deserializeDocument(String document) throws 
JsonProcessingException;
-
   protected void overrideProtocol(EventGrounding grounding) {
     var newProtocol = new 
EventGroundingProcessor().applyOverride(grounding.getTransportProtocol());
     grounding.setTransportProtocol(newProtocol);
   }
+
+  protected ObjectMapper getObjectMapper() {
+    return spMapper;
+  }
 }
diff --git 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AdapterResolver.java
 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AdapterResolver.java
index d22ae5ba72..0fdb6329d3 100644
--- 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AdapterResolver.java
+++ 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AdapterResolver.java
@@ -19,14 +19,24 @@
 
 package org.apache.streampipes.export.resolver;
 
+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.export.utils.SerializationUtils;
 import org.apache.streampipes.model.connect.adapter.AdapterDescription;
+import org.apache.streampipes.model.export.AssetExportConfiguration;
 import org.apache.streampipes.model.export.ExportItem;
+import org.apache.streampipes.resource.management.SpResourceManager;
+import org.apache.streampipes.resource.management.secret.SecretProvider;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class AdapterResolver extends AbstractResolver<AdapterDescription> {
 
+  private static final Logger LOG = 
LoggerFactory.getLogger(AdapterResolver.class);
+
   @Override
   public AdapterDescription findDocument(String resourceId) {
     return 
getNoSqlStore().getAdapterInstanceStorage().getElementById(resourceId);
@@ -37,6 +47,7 @@ public class AdapterResolver extends 
AbstractResolver<AdapterDescription> {
     adapterDescription.setRev(null);
     adapterDescription.setSelectedEndpointUrl(null);
     adapterDescription.setRunning(false);
+    SecretProvider.getDecryptionService().apply(adapterDescription);
 
     return adapterDescription;
   }
@@ -52,22 +63,41 @@ public class AdapterResolver extends 
AbstractResolver<AdapterDescription> {
   }
 
   @Override
-  public void writeDocument(String document) throws JsonProcessingException {
-    
getNoSqlStore().getAdapterInstanceStorage().persist(deserializeDocument(document));
-  }
-
   public void writeDocument(String document,
-                            boolean overrideDocument) throws 
JsonProcessingException {
+                            AssetExportConfiguration config) throws 
JsonProcessingException {
     var adapterDescription = deserializeDocument(document);
-    if (overrideDocument) {
+    if (config.isOverrideBrokerSettings()) {
       overrideProtocol(adapterDescription.getEventGrounding());
     }
+    SecretProvider.getEncryptionService().apply(adapterDescription);
     getNoSqlStore().getAdapterInstanceStorage().persist(adapterDescription);
   }
 
   @Override
-  protected AdapterDescription deserializeDocument(String document) throws 
JsonProcessingException {
+  public AdapterDescription deserializeDocument(String document) throws 
JsonProcessingException {
     return this.spMapper.readValue(document, AdapterDescription.class);
   }
 
+  @Override
+  public void deleteDocument(String document) throws JsonProcessingException {
+    var adapter = deserializeDocument(document);
+    var resourceId = adapter.getElementId();
+    var existingAdapter = 
getNoSqlStore().getAdapterInstanceStorage().getElementById(resourceId);
+    if (existingAdapter != null) {
+      if (existingAdapter.isRunning()) {
+        try {
+          new AdapterMasterManagement(
+              getNoSqlStore().getAdapterInstanceStorage(),
+              new SpResourceManager().manageAdapters(),
+              new SpResourceManager().manageDataStreams(),
+              AdapterMetricsManager.INSTANCE.getAdapterMetrics()
+          ).stopStreamAdapter(resourceId);
+        } catch (AdapterException e) {
+          LOG.warn("Error when stopping adapter with id {} and name {}", 
resourceId, existingAdapter.getName());
+        }
+      }
+      
getNoSqlStore().getAdapterInstanceStorage().deleteElementById(resourceId);
+    }
+  }
+
 }
diff --git 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/ChartResolver.java
 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/ChartResolver.java
index 4b65871510..212a3567cc 100644
--- 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/ChartResolver.java
+++ 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/ChartResolver.java
@@ -20,6 +20,7 @@ package org.apache.streampipes.export.resolver;
 
 import org.apache.streampipes.export.utils.SerializationUtils;
 import org.apache.streampipes.model.datalake.DataExplorerWidgetModel;
+import org.apache.streampipes.model.export.AssetExportConfiguration;
 import org.apache.streampipes.model.export.ExportItem;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
@@ -51,13 +52,20 @@ public class ChartResolver extends 
AbstractResolver<DataExplorerWidgetModel> {
   }
 
   @Override
-  public void writeDocument(String document) throws JsonProcessingException {
+  public void writeDocument(String document, AssetExportConfiguration config) 
throws JsonProcessingException {
     
getNoSqlStore().getDataExplorerWidgetStorage().persist(deserializeDocument(document));
   }
 
   @Override
-  protected DataExplorerWidgetModel deserializeDocument(String document) 
throws JsonProcessingException {
+  public DataExplorerWidgetModel deserializeDocument(String document) throws 
JsonProcessingException {
     return this.defaultMapper.readValue(document, 
DataExplorerWidgetModel.class);
   }
 
+  @Override
+  public void deleteDocument(String document) throws JsonProcessingException {
+    var chart = readDocument(document);
+    var resourceId = chart.getElementId();
+    
getNoSqlStore().getDataExplorerWidgetStorage().deleteElementById(resourceId);
+  }
+
 }
diff --git 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DashboardResolver.java
 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DashboardResolver.java
index 6c7439c1b3..d7cd1c128c 100644
--- 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DashboardResolver.java
+++ 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DashboardResolver.java
@@ -22,6 +22,7 @@ package org.apache.streampipes.export.resolver;
 import org.apache.streampipes.export.utils.SerializationUtils;
 import org.apache.streampipes.model.dashboard.DashboardItem;
 import org.apache.streampipes.model.dashboard.DashboardModel;
+import org.apache.streampipes.model.export.AssetExportConfiguration;
 import org.apache.streampipes.model.export.ExportItem;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
@@ -59,15 +60,22 @@ public class DashboardResolver extends 
AbstractResolver<DashboardModel> {
   }
 
   @Override
-  public void writeDocument(String document) throws JsonProcessingException {
+  public void writeDocument(String document, AssetExportConfiguration config) 
throws JsonProcessingException {
     
getNoSqlStore().getDataExplorerDashboardStorage().persist(deserializeDocument(document));
   }
 
   @Override
-  protected DashboardModel deserializeDocument(String document) throws 
JsonProcessingException {
+  public DashboardModel deserializeDocument(String document) throws 
JsonProcessingException {
     return this.spMapper.readValue(document, DashboardModel.class);
   }
 
+  @Override
+  public void deleteDocument(String document) throws JsonProcessingException {
+    var dashboard = readDocument(document);
+    var resourceId = dashboard.getElementId();
+    
getNoSqlStore().getDataExplorerDashboardStorage().deleteElementById(resourceId);
+  }
+
   public List<String> getCharts(String resourceId) {
     var document = findDocument(resourceId);
     return 
document.getWidgets().stream().map(DashboardItem::getId).collect(Collectors.toList());
diff --git 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataSourceResolver.java
 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataSourceResolver.java
index a20aa0b2a9..9072dd9682 100644
--- 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataSourceResolver.java
+++ 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataSourceResolver.java
@@ -20,6 +20,7 @@ package org.apache.streampipes.export.resolver;
 
 import org.apache.streampipes.export.utils.SerializationUtils;
 import org.apache.streampipes.model.SpDataStream;
+import org.apache.streampipes.model.export.AssetExportConfiguration;
 import org.apache.streampipes.model.export.ExportItem;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
@@ -48,14 +49,10 @@ public class DataSourceResolver extends 
AbstractResolver<SpDataStream> {
   }
 
   @Override
-  public void writeDocument(String document) throws JsonProcessingException {
-    
getNoSqlStore().getDataStreamStorage().persist(deserializeDocument(document));
-  }
-
   public void writeDocument(String document,
-                            boolean overrideDocument) throws 
JsonProcessingException {
+                            AssetExportConfiguration config) throws 
JsonProcessingException {
     var dataStream = deserializeDocument(document);
-    if (overrideDocument) {
+    if (config.isOverrideBrokerSettings()) {
       if (dataStream.getEventGrounding() != null) {
         overrideProtocol(dataStream.getEventGrounding());
       }
@@ -64,7 +61,14 @@ public class DataSourceResolver extends 
AbstractResolver<SpDataStream> {
   }
 
   @Override
-  protected SpDataStream deserializeDocument(String document) throws 
JsonProcessingException {
+  public SpDataStream deserializeDocument(String document) throws 
JsonProcessingException {
     return this.spMapper.readValue(document, SpDataStream.class);
   }
+
+  @Override
+  public void deleteDocument(String document) throws JsonProcessingException {
+    var dataSource = readDocument(document);
+    var resourceId = dataSource.getElementId();
+    getNoSqlStore().getDataStreamStorage().deleteElementById(resourceId);
+  }
 }
diff --git 
a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/CRUDStorage.java
 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DocumentResolver.java
similarity index 50%
copy from 
streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/CRUDStorage.java
copy to 
streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DocumentResolver.java
index 32e57df0af..2e4b4e35dc 100644
--- 
a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/CRUDStorage.java
+++ 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DocumentResolver.java
@@ -15,26 +15,29 @@
  * limitations under the License.
  *
  */
-package org.apache.streampipes.storage.api;
 
-import org.apache.streampipes.model.Tuple2;
+package org.apache.streampipes.export.resolver;
 
-import java.util.List;
+import org.apache.streampipes.model.export.AssetExportConfiguration;
+import org.apache.streampipes.model.export.ExportItem;
 
-public interface CRUDStorage<T> {
+import com.fasterxml.jackson.core.JsonProcessingException;
+import org.lightcouch.DocumentConflictException;
 
-  List<T> findAll();
+public interface DocumentResolver<T> {
 
-  Tuple2<Boolean, String> persist(T element);
+  T findDocument(String resourceId);
 
-  T getElementById(String id);
+  T modifyDocumentForExport(T document);
 
-  T updateElement(T element);
+  T readDocument(String serializedDocument) throws JsonProcessingException;
 
-  void deleteElement(T element);
+  ExportItem convert(T document);
 
-  default void deleteElementById(String id) {
-    var element = getElementById(id);
-    deleteElement(element);
-  }
+  void writeDocument(String document, AssetExportConfiguration config)
+      throws JsonProcessingException, DocumentConflictException;
+
+  T deserializeDocument(String document) throws JsonProcessingException;
+
+  void deleteDocument(String document) throws JsonProcessingException;
 }
diff --git 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/FileResolver.java
 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/FileResolver.java
index ab0179d8f1..f744c73465 100644
--- 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/FileResolver.java
+++ 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/FileResolver.java
@@ -19,6 +19,7 @@
 package org.apache.streampipes.export.resolver;
 
 import org.apache.streampipes.export.utils.SerializationUtils;
+import org.apache.streampipes.model.export.AssetExportConfiguration;
 import org.apache.streampipes.model.export.ExportItem;
 import org.apache.streampipes.model.file.FileMetadata;
 
@@ -48,12 +49,19 @@ public class FileResolver extends 
AbstractResolver<FileMetadata> {
   }
 
   @Override
-  public void writeDocument(String document) throws JsonProcessingException {
+  public void writeDocument(String document, AssetExportConfiguration config) 
throws JsonProcessingException {
     
getNoSqlStore().getFileMetadataStorage().persist(deserializeDocument(document));
   }
 
   @Override
-  protected FileMetadata deserializeDocument(String document) throws 
JsonProcessingException {
+  public FileMetadata deserializeDocument(String document) throws 
JsonProcessingException {
     return SerializationUtils.getSpObjectMapper().readValue(document, 
FileMetadata.class);
   }
+
+  @Override
+  public void deleteDocument(String document) throws JsonProcessingException {
+    var fileMetadata = readDocument(document);
+    var resourceId = fileMetadata.getElementId();
+    getNoSqlStore().getFileMetadataStorage().deleteElementById(resourceId);
+  }
 }
diff --git 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/GenericStorageDocumentResolver.java
 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/GenericStorageDocumentResolver.java
new file mode 100644
index 0000000000..da4a50162b
--- /dev/null
+++ 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/GenericStorageDocumentResolver.java
@@ -0,0 +1,97 @@
+/*
+ * 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.export.resolver;
+
+import org.apache.streampipes.export.utils.SerializationUtils;
+import org.apache.streampipes.model.export.AssetExportConfiguration;
+import org.apache.streampipes.model.export.ExportItem;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.lightcouch.DocumentConflictException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Map;
+
+public class GenericStorageDocumentResolver extends 
AbstractResolver<Map<String, Object>> {
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(GenericStorageDocumentResolver.class);
+
+  @Override
+  public Map<String, Object> findDocument(String resourceId) {
+    try {
+      return getNoSqlStore().getGenericStorage().findOne(resourceId);
+    } catch (IOException e) {
+      return null;
+    }
+  }
+
+  @Override
+  public Map<String, Object> modifyDocumentForExport(Map<String, Object> 
document) {
+    document.remove("_rev");
+    return document;
+  }
+
+  @Override
+  public Map<String, Object> readDocument(String serializedDocument) throws 
JsonProcessingException {
+    return 
SerializationUtils.getDefaultObjectMapper().readValue(serializedDocument, new 
TypeReference<>() {});
+  }
+
+  @Override
+  public ExportItem convert(Map<String, Object> document) {
+    var documentId = document.get("_id").toString();
+    return new ExportItem(documentId, documentId, true);
+  }
+
+  @Override
+  public void writeDocument(String document, AssetExportConfiguration config) 
throws JsonProcessingException, DocumentConflictException {
+    try {
+      getNoSqlStore().getGenericStorage().create(document);
+    } catch (IOException e) {
+      LOG.warn("Could not write document");
+    }
+  }
+
+  @Override
+  public Map<String, Object> deserializeDocument(String document) throws 
JsonProcessingException {
+    return SerializationUtils.getDefaultObjectMapper().readValue(document, new 
TypeReference<>() {});
+  }
+
+  @Override
+  public void deleteDocument(String document) throws JsonProcessingException {
+    try {
+      var asset = readDocument(document);
+      var resourceId = asset.get("_id").toString();
+      var storedAsset = 
getNoSqlStore().getGenericStorage().findOne(resourceId);
+      getNoSqlStore().getGenericStorage().delete(resourceId, 
storedAsset.get("_rev").toString());
+    } catch (IOException e) {
+      // Do nothing
+    }
+  }
+
+  @Override
+  protected ObjectMapper getObjectMapper() {
+    return defaultMapper;
+  }
+
+
+}
diff --git 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/MeasurementResolver.java
 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/MeasurementResolver.java
index e94012c91d..6e1373c073 100644
--- 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/MeasurementResolver.java
+++ 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/MeasurementResolver.java
@@ -20,6 +20,7 @@ package org.apache.streampipes.export.resolver;
 
 import org.apache.streampipes.export.utils.SerializationUtils;
 import org.apache.streampipes.model.datalake.DataLakeMeasure;
+import org.apache.streampipes.model.export.AssetExportConfiguration;
 import org.apache.streampipes.model.export.ExportItem;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
@@ -48,12 +49,19 @@ public class MeasurementResolver extends 
AbstractResolver<DataLakeMeasure> {
   }
 
   @Override
-  public void writeDocument(String document) throws JsonProcessingException {
+  public void writeDocument(String document, AssetExportConfiguration config) 
throws JsonProcessingException {
     
getNoSqlStore().getDataLakeStorage().persist(deserializeDocument(document));
   }
 
   @Override
-  protected DataLakeMeasure deserializeDocument(String document) throws 
JsonProcessingException {
+  public DataLakeMeasure deserializeDocument(String document) throws 
JsonProcessingException {
     return this.spMapper.readValue(document, DataLakeMeasure.class);
   }
+
+  @Override
+  public void deleteDocument(String document) throws JsonProcessingException {
+    var measurement = readDocument(document);
+    var resourceId = measurement.getElementId();
+    getNoSqlStore().getDataLakeStorage().deleteElementById(resourceId);
+  }
 }
diff --git 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/PipelineResolver.java
 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/PipelineResolver.java
index 53830c166f..73a4404fba 100644
--- 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/PipelineResolver.java
+++ 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/PipelineResolver.java
@@ -19,11 +19,15 @@
 package org.apache.streampipes.export.resolver;
 
 import org.apache.streampipes.export.utils.SerializationUtils;
+import org.apache.streampipes.manager.pipeline.PipelineManager;
+import org.apache.streampipes.model.export.AssetExportConfiguration;
 import org.apache.streampipes.model.export.ExportItem;
 import org.apache.streampipes.model.pipeline.Pipeline;
+import org.apache.streampipes.resource.management.secret.SecretProvider;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
 
+import java.util.ArrayList;
 import java.util.stream.Collectors;
 
 public class PipelineResolver extends AbstractResolver<Pipeline> {
@@ -40,9 +44,8 @@ public class PipelineResolver extends 
AbstractResolver<Pipeline> {
     doc.setRunning(false);
     doc.setSepas(doc.getSepas().stream().peek(s -> 
s.setSelectedEndpointUrl(null)).collect(Collectors.toList()));
     doc.setActions(doc.getActions().stream().peek(s -> 
s.setSelectedEndpointUrl(null)).collect(Collectors.toList()));
-    doc.setStreams(doc.getStreams()
-        .stream()
-        .collect(Collectors.toList()));
+    doc.setStreams(new ArrayList<>(doc.getStreams()));
+    SecretProvider.getDecryptionService().apply(doc);
     return doc;
   }
 
@@ -57,14 +60,10 @@ public class PipelineResolver extends 
AbstractResolver<Pipeline> {
   }
 
   @Override
-  public void writeDocument(String document) throws JsonProcessingException {
-    
getNoSqlStore().getPipelineStorageAPI().persist(deserializeDocument(document));
-  }
-
   public void writeDocument(String document,
-                            boolean overrideDocument) throws 
JsonProcessingException {
+                            AssetExportConfiguration config) throws 
JsonProcessingException {
     var pipeline = deserializeDocument(document);
-    if (overrideDocument) {
+    if (config.isOverrideBrokerSettings()) {
       pipeline.setSepas(pipeline.getSepas().stream().peek(processor -> {
         processor.getInputStreams()
             .forEach(is -> overrideProtocol(is.getEventGrounding()));
@@ -81,11 +80,25 @@ public class PipelineResolver extends 
AbstractResolver<Pipeline> {
       }).collect(Collectors.toList()));
 
     }
+    SecretProvider.getEncryptionService().apply(pipeline);
     getNoSqlStore().getPipelineStorageAPI().persist(pipeline);
   }
 
   @Override
-  protected Pipeline deserializeDocument(String document) throws 
JsonProcessingException {
+  public Pipeline deserializeDocument(String document) throws 
JsonProcessingException {
     return this.spMapper.readValue(document, Pipeline.class);
   }
+
+  @Override
+  public void deleteDocument(String document) throws JsonProcessingException {
+    var pipeline = readDocument(document);
+    var resourceId = pipeline.getElementId();
+    var storedPipeline = PipelineManager.getPipeline(resourceId);
+    if (storedPipeline != null) {
+      if (storedPipeline.isRunning()) {
+        PipelineManager.stopPipeline(resourceId, true);
+      }
+      getNoSqlStore().getPipelineStorageAPI().deleteElementById(resourceId);
+    }
+  }
 }
diff --git 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/utils/ImportAdapterMigrationUtils.java
 
b/streampipes-data-export/src/main/java/org/apache/streampipes/export/utils/ImportAdapterMigrationUtils.java
deleted file mode 100644
index 4100453e43..0000000000
--- 
a/streampipes-data-export/src/main/java/org/apache/streampipes/export/utils/ImportAdapterMigrationUtils.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.export.utils;
-
-import 
org.apache.streampipes.model.connect.adapter.migration.GenericAdapterConverter;
-import 
org.apache.streampipes.model.connect.adapter.migration.IAdapterConverter;
-import 
org.apache.streampipes.model.connect.adapter.migration.SpecificAdapterConverter;
-import 
org.apache.streampipes.model.connect.adapter.migration.utils.AdapterModels;
-
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-
-import static 
org.apache.streampipes.model.connect.adapter.migration.utils.AdapterModels.GENERIC_STREAM;
-
-public class ImportAdapterMigrationUtils {
-
-  public static String checkAndPerformMigration(String document) {
-    JsonObject doc = JsonParser.parseString(document).getAsJsonObject();
-    var docType = doc.get("@class").getAsString();
-    if (AdapterModels.shouldMigrate(docType)) {
-      if (AdapterModels.isSetAdapter(docType)) {
-        throw new IllegalArgumentException("Sets are no longer supported");
-      } else {
-        var converter = getAdapterConverter(docType);
-        return converter.convert(doc).toString();
-      }
-    } else {
-      return doc.toString();
-    }
-  }
-
-  private static IAdapterConverter getAdapterConverter(String adapterType) {
-    if (adapterType.equals(GENERIC_STREAM)) {
-      return new GenericAdapterConverter(true);
-    } else {
-      return new SpecificAdapterConverter(true);
-    }
-  }
-}
diff --git 
a/streampipes-model/src/main/java/org/apache/streampipes/model/export/AssetExportConfiguration.java
 
b/streampipes-model/src/main/java/org/apache/streampipes/model/export/AssetExportConfiguration.java
index bd1e946258..84c6ad3f46 100644
--- 
a/streampipes-model/src/main/java/org/apache/streampipes/model/export/AssetExportConfiguration.java
+++ 
b/streampipes-model/src/main/java/org/apache/streampipes/model/export/AssetExportConfiguration.java
@@ -34,8 +34,10 @@ public class AssetExportConfiguration {
   private Set<ExportItem> dataSources;
   private Set<ExportItem> pipelines;
   private Set<ExportItem> files;
+  private Set<ExportItem> genericStorageDocuments;
 
   private boolean overrideBrokerSettings;
+  private boolean overwriteExistingDocuments;
 
   public AssetExportConfiguration() {
     this.adapters = new HashSet<>();
@@ -46,6 +48,7 @@ public class AssetExportConfiguration {
     this.pipelines = new HashSet<>();
     this.files = new HashSet<>();
     this.assets = new HashSet<>();
+    this.genericStorageDocuments = new HashSet<>();
   }
 
   public Set<ExportItem> getAdapters() {
@@ -167,4 +170,24 @@ public class AssetExportConfiguration {
   public void setOverrideBrokerSettings(boolean overrideBrokerSettings) {
     this.overrideBrokerSettings = overrideBrokerSettings;
   }
+
+  public Set<ExportItem> getGenericStorageDocuments() {
+    return genericStorageDocuments;
+  }
+
+  public void setGenericStorageDocuments(Set<ExportItem> 
genericStorageDocuments) {
+    this.genericStorageDocuments = genericStorageDocuments;
+  }
+
+  public void addGenericStorageDocument(ExportItem exportItem) {
+    this.genericStorageDocuments.add(exportItem);
+  }
+
+  public boolean isOverwriteExistingDocuments() {
+    return overwriteExistingDocuments;
+  }
+
+  public void setOverwriteExistingDocuments(boolean 
overwriteExistingDocuments) {
+    this.overwriteExistingDocuments = overwriteExistingDocuments;
+  }
 }
diff --git 
a/streampipes-model/src/main/java/org/apache/streampipes/model/export/StreamPipesApplicationPackage.java
 
b/streampipes-model/src/main/java/org/apache/streampipes/model/export/StreamPipesApplicationPackage.java
index a95dc6344a..2fee061875 100644
--- 
a/streampipes-model/src/main/java/org/apache/streampipes/model/export/StreamPipesApplicationPackage.java
+++ 
b/streampipes-model/src/main/java/org/apache/streampipes/model/export/StreamPipesApplicationPackage.java
@@ -40,6 +40,7 @@ public class StreamPipesApplicationPackage {
   private Set<String> dataSources;
   private Set<String> pipelines;
   private Set<String> files;
+  private Set<String> genericStorageDocuments;
 
   public StreamPipesApplicationPackage() {
     this.requiredProcessorAppIds = new HashSet<>();
@@ -56,6 +57,7 @@ public class StreamPipesApplicationPackage {
     this.dataSources = new HashSet<>();
     this.pipelines = new HashSet<>();
     this.files = new HashSet<>();
+    this.genericStorageDocuments = new HashSet<>();
   }
 
   public Set<String> getRequiredProcessorAppIds() {
@@ -201,4 +203,16 @@ public class StreamPipesApplicationPackage {
   public void addAsset(String asset) {
     this.assets.add(asset);
   }
+
+  public Set<String> getGenericStorageDocuments() {
+    return genericStorageDocuments;
+  }
+
+  public void setGenericStorageDocuments(Set<String> genericStorageDocuments) {
+    this.genericStorageDocuments = genericStorageDocuments;
+  }
+
+  public void addGenericStorageDocument(String documentId) {
+    this.genericStorageDocuments.add(documentId);
+  }
 }
diff --git 
a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/CRUDStorage.java
 
b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/CRUDStorage.java
index 32e57df0af..ff16df6dc8 100644
--- 
a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/CRUDStorage.java
+++ 
b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/CRUDStorage.java
@@ -35,6 +35,8 @@ public interface CRUDStorage<T> {
 
   default void deleteElementById(String id) {
     var element = getElementById(id);
-    deleteElement(element);
+    if (element != null) {
+      deleteElement(element);
+    }
   }
 }
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 c990b15011..157c3538f5 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
@@ -16,10 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+
 /* tslint:disable */
 /* eslint-disable */
 // @ts-nocheck
-// Generated using typescript-generator version 3.2.1263 on 2025-02-24 
11:25:01.
+// Generated using typescript-generator version 3.2.1263 on 2025-03-10 
14:35:15.
 
 export class NamedStreamPipesEntity implements Storable {
     '@class':
@@ -610,7 +611,9 @@ export class AssetExportConfiguration {
     dataSources: ExportItem[];
     dataViews: ExportItem[];
     files: ExportItem[];
+    genericStorageDocuments: ExportItem[];
     overrideBrokerSettings: boolean;
+    overwriteExistingDocuments: boolean;
     pipelines: ExportItem[];
 
     static fromData(
@@ -640,7 +643,11 @@ export class AssetExportConfiguration {
             data.dataViews,
         );
         instance.files = __getCopyArrayFn(ExportItem.fromData)(data.files);
+        instance.genericStorageDocuments = __getCopyArrayFn(
+            ExportItem.fromData,
+        )(data.genericStorageDocuments);
         instance.overrideBrokerSettings = data.overrideBrokerSettings;
+        instance.overwriteExistingDocuments = data.overwriteExistingDocuments;
         instance.pipelines = __getCopyArrayFn(ExportItem.fromData)(
             data.pipelines,
         );
@@ -3809,6 +3816,7 @@ export class StreamPipesApplicationPackage {
     dataViewWidgets: string[];
     dataViews: string[];
     files: string[];
+    genericStorageDocuments: string[];
     pipelines: string[];
     requiredAdapterAppIds: string[];
     requiredDataSinkAppIds: string[];
@@ -3845,6 +3853,9 @@ export class StreamPipesApplicationPackage {
             data.dataViews,
         );
         instance.files = __getCopyArrayFn(__identity<string>())(data.files);
+        instance.genericStorageDocuments = __getCopyArrayFn(
+            __identity<string>(),
+        )(data.genericStorageDocuments);
         instance.pipelines = __getCopyArrayFn(__identity<string>())(
             data.pipelines,
         );
diff --git a/ui/src/app/configuration/configuration.module.ts 
b/ui/src/app/configuration/configuration.module.ts
index ff860383f5..accdfdec37 100644
--- a/ui/src/app/configuration/configuration.module.ts
+++ b/ui/src/app/configuration/configuration.module.ts
@@ -97,6 +97,8 @@ import { FileUploadDialogComponent } from 
'./dialog/file-upload/file-upload-dial
 import { FileRenameDialogComponent } from 
'./dialog/file-rename/file-rename-dialog.component';
 import { MatDialogModule } from '@angular/material/dialog';
 import { MatProgressBarModule } from '@angular/material/progress-bar';
+import { GenericStorageItemComponent } from 
'./export/export-dialog/generic-storage-items/generic-storage-item/generic-storage-item.component';
+import { GenericStorageItemsComponent } from 
'./export/export-dialog/generic-storage-items/generic-storage-items.component';
 
 @NgModule({
     imports: [
@@ -215,6 +217,8 @@ import { MatProgressBarModule } from 
'@angular/material/progress-bar';
         FileUploadDialogComponent,
         FileRenameDialogComponent,
         GeneralConfigurationComponent,
+        GenericStorageItemComponent,
+        GenericStorageItemsComponent,
         ExtensionsServiceManagementComponent,
         LocationFeaturesConfigurationComponent,
         ManageSiteDialogComponent,
diff --git 
a/ui/src/app/configuration/export/export-dialog/data-export-dialog.component.html
 
b/ui/src/app/configuration/export/export-dialog/data-export-dialog.component.html
index a088cf3333..2f23b38618 100644
--- 
a/ui/src/app/configuration/export/export-dialog/data-export-dialog.component.html
+++ 
b/ui/src/app/configuration/export/export-dialog/data-export-dialog.component.html
@@ -54,6 +54,10 @@
                     [exportItems]="config.pipelines"
                     sectionTitle="Pipelines"
                 ></sp-data-export-item>
+                <sp-generic-storage-items
+                    [exportItems]="config.genericStorageDocuments"
+                >
+                </sp-generic-storage-items>
             </div>
         </div>
         <div
diff --git 
a/ui/src/app/configuration/export/export-dialog/generic-storage-items/generic-storage-item/generic-storage-item.component.html
 
b/ui/src/app/configuration/export/export-dialog/generic-storage-items/generic-storage-item/generic-storage-item.component.html
new file mode 100644
index 0000000000..78e6b097e0
--- /dev/null
+++ 
b/ui/src/app/configuration/export/export-dialog/generic-storage-items/generic-storage-item/generic-storage-item.component.html
@@ -0,0 +1,39 @@
+<!--
+  ~ 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 fxLayout="row" fxLayoutAlign="start center">
+    @if (!importMode) {
+        <span fxFlex>{{ exportItem.resourceId }}</span>
+        <div fxLayoutAlign="end center">
+            <button
+                mat-icon-button
+                color="accent"
+                (click)="removeItem.emit(exportItem.resourceId)"
+            >
+                <i class="material-icons">remove</i>
+            </button>
+        </div>
+    } @else {
+        <mat-checkbox
+            [checked]="exportItem.selected"
+            (change)="removeItem.emit(exportItem.resourceId)"
+        >
+            {{ exportItem.resourceId }}
+        </mat-checkbox>
+    }
+</div>
diff --git 
a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/CRUDStorage.java
 
b/ui/src/app/configuration/export/export-dialog/generic-storage-items/generic-storage-item/generic-storage-item.component.ts
similarity index 64%
copy from 
streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/CRUDStorage.java
copy to 
ui/src/app/configuration/export/export-dialog/generic-storage-items/generic-storage-item/generic-storage-item.component.ts
index 32e57df0af..84c2e0cfce 100644
--- 
a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/CRUDStorage.java
+++ 
b/ui/src/app/configuration/export/export-dialog/generic-storage-items/generic-storage-item/generic-storage-item.component.ts
@@ -15,26 +15,21 @@
  * limitations under the License.
  *
  */
-package org.apache.streampipes.storage.api;
 
-import org.apache.streampipes.model.Tuple2;
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+import { ExportItem } from '@streampipes/platform-services';
 
-import java.util.List;
+@Component({
+    selector: 'sp-generic-storage-item',
+    templateUrl: './generic-storage-item.component.html',
+})
+export class GenericStorageItemComponent {
+    @Input()
+    exportItem: ExportItem;
 
-public interface CRUDStorage<T> {
+    @Input()
+    importMode = false;
 
-  List<T> findAll();
-
-  Tuple2<Boolean, String> persist(T element);
-
-  T getElementById(String id);
-
-  T updateElement(T element);
-
-  void deleteElement(T element);
-
-  default void deleteElementById(String id) {
-    var element = getElementById(id);
-    deleteElement(element);
-  }
+    @Output()
+    removeItem: EventEmitter<string> = new EventEmitter<string>();
 }
diff --git 
a/ui/src/app/configuration/export/export-dialog/generic-storage-items/generic-storage-items.component.html
 
b/ui/src/app/configuration/export/export-dialog/generic-storage-items/generic-storage-items.component.html
new file mode 100644
index 0000000000..0d42e274c1
--- /dev/null
+++ 
b/ui/src/app/configuration/export/export-dialog/generic-storage-items/generic-storage-items.component.html
@@ -0,0 +1,54 @@
+<!--
+  ~ 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 fxLayout="column" fxFlex="100">
+    <h5>Additional documents from generic storage</h5>
+
+    @for (exportItem of exportItems; track exportItem.resourceId) {
+        <sp-generic-storage-item
+            [exportItem]="exportItem"
+            [importMode]="importMode"
+            (removeItem)="handleDocumentRemoval($event)"
+        >
+        </sp-generic-storage-item>
+    }
+
+    @if (!importMode) {
+        <div fxLayout="row" fxLayoutAlign="start center" class="mt-10">
+            <div fxLayoutAlign="start center" fxFlex>
+                <mat-form-field color="accent" fxFlex 
subscriptSizing="dynamic">
+                    <mat-label>Document ID</mat-label>
+                    <input
+                        matInput
+                        placeholder="Document ID"
+                        [(ngModel)]="newDocumentId"
+                    />
+                </mat-form-field>
+            </div>
+            <div fxLayoutAlign="end center" class="ml-5">
+                <button
+                    mat-raised-button
+                    color="accent"
+                    (click)="addGenericStorageDocument()"
+                >
+                    Add
+                </button>
+            </div>
+        </div>
+    }
+</div>
diff --git 
a/ui/src/app/configuration/export/export-dialog/generic-storage-items/generic-storage-items.component.ts
 
b/ui/src/app/configuration/export/export-dialog/generic-storage-items/generic-storage-items.component.ts
new file mode 100644
index 0000000000..1f492681a5
--- /dev/null
+++ 
b/ui/src/app/configuration/export/export-dialog/generic-storage-items/generic-storage-items.component.ts
@@ -0,0 +1,36 @@
+import { Component, Input } from '@angular/core';
+import { ExportItem } from '@streampipes/platform-services';
+
+@Component({
+    selector: 'sp-generic-storage-items',
+    templateUrl: './generic-storage-items.component.html',
+})
+export class GenericStorageItemsComponent {
+    @Input()
+    exportItems: ExportItem[];
+
+    @Input()
+    importMode = false;
+
+    newDocumentId = '';
+
+    addGenericStorageDocument(): void {
+        this.exportItems.push({
+            resourceId: this.newDocumentId,
+            label: this.newDocumentId,
+            selected: true,
+        });
+    }
+
+    handleDocumentRemoval(resourceId: string): void {
+        const index = this.exportItems.findIndex(
+            e => e.resourceId === resourceId,
+        );
+        if (!this.importMode) {
+            this.exportItems.splice(index, 1);
+        } else {
+            this.exportItems[index].selected =
+                !this.exportItems[index].selected;
+        }
+    }
+}
diff --git 
a/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.html
 
b/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.html
index 9e60148469..d014998557 100644
--- 
a/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.html
+++ 
b/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.html
@@ -60,11 +60,11 @@
                     data-cy="select-upload-file-button"
                 >
                     <mat-icon *ngIf="uploadStatus < 99"
-                        >insert_drive_file</mat-icon
-                    >
+                        >insert_drive_file
+                    </mat-icon>
                     <mat-icon *ngIf="uploadStatus === 100" class="green-icon"
-                        >check_circle</mat-icon
-                    >
+                        >check_circle
+                    </mat-icon>
                 </button>
                 <mat-error *ngIf="!hasInput">
                     {{ errorMessage }}
@@ -77,7 +77,24 @@
             class="p-15"
             *ngIf="currentImportStep === 1"
         >
-            <h4>Select resources to import</h4>
+            <div fxLayout="row" fxLayoutAlign="start center">
+                <h4>Select resources to import</h4>
+                <button
+                    mat-raised-button
+                    color="accent"
+                    class="small-button ml-5"
+                    (click)="toggleSelect(true)"
+                >
+                    Select all
+                </button>
+                <button
+                    mat-raised-button
+                    class="small-button mat-basic"
+                    (click)="toggleSelect(false)"
+                >
+                    Deselect all
+                </button>
+            </div>
             <sp-data-export-item
                 [exportItems]="importConfiguration.assets"
                 sectionTitle="Assets"
@@ -110,7 +127,11 @@
                 [exportItems]="importConfiguration.pipelines"
                 sectionTitle="Pipelines"
             ></sp-data-export-item>
-
+            <sp-generic-storage-items
+                [exportItems]="importConfiguration.genericStorageDocuments"
+                [importMode]="true"
+            >
+            </sp-generic-storage-items>
             <div
                 fxFlex="100"
                 fxLayout="column"
@@ -121,8 +142,17 @@
                 <div fxLayout="column" *ngIf="importConfiguration">
                     <mat-checkbox
                         
[(ngModel)]="importConfiguration.overrideBrokerSettings"
-                        >Use broker settings from this instance</mat-checkbox
-                    >
+                        >Use broker settings from this instance
+                    </mat-checkbox>
+                    <div class="warning-box">
+                        <mat-checkbox
+                            [(ngModel)]="
+                                importConfiguration.overwriteExistingDocuments
+                            "
+                            >Update/overwrite existing documents with the same
+                            ID (operation may break things)
+                        </mat-checkbox>
+                    </div>
                 </div>
             </div>
         </div>
diff --git 
a/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.scss
 
b/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.scss
index fddade7bf6..2251ca4f01 100644
--- 
a/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.scss
+++ 
b/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.scss
@@ -17,3 +17,8 @@
  */
 
 @import '../../../../scss/sp/sp-dialog.scss';
+
+.warning-box {
+    border: 1px solid #dea843;
+    background: #f1f1e6;
+}
diff --git 
a/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.ts 
b/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.ts
index 05e341410e..5f23b5d1d7 100644
--- 
a/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.ts
+++ 
b/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.ts
@@ -20,7 +20,10 @@ import { Component } from '@angular/core';
 import { DialogRef } from '@streampipes/shared-ui';
 import { DataExportService } from '../data-export.service';
 import { HttpEventType, HttpResponse } from '@angular/common/http';
-import { AssetExportConfiguration } from 
'../../../../../dist/streampipes/platform-services';
+import {
+    AssetExportConfiguration,
+    ExportItem,
+} from '@streampipes/platform-services';
 
 @Component({
     selector: 'sp-data-import-dialog',
@@ -93,4 +96,29 @@ export class SpDataImportDialogComponent {
     close(): void {
         this.dialogRef.close();
     }
+
+    toggleSelect(select: boolean): void {
+        if (this.importConfiguration) {
+            this.toggleExportItems(select);
+        }
+    }
+
+    private toggleExportItems(select: boolean): void {
+        this.toggleAllItems(this.importConfiguration.files, select);
+        this.toggleAllItems(this.importConfiguration.dataSources, select);
+        this.toggleAllItems(this.importConfiguration.adapters, select);
+        this.toggleAllItems(this.importConfiguration.assets, select);
+        this.toggleAllItems(this.importConfiguration.dashboards, select);
+        this.toggleAllItems(this.importConfiguration.dataViews, select);
+        this.toggleAllItems(this.importConfiguration.dataLakeMeasures, select);
+        this.toggleAllItems(
+            this.importConfiguration.genericStorageDocuments,
+            select,
+        );
+        this.toggleAllItems(this.importConfiguration.pipelines, select);
+    }
+
+    private toggleAllItems(exportItem: ExportItem[], select: boolean): void {
+        exportItem.forEach(e => (e.selected = select));
+    }
 }

Reply via email to