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

zehnder pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/streampipes.git


The following commit(s) were added to refs/heads/dev by this push:
     new 3ebe611381 feat: Add connection test to export provider (#3942)
3ebe611381 is described below

commit 3ebe611381df5e8fadf39e806e23e427e504431c
Author: Jacqueline Höllig <[email protected]>
AuthorDate: Tue Nov 25 12:50:24 2025 +0100

    feat: Add connection test to export provider (#3942)
    
    Co-authored-by: Dominik Riemer <[email protected]>
---
 .../export/ObjectStorge/IObjectStorage.java        |  1 +
 .../export/ObjectStorge/LocalFolder.java           |  5 ++
 .../dataexplorer/export/ObjectStorge/S3.java       |  5 ++
 .../ObjectStorge/TestExportProviderConnection.java | 71 +++++++++++++++++++
 .../admin/ExportProviderConfigurationResource.java | 40 +++++++++--
 ui/deployment/i18n/de.json                         | 72 +++++++++-----------
 ui/deployment/i18n/en.json                         | 72 +++++++++-----------
 .../src/lib/apis/export-provider.service.ts        | 10 ++-
 .../model/config/export-provider-config.model.ts   | 15 ++--
 ui/src/app/configuration/configuration.module.ts   |  2 +
 .../datalake-configuration.component.html          | 38 +++++++++++
 .../datalake-configuration.component.ts            | 21 ++++++
 .../export-provider-connection-test.component.html | 79 ++++++++++++++++++++++
 .../export-provider-connection-test.component.ts   | 79 ++++++++++++++++++++++
 14 files changed, 413 insertions(+), 97 deletions(-)

diff --git 
a/streampipes-data-explorer-export/src/main/java/org/apache/streampipes/dataexplorer/export/ObjectStorge/IObjectStorage.java
 
b/streampipes-data-explorer-export/src/main/java/org/apache/streampipes/dataexplorer/export/ObjectStorge/IObjectStorage.java
index c913db65d4..3d291277e4 100644
--- 
a/streampipes-data-explorer-export/src/main/java/org/apache/streampipes/dataexplorer/export/ObjectStorge/IObjectStorage.java
+++ 
b/streampipes-data-explorer-export/src/main/java/org/apache/streampipes/dataexplorer/export/ObjectStorge/IObjectStorage.java
@@ -23,4 +23,5 @@ import java.io.IOException;
 
 public interface IObjectStorage {
     void store(StreamingResponseBody datastream) throws IOException;
+    String getFileName();
 }
\ No newline at end of file
diff --git 
a/streampipes-data-explorer-export/src/main/java/org/apache/streampipes/dataexplorer/export/ObjectStorge/LocalFolder.java
 
b/streampipes-data-explorer-export/src/main/java/org/apache/streampipes/dataexplorer/export/ObjectStorge/LocalFolder.java
index 1e59f24d9c..2e449aa164 100644
--- 
a/streampipes-data-explorer-export/src/main/java/org/apache/streampipes/dataexplorer/export/ObjectStorge/LocalFolder.java
+++ 
b/streampipes-data-explorer-export/src/main/java/org/apache/streampipes/dataexplorer/export/ObjectStorge/LocalFolder.java
@@ -42,6 +42,11 @@ public class LocalFolder implements IObjectStorage {
                 + Instant.now().toString() + "." + format);
 
     }
+    
+    @Override
+    public String getFileName(){
+        return this.filePath.toString();
+    }
 
     @Override
     public void store(StreamingResponseBody datastream) throws IOException {
diff --git 
a/streampipes-data-explorer-export/src/main/java/org/apache/streampipes/dataexplorer/export/ObjectStorge/S3.java
 
b/streampipes-data-explorer-export/src/main/java/org/apache/streampipes/dataexplorer/export/ObjectStorge/S3.java
index 885e4f9e90..118813e4b6 100644
--- 
a/streampipes-data-explorer-export/src/main/java/org/apache/streampipes/dataexplorer/export/ObjectStorge/S3.java
+++ 
b/streampipes-data-explorer-export/src/main/java/org/apache/streampipes/dataexplorer/export/ObjectStorge/S3.java
@@ -59,6 +59,11 @@ public class S3 implements IObjectStorage{
 
     }
 
+    @Override
+    public String getFileName(){
+        return this.fileName;
+    }
+
     @Override
     public void store(StreamingResponseBody datastream) throws IOException {
 
diff --git 
a/streampipes-data-explorer-export/src/main/java/org/apache/streampipes/dataexplorer/export/ObjectStorge/TestExportProviderConnection.java
 
b/streampipes-data-explorer-export/src/main/java/org/apache/streampipes/dataexplorer/export/ObjectStorge/TestExportProviderConnection.java
new file mode 100644
index 0000000000..eca9e743f0
--- /dev/null
+++ 
b/streampipes-data-explorer-export/src/main/java/org/apache/streampipes/dataexplorer/export/ObjectStorge/TestExportProviderConnection.java
@@ -0,0 +1,71 @@
+/*
+ * 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.dataexplorer.export.ObjectStorge;
+
+
+import org.apache.streampipes.model.configuration.ExportProviderSettings;
+import org.apache.streampipes.model.configuration.ProviderType;
+
+import 
org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class TestExportProviderConnection {
+
+    public static Map<String, Object> connectionTest(ExportProviderSettings 
setting) throws Exception {
+
+        ProviderType providerType = setting.getProviderType();
+
+        IObjectStorage exportProvider = 
ExportProviderFactory.createExportProvider(
+            providerType, "TEST", setting,
+            "csv");
+
+
+        String filePath = exportProvider.getFileName();
+
+        String csvData = "Message\nThis test file was automatically created as 
a connectivity test by StreamPipes.\n";
+        InputStream csvInputStream = new 
ByteArrayInputStream(csvData.getBytes());
+    StreamingResponseBody responseBody = outputStream -> {
+        byte[] buffer = new byte[1024];
+        int length;
+        while ((length = csvInputStream.read(buffer)) > 0) {
+          outputStream.write(buffer, 0, length);
+        }
+      };
+      try {
+        exportProvider.store(responseBody);
+      } catch (IOException e) {
+        throw new IOException("Failed to store data in the export 
provider.",e);
+
+      }
+
+
+      
+        Map<String, Object> response = new HashMap<>();
+        response.put("filePath", filePath);
+        response.put("setting", setting);
+
+        return response;
+    }
+}
\ No newline at end of file
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ExportProviderConfigurationResource.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ExportProviderConfigurationResource.java
index 774e9805be..9e3e2639e9 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ExportProviderConfigurationResource.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ExportProviderConfigurationResource.java
@@ -17,7 +17,9 @@
  */
 package org.apache.streampipes.rest.impl.admin;
 
+import 
org.apache.streampipes.dataexplorer.export.ObjectStorge.TestExportProviderConnection;
 import org.apache.streampipes.model.configuration.ExportProviderSettings;
+import org.apache.streampipes.model.monitoring.SpLogMessage;
 import 
org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource;
 import org.apache.streampipes.rest.security.AuthConstants;
 import 
org.apache.streampipes.user.management.encryption.SecretEncryptionManager;
@@ -35,6 +37,8 @@ import org.springframework.web.bind.annotation.RestController;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import java.util.Optional;
 import java.util.stream.Collectors;
 
 @RestController
@@ -48,14 +52,40 @@ public class ExportProviderConfigurationResource extends 
AbstractAuthGuardedRest
   }
 
   @GetMapping(value = "/{providerId}", produces = 
MediaType.APPLICATION_JSON_VALUE)
-@PreAuthorize(AuthConstants.IS_ADMIN_ROLE)
-public ResponseEntity<ExportProviderSettings> 
getExportProviderSettingById(@PathVariable String providerId) {
+  @PreAuthorize(AuthConstants.IS_ADMIN_ROLE)
+  public ResponseEntity<ExportProviderSettings> 
getExportProviderSettingById(@PathVariable String providerId) {
     return 
getSpCoreConfigurationStorage().get().getExportProviderSettings().stream()
         .filter(setting -> 
setting.getProviderId().equalsIgnoreCase(providerId))
         .findFirst()
         .map(ResponseEntity::ok)
         .orElse(ResponseEntity.notFound().build());
-}
+  }
+
+  @GetMapping(value = "/test/{providerId}", produces = 
MediaType.APPLICATION_JSON_VALUE)
+  @PreAuthorize(AuthConstants.IS_ADMIN_ROLE)
+  public ResponseEntity<?> testExportProviderSettingById(@PathVariable String 
providerId) {
+    // Get Export Provider Settings
+    Optional<ExportProviderSettings> exportProviderSetting = 
getSpCoreConfigurationStorage().get()
+        .getExportProviderSettings().stream()
+        .filter(setting -> 
setting.getProviderId().equalsIgnoreCase(providerId))
+        .findFirst();
+
+    if (exportProviderSetting.isPresent()) {
+      try {
+        Map<String, Object> response = 
TestExportProviderConnection.connectionTest(exportProviderSetting.get());
+ 
+
+      return ok(response);
+   
+      }  catch (Exception e) {
+        return serverError(SpLogMessage.from(e));
+      }
+
+     
+    } else {
+      return serverError("No provider found.");
+    }
+  }
 
   @PutMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
   @PreAuthorize(AuthConstants.IS_ADMIN_ROLE)
@@ -74,8 +104,8 @@ public ResponseEntity<ExportProviderSettings> 
getExportProviderSettingById(@Path
     }
 
     List<ExportProviderSettings> providerSettingsWithoutExisting = 
providerSettings.stream()
-    .filter(existing -> existing != null && 
!existing.getProviderId().equals(config.getProviderId()))
-    .collect(Collectors.toList());
+        .filter(existing -> existing != null && 
!existing.getProviderId().equals(config.getProviderId()))
+        .collect(Collectors.toList());
 
     providerSettingsWithoutExisting.add(config);
 
diff --git a/ui/deployment/i18n/de.json b/ui/deployment/i18n/de.json
index cb3ad1b92f..60ecb8a773 100644
--- a/ui/deployment/i18n/de.json
+++ b/ui/deployment/i18n/de.json
@@ -238,8 +238,8 @@
   "Add Mapping": "Mapping hinzufügen",
   "Value": "Wert",
   "Remove Mapping": "Mapping entfernen",
-  "Charts": "Diagramme",
   "New chart": "Neues Diagramm",
+  "Charts": "Diagramme",
   "Chart": "Diagramm",
   "Created": "Erstellt",
   "Edit chart": "Diagramm bearbeiten",
@@ -368,18 +368,6 @@
   "Store as template": "Als Vorlage speichern",
   "You can perform a forced stop, which will stop and reset the pipeline 
status.": "Sie können einen erzwungenen Stopp durchführen, der die Pipeline 
anhält und zurücksetzt.",
   "Force stop": "Stopp erzwingen",
-  "Owner": "Eigentümer",
-  "Public Element": "Öffentliches Element",
-  "visible to registered users": "sichtbar für registrierte Benutzer",
-  "Users": "Nutzer",
-  "Authorized Users": "Autorisierte Nutzer",
-  "User selection": "Auswahl der Nutzer",
-  "Groups": "Gruppen",
-  "Authorized Groups": "Autorisierte Gruppen",
-  "Group selection": "Auswahl der Gruppe",
-  "Public Link": "Öffentlicher Link",
-  "Allow anonymous access through public link": "Anonymen Zugang über einen 
öffentlichen Link ermöglichen",
-  "URL": "URL",
   "(no log messages available)": "(keine Protokollmeldungen verfügbar)",
   "You are about to start the following adapters:": "Sie sind dabei, die 
folgenden Adapter zu starten:",
   "You are about to stop the following adapters:": "Sie sind dabei, die 
folgenden Adapter zu stoppen:",
@@ -402,16 +390,13 @@
   "will be stopped and needs manual review": "wird gestoppt und muss manuell 
überprüft werden",
   "Please check and possibly modify existing dashboards and data views 
afterwards.": "Bitte überprüfen Sie die bestehenden Dashboards und 
Datenansichten und ändern Sie diese gegebenenfalls.",
   "Update adapter and migrate pipelines": "Adapter aktualisieren und Pipelines 
migrieren",
-  "Adapters": "Adapter",
   "New adapter": "Neuer Adapter",
   "Start all adapters": "Alle Adapter starten",
   "Stop all adapters": "Alle Adapter anhalten",
   "Refresh adapters": "Adapter neu laden",
+  "Adapters": "Adapter",
   "Messages": "Nachrichten",
   "Last message": "Letzte Nachricht",
-  "Select Adapter": "Adapter auswählen",
-  "Create adapter": "Adapter erstellen",
-  "Docs": "Doku",
   "Refresh": "Neu laden",
   "The desired adapter was not found!": "Der gewünschte Adapter wurde nicht 
gefunden!",
   "Last published message": "Zuletzt veröffentlichte Nachricht",
@@ -456,9 +441,12 @@
   "Save as template": "Als Vorlage speichern",
   "Any available service": "Jeder verfügbare Service",
   "Restrict to service tags": "Auf Service-Tags beschränken",
+  "Select Adapter": "Adapter auswählen",
+  "Create adapter": "Adapter erstellen",
+  "Docs": "Doku",
   "Sites & Areas": "Standorte & Bereiche",
   "Manage your organization's sites and production areas": "Verwaltung der 
Standorte und Produktionsbereiche",
-  "New site": "Neuer Standort",
+  "New": "Neu",
   "Site": "Standort",
   "Areas": "Bereiche",
   "Geo features": "Geo-Features",
@@ -468,30 +456,23 @@
   "Copyright notice if required by the tile server": "Copyright-Hinweis, falls 
vom Tile-Server erforderlich",
   "User Accounts": "Benutzerkonten",
   "Add and edit user accounts": "Benutzerkonten hinzufügen und bearbeiten",
-  "Existing user accounts": "Bestehende Benutzerkonten",
   "Service Accounts": "Servicekonten",
   "Add and edit service accounts": "Servicekonten hinzufügen und bearbeiten",
-  "Existing service accounts": "Bestehende Servicekonten",
+  "Groups": "Gruppen",
   "Manage user groups": "Benutzergruppen verwalten",
-  "Existing groups": "Bestehende Gruppen",
   "Roles": "Rollen",
   "Manage roles": "Rollen verwalten",
-  "Existing roles": "Bestehende Rollen",
   "Authentication": "Authentifizierung",
   "Auth & token settings": "Authentifizierung- und Token-Einstellungen",
   "JWT Signature": "JWT-Signature",
-  "New User Group": "Neue Benutzergruppe",
   "Group name": "Name der Benutzergruppe",
   "Group ID": "Gruppen-ID",
   "Edit user": "Benutzer bearbeiten",
   "Delete service": "Service löschen",
-  "New User": "Neuer Benutzer",
   "Full Name": "Vor- und Nachname",
   "Last Login": "Letzte Anmeldung",
   "Delete user": "Benutzer löschen",
-  "New Service Account": "Neues Servicekonto",
   "Username": "Benutzername",
-  "New Role": "Neue Rolle",
   "Role name": "Rollenbezeichnung",
   "Default Role": "Standardrolle",
   "Settings of externally-managed users cannot be changed.": "Die 
Einstellungen von extern verwalteten Benutzern können nicht geändert werden.",
@@ -520,7 +501,6 @@
   "Message Max Bytes": "Message Max Bytes",
   "Acks": "Acks",
   "Linger MS": "Linger MS",
-  "Update": "Aktualisieren",
   "Protocols": "Protokolle",
   "Manage the priority of protocols used": "Priorität der verwendeten 
Protokolle verwalten",
   "Broker Configuration": "Broker-Konfiguration",
@@ -529,8 +509,6 @@
   "Port": "Port",
   "Labels": "Labels",
   "Configure labels which can be assigned to assets and other resources": 
"Labels konfigurieren, die Assets und anderen Ressourcen zugewiesen werden 
können",
-  "New label": "Neues Label",
-  "Available labels": "Verfügbare Label",
   "Edit label": "Label bearbeiten",
   "Delete label": "Label löschen",
   "Basic": "Allgemein",
@@ -552,13 +530,10 @@
   "Links": "Links",
   "Configure application links": "Anwendungslinks konfigurieren",
   "Documentation Link": "Dokumentations-Link",
-  "Documentation URL": "Dokumentations-URL",
   "Show documentation link on login page": "Link zur Dokumentation auf 
Anmeldeseite anzeigen",
   "Show documentation link in user menu": "Link zur Dokumentation im 
Benutzermenü anzeigen",
-  "API Documentation Link": "Link zur API-Dokumentation",
   "Show API documentation link on login page": "Link zur API-Dokumentation auf 
der Login-Seite anzeigen",
   "Support Link": "Support-Link",
-  "Support URL": "Support-URL",
   "Show support link on login page": "Support-Link auf der Anmeldeseite 
anzeigen",
   "Files": "Dateien",
   "Upload and manage files that are used by adapters or pipeline elements.": 
"Hochladen und Verwalten von Dateien, die von Adaptern oder Pipeline-Elementen 
verwendet werden.",
@@ -577,6 +552,7 @@
   "Service ID": "Service-ID",
   "View service details": "Service-Details anzeigen",
   "Service Name": "Service-Name",
+  "Update": "Aktualisieren",
   "Issuer": "Aussteller",
   "Expires": "Läuft aus",
   "Certificate Details": "Zertifikat-Details",
@@ -603,11 +579,9 @@
   "Install": "Installieren",
   "Uninstall": "Deinstallieren",
   "Export": "Exportieren",
-  "Export application data": "Anwendungsdaten exportieren",
   "Export assets and all linked resources": "Assets und alle damit verbundenen 
Ressourcen exportieren",
   "Start export process": "Exportvorgang starten",
   "Import": "Importieren",
-  "Import application data": "Anwendungsdaten importieren",
   "Import from application package": "Import aus Anwendungspaket",
   "Start import process": "Importvorgang starten",
   "Upload application package file": "Anwendungspaket-Datei hochladen",
@@ -653,6 +627,7 @@
   "You can set various placeholder variables that will be replaced with the 
actual values when sending an email:": "Platzhalter festlegen, die beim Senden 
einer E-Mail ersetzt werden:",
   "Save changes": "Änderungen speichern",
   "Choose a name for your site": "Name des Standorts festlegen",
+  "New site": "Neuer Standort",
   "Site name is required": "Standortname erforderlich",
   "Available areas within the site (e.g. plants or facilities)": "Verfügbare 
Flächen innerhalb des Standorts (z.B. Werke oder Anlagen)",
   "Location": "Lage",
@@ -691,8 +666,6 @@
   "Do you really want to delete the export provider?": "Exportprovider 
wirklich löschen?",
   "This operation cannot be undone. Please ensure that the data provider is 
not used in a datalake retention.": "Dieser Vorgang kann nicht rückgängig 
gemacht werden. Bitte stellen Sie sicher, dass der Provider in keiner 
Speicherrichtlinie verwendet wird.",
   "Delete Data": "Daten löschen",
-  "Do you really want to delete the data index {{index}}?": "Möchten Sie die 
Daten in {{index}} wirklich löschen?",
-  "Do you really want to truncate the data in {{index}}?": "Möchten Sie die 
Daten in {{index}} wirklich leeren?",
   "Truncate Data": "Daten leeren",
   "Start Sync": "Synchronisierung starten",
   "Delete Sync": "Sync löschen",
@@ -711,7 +684,6 @@
   "No export providers found. Please create one first.": "Keine Exportanbieter 
gefunden. Bitte erstellen Sie zuerst einen.",
   "Data Lake Settings": "Data Lake Einstellungen",
   "Manage persisted data streams": "Verwalten von gespeicherten Datenströmen",
-  "Existing data lake indices": "Bestehende Data-Lake-Indizes",
   "Related Pipeline": "Zugehörige Pipelines",
   "# Events": "# Ereignisse",
   "Loading": "Laden",
@@ -725,11 +697,11 @@
   "(no stored measurements)": "(keine gespeicherten Measurements)",
   "Export Providers": "Exportanbieter",
   "Add, Edit, and Delete export providers used for backing up data lakes.": 
"Hinzufügen, Bearbeiten und Löschen von Exportanbietern, die für die Sicherung 
von Data Lakes verwendet werden.",
-  "Existing Export Providers": "Bestehende Exportanbieter",
-  "New Export Provider": "Neuer Exportanbieter",
   "Provider Type": "Anbieter Typ",
   "Edit Export Provider": "Exportanbieter bearbeiten",
   "Remove export provider configuration": "Konfiguration des Exportanbieters 
entfernen",
+  "Test": "Test",
+  "Test export provider configuration": "Konfiguration des Exportanbieters 
testen",
   "no stored export providers": "keine gespeicherten Exportanbieter",
   "success": "Erfolg",
   "error": "Fehler",
@@ -825,13 +797,14 @@
   "Location configuration updated": "Standortkonfiguration aktualisiert",
   "Ok": "Ok",
   "Edit user {{user}}": "Benutzer bearbeiten {{user}}",
-  "Add group": "Gruppe hinzufügen",
+  "Add user": "Benutzer hinzufügen",
   "Are you sure you want to delete this account?": "Sind Sie sicher, dass Sie 
dieses Konto löschen möchten?",
   "This action cannot be reversed!": "Diese Aktion kann nicht rückgängig 
gemacht werden!",
   "Delete User": "Benutzer löschen",
   "Are you sure you want to delete this group?": "Sind Sie sicher, dass Sie 
diese Gruppe löschen wollen?",
   "Delete Group": "Gruppe löschen",
   "Edit group {{groupName}}": "Gruppe {{groupName}} bearbeiten",
+  "Add group": "Gruppe hinzufügen",
   "Are you sure you want to delete this role?": "Sind Sie sicher, dass Sie 
diese Rolle löschen wollen?",
   "Delete Role": "Rolle löschen",
   "Edit role {{label}}": "Rolle {{label}} bearbeiten",
@@ -855,12 +828,29 @@
   "Email title": "E-Mail-Titel",
   "Email preheader": "E-Mail Pre-Header",
   "Email custom inner content (mandatory)": "Benutzerdefinierter E-Mail-Inhalt 
(erforderlich)",
+  "Testing the connection.": "Testen der Verbindung.",
+  "Connection was established and test file was successfully saved:": "Die 
Verbindung wurde hergestellt und die Testdatei wurde erfolgreich gespeichert:",
+  "Connection could not be established.": "Die Verbindung konnte nicht 
hergestellt werden.",
   "Truncating data...": "Daten leeren...",
   "Deleting data...": "Daten löschen...",
+  "New Export Provider": "Neuer Exportanbieter",
   "Truncate data": "Daten leeren",
   "Delete data": "Daten löschen",
   "Delete Export Provider": "Exportanbieter löschen",
+  " Test Export Provider Connection": " Test der Export-Provider-Verbindung",
   "Set Data Retention": "Speicherrichtlinie bearbeiten",
+  "Owner": "Eigentümer",
+  "Public Element": "Öffentliches Element",
+  "visible to registered users": "sichtbar für registrierte Benutzer",
+  "Users": "Nutzer",
+  "Authorized Users": "Autorisierte Nutzer",
+  "User selection": "Auswahl der Nutzer",
+  "Authorized Groups": "Autorisierte Gruppen",
+  "Group selection": "Auswahl der Gruppe",
+  "Public Link": "Öffentlicher Link",
+  "Allow anonymous access through public link": "Anonymen Zugang über einen 
öffentlichen Link ermöglichen",
+  "URL": "URL",
+  "Only admins and owners can manage permissions for this resource.": "Nur 
Administratoren und Eigentümer können die Berechtigungen für diese Ressource 
verwalten.",
   "Select Data": "Daten auswählen",
   "Previous": "Zurück",
   "Download": "Download",
@@ -901,8 +891,8 @@
   "No assets found - use assets to better organize resources!": "Keine Assets 
gefunden - verwenden Sie Assets, um Ressourcen besser zu organisieren!",
   "Manage assets": "Assets verwalten",
   "Asset Browser": "Asset-Browser",
-  "Browse assets": "Assets durchsuchen",
   "Filter assets": "Assets filtern",
+  "All assets": "Alle Assets",
   "Reset filters": "Filter zurücksetzen",
   "None": "Keine",
   "Quick Selection": "Schnellauswahl",
diff --git a/ui/deployment/i18n/en.json b/ui/deployment/i18n/en.json
index 779a67008c..025fe9df76 100644
--- a/ui/deployment/i18n/en.json
+++ b/ui/deployment/i18n/en.json
@@ -238,8 +238,8 @@
   "Add Mapping": null,
   "Value": null,
   "Remove Mapping": null,
-  "Charts": null,
   "New chart": null,
+  "Charts": null,
   "Chart": null,
   "Created": null,
   "Edit chart": null,
@@ -368,18 +368,6 @@
   "Store as template": null,
   "You can perform a forced stop, which will stop and reset the pipeline 
status.": null,
   "Force stop": null,
-  "Owner": null,
-  "Public Element": null,
-  "visible to registered users": null,
-  "Users": null,
-  "Authorized Users": null,
-  "User selection": null,
-  "Groups": null,
-  "Authorized Groups": null,
-  "Group selection": null,
-  "Public Link": null,
-  "Allow anonymous access through public link": null,
-  "URL": null,
   "(no log messages available)": null,
   "You are about to start the following adapters:": null,
   "You are about to stop the following adapters:": null,
@@ -402,16 +390,13 @@
   "will be stopped and needs manual review": null,
   "Please check and possibly modify existing dashboards and data views 
afterwards.": null,
   "Update adapter and migrate pipelines": null,
-  "Adapters": null,
   "New adapter": null,
   "Start all adapters": null,
   "Stop all adapters": null,
   "Refresh adapters": null,
+  "Adapters": null,
   "Messages": null,
   "Last message": null,
-  "Select Adapter": null,
-  "Create adapter": null,
-  "Docs": null,
   "Refresh": null,
   "The desired adapter was not found!": null,
   "Last published message": null,
@@ -456,9 +441,12 @@
   "Save as template": null,
   "Any available service": null,
   "Restrict to service tags": null,
+  "Select Adapter": null,
+  "Create adapter": null,
+  "Docs": null,
   "Sites & Areas": null,
   "Manage your organization's sites and production areas": null,
-  "New site": null,
+  "New": null,
   "Site": null,
   "Areas": null,
   "Geo features": null,
@@ -468,30 +456,23 @@
   "Copyright notice if required by the tile server": null,
   "User Accounts": null,
   "Add and edit user accounts": null,
-  "Existing user accounts": null,
   "Service Accounts": null,
   "Add and edit service accounts": null,
-  "Existing service accounts": null,
+  "Groups": null,
   "Manage user groups": null,
-  "Existing groups": null,
   "Roles": null,
   "Manage roles": null,
-  "Existing roles": null,
   "Authentication": null,
   "Auth & token settings": null,
   "JWT Signature": null,
-  "New User Group": null,
   "Group name": null,
   "Group ID": null,
   "Edit user": null,
   "Delete service": null,
-  "New User": null,
   "Full Name": null,
   "Last Login": null,
   "Delete user": null,
-  "New Service Account": null,
   "Username": null,
-  "New Role": null,
   "Role name": null,
   "Default Role": null,
   "Settings of externally-managed users cannot be changed.": null,
@@ -520,7 +501,6 @@
   "Message Max Bytes": null,
   "Acks": null,
   "Linger MS": null,
-  "Update": null,
   "Protocols": null,
   "Manage the priority of protocols used": null,
   "Broker Configuration": null,
@@ -529,8 +509,6 @@
   "Port": null,
   "Labels": null,
   "Configure labels which can be assigned to assets and other resources": null,
-  "New label": null,
-  "Available labels": null,
   "Edit label": null,
   "Delete label": null,
   "Basic": null,
@@ -552,13 +530,10 @@
   "Links": null,
   "Configure application links": null,
   "Documentation Link": null,
-  "Documentation URL": null,
   "Show documentation link on login page": null,
   "Show documentation link in user menu": null,
-  "API Documentation Link": null,
   "Show API documentation link on login page": null,
   "Support Link": null,
-  "Support URL": null,
   "Show support link on login page": null,
   "Files": null,
   "Upload and manage files that are used by adapters or pipeline elements.": 
null,
@@ -577,6 +552,7 @@
   "Service ID": null,
   "View service details": null,
   "Service Name": null,
+  "Update": null,
   "Issuer": null,
   "Expires": null,
   "Certificate Details": null,
@@ -603,11 +579,9 @@
   "Install": null,
   "Uninstall": null,
   "Export": null,
-  "Export application data": null,
   "Export assets and all linked resources": null,
   "Start export process": null,
   "Import": null,
-  "Import application data": null,
   "Import from application package": null,
   "Start import process": null,
   "Upload application package file": null,
@@ -653,6 +627,7 @@
   "You can set various placeholder variables that will be replaced with the 
actual values when sending an email:": null,
   "Save changes": null,
   "Choose a name for your site": null,
+  "New site": null,
   "Site name is required": null,
   "Available areas within the site (e.g. plants or facilities)": null,
   "Location": null,
@@ -709,7 +684,6 @@
   "No export providers found. Please create one first.": null,
   "Data Lake Settings": null,
   "Manage persisted data streams": null,
-  "Existing data lake indices": null,
   "Related Pipeline": null,
   "# Events": null,
   "Loading": null,
@@ -723,11 +697,11 @@
   "(no stored measurements)": null,
   "Export Providers": null,
   "Add, Edit, and Delete export providers used for backing up data lakes.": 
null,
-  "Existing Export Providers": null,
-  "New Export Provider": null,
   "Provider Type": null,
   "Edit Export Provider": null,
   "Remove export provider configuration": null,
+  "Test": null,
+  "Test export provider configuration": null,
   "no stored export providers": null,
   "success": null,
   "error": null,
@@ -823,13 +797,14 @@
   "Location configuration updated": null,
   "Ok": null,
   "Edit user {{user}}": "Edit user {{user}}",
-  "Add group": null,
+  "Add user": null,
   "Are you sure you want to delete this account?": null,
   "This action cannot be reversed!": null,
   "Delete User": null,
   "Are you sure you want to delete this group?": null,
   "Delete Group": null,
   "Edit group {{groupName}}": "Edit group {{groupName}}",
+  "Add group": null,
   "Are you sure you want to delete this role?": null,
   "Delete Role": null,
   "Edit role {{label}}": "Edit role {{label}}",
@@ -853,14 +828,29 @@
   "Email title": null,
   "Email preheader": null,
   "Email custom inner content (mandatory)": null,
+  "Testing the connection.": null,
+  "Connection was established and test file was successfully saved:": null,
+  "Connection could not be established.": null,
   "Truncating data...": null,
   "Deleting data...": null,
-  "Do you really want to delete the data index {{index}}?": "Do you really 
want to delete the data index {{index}}?",
-  "Do you really want to truncate the data in {{index}}?": "Do you really want 
to truncate the data in {{index}}?",
+  "New Export Provider": null,
   "Truncate data": null,
   "Delete data": null,
   "Delete Export Provider": null,
+  " Test Export Provider Connection": null,
   "Set Data Retention": null,
+  "Owner": null,
+  "Public Element": null,
+  "visible to registered users": null,
+  "Users": null,
+  "Authorized Users": null,
+  "User selection": null,
+  "Authorized Groups": null,
+  "Group selection": null,
+  "Public Link": null,
+  "Allow anonymous access through public link": null,
+  "URL": null,
+  "Only admins and owners can manage permissions for this resource.": null,
   "Select Data": null,
   "Previous": null,
   "Download": null,
@@ -901,8 +891,8 @@
   "No assets found - use assets to better organize resources!": null,
   "Manage assets": null,
   "Asset Browser": null,
-  "Browse assets": null,
   "Filter assets": null,
+  "All assets": null,
   "Reset filters": null,
   "None": null,
   "Quick Selection": null,
diff --git 
a/ui/projects/streampipes/platform-services/src/lib/apis/export-provider.service.ts
 
b/ui/projects/streampipes/platform-services/src/lib/apis/export-provider.service.ts
index a626085171..6e8b4e61d7 100644
--- 
a/ui/projects/streampipes/platform-services/src/lib/apis/export-provider.service.ts
+++ 
b/ui/projects/streampipes/platform-services/src/lib/apis/export-provider.service.ts
@@ -21,7 +21,7 @@ import { HttpClient } from '@angular/common/http';
 import { Observable } from 'rxjs';
 import { PlatformServicesCommons } from './commons.service';
 import { ExportProviderSettings } from '../model/gen/streampipes-model';
-
+import { ExportProviderResponse } from 
'../model/config/export-provider-config.model';
 @Injectable({
     providedIn: 'root',
 })
@@ -42,6 +42,14 @@ export class ExportProviderService {
         );
     }
 
+    testExportProviderById(
+        providerId: string,
+    ): Observable<ExportProviderResponse> {
+        return this.http.get<ExportProviderResponse>(
+            `${this.exportProviderBasePath}/test/${providerId}`,
+        );
+    }
+
     updateExportProvider(
         exportProviderSettings: ExportProviderSettings,
     ): Observable<ExportProviderSettings> {
diff --git 
a/streampipes-data-explorer-export/src/main/java/org/apache/streampipes/dataexplorer/export/ObjectStorge/IObjectStorage.java
 
b/ui/projects/streampipes/platform-services/src/lib/model/config/export-provider-config.model.ts
similarity index 73%
copy from 
streampipes-data-explorer-export/src/main/java/org/apache/streampipes/dataexplorer/export/ObjectStorge/IObjectStorage.java
copy to 
ui/projects/streampipes/platform-services/src/lib/model/config/export-provider-config.model.ts
index c913db65d4..4f60b8a675 100644
--- 
a/streampipes-data-explorer-export/src/main/java/org/apache/streampipes/dataexplorer/export/ObjectStorge/IObjectStorage.java
+++ 
b/ui/projects/streampipes/platform-services/src/lib/model/config/export-provider-config.model.ts
@@ -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.
@@ -15,12 +15,9 @@
  * limitations under the License.
  *
  */
-package org.apache.streampipes.dataexplorer.export.ObjectStorge;
 
-import 
org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
-
-import java.io.IOException;
-
-public interface IObjectStorage {
-    void store(StreamingResponseBody datastream) throws IOException;
-}
\ No newline at end of file
+import { ExportProviderSettings } from '../gen/streampipes-model';
+export interface ExportProviderResponse {
+    filePath: string;
+    setting: ExportProviderSettings;
+}
diff --git a/ui/src/app/configuration/configuration.module.ts 
b/ui/src/app/configuration/configuration.module.ts
index f4ffeaafec..dadfbcac9c 100644
--- a/ui/src/app/configuration/configuration.module.ts
+++ b/ui/src/app/configuration/configuration.module.ts
@@ -31,6 +31,7 @@ import { MessagingConfigurationComponent } from 
'./messaging-configuration/messa
 import { DragDropModule } from '@angular/cdk/drag-drop';
 import { DatalakeConfigurationComponent } from 
'./datalake-configuration/datalake-configuration.component';
 import { DeleteDatalakeIndexComponent } from 
'./dialog/delete-datalake-index/delete-datalake-index-dialog.component';
+import { ExportProviderConnectionTestComponent } from 
'./dialog/export-provider-connection-test/export-provider-connection-test.component';
 import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
 import { SecurityConfigurationComponent } from 
'./security-configuration/security-configuration.component';
 import { CoreUiModule } from '../core-ui/core-ui.module';
@@ -224,6 +225,7 @@ import { DeleteExportProviderComponent } from 
'./dialog/delete-export-provider/d
         ServiceConfigsItemComponent,
         ServiceConfigsNumberComponent,
         DeleteDatalakeIndexComponent,
+        ExportProviderConnectionTestComponent,
         EditAssetLocationComponent,
         EditAssetLocationAreaComponent,
         EditRoleDialogComponent,
diff --git 
a/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.html
 
b/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.html
index a78bea7e96..3a9f98b00a 100644
--- 
a/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.html
+++ 
b/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.html
@@ -413,6 +413,44 @@
                         </td>
                     </ng-container>
 
+                    <ng-container matColumnDef="test">
+                        <th mat-header-cell *matHeaderCellDef>
+                            {{ 'Test' | translate }}
+                        </th>
+                        <td mat-cell *matCellDef="let configurationEntry">
+                            <div>
+                                <div fxLayout="row">
+                                    <span
+                                        fxFlex
+                                        fxFlexOrder="3"
+                                        fxLayout="row"
+                                        fxLayoutAlign="start center"
+                                    >
+                                        <button
+                                            color="accent"
+                                            mat-icon-button
+                                            matTooltip="{{
+                                                'Test export provider 
configuration'
+                                                    | translate
+                                            }}"
+                                            data-cy="exportProvider-test-btn"
+                                            matTooltipPosition="above"
+                                            (click)="
+                                                testExportProvider(
+                                                    
configurationEntry.providerId
+                                                )
+                                            "
+                                        >
+                                            <i class="material-icons"
+                                                >bug_report</i
+                                            >
+                                        </button>
+                                    </span>
+                                </div>
+                            </div>
+                        </td>
+                    </ng-container>
+
                     <tr
                         mat-header-row
                         *matHeaderRowDef="displayedColumnsExport"
