You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by ri...@apache.org on 2020/09/15 18:07:26 UTC

[incubator-streampipes] branch rel/0.67.0 updated: [STREAMPIPES-217] Harmonize file management for pipeline elements and adapters

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

riemer pushed a commit to branch rel/0.67.0
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git


The following commit(s) were added to refs/heads/rel/0.67.0 by this push:
     new 8e5577f  [STREAMPIPES-217] Harmonize file management for pipeline elements and adapters
     new de0adab  Merge branch 'rel/0.67.0' of github.com:apache/incubator-streampipes into rel/0.67.0
8e5577f is described below

commit 8e5577f5da9aab7d24ac836c6b2608fcc3e6b483
Author: Dominik Riemer <ri...@fzi.de>
AuthorDate: Tue Sep 15 20:06:45 2020 +0200

    [STREAMPIPES-217] Harmonize file management for pipeline elements and adapters
---
 .../container/api/InvocableElement.java            | 34 ++++------
 .../model/client/file/FileMetadata.java            |  2 +
 .../model/staticproperty/FileStaticProperty.java   | 16 +++++
 .../streampipes/rest/api/IPipelineElementFile.java |  5 +-
 .../streampipes/rest/impl/PipelineElementFile.java | 31 +++++----
 ...AbstractConfigurablePipelineElementBuilder.java | 34 ++++++++++
 .../sdk/extractor/AbstractParameterExtractor.java  | 26 +++++---
 .../sdk/extractor/StaticPropertyExtractor.java     |  5 ++
 .../apache/streampipes/sdk/helpers/Filetypes.java  | 24 ++++---
 .../apache/streampipes/vocabulary/StreamPipes.java |  2 +
 ui/deployment/dev/config.yml                       |  1 +
 ui/deployment/modules.yml                          | 17 ++++-
 ui/src/app/app-routing.module.ts                   |  2 +
 .../app/core-model/gen/streampipes-model-client.ts | 29 ++++++++-
 ui/src/app/core-model/gen/streampipes-model.ts     | 14 ++--
 ui/src/app/core-ui/core-ui.module.ts               |  2 +
 .../base/abstract-static-property.ts               |  4 ++
 .../static-collection.component.ts                 |  5 --
 .../static-file-input.component.css                |  4 --
 .../static-file-input.component.html               | 49 ++++++++++----
 .../static-file-input.component.ts                 | 47 +++++++++++--
 .../static-mapping-unary.component.ts              |  6 +-
 .../static-mapping/static-mapping.ts               |  4 --
 .../core/components/base-navigation.component.ts   |  5 ++
 .../file-overview/file-overview.component.html     | 64 ++++++++++++++++++
 .../file-overview/file-overview.component.scss}    | 30 +++++----
 .../file-overview/file-overview.component.ts       | 63 ++++++++++++++++++
 .../file-upload/file-upload-dialog.component.html  | 53 +++++++++++++++
 .../file-upload/file-upload-dialog.component.scss} | 21 +-----
 .../file-upload/file-upload-dialog.component.ts    | 76 ++++++++++++++++++++++
 ui/src/app/files/files.component.html              | 53 +++++++++++++++
 .../files.component.scss}                          | 27 ++++----
 ui/src/app/files/files.component.ts                | 50 ++++++++++++++
 ui/src/app/files/files.module.ts                   | 75 +++++++++++++++++++++
 ui/src/app/platform-services/apis/files.service.ts | 59 +++++++++++++++++
 ui/src/app/platform-services/platform.module.ts    |  2 +
 36 files changed, 795 insertions(+), 146 deletions(-)

diff --git a/streampipes-container/src/main/java/org/apache/streampipes/container/api/InvocableElement.java b/streampipes-container/src/main/java/org/apache/streampipes/container/api/InvocableElement.java
index 6178cd1..4eaed84 100644
--- a/streampipes-container/src/main/java/org/apache/streampipes/container/api/InvocableElement.java
+++ b/streampipes-container/src/main/java/org/apache/streampipes/container/api/InvocableElement.java
@@ -18,8 +18,7 @@
 
 package org.apache.streampipes.container.api;
 
-import org.eclipse.rdf4j.repository.RepositoryException;
-import org.eclipse.rdf4j.rio.RDFParseException;
+import com.fasterxml.jackson.core.JsonProcessingException;
 import org.apache.streampipes.commons.exceptions.SpRuntimeException;
 import org.apache.streampipes.container.declarer.Declarer;
 import org.apache.streampipes.container.declarer.InvocableDeclarer;
@@ -34,19 +33,16 @@ import org.apache.streampipes.model.staticproperty.Option;
 import org.apache.streampipes.sdk.extractor.AbstractParameterExtractor;
 import org.apache.streampipes.sdk.extractor.StaticPropertyExtractor;
 import org.apache.streampipes.serializers.json.GsonSerializer;
+import org.apache.streampipes.serializers.json.JacksonSerializer;
+import org.eclipse.rdf4j.repository.RepositoryException;
+import org.eclipse.rdf4j.rio.RDFParseException;
 
