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>
+ 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,