diff --git 
a/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.ts
 
b/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.ts
index bd64e827da..bf28431c6e 100644
--- 
a/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.ts
+++ 
b/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.ts
@@ -48,6 +48,7 @@ import { DataRetentionDialogComponent } from 
'../dialog/data-retention-dialog/da
 import { ExportProviderComponent } from 
'../dialog/export-provider-dialog/export-provider-dialog.component';
 import { DeleteExportProviderComponent } from 
'../dialog/delete-export-provider/delete-export-provider-dialog.component';
 import { TranslateService } from '@ngx-translate/core';
+import { ExportProviderConnectionTestComponent } from 
'../dialog/export-provider-connection-test/export-provider-connection-test.component';
 
 @Component({
     selector: 'sp-datalake-configuration',
@@ -94,6 +95,7 @@ export class DatalakeConfigurationComponent implements OnInit 
{
         'bucket',
         'editExportProvider',
         'delete',
+        'test',
     ];
 
     pageSize = 15;
@@ -237,6 +239,25 @@ export class DatalakeConfigurationComponent implements 
OnInit {
             }
         });
     }
+    testExportProvider(providerId: string) {
+        const dialogRef: DialogRef<ExportProviderConnectionTestComponent> =
+            this.dialogService.open(ExportProviderConnectionTestComponent, {
+                panelType: PanelType.STANDARD_PANEL,
+                title: this.translateService.instant(
+                    'Test Export Provider Connection',
+                ),
+                width: '70vw',
+                data: {
+                    providerId: providerId,
+                },
+            });
+
+        dialogRef.afterClosed().subscribe(data => {
+            if (data) {
+                this.loadAvailableExportProvider();
+            }
+        });
+    }
 
     openDownloadDialog(measurementName: string) {
         this.dialogService.open(DataDownloadDialogComponent, {
diff --git 
a/ui/src/app/configuration/dialog/export-provider-connection-test/export-provider-connection-test.component.html
 
b/ui/src/app/configuration/dialog/export-provider-connection-test/export-provider-connection-test.component.html
new file mode 100644
index 0000000000..a753e674c9
--- /dev/null
+++ 
b/ui/src/app/configuration/dialog/export-provider-connection-test/export-provider-connection-test.component.html
@@ -0,0 +1,79 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<div class="sp-dialog-container">
+    <div class="sp-dialog-content p-15">
+        <div
+            fxLayoutAlign="center center"
+            fxLayout="column"
+            data-cy="connection-testing-in-progress"
+        >
+            <div fxLayout="row" fxLayoutAlign="space-around">
+                <b
+                    ><h4>{{ currentStatus }}</h4></b
+                >
+            </div>
+        </div>
+
+        <div
+            fxLayoutAlign="center center"
+            fxLayout="column"
+            data-cy="connection-testing-in-progress"
+        >
+            <div fxLayout="row" fxLayoutAlign="space-around">
+                {{ filePath }}
+            </div>
+        </div>
+
+        @if (isError) {
+            <div class="sp-dialog-content p-20">
+                <sp-exception-details [title]="title" [message]="errorMessage">
+                </sp-exception-details>
+            </div>
+        }
+
+        @if (isInProgress) {
+            <div
+                fxLayoutAlign="center center"
+                fxLayout="column"
+                data-cy="connection-testing-in-progress"
+            >
+                <div fxLayout="row" fxLayoutAlign="space-around">
+                    <mat-spinner
+                        [mode]="'indeterminate'"
+                        color="accent"
+                        diameter="25"
+                    ></mat-spinner>
+                </div>
+            </div>
+        }
+    </div>
+
+    <mat-divider></mat-divider>
+
+    <div class="sp-dialog-actions actions-align-right">
+        <button
+            mat-button
+            mat-flat-button
+            class="mat-basic"
+            (click)="close(false)"
+        >
+            {{ 'Close' | translate }}
+        </button>
+    </div>
+</div>
diff --git 
a/ui/src/app/configuration/dialog/export-provider-connection-test/export-provider-connection-test.component.ts
 
b/ui/src/app/configuration/dialog/export-provider-connection-test/export-provider-connection-test.component.ts
new file mode 100644
index 0000000000..91aa46d5be
--- /dev/null
+++ 
b/ui/src/app/configuration/dialog/export-provider-connection-test/export-provider-connection-test.component.ts
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { Component, inject, Input, OnInit } from '@angular/core';
+import { DialogRef } from '@streampipes/shared-ui';
+import { ExportProviderService } from '@streampipes/platform-services';
+import { TranslateService } from '@ngx-translate/core';
+
+@Component({
+    selector: 'sp-export-provider-connection-test',
+    templateUrl: './export-provider-connection-test.component.html',
+    standalone: false,
+})
+export class ExportProviderConnectionTestComponent implements OnInit {
+    ngOnInit(): void {
+        this.testExportProvider();
+    }
+    @Input()
+    providerId: string;
+
+    private dialogRef = inject(
+        DialogRef<ExportProviderConnectionTestComponent>,
+    );
+    private exportProviderRestService = inject(ExportProviderService);
+    private translateService = inject(TranslateService);
+
+    isInProgress = false;
+    currentStatus: string;
+    errorMessage = '';
+    isError = false;
+    message = '';
+    filePath = '';
+
+    close(refreshDataLakeIndex: boolean) {
+        this.dialogRef.close(refreshDataLakeIndex);
+    }
+
+    testExportProvider() {
+        this.isInProgress = true;
+        this.currentStatus = this.translateService.instant(
+            'Testing the connection.',
+        );
+        this.exportProviderRestService
+            .testExportProviderById(this.providerId)
+            .subscribe(
+                data => {
+                    this.isInProgress = false;
+                    this.isError = false;
+                    this.currentStatus = this.translateService.instant(
+                        'Connection was established and test file was 
successfully saved:',
+                    );
+                    this.filePath = data.filePath;
+                },
+                errorMessage => {
+                    this.currentStatus = this.translateService.instant(
+                        'Connection could not be established.',
+                    );
+                    this.errorMessage = errorMessage.error;
+                    this.isError = true;
+                    this.isInProgress = false;
+                },
+            );
+    }
+}


Reply via email to