+import javax.ws.rs.*;
+import javax.ws.rs.core.MediaType;
 import java.io.IOException;
 import java.util.List;
 import java.util.Map;
 
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-
 public abstract class InvocableElement<I extends InvocableStreamPipesEntity, D extends Declarer,
         P extends AbstractParameterExtractor<I>> extends Element<D> {
 
@@ -111,19 +107,17 @@ public abstract class InvocableElement<I extends InvocableStreamPipesEntity, D e
     @POST
     @Path("{elementId}/output")
     public String fetchOutputStrategy(@PathParam("elementId") String elementId, String payload) {
-
-        I runtimeOptionsRequest = GsonSerializer.getGsonWithIds().fromJson(payload, clazz);
-        ResolvesContainerProvidedOutputStrategy<I, P> resolvesOutput =
-                (ResolvesContainerProvidedOutputStrategy<I, P>)
-                getDeclarerById
-                (elementId);
-
         try {
-            return GsonSerializer.getGsonWithIds().toJson(resolvesOutput.resolveOutputStrategy
+            I runtimeOptionsRequest = JacksonSerializer.getObjectMapper().readValue(payload, clazz);
+            ResolvesContainerProvidedOutputStrategy<I, P> resolvesOutput =
+                    (ResolvesContainerProvidedOutputStrategy<I, P>)
+                            getDeclarerById
+                                    (elementId);
+            return JacksonSerializer.getObjectMapper().writeValueAsString(resolvesOutput.resolveOutputStrategy
                     (runtimeOptionsRequest, getExtractor(runtimeOptionsRequest)));
-        } catch (SpRuntimeException e) {
+        } catch (SpRuntimeException | JsonProcessingException e) {
             e.printStackTrace();
-            return Util.toResponseString(runtimeOptionsRequest.getElementId(), false);
+            return Util.toResponseString(elementId, false);
         }
     }
 
diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/file/FileMetadata.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/file/FileMetadata.java
index 5c0162a..165f229 100644
--- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/file/FileMetadata.java
+++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/file/FileMetadata.java
@@ -18,7 +18,9 @@
 package org.apache.streampipes.model.client.file;
 
 import com.google.gson.annotations.SerializedName;
+import org.apache.streampipes.model.shared.annotation.TsModel;
 
+@TsModel
 public class FileMetadata {
 
   private @SerializedName("_id")
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/staticproperty/FileStaticProperty.java b/streampipes-model/src/main/java/org/apache/streampipes/model/staticproperty/FileStaticProperty.java
index e25d542..f90422e 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/staticproperty/FileStaticProperty.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/staticproperty/FileStaticProperty.java
@@ -23,6 +23,8 @@ import io.fogsy.empire.annotations.RdfsClass;
 import org.apache.streampipes.vocabulary.StreamPipes;
 
 import javax.persistence.Entity;
+import java.util.ArrayList;
+import java.util.List;
 
 @RdfsClass(StreamPipes.FILE_STATIC_PROPERTY)
 @Entity
@@ -36,18 +38,24 @@ public class FileStaticProperty extends StaticProperty {
   @RdfProperty(StreamPipes.HAS_LOCATION_PATH)
   private String locationPath;
 
+  @RdfProperty(StreamPipes.HAS_REQUIRED_FILETYPES)
+  private List<String> requiredFiletypes;
+
   public FileStaticProperty() {
     super(StaticPropertyType.FileStaticProperty);
+    this.requiredFiletypes = new ArrayList<>();
   }
 
   public FileStaticProperty(FileStaticProperty other) {
     super(other);
     this.endpointUrl = other.getEndpointUrl();
     this.locationPath = other.getLocationPath();
+    this.requiredFiletypes = other.getRequiredFiletypes();
   }
 
   public FileStaticProperty(String internalName, String label, String description) {
     super(StaticPropertyType.FileStaticProperty, internalName, label, description);
+    this.requiredFiletypes = new ArrayList<>();
   }
 
   public String getEndpointUrl() {
@@ -65,4 +73,12 @@ public class FileStaticProperty extends StaticProperty {
   public void setLocationPath(String locationPath) {
     this.locationPath = locationPath;
   }
+
+  public List<String> getRequiredFiletypes() {
+    return requiredFiletypes;
+  }
+
+  public void setRequiredFiletypes(List<String> requiredFiletypes) {
+    this.requiredFiletypes = requiredFiletypes;
+  }
 }
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/api/IPipelineElementFile.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/api/IPipelineElementFile.java
index 9ce0251..feb7c38 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/api/IPipelineElementFile.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/api/IPipelineElementFile.java
@@ -19,14 +19,13 @@ package org.apache.streampipes.rest.api;
 
 import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
 
-import java.io.InputStream;
-
 import javax.ws.rs.core.Response;
+import java.io.InputStream;
 
 public interface IPipelineElementFile {
 
   Response storeFile(String username, InputStream inputStream, FormDataContentDisposition formData);
 
-  Response getFileInfo();
+  Response getFileInfo(String filteredFiletypes);
 
 }
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineElementFile.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineElementFile.java
index ad2556a..bb94a69 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineElementFile.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineElementFile.java
@@ -17,23 +17,19 @@
  */
 package org.apache.streampipes.rest.impl;
 
-import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
-import org.glassfish.jersey.media.multipart.FormDataParam;
 import org.apache.streampipes.manager.file.FileManager;
 import org.apache.streampipes.model.client.file.FileMetadata;
 import org.apache.streampipes.rest.api.IPipelineElementFile;
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+import org.glassfish.jersey.media.multipart.FormDataParam;
 
-import java.io.InputStream;
-import java.util.List;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
+import javax.ws.rs.*;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
 
 @Path("/v2/users/{username}/files")
 public class PipelineElementFile extends AbstractRestInterface implements IPipelineElementFile {
@@ -54,9 +50,18 @@ public class PipelineElementFile extends AbstractRestInterface implements IPipel
   @GET
   @Produces(MediaType.APPLICATION_JSON)
   @Override
-  public Response getFileInfo() {
+  public Response getFileInfo(@QueryParam("filetypes") String filetypes) {
     List<FileMetadata> allFiles = getFileMetadataStorage().getAllFileMetadataDescriptions();
-    return ok(allFiles);
+    return filetypes != null ? ok(filterFiletypes(allFiles, filetypes)) : ok(allFiles);
+  }
+
+  private List<FileMetadata> filterFiletypes(List<FileMetadata> allFiles, String filetypes) {
+    return allFiles
+            .stream()
+            .filter(fileMetadata -> Arrays
+                    .stream(filetypes.split(","))
+                    .anyMatch(ft -> ft.equals(fileMetadata.getFiletype())))
+            .collect(Collectors.toList());
   }
 
 }
diff --git a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/AbstractConfigurablePipelineElementBuilder.java b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/AbstractConfigurablePipelineElementBuilder.java
index 5203879..f653ed7 100644
--- a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/AbstractConfigurablePipelineElementBuilder.java
+++ b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/AbstractConfigurablePipelineElementBuilder.java
@@ -21,6 +21,7 @@ import org.apache.streampipes.model.base.NamedStreamPipesEntity;
 import org.apache.streampipes.model.staticproperty.*;
 import org.apache.streampipes.sdk.StaticProperties;
 import org.apache.streampipes.sdk.helpers.CodeLanguage;
+import org.apache.streampipes.sdk.helpers.Filetypes;
 import org.apache.streampipes.sdk.helpers.Label;
 import org.apache.streampipes.sdk.helpers.Labels;
 import org.apache.streampipes.vocabulary.XSD;
@@ -695,6 +696,39 @@ public abstract class AbstractConfigurablePipelineElementBuilder<BU extends
 
   }
 
+  /**
+   *
+   * @param label The {@link org.apache.streampipes.sdk.helpers.Label} that describes why this parameter is needed in a
+   *    user-friendly manner.
+   * @param requiredFiletypes A list of {@link org.apache.streampipes.sdk.helpers.Filetypes} required filetypes the element supports.
+   * @return this
+   */
+  public BU requiredFile(Label label, Filetypes... requiredFiletypes) {
+    List<String> collectedFiletypes = new ArrayList<>();
+    Arrays.stream(requiredFiletypes).forEach(rf -> collectedFiletypes.addAll(rf.getFileExtensions()));
+
+    return requiredFile(label, collectedFiletypes.toArray(new String[0]));
+  }
+
+  /**
+   *
+   * @param label The {@link org.apache.streampipes.sdk.helpers.Label} that describes why this parameter is needed in a
+   *    user-friendly manner.
+   * @param requiredFiletypes A list of required filetypes (a string marking the file extension) the element supports.
+   * @return this
+   */
+  public BU requiredFile(Label label, String... requiredFiletypes) {
+    FileStaticProperty fp =  new FileStaticProperty(label.getInternalId(), label.getLabel(), label
+            .getDescription());
+
+    List<String> collectedFiletypes = Arrays.asList(requiredFiletypes);
+    fp.setRequiredFiletypes(collectedFiletypes);
+    this.staticProperties.add(fp);
+
+    return me();
+
+  }
+
   public BU requiredAlternatives(Label label, StaticPropertyAlternative... alternatives) {
     StaticPropertyAlternatives alternativesContainer =
             new StaticPropertyAlternatives(label.getInternalId(), label.getLabel(), label.getDescription());
diff --git a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/extractor/AbstractParameterExtractor.java b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/extractor/AbstractParameterExtractor.java
index f968301..f8069c0 100644
--- a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/extractor/AbstractParameterExtractor.java
+++ b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/extractor/AbstractParameterExtractor.java
@@ -25,14 +25,11 @@ import org.apache.streampipes.config.backend.BackendConfig;
 import org.apache.streampipes.model.SpDataStream;
 import org.apache.streampipes.model.base.InvocableStreamPipesEntity;
 import org.apache.streampipes.model.constants.PropertySelectorConstants;
-import org.apache.streampipes.model.schema.EventProperty;
-import org.apache.streampipes.model.schema.EventPropertyList;
-import org.apache.streampipes.model.schema.EventPropertyNested;
-import org.apache.streampipes.model.schema.EventPropertyPrimitive;
-import org.apache.streampipes.model.schema.PropertyScope;
+import org.apache.streampipes.model.schema.*;
 import org.apache.streampipes.model.staticproperty.*;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -94,17 +91,28 @@ public abstract class AbstractParameterExtractor<T extends InvocableStreamPipesE
   }
 
   public String fileContentsAsString(String internalName) throws IOException {
-    String filename =
-            getStaticPropertyByName(internalName, FileStaticProperty.class).getLocationPath();
+    String filename = selectedFilename(internalName);
     return Request.Get(makeFileRequestPath(filename)).execute().returnContent().asString();
   }
 
   public byte[] fileContentsAsByteArray(String internalName) throws IOException {
-    String filename =
-            getStaticPropertyByName(internalName, FileStaticProperty.class).getLocationPath();
+    String filename = selectedFilename(internalName);
     return Request.Get(makeFileRequestPath(filename)).execute().returnContent().asBytes();
   }
 
+  public InputStream fileContentsAsStream(String internalName) throws IOException {
+    String filename = selectedFilename(internalName);
+    return Request.Get(makeFileRequestPath(filename)).execute().returnContent().asStream();
+  }
+
+  public String selectedFilename(String internalName) {
+    return getStaticPropertyByName(internalName, FileStaticProperty.class).getLocationPath();
+  }
+
+  public String selectedFileFetchUrl(String internalName) {
+    return makeFileRequestPath(selectedFilename(internalName));
+  }
+
   private String makeFileRequestPath(String filename) {
     return BackendConfig.INSTANCE.getBackendUrl()
             + "/streampipes-backend/api/v2/noauth"
diff --git a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/extractor/StaticPropertyExtractor.java b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/extractor/StaticPropertyExtractor.java
index 32b6125..c6413e5 100644
--- a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/extractor/StaticPropertyExtractor.java
+++ b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/extractor/StaticPropertyExtractor.java
@@ -21,6 +21,7 @@ import org.apache.streampipes.model.SpDataStream;
 import org.apache.streampipes.model.graph.DataSinkInvocation;
 import org.apache.streampipes.model.staticproperty.StaticProperty;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class StaticPropertyExtractor extends AbstractParameterExtractor<DataSinkInvocation> {
@@ -42,6 +43,10 @@ public class StaticPropertyExtractor extends AbstractParameterExtractor<DataSink
     return new StaticPropertyExtractor(dataSinkInvocation);
   }
 
+  public static StaticPropertyExtractor from(List<StaticProperty> staticProperties) {
+    return from(staticProperties, new ArrayList<>());
+  }
+
   private static DataSinkInvocation makeGraph(List<StaticProperty> staticProperties,
                                               List<SpDataStream> inputStreams) {
     DataSinkInvocation dataSinkInvocation = new DataSinkInvocation();
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/api/IPipelineElementFile.java b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/helpers/Filetypes.java
similarity index 66%
copy from streampipes-rest/src/main/java/org/apache/streampipes/rest/api/IPipelineElementFile.java
copy to streampipes-sdk/src/main/java/org/apache/streampipes/sdk/helpers/Filetypes.java
index 9ce0251..8ac43d2 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/api/IPipelineElementFile.java
+++ b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/helpers/Filetypes.java
@@ -15,18 +15,26 @@
  * limitations under the License.
  *
  */
-package org.apache.streampipes.rest.api;
+package org.apache.streampipes.sdk.helpers;
 
-import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+import java.util.Arrays;
+import java.util.List;
 
-import java.io.InputStream;
+public enum Filetypes {
 
-import javax.ws.rs.core.Response;
+  CSV("csv"),
+  JSON("json"),
+  XML("xml"),
+  ZIP("zip"),
+  JPG("jpg", "jpeg");
 
-public interface IPipelineElementFile {
+  private List<String> fileExtensions;
 
-  Response storeFile(String username, InputStream inputStream, FormDataContentDisposition formData);
-
-  Response getFileInfo();
+  Filetypes(String... fileExtensions) {
+    this.fileExtensions = Arrays.asList(fileExtensions);
+  }
 
+  public List<String> getFileExtensions() {
+    return fileExtensions;
+  }
 }
diff --git a/streampipes-vocabulary/src/main/java/org/apache/streampipes/vocabulary/StreamPipes.java b/streampipes-vocabulary/src/main/java/org/apache/streampipes/vocabulary/StreamPipes.java
index ddea3f1..245cb36 100644
--- a/streampipes-vocabulary/src/main/java/org/apache/streampipes/vocabulary/StreamPipes.java
+++ b/streampipes-vocabulary/src/main/java/org/apache/streampipes/vocabulary/StreamPipes.java
@@ -399,4 +399,6 @@ public class StreamPipes {
   public static final String USER_DEFINED_OUTPUT_STRATEGY = NS + "UserDefinedOutputStrategy";
   public static final String PE_CONFIGURED = NS + "isPeConfigured" ;
 
+  public static final String HAS_REQUIRED_FILETYPES = NS + "hasRequiredFiletypes" ;
+
 }
diff --git a/ui/deployment/dev/config.yml b/ui/deployment/dev/config.yml
index ea0ca38..12508da 100644
--- a/ui/deployment/dev/config.yml
+++ b/ui/deployment/dev/config.yml
@@ -25,4 +25,5 @@ modules:
   - spDataExplorer
   - spAppOverview
   - spAdd
+  - spFiles
   - spConfiguration
diff --git a/ui/deployment/modules.yml b/ui/deployment/modules.yml
index e4cc001..74f1189 100644
--- a/ui/deployment/modules.yml
+++ b/ui/deployment/modules.yml
@@ -142,4 +142,19 @@ spDataExplorer:
   description: 'The data explorer lets you visually inspect historical data from your connected sources.'
   icon: 'search'
   homeImage: '/assets/img/home/configuration.png'
-  admin: false
\ No newline at end of file
+  admin: false
+spFiles:
+  ng5: True
+  ng1_templateUrl: ''
+  ng1_controller: ''
+  ng5_moduleName: 'FilesModule'
+  ng5_component: 'FilesComponent'
+  ng5_componentPath: './files/files.component'
+  path: './files/files.module'
+  link: 'files'
+  url: '/files'
+  title: 'File Management'
+  description: 'The file management module lets you upload and manage files that are used by adapters or pipeline elements.'
+  icon: 'folder'
+  homeImage: '/assets/img/home/configuration.png'
+  admin: true
\ No newline at end of file
diff --git a/ui/src/app/app-routing.module.ts b/ui/src/app/app-routing.module.ts
index 09b212f..f5f773a 100644
--- a/ui/src/app/app-routing.module.ts
+++ b/ui/src/app/app-routing.module.ts
@@ -39,6 +39,7 @@ import { DashboardComponent } from './dashboard/dashboard.component';
 import { DataExplorerComponent } from './data-explorer/data-explorer.component';
 import { AppOverviewComponent } from './app-overview/app-overview.component';
 import { AddComponent } from './add/add.component';
+import { FilesComponent } from './files/files.component';
 import { ConfigurationComponent } from './configuration/configuration.component';
 
 const routes: Routes = [
@@ -56,6 +57,7 @@ const routes: Routes = [
       { path: 'dataexplorer', component: DataExplorerComponent },
       { path: 'app-overview', component: AppOverviewComponent },
       { path: 'add', component: AddComponent },
+      { path: 'files', component: FilesComponent },
       { path: 'configuration', component: ConfigurationComponent },
       { path: 'notifications', component: NotificationsComponent },
       { path: 'info', component: InfoComponent },
diff --git a/ui/src/app/core-model/gen/streampipes-model-client.ts b/ui/src/app/core-model/gen/streampipes-model-client.ts
index 7e3d9d7..e9fdac0 100644
--- a/ui/src/app/core-model/gen/streampipes-model-client.ts
+++ b/ui/src/app/core-model/gen/streampipes-model-client.ts
@@ -19,7 +19,34 @@
 /* tslint:disable */
 /* eslint-disable */
 // @ts-nocheck
-// Generated using typescript-generator version 2.24.612 on 2020-09-13 16:47:42.
+// Generated using typescript-generator version 2.24.612 on 2020-09-14 21:40:09.
+
+export class FileMetadata {
+    createdAt: number;
+    createdByUser: string;
+    fileId: string;
+    filetype: string;
+    internalFilename: string;
+    lastModified: number;
+    originalFilename: string;
+    rev: string;
+
+    static fromData(data: FileMetadata, target?: FileMetadata): FileMetadata {
+        if (!data) {
+            return data;
+        }
+        const instance = target || new FileMetadata();
+        instance.fileId = data.fileId;
+        instance.rev = data.rev;
+        instance.internalFilename = data.internalFilename;
+        instance.originalFilename = data.originalFilename;
+        instance.filetype = data.filetype;
+        instance.createdAt = data.createdAt;
+        instance.lastModified = data.lastModified;
+        instance.createdByUser = data.createdByUser;
+        return instance;
+    }
+}
 
 export class MatchingResultMessage {
     description: string;
diff --git a/ui/src/app/core-model/gen/streampipes-model.ts b/ui/src/app/core-model/gen/streampipes-model.ts
index 7bbb71f..67be548 100644
--- a/ui/src/app/core-model/gen/streampipes-model.ts
+++ b/ui/src/app/core-model/gen/streampipes-model.ts
@@ -19,7 +19,7 @@
 /* tslint:disable */
 /* eslint-disable */
 // @ts-nocheck
-// Generated using typescript-generator version 2.24.612 on 2020-09-13 16:47:40.
+// Generated using typescript-generator version 2.24.612 on 2020-09-15 08:51:13.
 
 export class AbstractStreamPipesEntity {
     "@class": "org.apache.streampipes.model.base.NamedStreamPipesEntity" | "org.apache.streampipes.model.connect.adapter.AdapterDescription" | "org.apache.streampipes.model.connect.adapter.AdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.GenericAdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.SpecificAdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.AdapterStreamDescription" | "org.apache.streampipes.model.connect.adapter.G [...]
@@ -1438,6 +1438,7 @@ export class FileStaticProperty extends StaticProperty {
     "@class": "org.apache.streampipes.model.staticproperty.FileStaticProperty";
     endpointUrl: string;
     locationPath: string;
+    requiredFiletypes: string[];
 
     static fromData(data: FileStaticProperty, target?: FileStaticProperty): FileStaticProperty {
         if (!data) {
@@ -1447,6 +1448,7 @@ export class FileStaticProperty extends StaticProperty {
         super.fromData(data, instance);
         instance.endpointUrl = data.endpointUrl;
         instance.locationPath = data.locationPath;
+        instance.requiredFiletypes = __getCopyArrayFn(__identity<string>())(data.requiredFiletypes);
         return instance;
     }
 }
@@ -1561,9 +1563,9 @@ export class GenericAdapterSetDescription extends AdapterSetDescription implemen
         }
         const instance = target || new GenericAdapterSetDescription();
         super.fromData(data, instance);
-        instance.protocolDescription = ProtocolDescription.fromData(data.protocolDescription);
-        instance.formatDescription = FormatDescription.fromData(data.formatDescription);
         instance.eventSchema = EventSchema.fromData(data.eventSchema);
+        instance.formatDescription = FormatDescription.fromData(data.formatDescription);
+        instance.protocolDescription = ProtocolDescription.fromData(data.protocolDescription);
         return instance;
     }
 }
@@ -1580,9 +1582,9 @@ export class GenericAdapterStreamDescription extends AdapterStreamDescription im
         }
         const instance = target || new GenericAdapterStreamDescription();
         super.fromData(data, instance);
-        instance.protocolDescription = ProtocolDescription.fromData(data.protocolDescription);
-        instance.formatDescription = FormatDescription.fromData(data.formatDescription);
         instance.eventSchema = EventSchema.fromData(data.eventSchema);
+        instance.formatDescription = FormatDescription.fromData(data.formatDescription);
+        instance.protocolDescription = ProtocolDescription.fromData(data.protocolDescription);
         return instance;
     }
 }
@@ -2461,8 +2463,8 @@ export class SpDataSet extends SpDataStream {
         instance.supportedGrounding = EventGrounding.fromData(data.supportedGrounding);
         instance.datasetInvocationId = data.datasetInvocationId;
         instance.correspondingPipeline = data.correspondingPipeline;
-        instance.brokerHostname = data.brokerHostname;
         instance.actualTopicName = data.actualTopicName;
+        instance.brokerHostname = data.brokerHostname;
         return instance;
     }
 }
diff --git a/ui/src/app/core-ui/core-ui.module.ts b/ui/src/app/core-ui/core-ui.module.ts
index 8d16215..ae22d1e 100644
--- a/ui/src/app/core-ui/core-ui.module.ts
+++ b/ui/src/app/core-ui/core-ui.module.ts
@@ -72,6 +72,7 @@ import {DisplayRecommendedPipe} from "./static-properties/filter/display-recomme
 import {ColorPickerModule} from "ngx-color-picker";
 import {QuillModule} from "ngx-quill";
 import {CodemirrorModule} from "@ctrl/ngx-codemirror";
+import {MatAutocompleteModule} from "@angular/material/autocomplete";
 
 @NgModule({
     imports: [
@@ -83,6 +84,7 @@ import {CodemirrorModule} from "@ctrl/ngx-codemirror";
         ReactiveFormsModule,
         FormsModule,
         CdkTableModule,
+        MatAutocompleteModule,
         MatSnackBarModule,
         MatProgressSpinnerModule,
         MatDatepickerModule,
diff --git a/ui/src/app/core-ui/static-properties/base/abstract-static-property.ts b/ui/src/app/core-ui/static-properties/base/abstract-static-property.ts
index f4cb726..3ba15a9 100644
--- a/ui/src/app/core-ui/static-properties/base/abstract-static-property.ts
+++ b/ui/src/app/core-ui/static-properties/base/abstract-static-property.ts
@@ -60,4 +60,8 @@ export abstract class AbstractStaticPropertyRenderer<T extends StaticProperty> {
 
   }
 
+  emitUpdate(valid?: boolean) {
+    this.updateEmitter.emit(new ConfigurationInfo(this.staticProperty.internalName, valid));
+  }
+
 }
\ No newline at end of file
diff --git a/ui/src/app/core-ui/static-properties/static-collection/static-collection.component.ts b/ui/src/app/core-ui/static-properties/static-collection/static-collection.component.ts
index d8b3636..d5b1a18 100644
--- a/ui/src/app/core-ui/static-properties/static-collection/static-collection.component.ts
+++ b/ui/src/app/core-ui/static-properties/static-collection/static-collection.component.ts
@@ -17,7 +17,6 @@
  */
 
 import {Component, OnInit} from '@angular/core';
-import {ConfigurationInfo} from '../../../connect/model/ConfigurationInfo';
 import {StaticPropertyUtilService} from '../static-property-util.service';
 import {CollectionStaticProperty} from "../../../core-model/gen/streampipes-model";
 import {AbstractValidatedStaticPropertyRenderer} from "../base/abstract-validated-static-property";
@@ -38,10 +37,6 @@ export class StaticCollectionComponent
     ngOnInit() {
     }
 
-    emitUpdate(valid) {
-        this.updateEmitter.emit(new ConfigurationInfo(this.staticProperty.internalName, valid));
-    }
-
     add() {
         if (!this.staticProperty.members) {
             this.staticProperty.members = [];
diff --git a/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.css b/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.css
index 8619eb7..8ca8b6c 100644
--- a/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.css
+++ b/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.css
@@ -16,10 +16,6 @@
  *
  */
 
-#formWrapper {
-    height: 60px;
-}
-
 p {
     width: 100px;
     float: left;
diff --git a/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.html b/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.html
index b8425d5..5176f4d 100644
--- a/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.html
+++ b/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.html
@@ -16,17 +16,40 @@
   ~
   -->
 
-<div id="formWrapper" fxFlex="100" fxLayout="row">
-    <div fxFlex fxLayout="row">
-        <form fxFlex>
-
-            <mat-form-field style="width: 95%" (click)="fileInput.click();">
-                <input  matInput placeholder="{{staticProperty.label}}" disabled (value)="fileName">
+<div fxFlex="100" fxLayout="column">
+    <div fxFlex="100" fxLayout="column">
+        <div fxFlex="row">
+            <mat-radio-group [(ngModel)]="chooseExistingFile" color="primary">
+                <mat-radio-button style="margin-right:10px;" [value]="true">Choose existing file</mat-radio-button>
+                <mat-radio-button [value]="false">Upload new file</mat-radio-button>
+            </mat-radio-group>
+        </div>
+        <div *ngIf="chooseExistingFile && filesLoaded">
+            <mat-form-field>
+                <input type="text"
+                       placeholder="Select file"
+                       [(ngModel)]="selectedFile"
+                       matInput
+                       [matAutocomplete]="auto">
+                <button mat-button *ngIf="selectedFile" matSuffix mat-icon-button aria-label="Clear" (click)="selectedFile={}">
+                    <mat-icon>close</mat-icon>
+                </button>
+                <mat-autocomplete #auto="matAutocomplete" (optionSelected)="selectOption($event.option.value)" [displayWith]="displayFn">
+                    <mat-option *ngFor="let fileMetadata of fileMetadata" [value]="fileMetadata">
+                        {{fileMetadata.originalFilename}}
+                    </mat-option>
+                </mat-autocomplete>
+            </mat-form-field>
+        </div>
+        <div *ngIf="!chooseExistingFile">
+            <mat-form-field style="width: 95%" (click)="fileInput.click();" *ngIf="!chooseExistingFile">
+                <input matInput placeholder="{{staticProperty.label}}" disabled (value)="fileName">
                 <input #fileInput type="file" style="display:none;"
                        (change)="handleFileInput($event.target.files)">
                 <div>
                     {{fileName}}
-                    <mat-progress-bar mode="determinate" value="{{uploadStatus}}" *ngIf="uploadStatus > 0"></mat-progress-bar>
+                    <mat-progress-bar mode="determinate" value="{{uploadStatus}}"
+                                      *ngIf="uploadStatus > 0"></mat-progress-bar>
                 </div>
 
 
@@ -41,12 +64,12 @@
                 </mat-error>
 
             </mat-form-field>
-        </form>
-        <!--<div fxLayoutAlign="center none">-->
-        <div>
-            <button color="primary" mat-raised-button (click)="upload()">
-                Upload
-            </button>
+            <!--<div fxLayoutAlign="center none">-->
+            <div>
+                <button color="primary" mat-raised-button (click)="upload()">
+                    Upload
+                </button>
+            </div>
         </div>
 
     </div>
diff --git a/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.ts b/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.ts
index d8ccbf3..cdf372f 100644
--- a/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.ts
+++ b/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.ts
@@ -22,6 +22,8 @@ import {StaticFileRestService} from './static-file-rest.service';
 import {HttpEventType, HttpResponse} from '@angular/common/http';
 import {AbstractStaticPropertyRenderer} from "../base/abstract-static-property";
 import {FileStaticProperty} from "../../../core-model/gen/streampipes-model";
+import {FilesService} from "../../../platform-services/apis/files.service";
+import {FileMetadata} from "../../../core-model/gen/streampipes-model-client";
 
 
 @Component({
@@ -33,6 +35,8 @@ export class StaticFileInputComponent extends AbstractStaticPropertyRenderer<Fil
 
     @Output() inputEmitter: EventEmitter<Boolean> = new EventEmitter<Boolean>();
 
+    chooseExistingFile: boolean = true;
+
     inputValue: String;
     fileName: String;
 
@@ -43,12 +47,38 @@ export class StaticFileInputComponent extends AbstractStaticPropertyRenderer<Fil
 
     uploadStatus = 0;
 
+    fileMetadata: FileMetadata[];
+    selectedFile: FileMetadata;
+
+    filesLoaded: boolean = false;
+
     constructor(public staticPropertyUtil: StaticPropertyUtilService,
-                private staticFileRestService: StaticFileRestService){
+                private staticFileRestService: StaticFileRestService,
+                private filesService: FilesService){
         super();
     }
 
     ngOnInit() {
+        this.fetchFileMetadata();
+    }
+
+    fetchFileMetadata() {
+        this.filesService.getFileMetadata(this.staticProperty.requiredFiletypes).subscribe(fm => {
+            this.fileMetadata = fm;
+            if (this.staticProperty.locationPath) {
+                this.selectedFile =
+                    this.fileMetadata.find(fm => fm.internalFilename === this.staticProperty.locationPath);
+            } else {
+                if (this.fileMetadata.length > 0) {
+                    this.selectedFile = this.fileMetadata[0];
+                    this.staticProperty.locationPath = this.selectedFile.internalFilename;
+                    this.emitUpdate(true);
+                } else {
+                    this.chooseExistingFile = false;
+                }
+            }
+            this.filesLoaded = true;
+        });
     }
 
     handleFileInput(files: any) {
@@ -60,19 +90,18 @@ export class StaticFileInputComponent extends AbstractStaticPropertyRenderer<Fil
     upload() {
         this.uploadStatus = 0;
         if (this.selectedUploadFile !== undefined) {
-            this.staticFileRestService.uploadFile(this.adapterId, this.selectedUploadFile).subscribe(
+            this.filesService.uploadFile(this.selectedUploadFile).subscribe(
                 event => {
                     if (event.type == HttpEventType.UploadProgress) {
                         this.uploadStatus = Math.round(100 * event.loaded / event.total);
                     } else if (event instanceof HttpResponse) {
+                        this.fetchFileMetadata();
                         (<FileStaticProperty> (this.staticProperty)).locationPath = event.body.notifications[0].title;
-                               this.valueChange(true);
+                               this.emitUpdate(true);
                     }
                 },
                 error => {
-                    this.valueChange(false);
                 },
-
             );
         }
     }
@@ -89,4 +118,12 @@ export class StaticFileInputComponent extends AbstractStaticPropertyRenderer<Fil
         this.inputEmitter.emit(this.hasInput);
     }
 
+    selectOption(fileMetadata: FileMetadata) {
+        this.staticProperty.locationPath = fileMetadata.internalFilename;
+    }
+
+    displayFn(fileMetadata: FileMetadata) {
+        return fileMetadata ? fileMetadata.originalFilename : "";
+    }
+
 }
\ No newline at end of file
diff --git a/ui/src/app/core-ui/static-properties/static-mapping-unary/static-mapping-unary.component.ts b/ui/src/app/core-ui/static-properties/static-mapping-unary/static-mapping-unary.component.ts
index 4d7bb79..0fef3ac 100644
--- a/ui/src/app/core-ui/static-properties/static-mapping-unary/static-mapping-unary.component.ts
+++ b/ui/src/app/core-ui/static-properties/static-mapping-unary/static-mapping-unary.component.ts
@@ -22,8 +22,6 @@ import {StaticPropertyUtilService} from '../static-property-util.service';
 import {PropertySelectorService} from "../../../services/property-selector.service";
 import {StaticMappingComponent} from "../static-mapping/static-mapping";
 import {MappingPropertyUnary} from "../../../core-model/gen/streampipes-model";
-import {ConfigurationInfo} from "../../../connect/model/ConfigurationInfo";
-
 
 @Component({
     selector: 'app-static-mapping-unary',
@@ -47,7 +45,7 @@ export class StaticMappingUnaryComponent extends StaticMappingComponent<MappingP
             .forEach(ep => ep.propertySelector = this.firstStreamPropertySelector + ep.runtimeName);
         if (!this.staticProperty.selectedProperty) {
             this.staticProperty.selectedProperty = this.availableProperties[0].propertySelector;
-            this.emitUpdate();
+            this.emitUpdate(true);
         }
         this.addValidator(this.staticProperty.selectedProperty, Validators.required);
         this.enableValidators();
@@ -58,7 +56,7 @@ export class StaticMappingUnaryComponent extends StaticMappingComponent<MappingP
 
     onValueChange(value: any) {
         this.staticProperty.selectedProperty = value;
-        this.emitUpdate();
+        this.emitUpdate(true);
     }
 
 }
\ No newline at end of file
diff --git a/ui/src/app/core-ui/static-properties/static-mapping/static-mapping.ts b/ui/src/app/core-ui/static-properties/static-mapping/static-mapping.ts
index e131802..f237a57 100644
--- a/ui/src/app/core-ui/static-properties/static-mapping/static-mapping.ts
+++ b/ui/src/app/core-ui/static-properties/static-mapping/static-mapping.ts
@@ -75,8 +75,4 @@ export abstract class StaticMappingComponent<T extends MappingProperty>
             return EventPropertyNested.fromData(ep, new EventPropertyNested());
         }
     }
-
-    emitUpdate() {
-        this.updateEmitter.emit(new ConfigurationInfo(this.staticProperty.internalName, true));
-    }
 }
\ No newline at end of file
diff --git a/ui/src/app/core/components/base-navigation.component.ts b/ui/src/app/core/components/base-navigation.component.ts
index de09dd7..e1a9ab0 100644
--- a/ui/src/app/core/components/base-navigation.component.ts
+++ b/ui/src/app/core/components/base-navigation.component.ts
@@ -71,6 +71,11 @@ export abstract class BaseNavigationComponent {
         icon: 'cloud_download'
     },
     {
+        link: 'files',
+        title: 'File Management',
+        icon: 'folder'
+    },
+    {
         link: 'configuration',
         title: 'Configuration',
         icon: 'settings'
diff --git a/ui/src/app/files/components/file-overview/file-overview.component.html b/ui/src/app/files/components/file-overview/file-overview.component.html
new file mode 100644
index 0000000..7402504
--- /dev/null
+++ b/ui/src/app/files/components/file-overview/file-overview.component.html
@@ -0,0 +1,64 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<div fxFlex="100" fxLayout="column" *ngIf="filesAvailable" style="margin:1px;">
+    <table fxFlex="100" mat-table [dataSource]="dataSource" style="width: 100%;">
+        <ng-container matColumnDef="filename">
+            <th mat-header-cell *matHeaderCellDef> Filename</th>
+            <td mat-cell *matCellDef="let fileMetadata">
+                <h4>{{fileMetadata.originalFilename}}</h4>
+            </td>
+        </ng-container>
+        <ng-container matColumnDef="filetype">
+            <th mat-header-cell *matHeaderCellDef> Filetype</th>
+            <td mat-cell *matCellDef="let fileMetadata">
+                <span class="filetype-container">{{fileMetadata.filetype}}</span>
+            </td>
+        </ng-container>
+        <ng-container matColumnDef="uploaded">
+            <th mat-header-cell *matHeaderCellDef> Uploaded</th>
+            <td mat-cell *matCellDef="let fileMetadata">
+                <h5>{{fileMetadata.createdAt | date:'dd.MM.yyyy HH:mm'}}</h5>
+            </td>
+        </ng-container>
+
+        <ng-container matColumnDef="action">
+            <th mat-header-cell *matHeaderCellDef> Action</th>
+            <td mat-cell *matCellDef="let fileMetadata">
+                <div fxLayout="row">
+                    <span fxFlex fxFlexOrder="3" fxLayout="row" fxLayoutAlign="center center">
+                    <button color="primary" mat-button mat-icon-button matTooltip="Delete pipeline" matTooltipPosition="above"
+                            (click)="deleteFile(fileMetadata)">
+                        <i class="material-icons">delete</i>
+                    </button>
+                </span>
+                </div>
+            </td>
+        </ng-container>
+
+        <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+        <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
+
+    </table>
+    <div fxFlex="100" fxLayoutAlign="end end">
+        <mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" [pageSize]="10"></mat-paginator>
+    </div>
+</div>
+<div fxFlex="100" fxLayout="column" fxLayoutAlign="center center" *ngIf="!filesAvailable">
+    <h5>(no files available)</h5>
+</div>
\ No newline at end of file
diff --git a/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.css b/ui/src/app/files/components/file-overview/file-overview.component.scss
similarity index 71%
copy from ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.css
copy to ui/src/app/files/components/file-overview/file-overview.component.scss
index 8619eb7..7b83d93 100644
--- a/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.css
+++ b/ui/src/app/files/components/file-overview/file-overview.component.scss
@@ -16,23 +16,25 @@
  *
  */
 
-#formWrapper {
-    height: 60px;
+.mat-table {
+  background: #FAFAFA;
 }
 
-p {
-    width: 100px;
-    float: left;
-    margin: 20px  15px 0 0;
-}
-form {
-    float: left;
+.mat-paginator {
+  border-top: 1px solid rgba(0,0,0,.12);
+  background: #FAFAFA;
 }
 
-.green-icon {
-    color: green;
+.mat-row:nth-child(even) {
+  background-color: #FAFAFA;
 }
-
-.green-icon svg {
-    fill: green;
+.mat-row:nth-child(odd) {
+  background-color:#ffffff;
 }
+
+.filetype-container {
+  background: #00aeff;
+  color: white;
+  padding: 5px 15px;
+  border-radius: 5px;
+}
\ No newline at end of file
diff --git a/ui/src/app/files/components/file-overview/file-overview.component.ts b/ui/src/app/files/components/file-overview/file-overview.component.ts
new file mode 100644
index 0000000..e2ec5ea
--- /dev/null
+++ b/ui/src/app/files/components/file-overview/file-overview.component.ts
@@ -0,0 +1,63 @@
+/*
+ * 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, OnInit, ViewChild} from "@angular/core";
+import {FilesService} from "../../../platform-services/apis/files.service";
+import {FileMetadata} from "../../../core-model/gen/streampipes-model-client";
+import {MatTableDataSource} from "@angular/material/table";
+import {MatPaginator} from "@angular/material/paginator";
+
+@Component({
+  selector: 'file-overview',
+  templateUrl: './file-overview.component.html',
+  styleUrls: ['./file-overview.component.scss']
+})
+export class FileOverviewComponent implements OnInit {
+
+  displayedColumns: string[] = ['filename', 'filetype', 'uploaded', 'action'];
+
+  dataSource: MatTableDataSource<FileMetadata>;
+  filesAvailable: boolean = false;
+
+  @ViewChild(MatPaginator) paginator: MatPaginator;
+  pageSize: number = 1;
+
+  constructor(private filesService: FilesService) {
+
+  }
+
+  ngOnInit() {
+    this.refreshFiles();
+  }
+
+  refreshFiles() {
+    console.log("refreshing files");
+    this.filesService.getFileMetadata().subscribe(fm => {
+      console.log(fm);
+      this.dataSource = new MatTableDataSource<FileMetadata>(fm);
+      this.filesAvailable = true;
+      setTimeout(() => {
+        this.dataSource.paginator = this.paginator;
+      });
+    });
+  }
+
+  deleteFile(fileMetadata: FileMetadata) {
+
+  }
+}
\ No newline at end of file
diff --git a/ui/src/app/files/dialog/file-upload/file-upload-dialog.component.html b/ui/src/app/files/dialog/file-upload/file-upload-dialog.component.html
new file mode 100644
index 0000000..2ec920f
--- /dev/null
+++ b/ui/src/app/files/dialog/file-upload/file-upload-dialog.component.html
@@ -0,0 +1,53 @@
+<!--
+~ 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 fxFlex="100">
+            <div fxFlex="100" style="margin:5px;width:100%">
+                <mat-form-field style="width: 95%" (click)="fileInput.click();">
+                    <input matInput placeholder="File" disabled (value)="fileName">
+                    <input #fileInput type="file" style="display:none;"
+                           (change)="handleFileInput($event.target.files)">
+                    <div>
+                        {{fileName}}
+                        <mat-progress-bar mode="determinate" value="{{uploadStatus}}" *ngIf="uploadStatus > 0"></mat-progress-bar>
+                    </div>
+                    <button color="primary" matSuffix
+                            mat-button style="min-width: 0px">
+                        <mat-icon *ngIf="uploadStatus < 99">insert_drive_file</mat-icon>
+                        <mat-icon *ngIf="uploadStatus == 100" class="green-icon">check_circle</mat-icon>
+                    </button>
+                    <mat-error *ngIf="!hasInput">
+                        {{errorMessage}}
+                    </mat-error>
+                </mat-form-field>
+            </div>
+        </div>
+    </div>
+    <mat-divider></mat-divider>
+    <div class="sp-dialog-actions">
+        <button mat-button mat-raised-button color="primary" (click)="store()" style="margin-right:10px;">
+            Store file
+        </button>
+        <button mat-button mat-raised-button class="mat-basic" (click)="cancel()" style="margin-right:10px;">
+            Cancel
+        </button>
+    </div>
+</div>
\ No newline at end of file
diff --git a/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.css b/ui/src/app/files/dialog/file-upload/file-upload-dialog.component.scss
similarity index 79%
copy from ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.css
copy to ui/src/app/files/dialog/file-upload/file-upload-dialog.component.scss
index 8619eb7..d25ee74 100644
--- a/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.css
+++ b/ui/src/app/files/dialog/file-upload/file-upload-dialog.component.scss
@@ -16,23 +16,4 @@
  *
  */
 
-#formWrapper {
-    height: 60px;
-}
-
-p {
-    width: 100px;
-    float: left;
-    margin: 20px  15px 0 0;
-}
-form {
-    float: left;
-}
-
-.green-icon {
-    color: green;
-}
-
-.green-icon svg {
-    fill: green;
-}
+@import 'src/scss/sp/sp-dialog';
\ No newline at end of file
diff --git a/ui/src/app/files/dialog/file-upload/file-upload-dialog.component.ts b/ui/src/app/files/dialog/file-upload/file-upload-dialog.component.ts
new file mode 100644
index 0000000..52b5ffa
--- /dev/null
+++ b/ui/src/app/files/dialog/file-upload/file-upload-dialog.component.ts
@@ -0,0 +1,76 @@
+/*
+ * 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, OnInit} from '@angular/core';
+import {DialogRef} from "../../../core-ui/dialog/base-dialog/dialog-ref";
+import {HttpEventType, HttpResponse} from "@angular/common/http";
+import {FilesService} from "../../../platform-services/apis/files.service";
+
+@Component({
+  selector: 'file-upload-dialog-component',
+  templateUrl: './file-upload-dialog.component.html',
+  styleUrls: ['./file-upload-dialog.component.scss']
+})
+export class FileUploadDialogComponent implements OnInit {
+
+  inputValue: String;
+  fileName: String;
+
+  selectedUploadFile: File;
+
+  hasInput: Boolean;
+  errorMessage = "Please enter a value";
+
+  uploadStatus = 0;
+
+  constructor(private dialogRef: DialogRef<FileUploadDialogComponent>,
+              private filesService: FilesService) {
+
+  }
+
+  ngOnInit(): void {
+  }
+
+  handleFileInput(files: any) {
+    this.selectedUploadFile = files[0];
+    this.fileName = this.selectedUploadFile.name;
+    this.uploadStatus = 0;
+  }
+
+  store() {
+    this.uploadStatus = 0;
+    if (this.selectedUploadFile !== undefined) {
+      this.filesService.uploadFile(this.selectedUploadFile).subscribe(
+          event => {
+            if (event.type == HttpEventType.UploadProgress) {
+              this.uploadStatus = Math.round(100 * event.loaded / event.total);
+            } else if (event instanceof HttpResponse) {
+              this.dialogRef.close();
+            }
+          },
+          error => {
+          },
+      );
+    }
+  }
+
+  cancel() {
+    this.dialogRef.close();
+  }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/files/files.component.html b/ui/src/app/files/files.component.html
new file mode 100644
index 0000000..1dc2825
--- /dev/null
+++ b/ui/src/app/files/files.component.html
@@ -0,0 +1,53 @@
+<!--
+  ~ 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" class="page-container">
+    <div fxLayout="row" style="padding:0px;background-color:#f6f6f6;">
+        <div fxFlex="100" style="line-height:24px;border-bottom:1px solid #ccc">
+            <div fxFlex="100" fxLayout="row">
+                <div fxFlex fxLayoutAlign="start center">
+                    <mat-tab-group>
+                        <mat-tab label="Files"></mat-tab>
+                    </mat-tab-group>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div fxLayout="row" class="fixed-height add-options">
+        <div class="add-options-item" fxLayoutAlign="start center" fxLayout="row" style="padding-left:5px;">
+            <div fxFlex="100" fxLayout="row">
+                <button mat-button mat-raised-button color="primary"
+                        (click)="openFileUploadDialog()" class="mr-10">
+                    <i class="material-icons">cloud_upload</i>
+                    &nbsp;Upload new file
+                </button>
+            </div>
+        </div>
+    </div>
+
+    <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100">
+        <div class="assemblyOptions sp-blue-bg mt-20" style="padding:5px;">
+            <div fxLayout="row" fxLayoutAlign="start center">
+                <h4>My files</h4>
+            </div>
+        </div>
+        <div class="sp-blue-border">
+            <file-overview #fileOverviewComponent></file-overview>
+        </div>
+    </div>
+</div>
diff --git a/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.css b/ui/src/app/files/files.component.scss
similarity index 77%
copy from ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.css
copy to ui/src/app/files/files.component.scss
index 8619eb7..35192f2 100644
--- a/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.css
+++ b/ui/src/app/files/files.component.scss
@@ -16,23 +16,18 @@
  *
  */
 
-#formWrapper {
-    height: 60px;
+.add-options {
+  background-color:#f6f6f6;
+  border-bottom: 1px solid #cccccc;
+  padding-top:10px;
+  padding-bottom:10px;
 }
 
-p {
-    width: 100px;
-    float: left;
-    margin: 20px  15px 0 0;
-}
-form {
-    float: left;
-}
-
-.green-icon {
-    color: green;
+.page-container-padding-inner {
+  margin: 20px;
 }
 
-.green-icon svg {
-    fill: green;
-}
+.add-options-item {
+  display: inline;
+  margin-right: 10px;
+}
\ No newline at end of file
diff --git a/ui/src/app/files/files.component.ts b/ui/src/app/files/files.component.ts
new file mode 100644
index 0000000..6cb89f4
--- /dev/null
+++ b/ui/src/app/files/files.component.ts
@@ -0,0 +1,50 @@
+/*
+ * 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, OnInit, ViewChild} from "@angular/core";
+import {PanelType} from "../core-ui/dialog/base-dialog/base-dialog.model";
+import {DialogService} from "../core-ui/dialog/base-dialog/base-dialog.service";
+import {FileUploadDialogComponent} from "./dialog/file-upload/file-upload-dialog.component";
+
+@Component({
+  templateUrl: './files.component.html',
+  styleUrls: ['./files.component.scss']
+})
+export class FilesComponent implements OnInit {
+
+  @ViewChild("fileOverviewComponent") fileOverviewComponent;
+
+  constructor(private dialogService: DialogService) {
+
+  }
+
+  ngOnInit() {
+
+  }
+
+  openFileUploadDialog() {
+    const dialogRef = this.dialogService.open(FileUploadDialogComponent,{
+      panelType: PanelType.SLIDE_IN_PANEL,
+      title: "Upload file",
+      width: "40vw",
+    });
+
+    dialogRef.afterClosed().subscribe(() => this.fileOverviewComponent.refreshFiles());
+  }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/files/files.module.ts b/ui/src/app/files/files.module.ts
new file mode 100644
index 0000000..398caeb
--- /dev/null
+++ b/ui/src/app/files/files.module.ts
@@ -0,0 +1,75 @@
+/*
+ * 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 {NgModule} from "@angular/core";
+import {CommonModule} from "@angular/common";
+import {FlexLayoutModule} from "@angular/flex-layout";
+import {MatButtonModule} from "@angular/material/button";
+import {MatGridListModule} from "@angular/material/grid-list";
+import {MatIconModule} from "@angular/material/icon";
+import {MatDividerModule} from "@angular/material/divider";
+import {MatListModule} from "@angular/material/list";
+import {FilesComponent} from "./files.component";
+import {MatTabsModule} from "@angular/material/tabs";
+import {CoreUiModule} from "../core-ui/core-ui.module";
+import {PlatformServicesModule} from "../platform-services/platform.module";
+import {FileUploadDialogComponent} from "./dialog/file-upload/file-upload-dialog.component";
+import {FormsModule, ReactiveFormsModule} from "@angular/forms";
+import {MatFormFieldModule} from "@angular/material/form-field";
+import {MatProgressBarModule} from "@angular/material/progress-bar";
+import {MatInputModule} from "@angular/material/input";
+import {ServicesModule} from "../services/services.module";
+import {FileOverviewComponent} from "./components/file-overview/file-overview.component";
+import {MatTableModule} from "@angular/material/table";
+import {MatPaginatorModule} from "@angular/material/paginator";
+import {MatChipsModule} from "@angular/material/chips";
+
+@NgModule({
+  imports: [
+    CommonModule,
+    CoreUiModule,
+    FlexLayoutModule,
+    FormsModule,
+    ReactiveFormsModule,
+    MatButtonModule,
+    MatChipsModule,
+    MatFormFieldModule,
+    MatGridListModule,
+    MatIconModule,
+    MatInputModule,
+    MatDividerModule,
+    MatListModule,
+    MatPaginatorModule,
+    MatProgressBarModule,
+    MatTableModule,
+    MatTabsModule,
+    PlatformServicesModule,
+    ServicesModule
+  ],
+  declarations: [
+    FilesComponent,
+    FileOverviewComponent,
+    FileUploadDialogComponent
+  ],
+  providers: [],
+  entryComponents: [
+    FilesComponent
+  ]
+})
+export class FilesModule {
+}
\ No newline at end of file
diff --git a/ui/src/app/platform-services/apis/files.service.ts b/ui/src/app/platform-services/apis/files.service.ts
new file mode 100644
index 0000000..f07a1bf
--- /dev/null
+++ b/ui/src/app/platform-services/apis/files.service.ts
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import {Injectable} from "@angular/core";
+import {HttpClient, HttpEvent, HttpParams, HttpRequest} from "@angular/common/http";
+import {PlatformServicesCommons} from "./commons.service";
+import {Observable} from "rxjs";
+import {map} from "rxjs/operators";
+import {FileMetadata} from "../../core-model/gen/streampipes-model-client";
+
+@Injectable()
+export class FilesService {
+
+  constructor(private http: HttpClient,
+              private platformServicesCommons: PlatformServicesCommons) {
+
+  }
+
+  uploadFile(file: File): Observable<HttpEvent<any>> {
+    const data: FormData = new FormData();
+    data.append('file_upload', file, file.name);
+
+    let params = new HttpParams();
+    const options = {
+      params: params,
+      reportProgress: true,
+    };
+
+    const req = new HttpRequest('POST', this.platformServicesCommons.authUserBasePath() + "/files", data, options);
+    return this.http.request(req);
+  }
+
+  getFileMetadata(requiredFiletypes?: string[]): Observable<FileMetadata[]> {
+    let requiredFiletypeAppendix: string = "";
+    if (requiredFiletypes && requiredFiletypes.length > 0) {
+      requiredFiletypeAppendix = "?filetypes=" + requiredFiletypes.join();
+    }
+    return this.http
+        .get(this.platformServicesCommons.authUserBasePath() + "/files" + requiredFiletypeAppendix)
+        .pipe(map(response => {
+          return (response as any[]).map(fm => FileMetadata.fromData(fm));
+        }));
+  }
+}
\ No newline at end of file
diff --git a/ui/src/app/platform-services/platform.module.ts b/ui/src/app/platform-services/platform.module.ts
index 4ce0f72..e96fc12 100644
--- a/ui/src/app/platform-services/platform.module.ts
+++ b/ui/src/app/platform-services/platform.module.ts
@@ -21,11 +21,13 @@ import {PipelineElementService} from "./apis/pipeline-element.service";
 import {PipelineService} from "./apis/pipeline.service";
 import {PlatformServicesCommons} from "./apis/commons.service";
 import {PipelineElementEndpointService} from "./apis/pipeline-element-endpoint.service";
+import {FilesService} from "./apis/files.service";
 
 @NgModule({
   imports: [],
   declarations: [],
   providers: [
+    FilesService,
     PlatformServicesCommons,
     PipelineElementEndpointService,
     //PipelineTemplateService,