Merge branch 'dev' into STREAMPIPES-527
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index af9fb37..f6eea9e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml
@@ -114,6 +114,14 @@ push: true tags: ${{ env.DOCKERHUB_APACHE_REPO }}/pipeline-elements-all-flink:${{ env.MVN_VERSION }} + - name: Build and Push Docker Image extensions-all-iiot + uses: docker/build-push-action@v2 + with: + context: ./streampipes-extensions/streampipes-extensions-all-iiot + platforms: linux/amd64,linux/arm64/v8,linux/arm/v7 + push: true + tags: ${{ env.DOCKERHUB_APACHE_REPO }}/extensions-all-iiot:${{ env.MVN_VERSION }} + - name: Build and Push Docker Image pipeline-elements-all-jvm uses: docker/build-push-action@v2 with: @@ -122,10 +130,11 @@ push: true tags: ${{ env.DOCKERHUB_APACHE_REPO }}/pipeline-elements-all-jvm:${{ env.MVN_VERSION }} - - name: Build and Push Docker Image sinks-internal-jvm + - name: Build and Push Docker Image sources-watertank-simulator uses: docker/build-push-action@v2 with: - context: ./streampipes-extensions/streampipes-sinks-internal-jvm + context: ./streampipes-extensions/streampipes-sources-watertank-simulator platforms: linux/amd64,linux/arm64/v8,linux/arm/v7 push: true - tags: ${{ env.DOCKERHUB_APACHE_REPO }}/sinks-internal-jvm:${{ env.MVN_VERSION }} \ No newline at end of file + tags: ${{ env.DOCKERHUB_APACHE_REPO }}/sources-watertank-simulator:${{ env.MVN_VERSION }} +
diff --git a/.gitignore b/.gitignore index 4b3258f..324db87 100644 --- a/.gitignore +++ b/.gitignore
@@ -83,7 +83,7 @@ /test_data/ ui/src/assets/lib/apps/* - +ui/.angular # compiled output ui/dist
diff --git a/.idea/runConfigurations/all_extensions_jvm.xml b/.idea/runConfigurations/all_extensions_jvm.xml index 20063d0..103f85d 100644 --- a/.idea/runConfigurations/all_extensions_jvm.xml +++ b/.idea/runConfigurations/all_extensions_jvm.xml
@@ -1,14 +1,14 @@ <component name="ProjectRunConfigurationManager"> <configuration default="false" name="all-extensions-jvm" type="Application" factoryName="Application"> <envs> - <env name="SP_PORT" value="7023" /> - <env name="SP_DEBUG" value="true" /> <env name="SP_COUCHDB_HOST" value="localhost" /> - <env name="SP_JMS_HOST" value="localhost" /> - <env name="SP_JMS_PORT" value="61616" /> <env name="SP_DATA_LAKE_HOST" value="localhost" /> <env name="SP_DATA_LAKE_PORT" value="8086" /> + <env name="SP_DEBUG" value="true" /> <env name="SP_IMAGE_STORAGE_LOCATION" value=".streampipes/spImages/" /> + <env name="SP_JMS_HOST" value="localhost" /> + <env name="SP_JMS_PORT" value="61616" /> + <env name="SP_PORT" value="7023" /> </envs> <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.extensions.all.jvm.AllExtensionsInit" /> <module name="streampipes-extensions-all-jvm" /> @@ -27,4 +27,4 @@ <option name="Make" enabled="true" /> </method> </configuration> -</component> \ No newline at end of file +</component>
diff --git a/.idea/runConfigurations/all_pipeline_elements_jvm.xml b/.idea/runConfigurations/all_pipeline_elements_jvm.xml index 08521f8..60c64ea 100644 --- a/.idea/runConfigurations/all_pipeline_elements_jvm.xml +++ b/.idea/runConfigurations/all_pipeline_elements_jvm.xml
@@ -1,7 +1,5 @@ <component name="ProjectRunConfigurationManager"> <configuration default="false" name="all-pipeline-elements-jvm" type="Application" factoryName="Application"> - <option name="ALTERNATIVE_JRE_PATH" value="/Library/Java/JavaVirtualMachines/jdk-17.0.1.jdk/Contents/Home" /> - <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" /> <envs> <env name="SP_PORT" value="7023" /> <env name="SP_DEBUG" value="true" />
diff --git a/.idea/runConfigurations/backend.xml b/.idea/runConfigurations/backend.xml index fb5908b..344ff6e 100644 --- a/.idea/runConfigurations/backend.xml +++ b/.idea/runConfigurations/backend.xml
@@ -1,20 +1,19 @@ <component name="ProjectRunConfigurationManager"> <configuration default="false" name="backend" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot"> - <module name="streampipes-backend" /> - <option name="SPRING_BOOT_MAIN_CLASS" value="org.apache.streampipes.backend.StreamPipesBackendApplication" /> - <option name="ALTERNATIVE_JRE_PATH" value="11" /> - <option name="SHORTEN_COMMAND_LINE" value="NONE" /> + <option name="ACTIVE_PROFILES" /> <envs> - <env name="SP_COUCHDB_HOST" value="localhost" /> <env name="SP_BACKEND_HOST" value="localhost" /> + <env name="SP_COUCHDB_HOST" value="localhost" /> + <env name="SP_DEBUG" value="true " /> <env name="SP_INFLUX_HOST" value="localhost" /> - <env name="SP_KAFKA_HOST" value="localhost" /> <env name="SP_INFLUX_PORT" value="8086" /> - <env name="SP_KAFKA_PORT" value="9094" /> <env name="SP_JMS_HOST" value="localhost" /> - <env name="SP_DEBUG" value="true" /> + <env name="SP_KAFKA_HOST" value="localhost" /> + <env name="SP_KAFKA_PORT" value="9094" /> <env name="SP_PRIORITIZED_PROTOCOL" value="mqtt" /> </envs> + <module name="streampipes-backend" /> + <option name="SPRING_BOOT_MAIN_CLASS" value="org.apache.streampipes.backend.StreamPipesBackendApplication" /> <method v="2"> <option name="Make" enabled="true" /> </method>
diff --git a/.idea/runConfigurations/processors_aggregation_flink.xml b/.idea/runConfigurations/processors_aggregation_flink.xml deleted file mode 100644 index 183a887..0000000 --- a/.idea/runConfigurations/processors_aggregation_flink.xml +++ /dev/null
@@ -1,14 +0,0 @@ -<component name="ProjectRunConfigurationManager"> - <configuration default="false" name="processors-aggregation-flink" type="Application" factoryName="Application"> - <envs> - <env name="SP_PORT" value="6005" /> - <env name="SP_DEBUG" value="true" /> - <env name="SP_FLINK_DEBUG" value="true" /> - </envs> - <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.processors.aggregation.flink.AggregationFlinkInit" /> - <module name="streampipes-processors-aggregation-flink" /> - <method v="2"> - <option name="Make" enabled="true" /> - </method> - </configuration> -</component>
diff --git a/.idea/runConfigurations/processors_enricher_flink.xml b/.idea/runConfigurations/processors_enricher_flink.xml deleted file mode 100644 index 274dfd1..0000000 --- a/.idea/runConfigurations/processors_enricher_flink.xml +++ /dev/null
@@ -1,14 +0,0 @@ -<component name="ProjectRunConfigurationManager"> - <configuration default="false" name="processors-enricher-flink" type="Application" factoryName="Application"> - <envs> - <env name="SP_PORT" value="6010" /> - <env name="SP_DEBUG" value="true" /> - <env name="SP_FLINK_DEBUG" value="true" /> - </envs> - <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.processors.enricher.flink.EnricherFlinkInit" /> - <module name="streampipes-processors-enricher-flink" /> - <method v="2"> - <option name="Make" enabled="true" /> - </method> - </configuration> -</component>
diff --git a/.idea/runConfigurations/processors_enricher_jvm.xml b/.idea/runConfigurations/processors_enricher_jvm.xml deleted file mode 100644 index ae43ed6..0000000 --- a/.idea/runConfigurations/processors_enricher_jvm.xml +++ /dev/null
@@ -1,13 +0,0 @@ -<component name="ProjectRunConfigurationManager"> - <configuration default="false" name="processors-enricher-jvm" type="Application" factoryName="Application"> - <envs> - <env name="SP_PORT" value="6015" /> - <env name="SP_DEBUG" value="true" /> - </envs> - <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.processors.enricher.jvm.EnricherJvmInit" /> - <module name="streampipes-processors-enricher-jvm" /> - <method v="2"> - <option name="Make" enabled="true" /> - </method> - </configuration> -</component>
diff --git a/.idea/runConfigurations/processors_filters_jvm.xml b/.idea/runConfigurations/processors_filters_jvm.xml deleted file mode 100644 index b504325..0000000 --- a/.idea/runConfigurations/processors_filters_jvm.xml +++ /dev/null
@@ -1,13 +0,0 @@ -<component name="ProjectRunConfigurationManager"> - <configuration default="false" name="processors-filters-jvm" type="Application" factoryName="Application"> - <envs> - <env name="SP_PORT" value="6025" /> - <env name="SP_DEBUG" value="true" /> - </envs> - <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.processors.filters.jvm.FiltersJvmInit" /> - <module name="streampipes-processors-filters-jvm" /> - <method v="2"> - <option name="Make" enabled="true" /> - </method> - </configuration> -</component>
diff --git a/.idea/runConfigurations/processors_filters_siddhi.xml b/.idea/runConfigurations/processors_filters_siddhi.xml deleted file mode 100644 index 6b060b6..0000000 --- a/.idea/runConfigurations/processors_filters_siddhi.xml +++ /dev/null
@@ -1,13 +0,0 @@ -<component name="ProjectRunConfigurationManager"> - <configuration default="false" name="processors-filters-siddhi" type="Application" factoryName="Application"> - <envs> - <env name="SP_PORT" value="6025" /> - <env name="SP_DEBUG" value="true" /> - </envs> - <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.processors.siddhi.FiltersSiddhiInit" /> - <module name="streampipes-processors-filters-siddhi" /> - <method v="2"> - <option name="Make" enabled="true" /> - </method> - </configuration> -</component>
diff --git a/.idea/runConfigurations/processors_geo_flink.xml b/.idea/runConfigurations/processors_geo_flink.xml deleted file mode 100644 index 5e89134..0000000 --- a/.idea/runConfigurations/processors_geo_flink.xml +++ /dev/null
@@ -1,14 +0,0 @@ -<component name="ProjectRunConfigurationManager"> - <configuration default="false" name="processors-geo-flink" type="Application" factoryName="Application"> - <envs> - <env name="SP_PORT" value="6025" /> - <env name="SP_DEBUG" value="true" /> - <env name="SP_FLINK_DEBUG" value="true" /> - </envs> - <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.processor.geo.flink.GeoFlinkInit" /> - <module name="streampipes-processors-geo-flink" /> - <method v="2"> - <option name="Make" enabled="true" /> - </method> - </configuration> -</component>
diff --git a/.idea/runConfigurations/processors_geo_jvm.xml b/.idea/runConfigurations/processors_geo_jvm.xml deleted file mode 100644 index 78165cd..0000000 --- a/.idea/runConfigurations/processors_geo_jvm.xml +++ /dev/null
@@ -1,13 +0,0 @@ -<component name="ProjectRunConfigurationManager"> - <configuration default="false" name="processors-geo-jvm" type="Application" factoryName="Application"> - <envs> - <env name="SP_PORT" value="8005" /> - <env name="SP_DEBUG" value="true" /> - </envs> - <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.processors.geo.jvm.GeoJvmInit" /> - <module name="streampipes-processors-geo-jvm" /> - <method v="2"> - <option name="Make" enabled="true" /> - </method> - </configuration> -</component>
diff --git a/.idea/runConfigurations/processors_imageprocessing_jvm.xml b/.idea/runConfigurations/processors_imageprocessing_jvm.xml deleted file mode 100644 index bb2e7b5..0000000 --- a/.idea/runConfigurations/processors_imageprocessing_jvm.xml +++ /dev/null
@@ -1,13 +0,0 @@ -<component name="ProjectRunConfigurationManager"> - <configuration default="false" name="processors-imageprocessing-jvm" type="Application" factoryName="Application"> - <envs> - <env name="SP_PORT" value="6035" /> - <env name="SP_DEBUG" value="true" /> - </envs> - <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.processors.imageprocessing.jvm.ImageProcessingJvmInit" /> - <module name="streampipes-processors-image-processing-jvm" /> - <method v="2"> - <option name="Make" enabled="true" /> - </method> - </configuration> -</component>
diff --git a/.idea/runConfigurations/processors_pattern_detection_flink.xml b/.idea/runConfigurations/processors_pattern_detection_flink.xml deleted file mode 100644 index 8ed0376..0000000 --- a/.idea/runConfigurations/processors_pattern_detection_flink.xml +++ /dev/null
@@ -1,14 +0,0 @@ -<component name="ProjectRunConfigurationManager"> - <configuration default="false" name="processors-pattern-detection-flink" type="Application" factoryName="Application"> - <envs> - <env name="SP_PORT" value="6040" /> - <env name="SP_DEBUG" value="true" /> - <env name="SP_FLINK_DEBUG" value="true" /> - </envs> - <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.processors.pattern.detection.flink.PatternDetectionFlinkInit" /> - <module name="streampipes-processors-pattern-detection-flink" /> - <method v="2"> - <option name="Make" enabled="true" /> - </method> - </configuration> -</component>
diff --git a/.idea/runConfigurations/processors_statistics_flink.xml b/.idea/runConfigurations/processors_statistics_flink.xml deleted file mode 100644 index e9b74c8..0000000 --- a/.idea/runConfigurations/processors_statistics_flink.xml +++ /dev/null
@@ -1,14 +0,0 @@ -<component name="ProjectRunConfigurationManager"> - <configuration default="false" name="processors-statistics-flink" type="Application" factoryName="Application"> - <envs> - <env name="SP_PORT" value="6045" /> - <env name="SP_DEBUG" value="true" /> - <env name="SP_FLINK_DEBUG" value="true" /> - </envs> - <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.processors.statistics.flink.StatisticsFlinkInit" /> - <module name="streampipes-processors-statistics-flink" /> - <method v="2"> - <option name="Make" enabled="true" /> - </method> - </configuration> -</component>
diff --git a/.idea/runConfigurations/processors_textmining_flink.xml b/.idea/runConfigurations/processors_textmining_flink.xml deleted file mode 100644 index 18a4204..0000000 --- a/.idea/runConfigurations/processors_textmining_flink.xml +++ /dev/null
@@ -1,14 +0,0 @@ -<component name="ProjectRunConfigurationManager"> - <configuration default="false" name="processors-textmining-flink" type="Application" factoryName="Application"> - <envs> - <env name="SP_PORT" value="6050" /> - <env name="SP_DEBUG" value="true" /> - <env name="SP_FLINK_DEBUG" value="true" /> - </envs> - <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.processors.textmining.flink.TextMiningFlinkInit" /> - <module name="streampipes-processors-text-mining-flink" /> - <method v="2"> - <option name="Make" enabled="true" /> - </method> - </configuration> -</component>
diff --git a/.idea/runConfigurations/processors_textmining_jvm.xml b/.idea/runConfigurations/processors_textmining_jvm.xml deleted file mode 100644 index 4fb63c4..0000000 --- a/.idea/runConfigurations/processors_textmining_jvm.xml +++ /dev/null
@@ -1,13 +0,0 @@ -<component name="ProjectRunConfigurationManager"> - <configuration default="false" name="processors-textmining-jvm" type="Application" factoryName="Application"> - <envs> - <env name="SP_PORT" value="6065" /> - <env name="SP_DEBUG" value="true" /> - </envs> - <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.processors.textmining.jvm.TextMiningJvmInit" /> - <module name="streampipes-processors-text-mining-jvm" /> - <method v="2"> - <option name="Make" enabled="true" /> - </method> - </configuration> -</component>
diff --git a/.idea/runConfigurations/processors_transformation_flink.xml b/.idea/runConfigurations/processors_transformation_flink.xml deleted file mode 100644 index 456b92c..0000000 --- a/.idea/runConfigurations/processors_transformation_flink.xml +++ /dev/null
@@ -1,14 +0,0 @@ -<component name="ProjectRunConfigurationManager"> - <configuration default="false" name="processors-transformation-flink" type="Application" factoryName="Application"> - <envs> - <env name="SP_PORT" value="6055" /> - <env name="SP_DEBUG" value="true" /> - <env name="SP_FLINK_DEBUG" value="true" /> - </envs> - <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.processors.transformation.flink.TransformationFlinkInit" /> - <module name="streampipes-processors-transformation-flink" /> - <method v="2"> - <option name="Make" enabled="true" /> - </method> - </configuration> -</component>
diff --git a/.idea/runConfigurations/processors_transformation_jvm.xml b/.idea/runConfigurations/processors_transformation_jvm.xml deleted file mode 100644 index bfa0fff..0000000 --- a/.idea/runConfigurations/processors_transformation_jvm.xml +++ /dev/null
@@ -1,13 +0,0 @@ -<component name="ProjectRunConfigurationManager"> - <configuration default="false" name="processors-transformation-jvm" type="Application" factoryName="Application"> - <envs> - <env name="SP_PORT" value="6060" /> - <env name="SP_DEBUG" value="true" /> - </envs> - <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.processors.transformation.jvm.TransformationJvmInit" /> - <module name="streampipes-processors-transformation-jvm" /> - <method v="2"> - <option name="Make" enabled="true" /> - </method> - </configuration> -</component>
diff --git a/.idea/runConfigurations/sinks_brokers_jvm.xml b/.idea/runConfigurations/sinks_brokers_jvm.xml deleted file mode 100644 index bb2962d..0000000 --- a/.idea/runConfigurations/sinks_brokers_jvm.xml +++ /dev/null
@@ -1,13 +0,0 @@ -<component name="ProjectRunConfigurationManager"> - <configuration default="false" name="sinks-brokers-jvm" type="Application" factoryName="Application"> - <envs> - <env name="SP_PORT" value="7005" /> - <env name="SP_DEBUG" value="true" /> - </envs> - <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.sinks.brokers.jvm.BrokersJvmInit" /> - <module name="streampipes-sinks-brokers-jvm" /> - <method v="2"> - <option name="Make" enabled="true" /> - </method> - </configuration> -</component>
diff --git a/.idea/runConfigurations/sinks_databases_flink.xml b/.idea/runConfigurations/sinks_databases_flink.xml deleted file mode 100644 index e0ec58c..0000000 --- a/.idea/runConfigurations/sinks_databases_flink.xml +++ /dev/null
@@ -1,15 +0,0 @@ -<component name="ProjectRunConfigurationManager"> - <configuration default="false" name="sinks-databases-flink" type="Application" factoryName="Application"> - <envs> - <env name="SP_PORT" value="7010" /> - <env name="SP_DEBUG" value="true" /> - <env name="SP_FLINK_DEBUG" value="true" /> - <env name="SP_ELASTICSEARCH_HOST" value="localhost" /> - </envs> - <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.sinks.databases.flink.DatabasesFlinkInit" /> - <module name="streampipes-sinks-databases-flink" /> - <method v="2"> - <option name="Make" enabled="true" /> - </method> - </configuration> -</component>
diff --git a/.idea/runConfigurations/sinks_databases_jvm.xml b/.idea/runConfigurations/sinks_databases_jvm.xml deleted file mode 100644 index 358b372..0000000 --- a/.idea/runConfigurations/sinks_databases_jvm.xml +++ /dev/null
@@ -1,13 +0,0 @@ -<component name="ProjectRunConfigurationManager"> - <configuration default="false" name="sinks-databases-jvm" type="Application" factoryName="Application"> - <envs> - <env name="SP_PORT" value="7015" /> - <env name="SP_DEBUG" value="true" /> - </envs> - <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.sinks.databases.jvm.DatabasesJvmInit" /> - <module name="streampipes-sinks-databases-jvm" /> - <method v="2"> - <option name="Make" enabled="true" /> - </method> - </configuration> -</component>
diff --git a/.idea/runConfigurations/sinks_notifications_jvm.xml b/.idea/runConfigurations/sinks_notifications_jvm.xml deleted file mode 100644 index 77748b2..0000000 --- a/.idea/runConfigurations/sinks_notifications_jvm.xml +++ /dev/null
@@ -1,22 +0,0 @@ -<component name="ProjectRunConfigurationManager"> - <configuration default="false" name="sinks-notifications-jvm" type="Application" factoryName="Application"> - <envs> - <env name="SP_PORT" value="7025" /> - <env name="SP_DEBUG" value="true" /> - <env name="SLACK_TOKEN" value="" /> - <env name="EMAIL_FROMS" value="" /> - <env name="EMAIL_USERNAME" value="" /> - <env name="EMAIL_PASSWORD" value="" /> - <env name="EMAIL_SMTP_HOST" value="" /> - <env name="EMAIL_SMTP_PORT" value="" /> - <env name="EMAIL_STARTTLS" value="" /> - <env name="EMAIL_SILL" value="" /> - <env name="WEBSOCKET_PROTOCOL" value="ws" /> - </envs> - <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.sinks.notifications.jvm.SinksNotificationsJvmInit" /> - <module name="streampipes-sinks-notifications-jvm" /> - <method v="2"> - <option name="Make" enabled="true" /> - </method> - </configuration> -</component>
diff --git a/Jenkinsfile b/Jenkinsfile index 8f7050b..c202e02 100644 --- a/Jenkinsfile +++ b/Jenkinsfile
@@ -30,7 +30,7 @@ tools { maven 'maven_3_latest' - jdk 'jdk_1.8_latest' + jdk 'jdk_11_latest' }
diff --git a/README.md b/README.md index f456bf5..b054d0a 100644 --- a/README.md +++ b/README.md
@@ -103,8 +103,8 @@ To properly build the StreamPipes core, the following tools should be installed: ### Prerequisites -* Java 8 JDK (minimum) -* Maven (tested with 3.6) +* Java 11 JDK (minimum) +* Maven (tested with 3.8) * NodeJS + NPM (tested with v12+/ v6+) * Docker + Docker-Compose @@ -126,7 +126,7 @@ ### Starting -To start StreamPipes, run ``docker-compose up -d`` from the root directory. +To start StreamPipes, run ``docker-compose up --build -d`` from the root directory. You can also use the installer or CLI as described in the ``Installation`` section. @@ -135,7 +135,7 @@ * **Connect adapters** for a variety of IoT data sources as well as * **Data Processors** and **Data Sinks** as ready-to-use pipeline elements. -A description of the standard elements can be found in the Github repository [streampipes-extensions](https://www.github.com/apache/incubator-streampipes-extensions). +A description of the standard elements can be found in [streampipes-extensions](https://github.com/apache/incubator-streampipes/tree/dev/streampipes-extensions). ## Extending StreamPipes
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index ec67a78..dbb6925 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md
@@ -21,12 +21,72 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). -# [Unreleased] -### New Features +# [0.70.0] -### Improvements +## Sub-task -### Bug Fixes +* [[STREAMPIPES-535](https://issues.apache.org/jira/browse/STREAMPIPES-535)] - Support JWT signing with private/public key + +## Bug + +* [[STREAMPIPES-243](https://issues.apache.org/jira/browse/STREAMPIPES-243)] - Configuration of And Processor is broken +* [[STREAMPIPES-255](https://issues.apache.org/jira/browse/STREAMPIPES-255)] - Error when importing AdapterDescriptions with file upload references +* [[STREAMPIPES-515](https://issues.apache.org/jira/browse/STREAMPIPES-515)] - Missing mapping in dev compose files for new docker-compose versions +* [[STREAMPIPES-521](https://issues.apache.org/jira/browse/STREAMPIPES-521)] - Filter can not be deleted in data explorer +* [[STREAMPIPES-524](https://issues.apache.org/jira/browse/STREAMPIPES-524)] - No data is shown in data explorer +* [[STREAMPIPES-529](https://issues.apache.org/jira/browse/STREAMPIPES-529)] - Newly created pipelines break dashboard +* [[STREAMPIPES-540](https://issues.apache.org/jira/browse/STREAMPIPES-540)] - Data download returns error +* [[STREAMPIPES-542](https://issues.apache.org/jira/browse/STREAMPIPES-542)] - Web UI pipelines won't import multiple pipelines +* [[STREAMPIPES-543](https://issues.apache.org/jira/browse/STREAMPIPES-543)] - Using UI can't choose a source for the new dashboard +* [[STREAMPIPES-547](https://issues.apache.org/jira/browse/STREAMPIPES-547)] - Fix repeating colors for time-series chart +* [[STREAMPIPES-548](https://issues.apache.org/jira/browse/STREAMPIPES-548)] - Aggregation settings for data-explorer partially not persisted +* [[STREAMPIPES-550](https://issues.apache.org/jira/browse/STREAMPIPES-550)] - Empty property configuration in data-explorer visualization config +* [[STREAMPIPES-551](https://issues.apache.org/jira/browse/STREAMPIPES-551)] - Missing naming for (multiple) data sources in visualization config of data-explorer +* [[STREAMPIPES-553](https://issues.apache.org/jira/browse/STREAMPIPES-553)] - Lite configuration for k8s does not include message broker +* [[STREAMPIPES-554](https://issues.apache.org/jira/browse/STREAMPIPES-554)] - Data-explorer widgets reload when token is renewed +* [[STREAMPIPES-564](https://issues.apache.org/jira/browse/STREAMPIPES-564)] - Group by fields don't change in data explorer +* [[STREAMPIPES-572](https://issues.apache.org/jira/browse/STREAMPIPES-572)] - Fix automatic lower casing when persisting data in connect +* [[STREAMPIPES-578](https://issues.apache.org/jira/browse/STREAMPIPES-578)] - Data Explorer download does not update measurement +* [[STREAMPIPES-579](https://issues.apache.org/jira/browse/STREAMPIPES-579)] - Larger live dashboards become unresponsive + +## New Feature + +* [[STREAMPIPES-209](https://issues.apache.org/jira/browse/STREAMPIPES-209)] - FileStaticProperty should support filtering for extensions +* [[STREAMPIPES-534](https://issues.apache.org/jira/browse/STREAMPIPES-534)] - Support authentication for extensions services +* [[STREAMPIPES-539](https://issues.apache.org/jira/browse/STREAMPIPES-539)] - Support full screen data view in data explorer +* [[STREAMPIPES-546](https://issues.apache.org/jira/browse/STREAMPIPES-546)] - Support data download of configured query in data explorer +* [[STREAMPIPES-549](https://issues.apache.org/jira/browse/STREAMPIPES-549)] - Add extensions service for IIoT-related processors and sinks +* [[STREAMPIPES-559](https://issues.apache.org/jira/browse/STREAMPIPES-559)] - Support templates for adapter configurations +* [[STREAMPIPES-561](https://issues.apache.org/jira/browse/STREAMPIPES-561)] - Add breadcrumb navigation +* [[STREAMPIPES-565](https://issues.apache.org/jira/browse/STREAMPIPES-565)] - Allow to export and import StreamPipes resources +* [[STREAMPIPES-569](https://issues.apache.org/jira/browse/STREAMPIPES-569)] - Export data from data lake configuration +* [[STREAMPIPES-570](https://issues.apache.org/jira/browse/STREAMPIPES-570)] - Import multiple files at once +* [[STREAMPIPES-573](https://issues.apache.org/jira/browse/STREAMPIPES-573)] - Make CSV delimiter selectable in download dialog + +## Improvement + +* [[STREAMPIPES-192](https://issues.apache.org/jira/browse/STREAMPIPES-192)] - A user has to enter too many names when using the system +* [[STREAMPIPES-223](https://issues.apache.org/jira/browse/STREAMPIPES-223)] - Add connection retry to consul for pipeline elements when starting up +* [[STREAMPIPES-228](https://issues.apache.org/jira/browse/STREAMPIPES-228)] - Edit dashboard +* [[STREAMPIPES-517](https://issues.apache.org/jira/browse/STREAMPIPES-517)] - Update UI to Angular 13 +* [[STREAMPIPES-522](https://issues.apache.org/jira/browse/STREAMPIPES-522)] - Deleting adapter instance after previously stopping adapter throws error +* [[STREAMPIPES-528](https://issues.apache.org/jira/browse/STREAMPIPES-528)] - Support images in data explorer +* [[STREAMPIPES-531](https://issues.apache.org/jira/browse/STREAMPIPES-531)] - Extract shared UI modules to Angular library +* [[STREAMPIPES-533](https://issues.apache.org/jira/browse/STREAMPIPES-533)] - Bump Spring dependencies +* [[STREAMPIPES-536](https://issues.apache.org/jira/browse/STREAMPIPES-536)] - Escape asterisk in installer/upgrade_versions.sh +* [[STREAMPIPES-552](https://issues.apache.org/jira/browse/STREAMPIPES-552)] - Cancel subscriptions in data explorer when config changes +* [[STREAMPIPES-556](https://issues.apache.org/jira/browse/STREAMPIPES-556)] - Add silent period to notifications sink +* [[STREAMPIPES-557](https://issues.apache.org/jira/browse/STREAMPIPES-557)] - Move notifications icon from iconbar to toolbar +* [[STREAMPIPES-558](https://issues.apache.org/jira/browse/STREAMPIPES-558)] - Change navigation of connect module +* [[STREAMPIPES-560](https://issues.apache.org/jira/browse/STREAMPIPES-560)] - Add confirm dialog before leaving data explorer widget view +* [[STREAMPIPES-575](https://issues.apache.org/jira/browse/STREAMPIPES-575)] - Migrate Math operators from Flink to plain JVM wrapper +* [[STREAMPIPES-576](https://issues.apache.org/jira/browse/STREAMPIPES-576)] - Migrate transformation processors from Flink to JVM + +## Task + +* [[STREAMPIPES-463](https://issues.apache.org/jira/browse/STREAMPIPES-463)] - Merge StreamPipes repos into a single repo +* [[STREAMPIPES-555](https://issues.apache.org/jira/browse/STREAMPIPES-555)] - Remove feedback button from UI +* [[STREAMPIPES-581](https://issues.apache.org/jira/browse/STREAMPIPES-581)] - Restructure documentantion # [0.69.0]
diff --git a/archetypes/streampipes-archetype-extensions-jvm/pom.xml b/archetypes/streampipes-archetype-extensions-jvm/pom.xml index 0bcfc76..f9f1152 100644 --- a/archetypes/streampipes-archetype-extensions-jvm/pom.xml +++ b/archetypes/streampipes-archetype-extensions-jvm/pom.xml
@@ -22,7 +22,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent> <artifactId>streampipes-archetype-extensions-jvm</artifactId>
diff --git a/archetypes/streampipes-archetype-extensions-jvm/src/main/resources/archetype-resources/pom.xml b/archetypes/streampipes-archetype-extensions-jvm/src/main/resources/archetype-resources/pom.xml index 365ab51..5fb4c9c 100644 --- a/archetypes/streampipes-archetype-extensions-jvm/src/main/resources/archetype-resources/pom.xml +++ b/archetypes/streampipes-archetype-extensions-jvm/src/main/resources/archetype-resources/pom.xml
@@ -25,7 +25,7 @@ <version>${version}</version> <properties> - <sp.version>0.70.0-SNAPSHOT</sp.version> + <sp.version>0.71.0-SNAPSHOT</sp.version> </properties> <dependencies>
diff --git a/archetypes/streampipes-archetype-pe-processors-flink/pom.xml b/archetypes/streampipes-archetype-pe-processors-flink/pom.xml index 5ea6bab..31ff42f 100644 --- a/archetypes/streampipes-archetype-pe-processors-flink/pom.xml +++ b/archetypes/streampipes-archetype-pe-processors-flink/pom.xml
@@ -22,7 +22,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent> <artifactId>streampipes-archetype-pe-processors-flink</artifactId>
diff --git a/archetypes/streampipes-archetype-pe-processors-flink/src/main/resources/archetype-resources/pom.xml b/archetypes/streampipes-archetype-pe-processors-flink/src/main/resources/archetype-resources/pom.xml index e55ddab..2a63d0c 100644 --- a/archetypes/streampipes-archetype-pe-processors-flink/src/main/resources/archetype-resources/pom.xml +++ b/archetypes/streampipes-archetype-pe-processors-flink/src/main/resources/archetype-resources/pom.xml
@@ -25,7 +25,7 @@ <version>${version}</version> <properties> - <sp.version>0.70.0-SNAPSHOT</sp.version> + <sp.version>0.71.0-SNAPSHOT</sp.version> </properties> <dependencies>
diff --git a/archetypes/streampipes-archetype-pe-sinks-flink/pom.xml b/archetypes/streampipes-archetype-pe-sinks-flink/pom.xml index 6d0837e..0771e8f 100644 --- a/archetypes/streampipes-archetype-pe-sinks-flink/pom.xml +++ b/archetypes/streampipes-archetype-pe-sinks-flink/pom.xml
@@ -22,7 +22,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent> <artifactId>streampipes-archetype-pe-sinks-flink</artifactId>
diff --git a/archetypes/streampipes-archetype-pe-sinks-flink/src/main/resources/archetype-resources/pom.xml b/archetypes/streampipes-archetype-pe-sinks-flink/src/main/resources/archetype-resources/pom.xml index cf27b6f..540d108 100644 --- a/archetypes/streampipes-archetype-pe-sinks-flink/src/main/resources/archetype-resources/pom.xml +++ b/archetypes/streampipes-archetype-pe-sinks-flink/src/main/resources/archetype-resources/pom.xml
@@ -25,7 +25,7 @@ <version>${version}</version> <properties> - <sp.version>0.70.0-SNAPSHOT</sp.version> + <sp.version>0.71.0-SNAPSHOT</sp.version> </properties> <dependencies>
diff --git a/installer/cli/.env b/installer/cli/.env index 8f4f118..09e1aa2 100644 --- a/installer/cli/.env +++ b/installer/cli/.env
@@ -14,7 +14,7 @@ # limitations under the License. SP_DOCKER_REGISTRY=apachestreampipes -SP_VERSION=0.70.0-SNAPSHOT +SP_VERSION=0.71.0-SNAPSHOT SP_SUBNET=172.31.0.0/16 SP_CONSUL_CONTAINER_IP=172.31.0.9 COMPOSE_PROJECT_NAME=streampipes
diff --git a/installer/cli/README.md b/installer/cli/README.md index bcfa97a..934a18f 100644 --- a/installer/cli/README.md +++ b/installer/cli/README.md
@@ -23,7 +23,7 @@ * new core features for **backend** and **ui**. <!-- BEGIN do not edit: set via ../upgrade_versions.sh --> -**Current version:** 0.70.0-SNAPSHOT +**Current version:** 0.71.0-SNAPSHOT <!-- END do not edit --> ## TL;DR
diff --git a/installer/cli/deploy/standalone/processors-aggregation-flink/docker-compose.dev.yml b/installer/cli/deploy/standalone/processors-aggregation-flink/docker-compose.dev.yml deleted file mode 100644 index dbde6e5..0000000 --- a/installer/cli/deploy/standalone/processors-aggregation-flink/docker-compose.dev.yml +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-aggregation-flink: -# ports: -# - "8098:8090"
diff --git a/installer/cli/deploy/standalone/processors-aggregation-flink/docker-compose.yml b/installer/cli/deploy/standalone/processors-aggregation-flink/docker-compose.yml deleted file mode 100644 index a0d0312..0000000 --- a/installer/cli/deploy/standalone/processors-aggregation-flink/docker-compose.yml +++ /dev/null
@@ -1,33 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-aggregation-flink: - image: ${SP_DOCKER_REGISTRY}/processors-aggregation-flink:${SP_VERSION} - depends_on: - - "consul" - - "jobmanager" - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "1" - networks: - spnet: - -networks: - spnet: - external: true
diff --git a/installer/cli/deploy/standalone/processors-enricher-flink/docker-compose.dev.yml b/installer/cli/deploy/standalone/processors-enricher-flink/docker-compose.dev.yml deleted file mode 100644 index 3519024..0000000 --- a/installer/cli/deploy/standalone/processors-enricher-flink/docker-compose.dev.yml +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-enricher-flink: -# ports: -# - "8098:8090"
diff --git a/installer/cli/deploy/standalone/processors-enricher-flink/docker-compose.yml b/installer/cli/deploy/standalone/processors-enricher-flink/docker-compose.yml deleted file mode 100644 index a1cbb64..0000000 --- a/installer/cli/deploy/standalone/processors-enricher-flink/docker-compose.yml +++ /dev/null
@@ -1,33 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-enricher-flink: - image: ${SP_DOCKER_REGISTRY}/processors-enricher-flink:${SP_VERSION} - depends_on: - - "consul" - - "jobmanager" - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "1" - networks: - spnet: - -networks: - spnet: - external: true
diff --git a/installer/cli/deploy/standalone/processors-enricher-jvm/docker-compose.dev.yml b/installer/cli/deploy/standalone/processors-enricher-jvm/docker-compose.dev.yml deleted file mode 100644 index 67ed576..0000000 --- a/installer/cli/deploy/standalone/processors-enricher-jvm/docker-compose.dev.yml +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-enricher-jvm: -# ports: -# - "8098:8090"
diff --git a/installer/cli/deploy/standalone/processors-enricher-jvm/docker-compose.yml b/installer/cli/deploy/standalone/processors-enricher-jvm/docker-compose.yml deleted file mode 100644 index 1230b85..0000000 --- a/installer/cli/deploy/standalone/processors-enricher-jvm/docker-compose.yml +++ /dev/null
@@ -1,32 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-enricher-jvm: - image: ${SP_DOCKER_REGISTRY}/processors-enricher-jvm:${SP_VERSION} - depends_on: - - "consul" - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "1" - networks: - spnet: - -networks: - spnet: - external: true
diff --git a/installer/cli/deploy/standalone/processors-filters-jvm/docker-compose.dev.yml b/installer/cli/deploy/standalone/processors-filters-jvm/docker-compose.dev.yml deleted file mode 100644 index 178b2b5..0000000 --- a/installer/cli/deploy/standalone/processors-filters-jvm/docker-compose.dev.yml +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-filters-jvm: -# ports: -# - "8098:8090"
diff --git a/installer/cli/deploy/standalone/processors-filters-jvm/docker-compose.yml b/installer/cli/deploy/standalone/processors-filters-jvm/docker-compose.yml deleted file mode 100644 index e3e2ce0..0000000 --- a/installer/cli/deploy/standalone/processors-filters-jvm/docker-compose.yml +++ /dev/null
@@ -1,32 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-filters-jvm: - image: ${SP_DOCKER_REGISTRY}/processors-filters-jvm:${SP_VERSION} - depends_on: - - "consul" - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "1" - networks: - spnet: - -networks: - spnet: - external: true
diff --git a/installer/cli/deploy/standalone/processors-filters-siddhi/docker-compose.dev.yml b/installer/cli/deploy/standalone/processors-filters-siddhi/docker-compose.dev.yml deleted file mode 100644 index 207d1ca..0000000 --- a/installer/cli/deploy/standalone/processors-filters-siddhi/docker-compose.dev.yml +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-filters-siddhi: -# ports: -# - "8098:8090"
diff --git a/installer/cli/deploy/standalone/processors-filters-siddhi/docker-compose.yml b/installer/cli/deploy/standalone/processors-filters-siddhi/docker-compose.yml deleted file mode 100644 index 0e647c9..0000000 --- a/installer/cli/deploy/standalone/processors-filters-siddhi/docker-compose.yml +++ /dev/null
@@ -1,32 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-filters-siddhi: - image: ${SP_DOCKER_REGISTRY}/processors-filters-siddhi:${SP_VERSION} - depends_on: - - "consul" - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "1" - networks: - spnet: - -networks: - spnet: - external: true
diff --git a/installer/cli/deploy/standalone/processors-geo-flink/docker-compose.dev.yml b/installer/cli/deploy/standalone/processors-geo-flink/docker-compose.dev.yml deleted file mode 100644 index 0369706..0000000 --- a/installer/cli/deploy/standalone/processors-geo-flink/docker-compose.dev.yml +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-geo-flink: -# ports: -# - "8098:8090"
diff --git a/installer/cli/deploy/standalone/processors-geo-flink/docker-compose.yml b/installer/cli/deploy/standalone/processors-geo-flink/docker-compose.yml deleted file mode 100644 index 8025853..0000000 --- a/installer/cli/deploy/standalone/processors-geo-flink/docker-compose.yml +++ /dev/null
@@ -1,33 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-geo-flink: - image: ${SP_DOCKER_REGISTRY}/processors-geo-flink:${SP_VERSION} - depends_on: - - "consul" - - "jobmanager" - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "1" - networks: - spnet: - -networks: - spnet: - external: true
diff --git a/installer/cli/deploy/standalone/processors-geo-jvm/docker-compose.dev.yml b/installer/cli/deploy/standalone/processors-geo-jvm/docker-compose.dev.yml deleted file mode 100644 index cb8ce93..0000000 --- a/installer/cli/deploy/standalone/processors-geo-jvm/docker-compose.dev.yml +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-geo-jvm: -# ports: -# - "8098:8090"
diff --git a/installer/cli/deploy/standalone/processors-geo-jvm/docker-compose.yml b/installer/cli/deploy/standalone/processors-geo-jvm/docker-compose.yml deleted file mode 100644 index 9bd02df..0000000 --- a/installer/cli/deploy/standalone/processors-geo-jvm/docker-compose.yml +++ /dev/null
@@ -1,32 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-geo-jvm: - image: ${SP_DOCKER_REGISTRY}/processors-geo-jvm:${SP_VERSION} - depends_on: - - "consul" - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "1" - networks: - spnet: - -networks: - spnet: - external: true
diff --git a/installer/cli/deploy/standalone/processors-image-processing-jvm/docker-compose.dev.yml b/installer/cli/deploy/standalone/processors-image-processing-jvm/docker-compose.dev.yml deleted file mode 100644 index d8130c0..0000000 --- a/installer/cli/deploy/standalone/processors-image-processing-jvm/docker-compose.dev.yml +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-image-processing-jvm: -# ports: -# - "8098:8090"
diff --git a/installer/cli/deploy/standalone/processors-image-processing-jvm/docker-compose.yml b/installer/cli/deploy/standalone/processors-image-processing-jvm/docker-compose.yml deleted file mode 100644 index 2580b4f..0000000 --- a/installer/cli/deploy/standalone/processors-image-processing-jvm/docker-compose.yml +++ /dev/null
@@ -1,32 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-image-processing-jvm: - image: ${SP_DOCKER_REGISTRY}/processors-image-processing-jvm:${SP_VERSION} - depends_on: - - "consul" - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "1" - networks: - spnet: - -networks: - spnet: - external: true
diff --git a/installer/cli/deploy/standalone/processors-pattern-detection-flink/docker-compose.dev.yml b/installer/cli/deploy/standalone/processors-pattern-detection-flink/docker-compose.dev.yml deleted file mode 100644 index 541a2f4..0000000 --- a/installer/cli/deploy/standalone/processors-pattern-detection-flink/docker-compose.dev.yml +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-pattern-detection-flink: -# ports: -# - "8098:8090"
diff --git a/installer/cli/deploy/standalone/processors-pattern-detection-flink/docker-compose.yml b/installer/cli/deploy/standalone/processors-pattern-detection-flink/docker-compose.yml deleted file mode 100644 index 7fcc509..0000000 --- a/installer/cli/deploy/standalone/processors-pattern-detection-flink/docker-compose.yml +++ /dev/null
@@ -1,33 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-pattern-detection-flink: - image: ${SP_DOCKER_REGISTRY}/processors-pattern-detection-flink:${SP_VERSION} - depends_on: - - "consul" - - "jobmanager" - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "1" - networks: - spnet: - -networks: - spnet: - external: true
diff --git a/installer/cli/deploy/standalone/processors-statistics-flink/docker-compose.dev.yml b/installer/cli/deploy/standalone/processors-statistics-flink/docker-compose.dev.yml deleted file mode 100644 index aeda1c1..0000000 --- a/installer/cli/deploy/standalone/processors-statistics-flink/docker-compose.dev.yml +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-statistics-flink: -# ports: -# - "8098:8090"
diff --git a/installer/cli/deploy/standalone/processors-statistics-flink/docker-compose.yml b/installer/cli/deploy/standalone/processors-statistics-flink/docker-compose.yml deleted file mode 100644 index 0d5c24d..0000000 --- a/installer/cli/deploy/standalone/processors-statistics-flink/docker-compose.yml +++ /dev/null
@@ -1,33 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-statistics-flink: - image: ${SP_DOCKER_REGISTRY}/processors-statistics-flink:${SP_VERSION} - depends_on: - - "consul" - - "jobmanager" - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "1" - networks: - spnet: - -networks: - spnet: - external: true
diff --git a/installer/cli/deploy/standalone/processors-text-mining-jvm/docker-compose.dev.yml b/installer/cli/deploy/standalone/processors-text-mining-jvm/docker-compose.dev.yml deleted file mode 100644 index 54bf152..0000000 --- a/installer/cli/deploy/standalone/processors-text-mining-jvm/docker-compose.dev.yml +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-text-mining-jvm: -# ports: -# - "8098:8090"
diff --git a/installer/cli/deploy/standalone/processors-text-mining-jvm/docker-compose.yml b/installer/cli/deploy/standalone/processors-text-mining-jvm/docker-compose.yml deleted file mode 100644 index 7342d8d..0000000 --- a/installer/cli/deploy/standalone/processors-text-mining-jvm/docker-compose.yml +++ /dev/null
@@ -1,34 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-text-mining-jvm: - image: ${SP_DOCKER_REGISTRY}/processors-text-mining-jvm:${SP_VERSION} - depends_on: - - "consul" - volumes: - - ./config/models:/data/models - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "1" - networks: - spnet: - -networks: - spnet: - external: true
diff --git a/installer/cli/deploy/standalone/processors-transformation-flink/docker-compose.dev.yml b/installer/cli/deploy/standalone/processors-transformation-flink/docker-compose.dev.yml deleted file mode 100644 index b1b8722..0000000 --- a/installer/cli/deploy/standalone/processors-transformation-flink/docker-compose.dev.yml +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-transformation-flink: -# ports: -# - "8098:8090"
diff --git a/installer/cli/deploy/standalone/processors-transformation-flink/docker-compose.yml b/installer/cli/deploy/standalone/processors-transformation-flink/docker-compose.yml deleted file mode 100644 index ad767bc..0000000 --- a/installer/cli/deploy/standalone/processors-transformation-flink/docker-compose.yml +++ /dev/null
@@ -1,33 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-transformation-flink: - image: ${SP_DOCKER_REGISTRY}/processors-transformation-flink:${SP_VERSION} - depends_on: - - "consul" - - "jobmanager" - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "1" - networks: - spnet: - -networks: - spnet: - external: true
diff --git a/installer/cli/deploy/standalone/processors-transformation-jvm/docker-compose.dev.yml b/installer/cli/deploy/standalone/processors-transformation-jvm/docker-compose.dev.yml deleted file mode 100644 index 92ae2be..0000000 --- a/installer/cli/deploy/standalone/processors-transformation-jvm/docker-compose.dev.yml +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-transformation-jvm: -# ports: -# - "8098:8090"
diff --git a/installer/cli/deploy/standalone/processors-transformation-jvm/docker-compose.yml b/installer/cli/deploy/standalone/processors-transformation-jvm/docker-compose.yml deleted file mode 100644 index f2269dc..0000000 --- a/installer/cli/deploy/standalone/processors-transformation-jvm/docker-compose.yml +++ /dev/null
@@ -1,34 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - processors-transformation-jvm: - image: ${SP_DOCKER_REGISTRY}/processors-transformation-jvm:${SP_VERSION} - depends_on: - - "consul" -# ports: -# - "8098:8090" - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "1" - networks: - spnet: - -networks: - spnet: - external: true
diff --git a/installer/cli/deploy/standalone/sinks-brokers-jvm/docker-compose.dev.yml b/installer/cli/deploy/standalone/sinks-brokers-jvm/docker-compose.dev.yml deleted file mode 100644 index 5959966..0000000 --- a/installer/cli/deploy/standalone/sinks-brokers-jvm/docker-compose.dev.yml +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - sinks-brokers-jvm: -# ports: -# - "8098:8090"
diff --git a/installer/cli/deploy/standalone/sinks-brokers-jvm/docker-compose.yml b/installer/cli/deploy/standalone/sinks-brokers-jvm/docker-compose.yml deleted file mode 100644 index 824ef28..0000000 --- a/installer/cli/deploy/standalone/sinks-brokers-jvm/docker-compose.yml +++ /dev/null
@@ -1,32 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - sinks-brokers-jvm: - image: ${SP_DOCKER_REGISTRY}/sinks-brokers-jvm:${SP_VERSION} - depends_on: - - "consul" - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "1" - networks: - spnet: - -networks: - spnet: - external: true
diff --git a/installer/cli/deploy/standalone/sinks-databases-flink/docker-compose.dev.yml b/installer/cli/deploy/standalone/sinks-databases-flink/docker-compose.dev.yml deleted file mode 100644 index 41becda..0000000 --- a/installer/cli/deploy/standalone/sinks-databases-flink/docker-compose.dev.yml +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - sinks-databases-flink: -# ports: -# - "8098:8090"
diff --git a/installer/cli/deploy/standalone/sinks-databases-flink/docker-compose.yml b/installer/cli/deploy/standalone/sinks-databases-flink/docker-compose.yml deleted file mode 100644 index 02467dd..0000000 --- a/installer/cli/deploy/standalone/sinks-databases-flink/docker-compose.yml +++ /dev/null
@@ -1,33 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - sinks-databases-flink: - image: ${SP_DOCKER_REGISTRY}/sinks-databases-flink:${SP_VERSION} - depends_on: - - "consul" - - "jobmanager" - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "1" - networks: - spnet: - -networks: - spnet: - external: true
diff --git a/installer/cli/deploy/standalone/sinks-databases-jvm/docker-compose.dev.yml b/installer/cli/deploy/standalone/sinks-databases-jvm/docker-compose.dev.yml deleted file mode 100644 index 8433b08..0000000 --- a/installer/cli/deploy/standalone/sinks-databases-jvm/docker-compose.dev.yml +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - sinks-databases-jvm: -# ports: -# - "8098:8090"
diff --git a/installer/cli/deploy/standalone/sinks-databases-jvm/docker-compose.yml b/installer/cli/deploy/standalone/sinks-databases-jvm/docker-compose.yml deleted file mode 100644 index ec593aa..0000000 --- a/installer/cli/deploy/standalone/sinks-databases-jvm/docker-compose.yml +++ /dev/null
@@ -1,32 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - sinks-databases-jvm: - image: ${SP_DOCKER_REGISTRY}/sinks-databases-jvm:${SP_VERSION} - depends_on: - - "consul" - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "1" - networks: - spnet: - -networks: - spnet: - external: true
diff --git a/installer/cli/deploy/standalone/sinks-notifications-jvm/docker-compose.dev.yml b/installer/cli/deploy/standalone/sinks-notifications-jvm/docker-compose.dev.yml deleted file mode 100644 index 25169fe..0000000 --- a/installer/cli/deploy/standalone/sinks-notifications-jvm/docker-compose.dev.yml +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - sinks-notifications-jvm: -# ports: -# - "8098:8090"
diff --git a/installer/cli/deploy/standalone/sinks-notifications-jvm/docker-compose.yml b/installer/cli/deploy/standalone/sinks-notifications-jvm/docker-compose.yml deleted file mode 100644 index 5ef9f78..0000000 --- a/installer/cli/deploy/standalone/sinks-notifications-jvm/docker-compose.yml +++ /dev/null
@@ -1,32 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version: "3.4" -services: - sinks-notifications-jvm: - image: ${SP_DOCKER_REGISTRY}/sinks-notifications-jvm:${SP_VERSION} - depends_on: - - "consul" - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "1" - networks: - spnet: - -networks: - spnet: - external: true
diff --git a/installer/compose/.env b/installer/compose/.env index 1b8ff24..d0e1f62 100644 --- a/installer/compose/.env +++ b/installer/compose/.env
@@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -SP_VERSION=0.70.0-SNAPSHOT +SP_VERSION=0.71.0-SNAPSHOT SP_DOCKER_REGISTRY=apachestreampipes SP_SUBNET=172.31.0.0/16 SP_CONSUL_CONTAINER_IP=172.31.0.9
diff --git a/installer/compose/README.md b/installer/compose/README.md index c22dbed..bd20296 100644 --- a/installer/compose/README.md +++ b/installer/compose/README.md
@@ -19,7 +19,7 @@ StreamPipes Compose is a simple collection of user-friendly `docker-compose` files that easily lets gain first-hand experience with Apache StreamPipes. <!-- BEGIN do not edit: set via ../upgrade_versions.sh --> -**Current version:** 0.70.0-SNAPSHOT +**Current version:** 0.71.0-SNAPSHOT <!-- END do not edit --> > **NOTE**: We recommend StreamPipes Compose to only use for initial try-out and testing. If you are a developer and want to develop new pipeline elements or core feature, use the [StreamPipes CLI](../cli).
diff --git a/installer/k8s/Chart.yaml b/installer/k8s/Chart.yaml index a42d4a8..e88c71a 100644 --- a/installer/k8s/Chart.yaml +++ b/installer/k8s/Chart.yaml
@@ -14,18 +14,9 @@ # limitations under the License. apiVersion: v1 -appVersion: "0.70.0-SNAPSHOT" +appVersion: "0.71.0-SNAPSHOT" description: Self-Service Data Analytics for the Industrial IoT name: streampipes-helm-chart home: https://streampipes.apache.org -version: 0.70.0-SNAPSHOT +version: 0.71.0-SNAPSHOT icon: https://avatars1.githubusercontent.com/u/33908576 -maintainers: - - name: Dominik Riemer - email: riemer@fzi.de - - name: Philipp Zehnder - email: zehnder@fzi.de - - name: Samuel Abt - email: abt@fzi.de - - name: Patrick Wiener - email: wiener@fzi.de
diff --git a/installer/k8s/README.md b/installer/k8s/README.md index 0449bc6..dff111a 100644 --- a/installer/k8s/README.md +++ b/installer/k8s/README.md
@@ -19,7 +19,7 @@ StreamPipes k8s is a helm chart to deploy StreamPipes on Kubernetes. <!-- BEGIN do not edit: set via ../upgrade_versions.sh --> -**Current version:** 0.70.0-SNAPSHOT +**Current version:** 0.71.0-SNAPSHOT <!-- END do not edit --> We provide two helm chart templates to get you going:
diff --git a/installer/k8s/templates/core/backend-deployment.yaml b/installer/k8s/templates/core/backend-deployment.yaml index a2a1b63..592c569 100644 --- a/installer/k8s/templates/core/backend-deployment.yaml +++ b/installer/k8s/templates/core/backend-deployment.yaml
@@ -44,7 +44,7 @@ imagePullPolicy: {{ .Values.pullPolicy }} env: - name: SP_PRIORITIZED_PROTOCOL - {{ if (eq .Values.deployment "lite") }} + {{ if (eq .Values.preferredBroker "mqtt") }} value: "mqtt" {{ else }} value: "kafka"
diff --git a/installer/k8s/templates/extensions/connect-adapters/connect-adapters-deployment.yaml b/installer/k8s/templates/extensions/connect-adapters/connect-adapters-deployment.yaml deleted file mode 100644 index 1dc5526..0000000 --- a/installer/k8s/templates/extensions/connect-adapters/connect-adapters-deployment.yaml +++ /dev/null
@@ -1,35 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: connect-adapters -spec: - selector: - matchLabels: - app: connect-adapters - replicas: 1 - template: - metadata: - labels: - app: connect-adapters - spec: - containers: - - name: connect-adapters - image: {{ .Values.streampipes.registry }}/connect-adapters:{{ .Values.streampipes.version }} - imagePullPolicy: {{ .Values.pullPolicy }} - ports: - - containerPort: 8090
diff --git a/installer/k8s/templates/extensions/connect-adapters/connect-adapters-iiot-deployment.yaml b/installer/k8s/templates/extensions/connect-adapters/connect-adapters-iiot-deployment.yaml deleted file mode 100644 index a67ff5e..0000000 --- a/installer/k8s/templates/extensions/connect-adapters/connect-adapters-iiot-deployment.yaml +++ /dev/null
@@ -1,35 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: connect-adapters-iiot -spec: - selector: - matchLabels: - app: connect-adapters-iiot - replicas: 1 - template: - metadata: - labels: - app: connect-adapters-iiot - spec: - containers: - - name: connect-adapters-iiot - image: {{ .Values.streampipes.registry }}/connect-adapters-iiot:{{ .Values.streampipes.version }} - imagePullPolicy: {{ .Values.pullPolicy }} - ports: - - containerPort: 8090
diff --git a/installer/k8s/templates/extensions/connect-adapters/connect-adapters-iiot-service.yaml b/installer/k8s/templates/extensions/connect-adapters/connect-adapters-iiot-service.yaml deleted file mode 100644 index d4ec559..0000000 --- a/installer/k8s/templates/extensions/connect-adapters/connect-adapters-iiot-service.yaml +++ /dev/null
@@ -1,27 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -apiVersion: v1 -kind: Service -metadata: - name: connect-adapters-iiot -spec: - selector: - app: connect-adapters-iiot - ports: - - name: main - protocol: TCP - port: 8090 - targetPort: 8002
diff --git a/installer/k8s/templates/extensions/connect-adapters/connect-adapters-service.yaml b/installer/k8s/templates/extensions/connect-adapters/connect-adapters-service.yaml deleted file mode 100644 index 213aef3..0000000 --- a/installer/k8s/templates/extensions/connect-adapters/connect-adapters-service.yaml +++ /dev/null
@@ -1,27 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -apiVersion: v1 -kind: Service -metadata: - name: connect-adapters -spec: - selector: - app: connect-adapters - ports: - - name: main - protocol: TCP - port: 8090 - targetPort: 8001
diff --git a/installer/k8s/templates/extensions/pipeline-elements/pipeline-elements-all-jvm-deployment.yaml b/installer/k8s/templates/extensions/pipeline-elements/extensions-all-jvm-deployment.yaml similarity index 77% rename from installer/k8s/templates/extensions/pipeline-elements/pipeline-elements-all-jvm-deployment.yaml rename to installer/k8s/templates/extensions/pipeline-elements/extensions-all-jvm-deployment.yaml index 6508e37..fb1cf7f 100644 --- a/installer/k8s/templates/extensions/pipeline-elements/pipeline-elements-all-jvm-deployment.yaml +++ b/installer/k8s/templates/extensions/pipeline-elements/extensions-all-jvm-deployment.yaml
@@ -16,27 +16,27 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: pipeline-elements-all-jvm + name: extensions-all-jvm spec: selector: matchLabels: - app: pipeline-elements-all-jvm + app: extensions-all-jvm replicas: 1 template: metadata: labels: - app: pipeline-elements-all-jvm + app: extensions-all-jvm spec: volumes: - name: files-pv persistentVolumeClaim: - claimName: files-pvc + claimName: files-pvc containers: - - name: pipeline-elements-all-jvm - image: {{ .Values.streampipes.registry }}/pipeline-elements-all-jvm:{{ .Values.streampipes.version }} + - name: extensions-all-jvm + image: {{ .Values.streampipes.registry }}/extensions-all-jvm:{{ .Values.streampipes.version }} imagePullPolicy: {{ .Values.pullPolicy }} ports: - containerPort: 8090 volumeMounts: - mountPath: "/spImages" - name: files-pv + name: files-pv
diff --git a/installer/k8s/templates/extensions/pipeline-elements/pipeline-elements-all-jvm-service.yaml b/installer/k8s/templates/extensions/pipeline-elements/extensions-all-jvm-service.yaml similarity index 89% rename from installer/k8s/templates/extensions/pipeline-elements/pipeline-elements-all-jvm-service.yaml rename to installer/k8s/templates/extensions/pipeline-elements/extensions-all-jvm-service.yaml index 1b1b01c..8a3a36a 100644 --- a/installer/k8s/templates/extensions/pipeline-elements/pipeline-elements-all-jvm-service.yaml +++ b/installer/k8s/templates/extensions/pipeline-elements/extensions-all-jvm-service.yaml
@@ -16,14 +16,14 @@ apiVersion: v1 kind: Service metadata: - name: pipeline-elements-all-jvm + name: extensions-all-jvm labels: - name: pipeline-elements-all-jvm + name: extensions-all-jvm spec: selector: - app: pipeline-elements-all-jvm + app: extensions-all-jvm ports: - name: main protocol: TCP port: 8090 - targetPort: 8090 \ No newline at end of file + targetPort: 8090
diff --git a/installer/k8s/templates/extensions/pipeline-elements/files-pvc.yaml b/installer/k8s/templates/extensions/pipeline-elements/files-pvc.yaml index bd6a088..ee0fb64 100644 --- a/installer/k8s/templates/extensions/pipeline-elements/files-pvc.yaml +++ b/installer/k8s/templates/extensions/pipeline-elements/files-pvc.yaml
@@ -31,7 +31,7 @@ kind: PersistentVolumeClaim metadata: labels: - app: pipeline-elements-all-jvm + app: extensions-all-jvm name: files-pvc spec: storageClassName: local-storage-files @@ -39,4 +39,4 @@ - {{ .Values.persistentVolumeAccessModes }} resources: requests: - storage: 250Mi \ No newline at end of file + storage: 250Mi
diff --git a/installer/k8s/templates/external/kafka/kafka-deployment.yaml b/installer/k8s/templates/external/kafka/kafka-deployment.yaml index eb844d7..4d45116 100644 --- a/installer/k8s/templates/external/kafka/kafka-deployment.yaml +++ b/installer/k8s/templates/external/kafka/kafka-deployment.yaml
@@ -13,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -{{- if (eq .Values.deployment "full") }} apiVersion: apps/v1 kind: Deployment metadata: @@ -66,4 +65,3 @@ value: "5000012" - name: KAFKA_REPLICA_FETCH_MAX_BYTES value: "10000000" -{{- end }} \ No newline at end of file
diff --git a/installer/k8s/templates/external/kafka/kafka-pvc.yaml b/installer/k8s/templates/external/kafka/kafka-pvc.yaml index 3bda2e2..894ae6c 100644 --- a/installer/k8s/templates/external/kafka/kafka-pvc.yaml +++ b/installer/k8s/templates/external/kafka/kafka-pvc.yaml
@@ -13,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -{{- if (eq .Values.deployment "full") }} apiVersion: v1 kind: PersistentVolume metadata: @@ -41,4 +40,3 @@ resources: requests: storage: 50M -{{- end }} \ No newline at end of file
diff --git a/installer/k8s/templates/external/kafka/kafka-service.yaml b/installer/k8s/templates/external/kafka/kafka-service.yaml index 1b75c43..1e1c265 100644 --- a/installer/k8s/templates/external/kafka/kafka-service.yaml +++ b/installer/k8s/templates/external/kafka/kafka-service.yaml
@@ -13,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -{{- if (eq .Values.deployment "full") }} apiVersion: v1 kind: Service metadata: @@ -27,4 +26,3 @@ - name: main protocol: TCP port: 9092 -{{- end }} \ No newline at end of file
diff --git a/installer/k8s/templates/external/zookeeper/zookeeper-deployment.yaml b/installer/k8s/templates/external/zookeeper/zookeeper-deployment.yaml index 6debfc6..756ae4e 100644 --- a/installer/k8s/templates/external/zookeeper/zookeeper-deployment.yaml +++ b/installer/k8s/templates/external/zookeeper/zookeeper-deployment.yaml
@@ -13,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -{{- if (eq .Values.deployment "full") }} apiVersion: apps/v1 kind: Deployment metadata: @@ -43,4 +42,3 @@ volumeMounts: - mountPath: "/opt/zookeeper-{{ .Values.external.zookeeperVersion }}/data" name: zookeeper-pv -{{- end }} \ No newline at end of file
diff --git a/installer/k8s/templates/external/zookeeper/zookeeper-pvc.yaml b/installer/k8s/templates/external/zookeeper/zookeeper-pvc.yaml index cbd9b45..741bc9b 100644 --- a/installer/k8s/templates/external/zookeeper/zookeeper-pvc.yaml +++ b/installer/k8s/templates/external/zookeeper/zookeeper-pvc.yaml
@@ -13,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -{{- if (eq .Values.deployment "full") }} apiVersion: v1 kind: PersistentVolume metadata: @@ -41,4 +40,3 @@ resources: requests: storage: 20M -{{- end }} \ No newline at end of file
diff --git a/installer/k8s/templates/external/zookeeper/zookeeper-service.yaml b/installer/k8s/templates/external/zookeeper/zookeeper-service.yaml index cb10589..d65bdb9 100644 --- a/installer/k8s/templates/external/zookeeper/zookeeper-service.yaml +++ b/installer/k8s/templates/external/zookeeper/zookeeper-service.yaml
@@ -13,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -{{- if (eq .Values.deployment "full") }} apiVersion: v1 kind: Service metadata: @@ -26,4 +25,3 @@ protocol: TCP port: 2181 targetPort: 2181 -{{- end }} \ No newline at end of file
diff --git a/installer/k8s/values.yaml b/installer/k8s/values.yaml index 0f662c7..cbbfd9b 100644 --- a/installer/k8s/values.yaml +++ b/installer/k8s/values.yaml
@@ -15,12 +15,13 @@ # lite or full (default: lite) deployment: lite +preferredBroker: "kafka" pullPolicy: "IfNotPresent" -persistentVolumeReclaimPolicy: "Retain" +persistentVolumeReclaimPolicy: "Delete" persistentVolumeAccessModes: "ReadWriteOnce" streampipes: - version: "0.70.0-SNAPSHOT" + version: "0.71.0-SNAPSHOT" registry: "apachestreampipes" external:
diff --git a/installer/upgrade_versions.sh b/installer/upgrade_versions.sh index 1c98145..fef8845 100755 --- a/installer/upgrade_versions.sh +++ b/installer/upgrade_versions.sh
@@ -47,7 +47,7 @@ for opt in "${options[@]}" do - sed -i 's/**Current version:** .*/**Current version:** '$NEW_VERSION'/g' ./$opt/README.md + sed -i 's/\*\*Current version:\*\* .*/\*\*Current version:\*\* '$NEW_VERSION'/g' ./$opt/README.md done ;; esac
diff --git a/pom.xml b/pom.xml index e35c0f4..30e1d65 100644 --- a/pom.xml +++ b/pom.xml
@@ -17,8 +17,7 @@ ~ --> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> @@ -29,7 +28,7 @@ <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> -<version>0.70.0-SNAPSHOT</version> +<version>0.71.0-SNAPSHOT</version> <packaging>pom</packaging> <properties> @@ -83,7 +82,7 @@ <jboss-logging-processor.version>2.2.1.Final</jboss-logging-processor.version> <jersey.version>2.35</jersey.version> <jetbrains-annotations.version>16.0.2</jetbrains-annotations.version> - <jetty.version>9.4.44.v20210927</jetty.version> + <jetty.version>10.0.10</jetty.version> <jgrapht.version>1.3.1</jgrapht.version> <jjwt.version>0.11.2</jjwt.version> <json-path.version>3.1.0</json-path.version> @@ -109,14 +108,15 @@ <slf4j.version>1.7.30</slf4j.version> <snakeyaml.version>1.26</snakeyaml.version> <snappy-java.version>1.1.7.7</snappy-java.version> - <spring.version>5.3.19</spring.version> + <spring.version>5.3.20</spring.version> <spring-boot.version>2.6.7</spring-boot.version> - <spring-security.version>5.6.3</spring-security.version> + <spring-security.version>5.6.4</spring-security.version> <swagger.version>2.1.12</swagger.version> <type-parser.version>0.6.0</type-parser.version> <underscore.version>1.47</underscore.version> <wildfly-common.version>1.5.4.Final</wildfly-common.version> <hawtbuf.version>1.11</hawtbuf.version> + <netty-tc-native.version>2.0.52.Final</netty-tc-native.version> <!-- Test dependencies --> <junit.version>4.13.2</junit.version> @@ -222,7 +222,7 @@ <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> - <version>2.8.8</version> + <version>2.8.9</version> </dependency> <dependency> <groupId>com.google.guava</groupId> @@ -840,6 +840,11 @@ <artifactId>siddhi-query-compiler</artifactId> <version>${siddhi.version}</version> </dependency> + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty-tcnative-classes</artifactId> + <version>${netty-tc-native.version}</version> + </dependency> <!-- Test dependencies --> <dependency> @@ -956,7 +961,9 @@ <module>streampipes-mail</module> <module>streampipes-resource-management</module> <module>streampipes-sdk-bundle</module> - </modules> + <module>streampipes-data-explorer-commons</module> + <module>streampipes-data-export</module> + </modules> <profiles> <profile> @@ -1153,7 +1160,7 @@ </goals> <configuration> <rules> - <dependencyConvergence/> + <dependencyConvergence /> </rules> </configuration> </execution> @@ -1272,6 +1279,9 @@ <!-- Exclude some UI files which we need to check in more detail --> <exclude>ui/src/assets/img/svg/**</exclude> + <!-- Exclude .angular folder --> + <exclude>ui/.angular/**</exclude> + <!-- Exclude disclaimer and notice files --> <exclude>DISCLAIMER</exclude> <exclude>NOTICE-binary</exclude> @@ -1381,7 +1391,7 @@ <developerConnection>scm:git:ssh://git@github.com/apache/incubator-streampipes.git</developerConnection> <connection>scm:git:ssh://git@github.com/apache/incubator-streampipes.git</connection> <url>https://github.com/apache/incubator-streampipes</url> - <tag>HEAD</tag> + <tag>rel/0.70.0</tag> </scm> <issueManagement>
diff --git a/streampipes-backend/pom.xml b/streampipes-backend/pom.xml index 30797b6..a0c5280 100644 --- a/streampipes-backend/pom.xml +++ b/streampipes-backend/pom.xml
@@ -21,7 +21,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <artifactId>streampipes-backend</artifactId> @@ -33,7 +33,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-service-base</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> @@ -44,27 +44,27 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-config</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging-kafka</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-rest</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-connect-container-master</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-platform-services</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies --> <dependency>
diff --git a/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesBackendApplication.java b/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesBackendApplication.java index 6b0fe4f..260fc6f 100644 --- a/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesBackendApplication.java +++ b/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesBackendApplication.java
@@ -17,6 +17,7 @@ */ package org.apache.streampipes.backend; +import org.apache.streampipes.backend.migrations.MigrationsHandler; import org.apache.streampipes.config.backend.BackendConfig; import org.apache.streampipes.manager.health.PipelineHealthCheck; import org.apache.streampipes.manager.operations.Operations; @@ -27,6 +28,7 @@ import org.apache.streampipes.service.base.BaseNetworkingConfig; import org.apache.streampipes.service.base.StreamPipesServiceBase; import org.apache.streampipes.storage.api.IPipelineStorage; +import org.apache.streampipes.storage.couchdb.utils.CouchDbViewGenerator; import org.apache.streampipes.storage.management.StorageDispatcher; import org.apache.streampipes.svcdiscovery.api.model.DefaultSpServiceGroups; import org.apache.streampipes.svcdiscovery.api.model.DefaultSpServiceTags; @@ -96,11 +98,14 @@ this.executorService = Executors.newSingleThreadScheduledExecutor(); this.healthCheckExecutorService = Executors.newSingleThreadScheduledExecutor(); + new StreamPipesEnvChecker().updateEnvironmentVariables(); + new CouchDbViewGenerator().createGenericDatabaseIfNotExists(); + if (!isConfigured()) { doInitialSetup(); } - new StreamPipesEnvChecker().updateEnvironmentVariables(); + new MigrationsHandler().performMigrations(); executorService.schedule(this::startAllPreviouslyStoppedPipelines, 5, TimeUnit.SECONDS); LOG.info("Pipeline health check will run every {} seconds", HEALTH_CHECK_INTERVAL);
diff --git a/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesResourceConfig.java b/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesResourceConfig.java index 80dd28b..96ccf69 100644 --- a/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesResourceConfig.java +++ b/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesResourceConfig.java
@@ -19,10 +19,7 @@ package org.apache.streampipes.backend; import io.swagger.v3.jaxrs2.integration.resources.OpenApiResource; -import org.apache.streampipes.ps.DataLakeImageResource; -import org.apache.streampipes.ps.DataLakeResourceV3; -import org.apache.streampipes.ps.DataLakeResourceV4; -import org.apache.streampipes.ps.PipelineElementTemplateResource; +import org.apache.streampipes.ps.*; import org.apache.streampipes.rest.impl.*; import org.apache.streampipes.rest.impl.admin.*; import org.apache.streampipes.rest.impl.connect.*; @@ -30,7 +27,6 @@ import org.apache.streampipes.rest.impl.dashboard.DashboardWidget; import org.apache.streampipes.rest.impl.dashboard.VisualizablePipelineResource; import org.apache.streampipes.rest.impl.datalake.DataLakeDashboardResource; -import org.apache.streampipes.rest.impl.datalake.DataLakeMeasureResourceV3; import org.apache.streampipes.rest.impl.datalake.DataLakeWidgetResource; import org.apache.streampipes.rest.impl.datalake.PersistedDataStreamResource; import org.apache.streampipes.rest.impl.nouser.PipelineElementImportNoUser; @@ -55,20 +51,25 @@ register(AccountActivationResource.class); register(Authentication.class); register(AssetDashboardResource.class); + register(AssetManagementResource.class); register(AutoComplete.class); register(CategoryResource.class); register(ConsulConfig.class); register(ContainerProvidedOptions.class); register(DashboardWidget.class); register(Dashboard.class); + register(DataExportResource.class); + register(DataImportResource.class); register(DataLakeImageResource.class); register(DataLakeResourceV3.class); register(DataLakeMeasureResourceV3.class); + register(DataLakeMeasureResourceV4.class); register(DataStream.class); register(EmailConfigurationResource.class); register(EmailResource.class); register(ExtensionsServiceEndpointResource.class); register(GeneralConfigurationResource.class); + register(GenericStorageResource.class); register(LabelResource.class); register(MeasurementUnitResource.class); register(Notification.class); @@ -102,7 +103,6 @@ register(DataLakeDashboardResource.class); register(DataLakeWidgetResource.class); register(DataLakeResourceV3.class); - register(DataLakeMeasureResourceV3.class); register(PipelineElementFile.class); register(DashboardWidget.class); register(Dashboard.class);
diff --git a/streampipes-backend/src/main/java/org/apache/streampipes/backend/migrations/AvailableMigrations.java b/streampipes-backend/src/main/java/org/apache/streampipes/backend/migrations/AvailableMigrations.java new file mode 100644 index 0000000..5b26d79 --- /dev/null +++ b/streampipes-backend/src/main/java/org/apache/streampipes/backend/migrations/AvailableMigrations.java
@@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +package org.apache.streampipes.backend.migrations; + +import org.apache.streampipes.backend.migrations.v070.CreateAssetLinkTypeMigration; +import org.apache.streampipes.backend.migrations.v070.CreateDefaultAssetMigration; +import org.apache.streampipes.backend.migrations.v070.CreateFileAssetTypeMigration; + +import java.util.Arrays; +import java.util.List; + +public class AvailableMigrations { + + public List<Migration> getAvailableMigrations() { + return Arrays.asList( + new CreateAssetLinkTypeMigration(), + new CreateDefaultAssetMigration(), + new CreateFileAssetTypeMigration() + ); + } +}
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/streampipes-backend/src/main/java/org/apache/streampipes/backend/migrations/Migration.java similarity index 78% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to streampipes-backend/src/main/java/org/apache/streampipes/backend/migrations/Migration.java index 58ba04b..0cabbfa 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/streampipes-backend/src/main/java/org/apache/streampipes/backend/migrations/Migration.java
@@ -16,3 +16,16 @@ * */ + +package org.apache.streampipes.backend.migrations; + +import java.io.IOException; + +public interface Migration { + + boolean shouldExecute(); + + void executeMigration() throws IOException; + + String getDescription(); +}
diff --git a/streampipes-backend/src/main/java/org/apache/streampipes/backend/migrations/MigrationsHandler.java b/streampipes-backend/src/main/java/org/apache/streampipes/backend/migrations/MigrationsHandler.java new file mode 100644 index 0000000..72ea592 --- /dev/null +++ b/streampipes-backend/src/main/java/org/apache/streampipes/backend/migrations/MigrationsHandler.java
@@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +package org.apache.streampipes.backend.migrations; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +public class MigrationsHandler { + + private static final Logger LOG = LoggerFactory.getLogger(MigrationsHandler.class); + + public void performMigrations() { + LOG.info("Checking for required migrations..."); + var availableMigrations = new AvailableMigrations().getAvailableMigrations(); + + availableMigrations.forEach(migration -> { + if (migration.shouldExecute()) { + LOG.info("Performing migration: {}", migration.getDescription()); + try { + migration.executeMigration(); + } catch (IOException e) { + LOG.error("An error has occurred while executing migration '{}'", migration.getDescription(), e); + } + } + }); + + LOG.info("All migrations completed."); + } +}
diff --git a/streampipes-backend/src/main/java/org/apache/streampipes/backend/migrations/v070/CreateAssetLinkTypeMigration.java b/streampipes-backend/src/main/java/org/apache/streampipes/backend/migrations/v070/CreateAssetLinkTypeMigration.java new file mode 100644 index 0000000..27463d9 --- /dev/null +++ b/streampipes-backend/src/main/java/org/apache/streampipes/backend/migrations/v070/CreateAssetLinkTypeMigration.java
@@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +package org.apache.streampipes.backend.migrations.v070; + +import org.apache.streampipes.backend.migrations.Migration; +import org.apache.streampipes.commons.constants.GenericDocTypes; +import org.apache.streampipes.manager.setup.tasks.CreateAssetLinkTypeTask; +import org.apache.streampipes.storage.management.StorageDispatcher; + +import java.io.IOException; + +public class CreateAssetLinkTypeMigration implements Migration { + + @Override + public boolean shouldExecute() { + try { + return StorageDispatcher.INSTANCE.getNoSqlStore().getGenericStorage().findAll(GenericDocTypes.DOC_ASSET_LINK_TYPE).size() == 0; + } catch (IOException e) { + return true; + } + } + + @Override + public void executeMigration() { + new CreateAssetLinkTypeTask().execute(); + } + + @Override + public String getDescription() { + return "Populating database with default asset links"; + } +}
diff --git a/streampipes-backend/src/main/java/org/apache/streampipes/backend/migrations/v070/CreateDefaultAssetMigration.java b/streampipes-backend/src/main/java/org/apache/streampipes/backend/migrations/v070/CreateDefaultAssetMigration.java new file mode 100644 index 0000000..7cf10d5 --- /dev/null +++ b/streampipes-backend/src/main/java/org/apache/streampipes/backend/migrations/v070/CreateDefaultAssetMigration.java
@@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +package org.apache.streampipes.backend.migrations.v070; + +import org.apache.streampipes.backend.migrations.Migration; +import org.apache.streampipes.commons.constants.GenericDocTypes; +import org.apache.streampipes.manager.setup.tasks.CreateDefaultAssetTask; +import org.apache.streampipes.storage.management.StorageDispatcher; + +import java.io.IOException; + +public class CreateDefaultAssetMigration implements Migration { + + @Override + public boolean shouldExecute() { + try { + return StorageDispatcher.INSTANCE.getNoSqlStore().getGenericStorage().findOne(GenericDocTypes.DEFAULT_ASSET_DOC_ID) == null; + } catch (IOException e) { + return true; + } + } + + @Override + public void executeMigration() { + new CreateDefaultAssetTask().execute(); + } + + @Override + public String getDescription() { + return "Creating a default asset representation"; + } +}
diff --git a/streampipes-backend/src/main/java/org/apache/streampipes/backend/migrations/v070/CreateFileAssetTypeMigration.java b/streampipes-backend/src/main/java/org/apache/streampipes/backend/migrations/v070/CreateFileAssetTypeMigration.java new file mode 100644 index 0000000..56d837b --- /dev/null +++ b/streampipes-backend/src/main/java/org/apache/streampipes/backend/migrations/v070/CreateFileAssetTypeMigration.java
@@ -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. + * + */ + +package org.apache.streampipes.backend.migrations.v070; + +import org.apache.streampipes.backend.migrations.Migration; +import org.apache.streampipes.commons.constants.GenericDocTypes; +import org.apache.streampipes.commons.random.UUIDGenerator; +import org.apache.streampipes.model.assets.AssetLinkType; +import org.apache.streampipes.storage.management.StorageDispatcher; + +import java.io.IOException; +import java.util.List; + +public class CreateFileAssetTypeMigration implements Migration { + + @Override + public boolean shouldExecute() { + try { + return StorageDispatcher + .INSTANCE + .getNoSqlStore() + .getGenericStorage() + .findAll(GenericDocTypes.DOC_ASSET_LINK_TYPE) + .stream() + .noneMatch(al -> al.get("linkType").equals("file")); + } catch (IOException e) { + return true; + } + } + + @Override + public void executeMigration() throws IOException { + var fileAsset = new AssetLinkType("file", "File", "var(--color-file)", "draft", "file", List.of(), false); + fileAsset.setId(UUIDGenerator.generateUuid()); + StorageDispatcher.INSTANCE.getNoSqlStore().getGenericStorage().create(fileAsset, AssetLinkType.class); + + } + + @Override + public String getDescription() { + return "Create asset type 'File'"; + } +}
diff --git a/streampipes-client/pom.xml b/streampipes-client/pom.xml index be30324..b654f3b 100644 --- a/streampipes-client/pom.xml +++ b/streampipes-client/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,42 +32,42 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat-json</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat-cbor</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat-fst</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging-kafka</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model-client</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-security-jwt</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-serializers-json</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- 3rd party Dependencies -->
diff --git a/streampipes-client/src/main/java/org/apache/streampipes/client/http/HttpRequest.java b/streampipes-client/src/main/java/org/apache/streampipes/client/http/HttpRequest.java index 5c11455..cd5d178 100644 --- a/streampipes-client/src/main/java/org/apache/streampipes/client/http/HttpRequest.java +++ b/streampipes-client/src/main/java/org/apache/streampipes/client/http/HttpRequest.java
@@ -74,11 +74,11 @@ return headers.toArray(new Header[0]); } - protected String makeUrl() { + protected String makeUrl() throws SpRuntimeException { return makeUrl(true); } - protected String makeUrl(boolean includePath) { + protected String makeUrl(boolean includePath) throws SpRuntimeException { String baseUrl = clientConfig.getConnectionConfig().getBaseUrl(); if (includePath) { baseUrl = baseUrl + "/" + apiPath.toString(); @@ -87,7 +87,7 @@ return baseUrl; } - public DT executeRequest() throws SpRuntimeException { + public DT executeRequest() { Request request = makeRequest(serializer); try { HttpResponse response = request.execute().returnResponse(); @@ -101,10 +101,8 @@ throw new SpRuntimeException(status.getStatusCode() + " - " + status.getReasonPhrase()); } } - } catch (NoHttpResponseException e) { - throw new SpRuntimeException("Could not connect to the StreamPipes API - please check that StreamPipes is available at " + makeUrl(false)); - } catch (IOException e) { - throw new SpRuntimeException(e.getMessage()); + } catch (IOException | SpRuntimeException e) { + throw new SpRuntimeException("Could not connect to the StreamPipes API - please check that StreamPipes is available"); } }
diff --git a/streampipes-commons/pom.xml b/streampipes-commons/pom.xml index ab46b5f..8a9e80b 100644 --- a/streampipes-commons/pom.xml +++ b/streampipes-commons/pom.xml
@@ -21,7 +21,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <artifactId>streampipes-commons</artifactId>
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/streampipes-commons/src/main/java/org/apache/streampipes/commons/constants/GenericDocTypes.java similarity index 72% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to streampipes-commons/src/main/java/org/apache/streampipes/commons/constants/GenericDocTypes.java index 58ba04b..813f06b 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/streampipes-commons/src/main/java/org/apache/streampipes/commons/constants/GenericDocTypes.java
@@ -16,3 +16,13 @@ * */ +package org.apache.streampipes.commons.constants; + +public class GenericDocTypes { + + public static final String DOC_ASSET_MANGEMENT = "asset-management"; + public static final String DOC_ASSET_LINK_TYPE = "asset-link-type"; + + + public static final String DEFAULT_ASSET_DOC_ID = "default-asset"; +}
diff --git a/streampipes-commons/src/main/java/org/apache/streampipes/commons/exceptions/SpConfigurationException.java b/streampipes-commons/src/main/java/org/apache/streampipes/commons/exceptions/SpConfigurationException.java new file mode 100644 index 0000000..321330b --- /dev/null +++ b/streampipes-commons/src/main/java/org/apache/streampipes/commons/exceptions/SpConfigurationException.java
@@ -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. + * + */ + +package org.apache.streampipes.commons.exceptions; + +public class SpConfigurationException extends Exception { + + /** + * Creates a new Exception with the given message and null as the cause. + * + * @param message The exception message + */ + public SpConfigurationException(String message) { + super(message); + } + + /** + * Creates a new exception with a null message and the given cause. + * + * @param cause The exception that caused this exception + */ + public SpConfigurationException(Throwable cause) { + super(cause); + } + + /** + * Creates a new exception with the given message and cause + * + * @param message The exception message + * @param cause The exception that caused this exception + */ + public SpConfigurationException(String message, Throwable cause) { + super(message, cause); + } +}
diff --git a/streampipes-commons/src/main/java/org/apache/streampipes/commons/networking/Networking.java b/streampipes-commons/src/main/java/org/apache/streampipes/commons/networking/Networking.java index 489a557..bb98349 100644 --- a/streampipes-commons/src/main/java/org/apache/streampipes/commons/networking/Networking.java +++ b/streampipes-commons/src/main/java/org/apache/streampipes/commons/networking/Networking.java
@@ -21,13 +21,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.InetAddress; -import java.net.UnknownHostException; +import java.io.IOException; +import java.net.*; public class Networking { private static final Logger LOG = LoggerFactory.getLogger(Networking.class); + private static final String DEFAULT_LOCALHOST_IP = "127.0.0.1"; + public static String getHostname() throws UnknownHostException { String selectedAddress; if (Envs.SP_HOST.exists()) { @@ -35,12 +37,43 @@ LOG.info("Using IP from provided environment variable {}: {}", Envs.SP_HOST, selectedAddress); } else { selectedAddress = InetAddress.getLocalHost().getHostAddress(); + + // this condition is only used as a workaround when the IP address was not derived correctly + // when this also does not work, you must set the environment variable SP_HOST manually + if (selectedAddress.equals(DEFAULT_LOCALHOST_IP)) { + selectedAddress = getIpAddressForOsx(); + } + LOG.info("Using auto-discovered IP: {}", selectedAddress); } return selectedAddress; } + /** + * this method is a workaround for developers using osx + * in OSX InetAddress.getLocalHost().getHostAddress() always returns 127.0.0.1 + * as a workaround developers must manually set the SP_HOST environment variable with the actual ip + * with this method the IP is set automatically + * + * @return IP + */ + private static String getIpAddressForOsx() { + + Socket socket = new Socket(); + String result = DEFAULT_LOCALHOST_IP; + try { + socket.connect(new InetSocketAddress("streampipes.apache.org", 80)); + result = socket.getLocalAddress().getHostAddress(); + socket.close(); + } catch (IOException e) { + LOG.error(e.getMessage()); + LOG.error("IP address was not set automatically. Use the environment variable SP_HOST to set it manually."); + } + + return result; + } + public static Integer getPort(Integer defaultPort) { Integer selectedPort; if (Envs.SP_PORT.exists()) {
diff --git a/streampipes-commons/src/main/java/org/apache/streampipes/commons/zip/ZipFileExtractor.java b/streampipes-commons/src/main/java/org/apache/streampipes/commons/zip/ZipFileExtractor.java index 5ada0f4..12e5af6 100644 --- a/streampipes-commons/src/main/java/org/apache/streampipes/commons/zip/ZipFileExtractor.java +++ b/streampipes-commons/src/main/java/org/apache/streampipes/commons/zip/ZipFileExtractor.java
@@ -17,10 +17,9 @@ */ package org.apache.streampipes.commons.zip; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; +import java.util.HashMap; +import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -32,6 +31,32 @@ this.zipInputStream = zipInputStream; } + // TODO used by export feature - extend this to support binaries + public Map<String, byte[]> extractZipToMap() throws IOException { + byte[] buffer = new byte[1024]; + Map<String, byte[]> entries = new HashMap<>(); + ZipInputStream zis = new ZipInputStream(zipInputStream); + ZipEntry zipEntry = zis.getNextEntry(); + while (zipEntry != null) { + ByteArrayOutputStream fos = new ByteArrayOutputStream(); + int len; + while ((len = zis.read(buffer)) > 0) { + fos.write(buffer, 0, len); + } + entries.put(sanitizeName(zipEntry.getName()), fos.toByteArray()); + fos.close(); + zipEntry = zis.getNextEntry(); + } + zis.closeEntry(); + zis.close(); + + return entries; + } + + private String sanitizeName(String name) { + return name.split("\\.")[0]; + } + public void extractZipToFile(String targetFolder) throws IOException { File destDir = new File(targetFolder); if (!destDir.exists()) {
diff --git a/streampipes-config/pom.xml b/streampipes-config/pom.xml index 48c4a4f..5e953bb 100644 --- a/streampipes-config/pom.xml +++ b/streampipes-config/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,17 +32,17 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-serializers-json</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-vocabulary</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-service-discovery</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-connect-api/pom.xml b/streampipes-connect-api/pom.xml index 75f5c9b..a7bbbd9 100644 --- a/streampipes-connect-api/pom.xml +++ b/streampipes-connect-api/pom.xml
@@ -17,13 +17,11 @@ ~ --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -33,7 +31,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> </dependencies> <properties>
diff --git a/streampipes-connect-api/src/main/java/org/apache/streampipes/connect/api/IParser.java b/streampipes-connect-api/src/main/java/org/apache/streampipes/connect/api/IParser.java index 482bf9f..017adb6 100644 --- a/streampipes-connect-api/src/main/java/org/apache/streampipes/connect/api/IParser.java +++ b/streampipes-connect-api/src/main/java/org/apache/streampipes/connect/api/IParser.java
@@ -19,6 +19,7 @@ import org.apache.streampipes.connect.api.exception.ParseException; import org.apache.streampipes.model.connect.grounding.FormatDescription; +import org.apache.streampipes.model.connect.guess.AdapterGuessInfo; import org.apache.streampipes.model.schema.EventSchema; import java.io.InputStream; @@ -39,4 +40,12 @@ * @return */ EventSchema getEventSchema(List<byte[]> oneEvent); + + default boolean supportsPreview() { + return false; + } + + default AdapterGuessInfo getSchemaAndSample(List<byte[]> eventSample) throws ParseException { + throw new RuntimeException("Not yet implemented!"); + } }
diff --git a/streampipes-connect-api/src/main/java/org/apache/streampipes/connect/api/exception/ParseException.java b/streampipes-connect-api/src/main/java/org/apache/streampipes/connect/api/exception/ParseException.java index 2064f29..37c3ed3 100644 --- a/streampipes-connect-api/src/main/java/org/apache/streampipes/connect/api/exception/ParseException.java +++ b/streampipes-connect-api/src/main/java/org/apache/streampipes/connect/api/exception/ParseException.java
@@ -19,10 +19,16 @@ package org.apache.streampipes.connect.api.exception; public class ParseException extends RuntimeException { + public ParseException() {} public ParseException(String message) { super(message); } + + public ParseException(String message, + Throwable throwable) { + super(message, throwable); + } }
diff --git a/streampipes-connect-container-master/pom.xml b/streampipes-connect-container-master/pom.xml index 3d4207c..b1b9c26 100644 --- a/streampipes-connect-container-master/pom.xml +++ b/streampipes-connect-container-master/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,32 +32,32 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-connect</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-measurement-units</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-pipeline-management</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-storage-couchdb</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-user-management</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-data-explorer</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/AdapterMasterManagement.java b/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/AdapterMasterManagement.java index fc955bb..dc32b88 100644 --- a/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/AdapterMasterManagement.java +++ b/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/AdapterMasterManagement.java
@@ -189,7 +189,7 @@ LOG.info("Started adapter " + elementId + " on: " + baseUrl); } catch (NoServiceEndpointsAvailableException | URISyntaxException e) { - e.printStackTrace(); + throw new AdapterException("Could not start adapter due to unavailable service endpoint", e); } } }
diff --git a/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/DescriptionManagement.java b/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/DescriptionManagement.java index 834c764..da40e49 100644 --- a/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/DescriptionManagement.java +++ b/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/DescriptionManagement.java
@@ -18,6 +18,7 @@ package org.apache.streampipes.connect.container.master.management; +import org.apache.streampipes.commons.exceptions.SpRuntimeException; import org.apache.streampipes.connect.adapter.AdapterRegistry; import org.apache.streampipes.connect.api.IFormat; import org.apache.streampipes.connect.api.exception.AdapterException; @@ -25,6 +26,7 @@ import org.apache.streampipes.model.connect.grounding.FormatDescription; import org.apache.streampipes.storage.api.IAdapterStorage; import org.apache.streampipes.storage.couchdb.CouchDbStorageManager; +import org.apache.streampipes.storage.management.StorageDispatcher; import java.util.ArrayList; import java.util.List; @@ -55,6 +57,15 @@ .findFirst(); } + public void deleteAdapterDescription(String id) throws SpRuntimeException { + var adapterStorage = CouchDbStorageManager.INSTANCE.getAdapterDescriptionStorage(); + var adapter = adapterStorage.getAdapter(id); + if (!isAdapterUsed(adapter)) { + adapterStorage.deleteAdapter(id); + } else { + throw new SpRuntimeException("This adapter is used by an existing instance and cannot be deleted"); + } + } public String getAssets(String baseUrl) throws AdapterException { return WorkerRestClient.getAssets(baseUrl); } @@ -67,4 +78,12 @@ return WorkerRestClient.getDocumentationAsset(baseUrl); } + private boolean isAdapterUsed(AdapterDescription adapter) { + var allAdapters = StorageDispatcher.INSTANCE.getNoSqlStore().getAdapterInstanceStorage().getAllAdapters(); + + return allAdapters + .stream() + .anyMatch(runningAdapter -> runningAdapter.getAppId().equals(adapter.getAppId())); + } + }
diff --git a/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/GuessManagement.java b/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/GuessManagement.java index 0d867bb..de66c54 100644 --- a/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/GuessManagement.java +++ b/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/GuessManagement.java
@@ -26,18 +26,21 @@ import org.apache.http.entity.ContentType; import org.apache.http.util.EntityUtils; import org.apache.streampipes.commons.exceptions.NoServiceEndpointsAvailableException; -import org.apache.streampipes.connect.api.exception.AdapterException; +import org.apache.streampipes.commons.exceptions.SpConfigurationException; +import org.apache.streampipes.connect.adapter.model.pipeline.AdapterEventPreviewPipeline; import org.apache.streampipes.connect.api.exception.ParseException; import org.apache.streampipes.connect.api.exception.WorkerAdapterException; import org.apache.streampipes.connect.container.master.util.WorkerPaths; import org.apache.streampipes.model.connect.adapter.AdapterDescription; +import org.apache.streampipes.model.connect.guess.AdapterEventPreview; import org.apache.streampipes.model.connect.guess.GuessSchema; -import org.apache.streampipes.model.message.ErrorMessage; +import org.apache.streampipes.model.connect.guess.GuessTypeInfo; import org.apache.streampipes.serializers.json.JacksonSerializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.util.Map; public class GuessManagement { @@ -48,8 +51,7 @@ this.workerUrlProvider = new WorkerUrlProvider(); } - public GuessSchema guessSchema(AdapterDescription adapterDescription) throws AdapterException, ParseException, WorkerAdapterException { - try { + public GuessSchema guessSchema(AdapterDescription adapterDescription) throws ParseException, WorkerAdapterException, NoServiceEndpointsAvailableException, IOException { String workerUrl = workerUrlProvider.getWorkerBaseUrl(adapterDescription.getAppId()); workerUrl = workerUrl + WorkerPaths.getGuessSchemaPath(); @@ -67,18 +69,14 @@ String responseString = EntityUtils.toString(httpResponse.getEntity()); if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { - return mapper.readValue(responseString, GuessSchema.class); - } else { - ErrorMessage errorMessage = mapper.readValue(responseString, ErrorMessage.class); - - LOG.error(errorMessage.getElementName()); - throw new WorkerAdapterException(errorMessage); + return mapper.readValue(responseString, GuessSchema.class); + } else { + var exception = mapper.readValue(responseString, SpConfigurationException.class); + throw new WorkerAdapterException(exception.getMessage(), exception.getCause()); } - - } catch (IOException | NoServiceEndpointsAvailableException e) { - LOG.error(e.getMessage()); - throw new AdapterException("Error in connect worker: ", e); - } } + public Map<String, GuessTypeInfo> performAdapterEventPreview(AdapterEventPreview previewRequest) { + return new AdapterEventPreviewPipeline(previewRequest).makePreview(); + } }
diff --git a/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/WorkerAdministrationManagement.java b/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/WorkerAdministrationManagement.java index 9d3b5e3..1124929 100644 --- a/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/WorkerAdministrationManagement.java +++ b/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/WorkerAdministrationManagement.java
@@ -49,7 +49,7 @@ // only install once adapter description per service group boolean alreadyInstalled = alreadyRegisteredAdapters .stream() - .anyMatch(a -> a.getAppId().equals(adapterDescription.getAppId()) && a.getCorrespondingServiceGroup().equals(adapterDescription.getCorrespondingServiceGroup())); + .anyMatch(a -> a.getAppId().equals(adapterDescription.getAppId())); if (!alreadyInstalled) { this.adapterDescriptionStorage.storeAdapter(adapterDescription); }
diff --git a/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/WorkerRestClient.java b/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/WorkerRestClient.java index 8c9f107..241b93f 100644 --- a/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/WorkerRestClient.java +++ b/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/WorkerRestClient.java
@@ -18,8 +18,12 @@ package org.apache.streampipes.connect.container.master.management; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; import org.apache.http.client.fluent.Request; import org.apache.http.entity.ContentType; +import org.apache.streampipes.commons.exceptions.SpConfigurationException; import org.apache.streampipes.connect.api.exception.AdapterException; import org.apache.streampipes.connect.container.master.util.WorkerPaths; import org.apache.streampipes.model.connect.adapter.AdapterDescription; @@ -37,6 +41,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.List; /** @@ -99,66 +104,75 @@ public static void startAdapter(String url, AdapterDescription ad) throws AdapterException { - try { - logger.info("Trying to start adapter on endpoint: " + url); - - String adapterDescription = JacksonSerializer.getObjectMapper().writeValueAsString(ad); - - String responseString = Request.Post(url) - .bodyString(adapterDescription, ContentType.APPLICATION_JSON) - .connectTimeout(1000) - .socketTimeout(100000) - .execute().returnContent().asString(); - - logger.info("Adapter started on endpoint: " + url); - - } catch (IOException e) { - logger.error("Adapter did not start", e); - throw new AdapterException("Adapter with URL: " + url + " did not start"); - } + logger.info("Trying to start adapter on endpoint {} ", url); + triggerAdapterStateChange(ad, url, "started"); } public static void stopAdapter(AdapterDescription ad, String url) throws AdapterException { - // Stop execution of adapter - try { - logger.info("Trying to stop adapter on endpoint: " + url); + logger.info("Trying to stop adapter on endpoint {} ", url); + triggerAdapterStateChange(ad, url, "stopped"); + } + private static void triggerAdapterStateChange(AdapterDescription ad, + String url, + String action) throws AdapterException { + try { String adapterDescription = JacksonSerializer.getObjectMapper().writeValueAsString(ad); - // TODO change this to a delete request - String responseString = Request.Post(url) - .bodyString(adapterDescription, ContentType.APPLICATION_JSON) - .connectTimeout(1000) - .socketTimeout(100000) - .execute().returnContent().asString(); + var response = triggerPost(url, adapterDescription); + var responseString = getResponseBody(response); - logger.info("Adapter stopped on endpoint: " + url + " with Response: " + responseString); + if (response.getStatusLine().getStatusCode() != 200) { + var exception = getSerializer().readValue(responseString, AdapterException.class); + throw new AdapterException(exception.getMessage(), exception.getCause()); + } + + logger.info("Adapter {} on endpoint: " + url + " with Response: " + responseString); } catch (IOException e) { - logger.error("Adapter was not stopped successfully", e); - throw new AdapterException("Adapter was not stopped successfully with url: " + url); + logger.error("Adapter was not {} successfully", action, e); + throw new AdapterException("Adapter was not " + action + " successfully with url " + url, e); } + } + private static String getResponseBody(HttpResponse response) throws IOException { + return IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8); + } + + private static HttpResponse triggerPost(String url, + String payload) throws IOException { + return Request.Post(url) + .bodyString(payload, ContentType.APPLICATION_JSON) + .connectTimeout(1000) + .socketTimeout(100000) + .execute().returnResponse(); } public static RuntimeOptionsResponse getConfiguration(String workerEndpoint, String appId, - RuntimeOptionsRequest runtimeOptionsRequest) throws AdapterException { + RuntimeOptionsRequest runtimeOptionsRequest) throws AdapterException, SpConfigurationException { String url = workerEndpoint + WorkerPaths.getRuntimeResolvablePath(appId); try { String payload = JacksonSerializer.getObjectMapper().writeValueAsString(runtimeOptionsRequest); - String responseString = Request.Post(url) + var response = Request.Post(url) .bodyString(payload, ContentType.APPLICATION_JSON) .connectTimeout(1000) .socketTimeout(100000) - .execute().returnContent().asString(); + .execute() + .returnResponse(); - return JacksonSerializer.getObjectMapper().readValue(responseString, RuntimeOptionsResponse.class); + String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8); + if (response.getStatusLine().getStatusCode() == 200) { + return getSerializer().readValue(responseString, RuntimeOptionsResponse.class); + } else { + var exception = getSerializer().readValue(responseString, SpConfigurationException.class); + throw new SpConfigurationException(exception.getMessage(), exception.getCause()); + } } catch (IOException e) { e.printStackTrace(); throw new AdapterException("Could not resolve runtime configurations from " + url); @@ -245,5 +259,9 @@ private static IAdapterStorage getAdapterStorage() { return StorageDispatcher.INSTANCE.getNoSqlStore().getAdapterInstanceStorage(); } + + private static ObjectMapper getSerializer() { + return JacksonSerializer.getObjectMapper(); + } }
diff --git a/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/util/WorkerPaths.java b/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/util/WorkerPaths.java index f3af79b..1a48828 100644 --- a/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/util/WorkerPaths.java +++ b/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/util/WorkerPaths.java
@@ -60,8 +60,7 @@ SpServiceUrlProvider serviceUrlProvider = SpServiceUrlProvider.ADAPTER; String endpointUrl = new ExtensionsServiceEndpointGenerator(appId, serviceUrlProvider).getEndpointResourceUrl(); URI uri = new URI(endpointUrl); - String baseUrl = uri.getScheme() + "://" + uri.getAuthority(); - return baseUrl; + return uri.getScheme() + "://" + uri.getAuthority(); }
diff --git a/streampipes-connect-container-worker/pom.xml b/streampipes-connect-container-worker/pom.xml index dc1e74b..09dd177 100644 --- a/streampipes-connect-container-worker/pom.xml +++ b/streampipes-connect-container-worker/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,37 +32,37 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-config</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-connect</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-container</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-client</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-service-extensions-base</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-rest-shared</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-serializers-json</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/management/AdapterWorkerManagement.java b/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/management/AdapterWorkerManagement.java index 1c8d606..f250ac7 100644 --- a/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/management/AdapterWorkerManagement.java +++ b/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/management/AdapterWorkerManagement.java
@@ -80,11 +80,9 @@ IAdapter<?> adapter = RunningAdapterInstances.INSTANCE.removeAdapter(elementId); - if (adapter == null) { - throw new AdapterException("Adapter with id " + elementId + " was not found in this container and cannot be stopped."); + if (adapter != null) { + adapter.stopAdapter(); } - - adapter.stopAdapter(); } }
diff --git a/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/management/GuessManagement.java b/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/management/GuessManagement.java index 41f81de..362c63a 100644 --- a/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/management/GuessManagement.java +++ b/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/management/GuessManagement.java
@@ -60,8 +60,7 @@ throw new ParseException(errorClass + e.getMessage()); } catch (Exception e) { - LOG.error("Unknown Error: " + e.toString()); - throw new AdapterException(e.toString()); + throw new AdapterException(e.getMessage(), e); } return guessSchema;
diff --git a/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/rest/AdapterWorkerResource.java b/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/rest/AdapterWorkerResource.java index e423590..9aa69c8 100644 --- a/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/rest/AdapterWorkerResource.java +++ b/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/rest/AdapterWorkerResource.java
@@ -20,6 +20,7 @@ import org.apache.streampipes.connect.api.exception.AdapterException; import org.apache.streampipes.connect.container.worker.management.AdapterWorkerManagement; +import org.apache.streampipes.model.StreamPipesErrorMessage; import org.apache.streampipes.model.connect.adapter.AdapterSetDescription; import org.apache.streampipes.model.connect.adapter.AdapterStreamDescription; import org.apache.streampipes.model.message.Notifications; @@ -65,14 +66,13 @@ try { adapterManagement.invokeStreamAdapter(adapterStreamDescription); + String responseMessage = "Stream adapter with id " + adapterStreamDescription.getUri() + " successfully started"; + logger.info(responseMessage); + return ok(Notifications.success(responseMessage)); } catch (AdapterException e) { logger.error("Error while starting adapter with id " + adapterStreamDescription.getUri(), e); - return ok(Notifications.error(e.getMessage())); + return serverError(StreamPipesErrorMessage.from(e)); } - String responseMessage = "Stream adapter with id " + adapterStreamDescription.getUri() + " successfully started"; - - logger.info(responseMessage); - return ok(Notifications.success(responseMessage)); } @POST @@ -82,17 +82,20 @@ @Produces(MediaType.APPLICATION_JSON) public Response stopStreamAdapter(AdapterStreamDescription adapterStreamDescription) { + String responseMessage; try { - adapterManagement.stopStreamAdapter(adapterStreamDescription); + if (adapterStreamDescription.isRunning()) { + adapterManagement.stopStreamAdapter(adapterStreamDescription); + responseMessage = "Stream adapter with id " + adapterStreamDescription.getElementId() + " successfully stopped"; + } else { + responseMessage = "Stream adapter with id " + adapterStreamDescription.getElementId() + " seems not to be running"; + } + logger.info(responseMessage); + return ok(Notifications.success(responseMessage)); } catch (AdapterException e) { - logger.error("Error while stopping adapter with id " + adapterStreamDescription.getUri(), e); - return ok(Notifications.error(e.getMessage())); + logger.error("Error while stopping adapter with id " + adapterStreamDescription.getElementId(), e); + return serverError(StreamPipesErrorMessage.from(e)); } - - String responseMessage = "Stream adapter with id " + adapterStreamDescription.getUri() + " successfully stopped"; - - logger.info(responseMessage); - return ok(Notifications.success(responseMessage)); } @POST
diff --git a/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/rest/GuessResource.java b/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/rest/GuessResource.java index 39d8784..c357a54 100644 --- a/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/rest/GuessResource.java +++ b/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/rest/GuessResource.java
@@ -18,11 +18,11 @@ package org.apache.streampipes.connect.container.worker.rest; +import org.apache.streampipes.connect.api.exception.AdapterException; import org.apache.streampipes.connect.api.exception.ParseException; import org.apache.streampipes.connect.container.worker.management.GuessManagement; import org.apache.streampipes.model.connect.adapter.AdapterDescription; import org.apache.streampipes.model.connect.guess.GuessSchema; -import org.apache.streampipes.model.message.Notifications; import org.apache.streampipes.rest.shared.annotation.JacksonSerialized; import org.apache.streampipes.rest.shared.impl.AbstractSharedRestInterface; import org.slf4j.Logger; @@ -62,10 +62,10 @@ return ok(result); } catch (ParseException e) { logger.error("Error while parsing events: ", e); - return serverError(Notifications.error(e.getMessage())); - } catch (Exception e) { - logger.error("Error while guess schema for AdapterDescription: " + adapterDescription.getElementId(), e); - return serverError(Notifications.error(e.getMessage())); + return serverError(e); + } catch (AdapterException e) { + logger.error("Error while guessing schema for AdapterDescription: {}, {}", adapterDescription.getElementId(), e.getMessage()); + return serverError(e); } }
diff --git a/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/rest/RuntimeResolvableResource.java b/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/rest/RuntimeResolvableResource.java index 92a81fd..72a2094 100644 --- a/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/rest/RuntimeResolvableResource.java +++ b/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/rest/RuntimeResolvableResource.java
@@ -18,6 +18,8 @@ package org.apache.streampipes.connect.container.worker.rest; +import org.apache.streampipes.commons.exceptions.SpConfigurationException; +import org.apache.streampipes.commons.exceptions.SpRuntimeException; import org.apache.streampipes.connect.api.Connector; import org.apache.streampipes.connect.container.worker.management.RuntimeResovable; import org.apache.streampipes.container.api.ResolvesContainerProvidedOptions; @@ -47,15 +49,21 @@ RuntimeOptionsResponse response; RuntimeResolvableRequestHandler handler = new RuntimeResolvableRequestHandler(); - if (connector instanceof ResolvesContainerProvidedOptions) { - response = handler.handleRuntimeResponse((ResolvesContainerProvidedOptions) connector, runtimeOptionsRequest); - } else if (connector instanceof SupportsRuntimeConfig) { - response = handler.handleRuntimeResponse((SupportsRuntimeConfig) connector, runtimeOptionsRequest); - } else { - throw new WebApplicationException(javax.ws.rs.core.Response.Status.BAD_REQUEST); + try { + if (connector instanceof ResolvesContainerProvidedOptions) { + response = handler.handleRuntimeResponse((ResolvesContainerProvidedOptions) connector, runtimeOptionsRequest); + return ok(response); + } else if (connector instanceof SupportsRuntimeConfig) { + response = handler.handleRuntimeResponse((SupportsRuntimeConfig) connector, runtimeOptionsRequest); + return ok(response); + } else { + throw new SpRuntimeException("This element does not support dynamic options - is the pipeline element description up to date?"); + } + } catch (SpConfigurationException e) { + return javax.ws.rs.core.Response + .status(400) + .entity(e) + .build(); } - - return ok(response); } - }
diff --git a/streampipes-connect-container-worker/src/test/java/org/apache/streampipes/connect/container/worker/management/AdapterWorkerManagementTest.java b/streampipes-connect-container-worker/src/test/java/org/apache/streampipes/connect/container/worker/management/AdapterWorkerManagementTest.java index 631f3f9..f16a2e7 100644 --- a/streampipes-connect-container-worker/src/test/java/org/apache/streampipes/connect/container/worker/management/AdapterWorkerManagementTest.java +++ b/streampipes-connect-container-worker/src/test/java/org/apache/streampipes/connect/container/worker/management/AdapterWorkerManagementTest.java
@@ -42,22 +42,6 @@ public class AdapterWorkerManagementTest { @Test - public void stopStreamAdapterFail() { - String expected = "Adapter with id http://test.de was not found in this container and cannot be stopped."; - AdapterStreamDescription asd = new GenericAdapterStreamDescription(); - asd.setUri("http://test.de"); - - AdapterWorkerManagement adapterManagement = new AdapterWorkerManagement(); - - try { - adapterManagement.stopStreamAdapter(asd); - fail(); - } catch (AdapterException e) { - assertEquals(expected, e.getMessage()); - } - } - - @Test public void stopStreamAdapterSuccess() throws AdapterException { TestAdapter testAdapter = getTestAdapterInstance(); RunningAdapterInstances.INSTANCE.addAdapter("http://t.de/", testAdapter, null); @@ -69,22 +53,6 @@ } @Test - public void stopSetAdapterFail() { - String expected = "Adapter with id http://test.de was not found in this container and cannot be stopped."; - AdapterSetDescription asd = new GenericAdapterSetDescription(); - asd.setUri("http://test.de"); - - AdapterWorkerManagement adapterManagement = new AdapterWorkerManagement(); - - try { - adapterManagement.stopSetAdapter(asd); - fail(); - } catch (AdapterException e) { - assertEquals(expected, e.getMessage()); - } - } - - @Test public void stopSetAdapterSuccess() throws AdapterException { TestAdapter testAdapter = getTestAdapterInstance();
diff --git a/streampipes-connect/pom.xml b/streampipes-connect/pom.xml index 2f36435..7517b49 100755 --- a/streampipes-connect/pom.xml +++ b/streampipes-connect/pom.xml
@@ -21,7 +21,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,72 +32,72 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-config</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-connect-api</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat-json</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat-smile</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat-cbor</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat-fst</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-measurement-units</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging-kafka</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging-jms</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging-mqtt</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-rest-shared</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-serializers-json</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencis -->
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/Adapter.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/Adapter.java index 8b6ee89..d5d495a 100644 --- a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/Adapter.java +++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/Adapter.java
@@ -22,29 +22,17 @@ import org.apache.streampipes.config.backend.BackendConfig; import org.apache.streampipes.config.backend.SpProtocol; import org.apache.streampipes.connect.adapter.model.pipeline.AdapterPipeline; -import org.apache.streampipes.connect.adapter.preprocessing.transform.stream.DuplicateFilterPipelineElement; -import org.apache.streampipes.connect.api.IAdapterPipelineElement; -import org.apache.streampipes.connect.adapter.preprocessing.elements.*; +import org.apache.streampipes.connect.adapter.preprocessing.elements.SendToJmsAdapterSink; +import org.apache.streampipes.connect.adapter.preprocessing.elements.SendToKafkaAdapterSink; +import org.apache.streampipes.connect.adapter.preprocessing.elements.SendToMqttAdapterSink; import org.apache.streampipes.connect.api.IAdapter; import org.apache.streampipes.model.connect.adapter.AdapterDescription; -import org.apache.streampipes.model.connect.rules.TransformationRuleDescription; -import org.apache.streampipes.model.connect.rules.stream.EventRateTransformationRuleDescription; -import org.apache.streampipes.model.connect.rules.stream.RemoveDuplicatesTransformationRuleDescription; -import org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescription; -import org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription; -import org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription; import org.apache.streampipes.model.grounding.JmsTransportProtocol; import org.apache.streampipes.model.grounding.KafkaTransportProtocol; import org.apache.streampipes.model.grounding.MqttTransportProtocol; import org.apache.streampipes.model.grounding.TransportProtocol; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.List; public abstract class Adapter<T extends AdapterDescription> implements IAdapter<T> { - Logger logger = LoggerFactory.getLogger(Adapter.class); private boolean debug; @@ -100,97 +88,7 @@ } private AdapterPipeline getAdapterPipeline(T adapterDescription) { - - List<IAdapterPipelineElement> pipelineElements = new ArrayList<>(); - - // Must be before the schema transformations to ensure that user can move this event property - AddTimestampRuleDescription timestampTransformationRuleDescription = getTimestampRule(adapterDescription); - if (timestampTransformationRuleDescription != null) { - pipelineElements.add(new AddTimestampPipelineElement( - timestampTransformationRuleDescription.getRuntimeKey())); - } - - AddValueTransformationRuleDescription valueTransformationRuleDescription = getAddValueRule(adapterDescription); - if (valueTransformationRuleDescription != null) { - pipelineElements.add(new AddValuePipelineElement( - valueTransformationRuleDescription.getRuntimeKey(), - valueTransformationRuleDescription.getStaticValue())); - } - - - // first transform schema before transforming vales - // value rules should use unique keys for of new schema - pipelineElements.add(new TransformSchemaAdapterPipelineElement(adapterDescription.getSchemaRules())); - pipelineElements.add(new TransformValueAdapterPipelineElement(adapterDescription.getValueRules())); - - - RemoveDuplicatesTransformationRuleDescription duplicatesTransformationRuleDescription = getRemoveDuplicateRule(adapterDescription); - if (duplicatesTransformationRuleDescription != null) { - pipelineElements.add(new DuplicateFilterPipelineElement(duplicatesTransformationRuleDescription.getFilterTimeWindow())); - } - - TransformStreamAdapterElement transformStreamAdapterElement = new TransformStreamAdapterElement(); - EventRateTransformationRuleDescription eventRateTransformationRuleDescription = getEventRateTransformationRule(adapterDescription); - if (eventRateTransformationRuleDescription != null) { - transformStreamAdapterElement.addStreamTransformationRuleDescription(eventRateTransformationRuleDescription); - } - pipelineElements.add(transformStreamAdapterElement); - - // Needed when adapter is ( - if (adapterDescription.getEventGrounding() != null && adapterDescription.getEventGrounding().getTransportProtocol() != null - && adapterDescription.getEventGrounding().getTransportProtocol().getBrokerHostname() != null) { - return new AdapterPipeline(pipelineElements, getAdapterSink(adapterDescription)); - } - - return new AdapterPipeline(pipelineElements); - } - - private SendToBrokerAdapterSink<?> getAdapterSink(AdapterDescription adapterDescription) { - SpProtocol prioritizedProtocol = - BackendConfig.INSTANCE.getMessagingSettings().getPrioritizedProtocols().get(0); - - if (GroundingService.isPrioritized(prioritizedProtocol, JmsTransportProtocol.class)) { - return new SendToJmsAdapterSink(adapterDescription); - } - else if (GroundingService.isPrioritized(prioritizedProtocol, KafkaTransportProtocol.class)) { - return new SendToKafkaAdapterSink(adapterDescription); - } - else { - return new SendToMqttAdapterSink(adapterDescription); - } - } - - private RemoveDuplicatesTransformationRuleDescription getRemoveDuplicateRule(T adapterDescription) { - return getRule(adapterDescription, RemoveDuplicatesTransformationRuleDescription.class); - } - - private EventRateTransformationRuleDescription getEventRateTransformationRule(T adapterDescription) { - return getRule(adapterDescription, EventRateTransformationRuleDescription.class); - } - - private AddTimestampRuleDescription getTimestampRule(T adapterDescription) { - return getRule(adapterDescription, AddTimestampRuleDescription.class); - } - - private AddValueTransformationRuleDescription getAddValueRule(T adapterDescription) { - return getRule(adapterDescription, AddValueTransformationRuleDescription.class); - } - - private CorrectionValueTransformationRuleDescription getCorrectionValueRule(T adapterDescription) { - return getRule(adapterDescription, CorrectionValueTransformationRuleDescription.class); - } - - private <G extends TransformationRuleDescription> G getRule(T adapterDescription, Class<G> type) { - - if (adapterDescription != null) { - for (TransformationRuleDescription tr : adapterDescription.getRules()) { - if (type.isInstance(tr)) { - return type.cast(tr); - } - } - } - - return null; + return new AdapterPipelineGenerator().generatePipeline(adapterDescription); } @Override
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/AdapterPipelineGenerator.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/AdapterPipelineGenerator.java new file mode 100644 index 0000000..76ecd9f --- /dev/null +++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/AdapterPipelineGenerator.java
@@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.connect.adapter; + +import org.apache.streampipes.config.backend.BackendConfig; +import org.apache.streampipes.connect.adapter.model.pipeline.AdapterPipeline; +import org.apache.streampipes.connect.adapter.preprocessing.elements.*; +import org.apache.streampipes.connect.adapter.preprocessing.transform.stream.DuplicateFilterPipelineElement; +import org.apache.streampipes.connect.api.IAdapterPipelineElement; +import org.apache.streampipes.model.connect.adapter.AdapterDescription; +import org.apache.streampipes.model.connect.rules.TransformationRuleDescription; +import org.apache.streampipes.model.connect.rules.schema.SchemaTransformationRuleDescription; +import org.apache.streampipes.model.connect.rules.stream.EventRateTransformationRuleDescription; +import org.apache.streampipes.model.connect.rules.stream.RemoveDuplicatesTransformationRuleDescription; +import org.apache.streampipes.model.connect.rules.value.*; +import org.apache.streampipes.model.grounding.JmsTransportProtocol; +import org.apache.streampipes.model.grounding.KafkaTransportProtocol; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class AdapterPipelineGenerator { + + public AdapterPipeline generatePipeline(AdapterDescription adapterDescription) { + + var pipelineElements = makeAdapterPipelineElements(adapterDescription.getRules()); + + var duplicatesTransformationRuleDescription = getRemoveDuplicateRule(adapterDescription.getRules()); + if (duplicatesTransformationRuleDescription != null) { + pipelineElements.add(new DuplicateFilterPipelineElement(duplicatesTransformationRuleDescription.getFilterTimeWindow())); + } + + var transformStreamAdapterElement = new TransformStreamAdapterElement(); + var eventRateTransformationRuleDescription = getEventRateTransformationRule(adapterDescription.getRules()); + if (eventRateTransformationRuleDescription != null) { + transformStreamAdapterElement.addStreamTransformationRuleDescription(eventRateTransformationRuleDescription); + } + pipelineElements.add(transformStreamAdapterElement); + + // TODO decide what was meant with this comment + // Needed when adapter is ( + if (adapterDescription.getEventGrounding() != null && adapterDescription.getEventGrounding().getTransportProtocol() != null + && adapterDescription.getEventGrounding().getTransportProtocol().getBrokerHostname() != null) { + return new AdapterPipeline(pipelineElements, getAdapterSink(adapterDescription)); + } + + return new AdapterPipeline(pipelineElements); + } + + public List<IAdapterPipelineElement> makeAdapterPipelineElements(List<TransformationRuleDescription> rules) { + List<IAdapterPipelineElement> pipelineElements = new ArrayList<>(); + + // Must be before the schema transformations to ensure that user can move this event property + var timestampTransformationRuleDescription = getTimestampRule(rules); + if (timestampTransformationRuleDescription != null) { + pipelineElements.add(new AddTimestampPipelineElement( + timestampTransformationRuleDescription.getRuntimeKey())); + } + + var valueTransformationRuleDescription = getAddValueRule(rules); + if (valueTransformationRuleDescription != null) { + pipelineElements.add(new AddValuePipelineElement( + valueTransformationRuleDescription.getRuntimeKey(), + valueTransformationRuleDescription.getStaticValue())); + } + + // first transform schema before transforming vales + // value rules should use unique keys for of new schema + pipelineElements.add(new TransformSchemaAdapterPipelineElement(getSchemaRules(rules))); + pipelineElements.add(new TransformValueAdapterPipelineElement(getValueRules(rules))); + + return pipelineElements; + } + + private SendToBrokerAdapterSink<?> getAdapterSink(AdapterDescription adapterDescription) { + var prioritizedProtocol = + BackendConfig.INSTANCE.getMessagingSettings().getPrioritizedProtocols().get(0); + + if (GroundingService.isPrioritized(prioritizedProtocol, JmsTransportProtocol.class)) { + return new SendToJmsAdapterSink(adapterDescription); + } + else if (GroundingService.isPrioritized(prioritizedProtocol, KafkaTransportProtocol.class)) { + return new SendToKafkaAdapterSink(adapterDescription); + } + else { + return new SendToMqttAdapterSink(adapterDescription); + } + } + + private RemoveDuplicatesTransformationRuleDescription getRemoveDuplicateRule(List<TransformationRuleDescription> rules) { + return getRule(rules, RemoveDuplicatesTransformationRuleDescription.class); + } + + private EventRateTransformationRuleDescription getEventRateTransformationRule(List<TransformationRuleDescription> rules) { + return getRule(rules, EventRateTransformationRuleDescription.class); + } + + private AddTimestampRuleDescription getTimestampRule(List<TransformationRuleDescription> rules) { + return getRule(rules, AddTimestampRuleDescription.class); + } + + private AddValueTransformationRuleDescription getAddValueRule(List<TransformationRuleDescription> rules) { + return getRule(rules, AddValueTransformationRuleDescription.class); + } + + private <G extends TransformationRuleDescription> G getRule(List<TransformationRuleDescription> rules, + Class<G> type) { + + if (rules != null) { + for (TransformationRuleDescription tr : rules) { + if (type.isInstance(tr)) { + return type.cast(tr); + } + } + } + + return null; + } + + private List<TransformationRuleDescription> getValueRules(List<TransformationRuleDescription> rules) { + return rules + .stream() + .filter(r -> r instanceof ValueTransformationRuleDescription && !(r instanceof AddTimestampRuleDescription)) + .collect(Collectors.toList()); + } + + private List<TransformationRuleDescription> getSchemaRules(List<TransformationRuleDescription> rules) { + return rules + .stream() + .filter(r -> r instanceof SchemaTransformationRuleDescription) + .collect(Collectors.toList()); + } +}
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/csv/CsvParser.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/csv/CsvParser.java index 4f6b873..0b3e6be 100644 --- a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/csv/CsvParser.java +++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/csv/CsvParser.java
@@ -19,20 +19,23 @@ package org.apache.streampipes.connect.adapter.format.csv; -import org.apache.streampipes.connect.api.EmitBinaryEvent; import org.apache.streampipes.connect.adapter.model.generic.Parser; import org.apache.streampipes.connect.adapter.sdk.ParameterExtractor; +import org.apache.streampipes.connect.adapter.util.DatatypeUtils; +import org.apache.streampipes.connect.api.EmitBinaryEvent; import org.apache.streampipes.connect.api.exception.ParseException; import org.apache.streampipes.model.connect.grounding.FormatDescription; +import org.apache.streampipes.model.connect.guess.AdapterGuessInfo; +import org.apache.streampipes.model.connect.guess.GuessTypeInfo; import org.apache.streampipes.model.schema.EventPropertyPrimitive; import org.apache.streampipes.model.schema.EventSchema; -import org.apache.streampipes.vocabulary.XSD; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; @@ -81,7 +84,13 @@ } @Override - public EventSchema getEventSchema(List<byte[]> oneEvent) { + public boolean supportsPreview() { + return true; + } + + @Override + public AdapterGuessInfo getSchemaAndSample(List<byte[]> oneEvent) { + var sample = new HashMap<String, GuessTypeInfo>(); String[] keys; String[] data; @@ -99,28 +108,20 @@ EventSchema resultSchema = new EventSchema(); for (int i = 0; i < keys.length; i++) { EventPropertyPrimitive p = new EventPropertyPrimitive(); + var runtimeType = DatatypeUtils.getXsdDatatype(data[i], true); + var convertedValue = DatatypeUtils.convertValue(data[i], runtimeType); p.setRuntimeName(keys[i]); - p.setRuntimeType(getTypeString(data[i])); + p.setRuntimeType(runtimeType); + sample.put(keys[i], new GuessTypeInfo(DatatypeUtils.getCanonicalTypeClassName(data[i], true), convertedValue)); resultSchema.addEventProperty(p); } - return resultSchema; + return new AdapterGuessInfo(resultSchema, sample); } - private String getTypeString(String o) { - - try { - Double.parseDouble(o); - return XSD._float.toString(); - } catch (NumberFormatException e) { - - } - - if (o.equalsIgnoreCase("true") || o.equalsIgnoreCase("false")) { - return XSD._boolean.toString(); - } - - return XSD._string.toString(); + @Override + public EventSchema getEventSchema(List<byte[]> oneEvent) { + return getSchemaAndSample(oneEvent).getEventSchema(); }
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/AbstractJsonFormat.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/AbstractJsonFormat.java index a7116ae..1da9b16 100644 --- a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/AbstractJsonFormat.java +++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/AbstractJsonFormat.java
@@ -21,7 +21,6 @@ import org.apache.streampipes.connect.api.IFormat; import org.apache.streampipes.connect.api.exception.ParseException; import org.apache.streampipes.dataformat.json.JsonDataFormatDefinition; -import org.apache.streampipes.model.schema.EventSchema; import java.util.Map; @@ -30,8 +29,6 @@ @Override public Map<String, Object> parse(byte[] object) throws ParseException { - EventSchema resultSchema = new EventSchema(); - JsonDataFormatDefinition jsonDefinition = new JsonDataFormatDefinition(); Map<String, Object> result = null;
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/object/JsonObjectParser.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/object/JsonObjectParser.java index 3419bc9..06c5cf5 100644 --- a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/object/JsonObjectParser.java +++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/object/JsonObjectParser.java
@@ -20,24 +20,26 @@ import com.fasterxml.jackson.databind.ObjectMapper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.apache.streampipes.commons.exceptions.SpRuntimeException; -import org.apache.streampipes.connect.api.EmitBinaryEvent; -import org.apache.streampipes.connect.adapter.model.generic.Parser; import org.apache.streampipes.connect.adapter.format.util.JsonEventProperty; +import org.apache.streampipes.connect.adapter.model.generic.Parser; +import org.apache.streampipes.connect.api.EmitBinaryEvent; import org.apache.streampipes.connect.api.exception.ParseException; import org.apache.streampipes.dataformat.json.JsonDataFormatDefinition; import org.apache.streampipes.model.connect.grounding.FormatDescription; +import org.apache.streampipes.model.connect.guess.AdapterGuessInfo; +import org.apache.streampipes.model.connect.guess.GuessTypeInfo; import org.apache.streampipes.model.schema.EventProperty; import org.apache.streampipes.model.schema.EventSchema; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; public class JsonObjectParser extends Parser { @@ -75,9 +77,17 @@ @Override public EventSchema getEventSchema(List<byte[]> oneEvent) { - EventSchema resultSchema = new EventSchema(); + return getSchemaAndSample(oneEvent).getEventSchema(); + } -// resultSchema.setEventProperties(Arrays.asList(EpProperties.timestampProperty("timestamp"))); + @Override + public boolean supportsPreview() { + return true; + } + + @Override + public AdapterGuessInfo getSchemaAndSample(List<byte[]> eventSample) throws ParseException { + EventSchema resultSchema = new EventSchema(); JsonDataFormatDefinition jsonDefinition = new JsonDataFormatDefinition(); @@ -85,107 +95,22 @@ Map<String, Object> exampleEvent = null; try { - exampleEvent = jsonDefinition.toMap(oneEvent.get(0)); - } catch (SpRuntimeException e) { - e.printStackTrace(); - } + exampleEvent = jsonDefinition.toMap(eventSample.get(0)); + var sample = exampleEvent + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> + new GuessTypeInfo(e.getValue().getClass().getCanonicalName(), e.getValue()))); - for (Map.Entry<String, Object> entry : exampleEvent.entrySet()) - { -// System.out.println(entry.getKey() + "/" + entry.getValue()); - EventProperty p = JsonEventProperty.getEventProperty(entry.getKey(), entry.getValue()); + for (Map.Entry<String, Object> entry : exampleEvent.entrySet()) { + EventProperty p = JsonEventProperty.getEventProperty(entry.getKey(), entry.getValue()); - resultSchema.addEventProperty(p); - - } - - return resultSchema; - } - - public Map<String, Object> parseObject(javax.json.stream.JsonParser jsonParser, boolean root, int start) { - // this variable is needed to skip the first object start - String mapKey = ""; - Map<String, Object> result = new HashMap<>(); - List<Object> arr = null; - - while (jsonParser.hasNext()) { - javax.json.stream.JsonParser.Event event = jsonParser.next(); - switch (event) { - case KEY_NAME: - mapKey = jsonParser.getString(); - logger.debug("key: " + mapKey ); - break; - case START_OBJECT: - if (start == 0) { - Map<String, Object> ob = parseObject(jsonParser, false, 0); - if (arr == null) { - result.put(mapKey, ob); - } else { - arr.add(ob); - } - } else { - start--; - } - logger.debug("start object"); - break; - case END_OBJECT: - - logger.debug("end object"); - return result; - case START_ARRAY: - arr = new ArrayList<>(); - logger.debug("start array"); - break; - case END_ARRAY: - // Check if just the end of array is entered - if (result.keySet().size() == 0 && mapKey.equals("")) { - return null; - } - result.put(mapKey, arr); - arr = null; - logger.debug("end array"); - break; - case VALUE_TRUE: - if (arr == null) { - result.put(mapKey, true); - } else { - arr.add(true); - } - logger.debug("value: true"); - break; - case VALUE_FALSE: - if (arr == null) { - result.put(mapKey, false); - } else { - arr.add(false); - } - logger.debug("value: false"); - break; - case VALUE_STRING: - if (arr == null) { - result.put(mapKey, jsonParser.getString()); - } else { - arr.add(jsonParser.getString()); - } - logger.debug("value string: " + jsonParser.getString()); - break; - case VALUE_NUMBER: - if (arr == null) { - result.put(mapKey, jsonParser.getBigDecimal()); - } else { - arr.add(jsonParser.getBigDecimal()); - } - logger.debug("value number: " + jsonParser.getBigDecimal()); - break; - case VALUE_NULL: - logger.debug("value null"); - break; - default: - logger.error("Error: " + event + " event is not handled in the JSON parser"); - break; + resultSchema.addEventProperty(p); } - } - return result; + return new AdapterGuessInfo(resultSchema, sample); + } catch (SpRuntimeException e) { + throw new ParseException("Could not serialize event, did you choose the correct format?", e); + } } }
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/util/JsonEventProperty.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/util/JsonEventProperty.java index 6721638..a203190 100644 --- a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/util/JsonEventProperty.java +++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/util/JsonEventProperty.java
@@ -55,7 +55,7 @@ resultProperty = new EventPropertyPrimitive(); resultProperty.setRuntimeName(key); ((EventPropertyPrimitive) resultProperty).setRuntimeType(XSD._string.toString()); - } else if (o.getClass().equals(Integer.class) || o.getClass().equals(Double.class)|| o.getClass().equals(Long.class)) { + } else if (o.getClass().equals(Integer.class) || o.getClass().equals(Double.class) || o.getClass().equals(Float.class) || o.getClass().equals(Long.class)) { resultProperty = new EventPropertyPrimitive(); resultProperty.setRuntimeName(key); ((EventPropertyPrimitive) resultProperty).setRuntimeType(XSD._float.toString());
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/guess/SchemaGuesser.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/guess/SchemaGuesser.java index 53be8ab..29f534e 100644 --- a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/guess/SchemaGuesser.java +++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/guess/SchemaGuesser.java
@@ -18,16 +18,24 @@ package org.apache.streampipes.connect.adapter.guess; +import org.apache.streampipes.model.connect.guess.AdapterGuessInfo; import org.apache.streampipes.model.connect.guess.GuessSchema; import org.apache.streampipes.model.schema.EventSchema; public class SchemaGuesser { - public static GuessSchema guessSchma(EventSchema eventSchema) { + public static GuessSchema guessSchema(EventSchema eventSchema) { GuessSchema result = new GuessSchema(); result.setEventSchema(eventSchema); return result; } + + public static GuessSchema guessSchema(AdapterGuessInfo guessInfo) { + var result = guessSchema(guessInfo.getEventSchema()); + result.setEventPreview(guessInfo.getEventPreview()); + + return result; + } }
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/model/pipeline/AdapterEventPreviewPipeline.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/model/pipeline/AdapterEventPreviewPipeline.java new file mode 100644 index 0000000..3e36ad5 --- /dev/null +++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/model/pipeline/AdapterEventPreviewPipeline.java
@@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +package org.apache.streampipes.connect.adapter.model.pipeline; + +import org.apache.streampipes.connect.adapter.AdapterPipelineGenerator; +import org.apache.streampipes.connect.api.IAdapterPipeline; +import org.apache.streampipes.connect.api.IAdapterPipelineElement; +import org.apache.streampipes.model.connect.guess.AdapterEventPreview; +import org.apache.streampipes.model.connect.guess.GuessTypeInfo; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class AdapterEventPreviewPipeline implements IAdapterPipeline { + + private List<IAdapterPipelineElement> pipelineElements; + private Map<String, GuessTypeInfo> event; + + public AdapterEventPreviewPipeline(AdapterEventPreview previewRequest) { + this.pipelineElements = new AdapterPipelineGenerator().makeAdapterPipelineElements(previewRequest.getRules()); + this.event = previewRequest.getInputData(); + } + + @Override + public void process(Map<String, Object> event) { + for (IAdapterPipelineElement pe : this.pipelineElements) { + event = pe.process(event); + } + } + + @Override + public List<IAdapterPipelineElement> getPipelineElements() { + return null; + } + + @Override + public void setPipelineElements(List<IAdapterPipelineElement> pipelineElements) { + + } + + @Override + public void changePipelineSink(IAdapterPipelineElement pipelineSink) { + + } + + @Override + public IAdapterPipelineElement getPipelineSink() { + return null; + } + + public Map<String, GuessTypeInfo> makePreview() { + Map<String, Object> ev = this.event + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getValue())); + this.process(ev); + + return ev + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e-> new GuessTypeInfo(e.getValue().getClass().getCanonicalName(), e.getValue()))); + } +}
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/preprocessing/elements/TransformSchemaAdapterPipelineElement.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/preprocessing/elements/TransformSchemaAdapterPipelineElement.java index 735933f..e795af3 100644 --- a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/preprocessing/elements/TransformSchemaAdapterPipelineElement.java +++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/preprocessing/elements/TransformSchemaAdapterPipelineElement.java
@@ -27,6 +27,7 @@ import org.apache.streampipes.model.connect.rules.*; import org.apache.streampipes.model.connect.rules.schema.*; +import javax.xml.crypto.dsig.Transform; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -36,7 +37,7 @@ private SchemaEventTransformer eventTransformer; Logger logger = LoggerFactory.getLogger(TransformSchemaAdapterPipelineElement.class); - public TransformSchemaAdapterPipelineElement(List<SchemaTransformationRuleDescription> transformationRuleDescriptions) { + public TransformSchemaAdapterPipelineElement(List<? extends TransformationRuleDescription> transformationRuleDescriptions) { List<TransformationRule> rules = new ArrayList<>(); // transforms description to actual rules
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/preprocessing/elements/TransformValueAdapterPipelineElement.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/preprocessing/elements/TransformValueAdapterPipelineElement.java index 137966c..abb1bd2 100644 --- a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/preprocessing/elements/TransformValueAdapterPipelineElement.java +++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/preprocessing/elements/TransformValueAdapterPipelineElement.java
@@ -18,16 +18,16 @@ package org.apache.streampipes.connect.adapter.preprocessing.elements; -import org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.apache.streampipes.connect.api.IAdapterPipelineElement; import org.apache.streampipes.connect.adapter.preprocessing.Util; import org.apache.streampipes.connect.adapter.preprocessing.transform.value.*; +import org.apache.streampipes.connect.api.IAdapterPipelineElement; import org.apache.streampipes.model.connect.rules.TransformationRuleDescription; +import org.apache.streampipes.model.connect.rules.value.ChangeDatatypeTransformationRuleDescription; +import org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription; import org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription; import org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription; -import org.apache.streampipes.model.connect.rules.value.ValueTransformationRuleDescription; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; @@ -35,20 +35,20 @@ public class TransformValueAdapterPipelineElement implements IAdapterPipelineElement { - private ValueEventTransformer eventTransformer; - private Logger logger = LoggerFactory.getLogger(TransformValueAdapterPipelineElement.class); + private final ValueEventTransformer eventTransformer; + private final static Logger logger = LoggerFactory.getLogger(TransformValueAdapterPipelineElement.class); - public TransformValueAdapterPipelineElement(List<ValueTransformationRuleDescription> transformationRuleDescriptions) { + public TransformValueAdapterPipelineElement(List<? extends TransformationRuleDescription> transformationRuleDescriptions) { List<ValueTransformationRule> rules = new ArrayList<>(); // transforms description to actual rules for (TransformationRuleDescription ruleDescription : transformationRuleDescriptions) { if (ruleDescription instanceof UnitTransformRuleDescription) { - UnitTransformRuleDescription tmp = (UnitTransformRuleDescription) ruleDescription; + var tmp = (UnitTransformRuleDescription) ruleDescription; rules.add(new UnitTransformationRule(Util.toKeyArray(tmp.getRuntimeKey()), tmp.getFromUnitRessourceURL(), tmp.getToUnitRessourceURL())); - } else if(ruleDescription instanceof TimestampTranfsformationRuleDescription) { - TimestampTranfsformationRuleDescription tmp = (TimestampTranfsformationRuleDescription) ruleDescription; + } else if (ruleDescription instanceof TimestampTranfsformationRuleDescription) { + var tmp = (TimestampTranfsformationRuleDescription) ruleDescription; TimestampTranformationRuleMode mode = null; switch (tmp.getMode()) { case "formatString": mode = TimestampTranformationRuleMode.FORMAT_STRING; @@ -58,9 +58,12 @@ rules.add(new TimestampTranformationRule(Util.toKeyArray(tmp.getRuntimeKey()), mode, tmp.getFormatString(), tmp.getMultiplier())); } - else if(ruleDescription instanceof CorrectionValueTransformationRuleDescription) { - CorrectionValueTransformationRuleDescription tmp = (CorrectionValueTransformationRuleDescription) ruleDescription; + else if (ruleDescription instanceof CorrectionValueTransformationRuleDescription) { + var tmp = (CorrectionValueTransformationRuleDescription) ruleDescription; rules.add(new CorrectionValueTransformationRule(Util.toKeyArray(tmp.getRuntimeKey()), tmp.getCorrectionValue(), tmp.getOperator())); + } else if (ruleDescription instanceof ChangeDatatypeTransformationRuleDescription) { + var tmp = (ChangeDatatypeTransformationRuleDescription) ruleDescription; + rules.add(new DatatypeTransformationRule(tmp.getRuntimeKey(), tmp.getOriginalDatatypeXsd(), tmp.getTargetDatatypeXsd())); } else {
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/preprocessing/transform/value/DatatypeTransformationRule.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/preprocessing/transform/value/DatatypeTransformationRule.java new file mode 100644 index 0000000..d8c6d8a --- /dev/null +++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/preprocessing/transform/value/DatatypeTransformationRule.java
@@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.connect.adapter.preprocessing.transform.value; + +import org.apache.streampipes.connect.adapter.util.DatatypeUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +public class DatatypeTransformationRule implements ValueTransformationRule { + + private static final Logger LOG = LoggerFactory.getLogger(DatatypeTransformationRule.class); + + private String eventKey; + private String originalDatatypeXsd; + private String targetDatatypeXsd; + + public DatatypeTransformationRule(String eventKey, String originalDatatypeXsd, String targetDatatypeXsd) { + this.eventKey = eventKey; + this.originalDatatypeXsd = originalDatatypeXsd; + this.targetDatatypeXsd = targetDatatypeXsd; + } + + @Override + public Map<String, Object> transform(Map<String, Object> event) { + Object value = event.get(eventKey); + Object transformedValue = transformDatatype(value); + event.put(eventKey, transformedValue); + return event; + } + + public Object transformDatatype(Object value) { + return DatatypeUtils.convertValue(value, targetDatatypeXsd); + } +}
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/preprocessing/transform/value/ValueEventTransformer.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/preprocessing/transform/value/ValueEventTransformer.java index 939cbad..c965c89 100644 --- a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/preprocessing/transform/value/ValueEventTransformer.java +++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/preprocessing/transform/value/ValueEventTransformer.java
@@ -26,14 +26,16 @@ public class ValueEventTransformer implements ValueTransformationRule { - private List<UnitTransformationRule> unitTransformationRules; - private List<TimestampTranformationRule> timestampTransformationRules; - private List<CorrectionValueTransformationRule> correctionValueTransformationRules; + private final List<UnitTransformationRule> unitTransformationRules; + private final List<TimestampTranformationRule> timestampTransformationRules; + private final List<CorrectionValueTransformationRule> correctionValueTransformationRules; + private final List<DatatypeTransformationRule> datatypeTransformationRules; public ValueEventTransformer(List<ValueTransformationRule> rules) { this.unitTransformationRules = new ArrayList<>(); this.timestampTransformationRules = new ArrayList<>(); this.correctionValueTransformationRules = new ArrayList<>(); + this.datatypeTransformationRules = new ArrayList<>(); for (TransformationRule rule : rules) { if (rule instanceof UnitTransformationRule) { @@ -42,16 +44,12 @@ this.timestampTransformationRules.add((TimestampTranformationRule) rule); } else if (rule instanceof CorrectionValueTransformationRule) { this.correctionValueTransformationRules.add((CorrectionValueTransformationRule) rule); + } else if (rule instanceof DatatypeTransformationRule) { + this.datatypeTransformationRules.add((DatatypeTransformationRule) rule); } } } -/* - public ValueEventTransformer(List<UnitTransformationRule> unitTransformationRule) { - this.unitTransformationRules = new ArrayList<>(); - } -*/ - @Override public Map<String, Object> transform(Map<String, Object> event) { @@ -63,36 +61,14 @@ event = rule.transform(event); } + for (var rule: datatypeTransformationRules) { + event = rule.transform(event); + } + for (CorrectionValueTransformationRule rule : correctionValueTransformationRules) { event = rule.transform(event); } - return event; } - - - public List<UnitTransformationRule> getUnitTransformationRules() { - return unitTransformationRules; - } - - public void setUnitTransformationRules(List<UnitTransformationRule> unitTransformationRules) { - this.unitTransformationRules = unitTransformationRules; - } - - public List<TimestampTranformationRule> getTimestampTransformationRules() { - return timestampTransformationRules; - } - - public void setTimestampTransformationRules(List<TimestampTranformationRule> timestampTransformationRules) { - this.timestampTransformationRules = timestampTransformationRules; - } - - public List<CorrectionValueTransformationRule> getCorrectionValueTransformationRules() { - return correctionValueTransformationRules; - } - - public void setCorrectionValueTransformationRules(List<CorrectionValueTransformationRule> correctionValueTransformationRules) { - this.correctionValueTransformationRules = correctionValueTransformationRules; - } }
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/util/DatatypeUtils.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/util/DatatypeUtils.java new file mode 100644 index 0000000..f87bab3 --- /dev/null +++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/util/DatatypeUtils.java
@@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.connect.adapter.util; + +import org.apache.commons.lang3.math.NumberUtils; +import org.apache.streampipes.vocabulary.XSD; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DatatypeUtils { + + private static final Logger LOG = LoggerFactory.getLogger(DatatypeUtils.class); + + public static Object convertValue(Object value, + String targetDatatypeXsd) { + var stringValue = String.valueOf(value); + if (XSD._string.toString().equals(targetDatatypeXsd)) { + return stringValue; + } else { + try { + if (XSD._double.toString().equals(targetDatatypeXsd)) { + return Double.parseDouble(stringValue); + } else if (XSD._float.toString().equals(targetDatatypeXsd)) { + return Float.parseFloat(stringValue); + } else if (XSD._boolean.toString().equals(targetDatatypeXsd)) { + return Boolean.parseBoolean(stringValue); + } else if (XSD._integer.toString().equals(targetDatatypeXsd)) { + var floatingNumber = Float.parseFloat(stringValue); + return Integer.parseInt(String.valueOf(Math.round(floatingNumber))); + } else if (XSD._long.toString().equals(targetDatatypeXsd)) { + var floatingNumber = Double.parseDouble(stringValue); + return Long.parseLong(String.valueOf(Math.round(floatingNumber))); + } + } catch (NumberFormatException e) { + LOG.error("Number format exception {}", value); + return value; + } + } + + return value; + } + + public static String getCanonicalTypeClassName(String value, + boolean preferFloat) { + return getTypeClass(value, preferFloat).getCanonicalName(); + } + + public static String getXsdDatatype(String value, + boolean preferFloat) { + var clazz = getTypeClass(value, preferFloat); + if (clazz.equals(Integer.class)) { + return XSD._integer.toString(); + } else if (clazz.equals(Long.class)) { + return XSD._long.toString(); + } else if (clazz.equals(Float.class)) { + return XSD._float.toString(); + } else if (clazz.equals(Double.class)) { + return XSD._double.toString(); + } else if (clazz.equals(Boolean.class)) { + return XSD._boolean.toString(); + } else { + return XSD._string.toString(); + } + } + + public static Class<?> getTypeClass(String value, + boolean preferFloat) { + if (NumberUtils.isParsable(value)) { + try { + Integer.parseInt(value); + return preferFloat ? Float.class : Integer.class; + } catch (NumberFormatException ignored) { + } + + try { + Long.parseLong(value); + return preferFloat ? Float.class : Long.class; + } catch (NumberFormatException ignored) { + } + + try { + Double.parseDouble(value); + return Float.class; + } catch (NumberFormatException ignored) { + } + + } + + if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) { + return Boolean.class; + } + + return String.class; + } + + public static void main(String[] args) { + long max = Long.MAX_VALUE; + String className = getCanonicalTypeClassName(String.valueOf(max), true); + System.out.println(className); + System.out.println(convertValue(max, className)); + } +}
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/util/PollingSettings.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/util/PollingSettings.java index 79dea5b..177702c 100644 --- a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/util/PollingSettings.java +++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/util/PollingSettings.java
@@ -15,6 +15,7 @@ * limitations under the License. * */ + package org.apache.streampipes.connect.adapter.util; import java.util.concurrent.TimeUnit;
diff --git a/streampipes-container-extensions/pom.xml b/streampipes-container-extensions/pom.xml index 0166eb2..55c0192 100644 --- a/streampipes-container-extensions/pom.xml +++ b/streampipes-container-extensions/pom.xml
@@ -17,13 +17,11 @@ --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -34,17 +32,17 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-connect-container-worker</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-container-standalone</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-service-extensions-base</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-container-standalone/pom.xml b/streampipes-container-standalone/pom.xml index b3ac21d..8bac498 100644 --- a/streampipes-container-standalone/pom.xml +++ b/streampipes-container-standalone/pom.xml
@@ -21,7 +21,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,12 +32,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-container</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-service-extensions-base</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-container-standalone/src/main/java/org/apache/streampipes/container/standalone/init/StandaloneModelSubmitter.java b/streampipes-container-standalone/src/main/java/org/apache/streampipes/container/standalone/init/StandaloneModelSubmitter.java index a23482c..037a6fb 100644 --- a/streampipes-container-standalone/src/main/java/org/apache/streampipes/container/standalone/init/StandaloneModelSubmitter.java +++ b/streampipes-container-standalone/src/main/java/org/apache/streampipes/container/standalone/init/StandaloneModelSubmitter.java
@@ -24,6 +24,7 @@ import org.apache.streampipes.container.model.PeConfig; import org.apache.streampipes.container.model.SpServiceDefinition; import org.apache.streampipes.service.extensions.base.StreamPipesExtensionsServiceBase; +import org.apache.streampipes.service.extensions.base.WebSecurityConfig; import org.apache.streampipes.svcdiscovery.api.model.SpServiceTag; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,7 +38,7 @@ @Deprecated @Configuration @EnableAutoConfiguration -@Import({ PipelineElementContainerResourceConfig.class }) +@Import({ PipelineElementContainerResourceConfig.class, WebSecurityConfig.class}) public abstract class StandaloneModelSubmitter extends StreamPipesExtensionsServiceBase { private static final Logger LOG =
diff --git a/streampipes-container/pom.xml b/streampipes-container/pom.xml index 5bc38c9..53bd31d 100644 --- a/streampipes-container/pom.xml +++ b/streampipes-container/pom.xml
@@ -21,7 +21,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <artifactId>streampipes-container</artifactId> @@ -33,44 +33,38 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-connect-api</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-serializers-json</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-service-discovery</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-rest-shared</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> -<!-- <dependency>--> -<!-- <groupId>org.apache.streampipes</groupId>--> -<!-- <artifactId>streampipes-connect-container-worker</artifactId>--> -<!-- <version>0.68.0-SNAPSHOT</version>--> -<!-- </dependency>--> - <!-- External dependencies --> <dependency>
diff --git a/streampipes-container/src/main/java/org/apache/streampipes/container/api/InvocablePipelineElementResource.java b/streampipes-container/src/main/java/org/apache/streampipes/container/api/InvocablePipelineElementResource.java index 9936bd2..780b704 100644 --- a/streampipes-container/src/main/java/org/apache/streampipes/container/api/InvocablePipelineElementResource.java +++ b/streampipes-container/src/main/java/org/apache/streampipes/container/api/InvocablePipelineElementResource.java
@@ -19,6 +19,7 @@ package org.apache.streampipes.container.api; import org.apache.streampipes.commons.constants.Envs; +import org.apache.streampipes.commons.exceptions.SpConfigurationException; import org.apache.streampipes.commons.exceptions.SpRuntimeException; import org.apache.streampipes.container.declarer.Declarer; import org.apache.streampipes.container.declarer.InvocableDeclarer; @@ -106,14 +107,21 @@ D declarer = getDeclarerById(elementId); RuntimeOptionsResponse responseOptions; - if (declarer instanceof ResolvesContainerProvidedOptions) { - responseOptions = new RuntimeResolvableRequestHandler().handleRuntimeResponse((ResolvesContainerProvidedOptions) declarer, req); - return ok(responseOptions); - } else if (declarer instanceof SupportsRuntimeConfig) { - responseOptions = new RuntimeResolvableRequestHandler().handleRuntimeResponse((SupportsRuntimeConfig) declarer, req); - return ok(responseOptions); - } else { - throw new WebApplicationException(javax.ws.rs.core.Response.Status.BAD_REQUEST); + try { + if (declarer instanceof ResolvesContainerProvidedOptions) { + responseOptions = new RuntimeResolvableRequestHandler().handleRuntimeResponse((ResolvesContainerProvidedOptions) declarer, req); + return ok(responseOptions); + } else if (declarer instanceof SupportsRuntimeConfig) { + responseOptions = new RuntimeResolvableRequestHandler().handleRuntimeResponse((SupportsRuntimeConfig) declarer, req); + return ok(responseOptions); + } else { + return javax.ws.rs.core.Response.status(500).build(); + } + } catch (SpConfigurationException e) { + return javax.ws.rs.core.Response + .status(400) + .entity(e) + .build(); } } @@ -131,8 +139,7 @@ (elementId); return ok(resolvesOutput.resolveOutputStrategy (runtimeOptionsRequest, getExtractor(runtimeOptionsRequest))); - } catch (SpRuntimeException e) { - e.printStackTrace(); + } catch (SpRuntimeException | SpConfigurationException e) { return ok(new Response(elementId, false)); } }
diff --git a/streampipes-container/src/main/java/org/apache/streampipes/container/api/ResolvesContainerProvidedOptions.java b/streampipes-container/src/main/java/org/apache/streampipes/container/api/ResolvesContainerProvidedOptions.java index a32a1de..110d95e 100644 --- a/streampipes-container/src/main/java/org/apache/streampipes/container/api/ResolvesContainerProvidedOptions.java +++ b/streampipes-container/src/main/java/org/apache/streampipes/container/api/ResolvesContainerProvidedOptions.java
@@ -17,6 +17,7 @@ */ package org.apache.streampipes.container.api; +import org.apache.streampipes.commons.exceptions.SpConfigurationException; import org.apache.streampipes.model.staticproperty.Option; import org.apache.streampipes.sdk.extractor.StaticPropertyExtractor; @@ -29,5 +30,5 @@ public interface ResolvesContainerProvidedOptions { List<Option> resolveOptions(String staticPropertyInternalName, - StaticPropertyExtractor parameterExtractor); + StaticPropertyExtractor parameterExtractor) throws SpConfigurationException; }
diff --git a/streampipes-container/src/main/java/org/apache/streampipes/container/api/ResolvesContainerProvidedOutputStrategy.java b/streampipes-container/src/main/java/org/apache/streampipes/container/api/ResolvesContainerProvidedOutputStrategy.java index 83ed622..ab44539 100644 --- a/streampipes-container/src/main/java/org/apache/streampipes/container/api/ResolvesContainerProvidedOutputStrategy.java +++ b/streampipes-container/src/main/java/org/apache/streampipes/container/api/ResolvesContainerProvidedOutputStrategy.java
@@ -17,7 +17,7 @@ */ package org.apache.streampipes.container.api; -import org.apache.streampipes.commons.exceptions.SpRuntimeException; +import org.apache.streampipes.commons.exceptions.SpConfigurationException; import org.apache.streampipes.model.base.InvocableStreamPipesEntity; import org.apache.streampipes.model.schema.EventSchema; import org.apache.streampipes.sdk.extractor.AbstractParameterExtractor; @@ -25,5 +25,5 @@ public interface ResolvesContainerProvidedOutputStrategy<T extends InvocableStreamPipesEntity, P extends AbstractParameterExtractor<T>> { - EventSchema resolveOutputStrategy(T processingElement, P parameterExtractor) throws SpRuntimeException; + EventSchema resolveOutputStrategy(T processingElement, P parameterExtractor) throws SpConfigurationException; }
diff --git a/streampipes-container/src/main/java/org/apache/streampipes/container/api/RuntimeResolvableRequestHandler.java b/streampipes-container/src/main/java/org/apache/streampipes/container/api/RuntimeResolvableRequestHandler.java index aba1322..91e18f9 100644 --- a/streampipes-container/src/main/java/org/apache/streampipes/container/api/RuntimeResolvableRequestHandler.java +++ b/streampipes-container/src/main/java/org/apache/streampipes/container/api/RuntimeResolvableRequestHandler.java
@@ -18,6 +18,7 @@ package org.apache.streampipes.container.api; +import org.apache.streampipes.commons.exceptions.SpConfigurationException; import org.apache.streampipes.model.runtime.RuntimeOptionsRequest; import org.apache.streampipes.model.runtime.RuntimeOptionsResponse; import org.apache.streampipes.model.staticproperty.Option; @@ -31,7 +32,7 @@ // for backwards compatibility public RuntimeOptionsResponse handleRuntimeResponse(ResolvesContainerProvidedOptions resolvesOptions, - RuntimeOptionsRequest req) { + RuntimeOptionsRequest req) throws SpConfigurationException { List<Option> availableOptions = resolvesOptions.resolveOptions(req.getRequestId(), makeExtractor(req)); @@ -43,7 +44,7 @@ } public RuntimeOptionsResponse handleRuntimeResponse(SupportsRuntimeConfig declarer, - RuntimeOptionsRequest req) { + RuntimeOptionsRequest req) throws SpConfigurationException { StaticProperty result = declarer.resolveConfiguration( req.getRequestId(), makeExtractor(req));
diff --git a/streampipes-container/src/main/java/org/apache/streampipes/container/api/SupportsRuntimeConfig.java b/streampipes-container/src/main/java/org/apache/streampipes/container/api/SupportsRuntimeConfig.java index 10cacd1..4ebd768 100644 --- a/streampipes-container/src/main/java/org/apache/streampipes/container/api/SupportsRuntimeConfig.java +++ b/streampipes-container/src/main/java/org/apache/streampipes/container/api/SupportsRuntimeConfig.java
@@ -18,12 +18,13 @@ package org.apache.streampipes.container.api; +import org.apache.streampipes.commons.exceptions.SpConfigurationException; import org.apache.streampipes.model.staticproperty.StaticProperty; import org.apache.streampipes.sdk.extractor.StaticPropertyExtractor; public interface SupportsRuntimeConfig { StaticProperty resolveConfiguration(String staticPropertyInternalName, - StaticPropertyExtractor extractor); + StaticPropertyExtractor extractor) throws SpConfigurationException; }
diff --git a/streampipes-container/src/main/java/org/apache/streampipes/container/model/SpServiceDefinitionBuilder.java b/streampipes-container/src/main/java/org/apache/streampipes/container/model/SpServiceDefinitionBuilder.java index 3ad1308..0e0f290 100644 --- a/streampipes-container/src/main/java/org/apache/streampipes/container/model/SpServiceDefinitionBuilder.java +++ b/streampipes-container/src/main/java/org/apache/streampipes/container/model/SpServiceDefinitionBuilder.java
@@ -28,6 +28,7 @@ import org.slf4j.LoggerFactory; import java.util.Arrays; +import java.util.List; public class SpServiceDefinitionBuilder { @@ -80,6 +81,11 @@ return this; } + public SpServiceDefinitionBuilder addConfigs(List<ConfigItem> configItems) { + configItems.stream().forEach(configItem -> this.serviceDefinition.addConfig(configItem)); + return this; + } + public SpServiceDefinitionBuilder registerPipelineElement(Declarer<?> declarer) { this.serviceDefinition.addDeclarer(declarer); return this;
diff --git a/streampipes-data-explorer-commons/pom.xml b/streampipes-data-explorer-commons/pom.xml new file mode 100644 index 0000000..c42e050 --- /dev/null +++ b/streampipes-data-explorer-commons/pom.xml
@@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ 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. + ~ + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>streampipes-parent</artifactId> + <groupId>org.apache.streampipes</groupId> + <version>0.71.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>streampipes-data-explorer-commons</artifactId> + <dependencies> + <!-- StreamPipes --> + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-service-discovery-api</artifactId> + <version>0.71.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-model</artifactId> + <version>0.71.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-client</artifactId> + <version>0.71.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-commons</artifactId> + <version>0.71.0-SNAPSHOT</version> + </dependency> + + + <!-- Others --> + <dependency> + <groupId>org.lightcouch</groupId> + <artifactId>lightcouch</artifactId> + </dependency> + <dependency> + <groupId>org.influxdb</groupId> + <artifactId>influxdb-java</artifactId> + </dependency> + </dependencies> + + + +</project>
diff --git a/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/DataExplorerUtils.java b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/DataExplorerUtils.java new file mode 100644 index 0000000..4fde783 --- /dev/null +++ b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/DataExplorerUtils.java
@@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.streampipes.dataexplorer.commons; + +import org.apache.streampipes.client.StreamPipesClient; +import org.apache.streampipes.commons.exceptions.SpRuntimeException; +import org.apache.streampipes.dataexplorer.commons.influx.InfluxNameSanitizer; +import org.apache.streampipes.model.datalake.DataLakeMeasure; +import org.apache.streampipes.model.schema.EventProperty; + +import java.util.List; +import java.util.stream.Collectors; + +public class DataExplorerUtils { + /** + * Sanitizes the event schema and stores the DataLakeMeasurement to the couchDB + * + * @param client StreamPipes client to store measure + * @param measure DataLakeMeasurement + */ + public static DataLakeMeasure sanitizeAndRegisterAtDataLake(StreamPipesClient client, + DataLakeMeasure measure) throws SpRuntimeException { + sanitizeDataLakeMeasure(measure); + registerAtDataLake(client, measure); + + return measure; + } + + private static void registerAtDataLake(StreamPipesClient client, + DataLakeMeasure measure) throws SpRuntimeException { + client + .customRequest() + .sendPost("api/v4/datalake/measure/", measure); + } + + + private static void sanitizeDataLakeMeasure(DataLakeMeasure measure) throws SpRuntimeException { + + // Removes selected timestamp from event schema + removeTimestampsFromEventSchema(measure); + + // Removes all spaces with _ and validates that no special terms are used as runtime names + measure.getEventSchema() + .getEventProperties() + .forEach(ep -> ep.setRuntimeName(InfluxNameSanitizer.renameReservedKeywords(ep.getRuntimeName()))); + + } + + private static void removeTimestampsFromEventSchema(DataLakeMeasure measure) { + List<EventProperty> eventPropertiesWithoutTimestamp = measure.getEventSchema().getEventProperties() + .stream() + .filter(eventProperty -> !measure.getTimestampField().endsWith(eventProperty.getRuntimeName())) + .collect(Collectors.toList()); + measure.getEventSchema().setEventProperties(eventPropertiesWithoutTimestamp); + } + +}
diff --git a/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/DataExplorerWriter.java b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/DataExplorerWriter.java new file mode 100644 index 0000000..925a08b --- /dev/null +++ b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/DataExplorerWriter.java
@@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.dataexplorer.commons; + +import org.apache.streampipes.dataexplorer.commons.configs.DataExplorerConfigurations; +import org.apache.streampipes.dataexplorer.commons.influx.InfluxConnectionSettings; +import org.influxdb.InfluxDB; +import org.influxdb.InfluxDBFactory; +import org.influxdb.dto.Point; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@Deprecated +public class DataExplorerWriter { + private InfluxDB influxDB; + + // TODO return a connection here + public void connect(InfluxConnectionSettings dataExplorerConnectionSettings) { + this.influxDB = InfluxDBFactory.connect(dataExplorerConnectionSettings.getInfluxDbHost() + ":" + dataExplorerConnectionSettings.getInfluxDbPort(), + dataExplorerConnectionSettings.getUser(), dataExplorerConnectionSettings.getPassword()); + this.influxDB.setDatabase(DataExplorerConfigurations.DATA_LAKE_DATABASE_NAME); + } + + public void close() { + this.influxDB.close(); + } + + public void write(Map<String, Object> data, + String measurement) { + Point.Builder builder = Point.measurement(measurement) + .time((Long) data.get("timestamp"), TimeUnit.MILLISECONDS); + + data.remove("timestamp"); + + for (String key : data.keySet()) { + if (data.get(key) instanceof Double || data.get(key) == null) { + builder.addField(key, (Double) data.get(key)); + } else if (data.get(key) instanceof Integer) { + builder.addField(key, (Integer) data.get(key)); + } else { + builder.tag(key, (String) data.get(key)); + } + } + + this.influxDB.write(builder.build()); + } + +}
diff --git a/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/TimeSeriesStore.java b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/TimeSeriesStore.java new file mode 100644 index 0000000..27fdcb3 --- /dev/null +++ b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/TimeSeriesStore.java
@@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.dataexplorer.commons; + +import org.apache.streampipes.client.StreamPipesClient; +import org.apache.streampipes.commons.exceptions.SpRuntimeException; +import org.apache.streampipes.dataexplorer.commons.image.ImageStore; +import org.apache.streampipes.dataexplorer.commons.influx.InfluxStore; +import org.apache.streampipes.model.datalake.DataLakeMeasure; +import org.apache.streampipes.model.runtime.Event; +import org.apache.streampipes.svcdiscovery.api.SpConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +public class TimeSeriesStore { + + private static final Logger LOG = LoggerFactory.getLogger(TimeSeriesStore.class); + + private ImageStore imageStore; + private final InfluxStore influxStore; + + + public TimeSeriesStore(SpConfig config, + StreamPipesClient client, + DataLakeMeasure measure, + boolean enableImageStore) { + + measure = DataExplorerUtils.sanitizeAndRegisterAtDataLake(client, measure); + + if (enableImageStore) { + // TODO check if event properties are replaces correctly + this.imageStore = new ImageStore(measure, config); + } + + this.influxStore = new InfluxStore(measure, config); + + } + + public boolean onEvent(Event event) throws SpRuntimeException { + // Store all images in image store and replace image with internal id + if (imageStore != null) { + this.imageStore.onEvent(event); + } + + // Store event in time series database + this.influxStore.onEvent(event); + + return true; + } + + + public boolean alterRetentionTime(DataLakeMeasure dataLakeMeasure) { + return true; + } + + public void close() throws SpRuntimeException { + if (imageStore != null) { + try { + this.imageStore.close(); + } catch (IOException e) { + LOG.error("Could not close couchDB connection"); + throw new SpRuntimeException(e); + } + } + + this.influxStore.close(); + } +}
diff --git a/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/configs/CouchDbConfigurations.java b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/configs/CouchDbConfigurations.java new file mode 100644 index 0000000..8079e9d --- /dev/null +++ b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/configs/CouchDbConfigurations.java
@@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.streampipes.dataexplorer.commons.configs; + +import org.apache.streampipes.svcdiscovery.api.model.ConfigItem; + +import java.util.Arrays; +import java.util.List; + +public class CouchDbConfigurations { + + public static List<ConfigItem> getDefaults() { + return Arrays.asList( + ConfigItem.from(CouchDbEnvKeys.COUCHDB_HOST, "couchdb", "Hostname for CouchDB to store image blobs"), + ConfigItem.from(CouchDbEnvKeys.COUCHDB_PORT, 5984, ""), + ConfigItem.from(CouchDbEnvKeys.COUCHDB_PROTOCOL, "http", "") + ); + } + +} \ No newline at end of file
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/configs/CouchDbEnvKeys.java similarity index 72% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/configs/CouchDbEnvKeys.java index 58ba04b..69a5257 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/configs/CouchDbEnvKeys.java
@@ -16,3 +16,10 @@ * */ +package org.apache.streampipes.dataexplorer.commons.configs; + +public class CouchDbEnvKeys { + public final static String COUCHDB_HOST = "SP_COUCHDB_HOST"; + public final static String COUCHDB_PORT = "SP_COUCHDB_PORT"; + public final static String COUCHDB_PROTOCOL = "SP_COUCHDB_PROTOCOL"; +}
diff --git a/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/configs/DataExplorerConfigurations.java b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/configs/DataExplorerConfigurations.java new file mode 100644 index 0000000..e0e483c --- /dev/null +++ b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/configs/DataExplorerConfigurations.java
@@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.streampipes.dataexplorer.commons.configs; + +import org.apache.streampipes.svcdiscovery.api.model.ConfigItem; + +import java.util.Arrays; +import java.util.List; + + +public class DataExplorerConfigurations { + public final static String DATA_LAKE_DATABASE_NAME = "sp"; + + public static List<ConfigItem> getDefaults() { + + return Arrays.asList( + ConfigItem.from(DataExplorerEnvKeys.DATA_LAKE_HOST, "influxdb", "Hostname for the StreamPipes data lake database"), + ConfigItem.from(DataExplorerEnvKeys.DATA_LAKE_PROTOCOL, "http", "Protocol for the StreamPipes data lake database"), + ConfigItem.from(DataExplorerEnvKeys.DATA_LAKE_PORT, 8086, "Port for the StreamPipes data lake database"), + ConfigItem.from(DataExplorerEnvKeys.DATA_LAKE_USERNAME, "default", "Username for the StreamPipes data lake database"), + ConfigItem.from(DataExplorerEnvKeys.DATA_LAKE_PASSWORD, "default", "Password for the StreamPipes data lake database"), + ConfigItem.from(DataExplorerEnvKeys.DATA_LAKE_DATABASE_NAME, DATA_LAKE_DATABASE_NAME, "Database name for the StreamPipes data lake database") + ); + } + +} \ No newline at end of file
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/config/ConfigKeys.java b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/configs/DataExplorerEnvKeys.java similarity index 80% rename from streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/config/ConfigKeys.java rename to streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/configs/DataExplorerEnvKeys.java index 4d6f0d9..cd4d17c 100644 --- a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/config/ConfigKeys.java +++ b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/configs/DataExplorerEnvKeys.java
@@ -15,10 +15,9 @@ * limitations under the License. * */ +package org.apache.streampipes.dataexplorer.commons.configs; -package org.apache.streampipes.sinks.internal.jvm.config; - -public class ConfigKeys { +public class DataExplorerEnvKeys { public final static String DATA_LAKE_HOST = "SP_DATA_LAKE_HOST"; public final static String DATA_LAKE_PROTOCOL = "SP_DATA_LAKE_PROTOCOL"; public final static String DATA_LAKE_PORT = "SP_DATA_LAKE_PORT"; @@ -26,7 +25,4 @@ public final static String DATA_LAKE_PASSWORD = "SP_DATA_LAKE_PASSWORD"; public final static String DATA_LAKE_DATABASE_NAME = "SP_DATA_LAKE_DATABASE_NAME"; - public final static String COUCHDB_HOST = "SP_COUCHDB_HOST"; - public final static String COUCHDB_PORT = "SP_COUCHDB_PORT"; - public final static String COUCHDB_PROTOCOL = "SP_COUCHDB_PROTOCOL"; }
diff --git a/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/image/ImageStore.java b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/image/ImageStore.java new file mode 100644 index 0000000..21c51c2 --- /dev/null +++ b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/image/ImageStore.java
@@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.dataexplorer.commons.image; + +import org.apache.commons.codec.binary.Base64; +import org.apache.streampipes.commons.exceptions.SpRuntimeException; +import org.apache.streampipes.dataexplorer.commons.configs.CouchDbEnvKeys; +import org.apache.streampipes.model.datalake.DataLakeMeasure; +import org.apache.streampipes.model.runtime.Event; +import org.apache.streampipes.model.schema.EventProperty; +import org.apache.streampipes.svcdiscovery.api.SpConfig; +import org.lightcouch.CouchDbClient; +import org.lightcouch.CouchDbProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.List; +import java.util.UUID; + +public class ImageStore { + + private static final Logger LOG = LoggerFactory.getLogger(ImageStore.class); + private static final String DB_NAME = "images"; + + private List<EventProperty> imageProperties; + private CouchDbClient couchDbClient; + + public ImageStore(DataLakeMeasure measure, SpConfig config) { + this.couchDbClient = new CouchDbClient(from(config)); + this.imageProperties = ImageStoreUtils.getImageProperties(measure); + } + + public void onEvent(Event event) throws SpRuntimeException{ + this.imageProperties.forEach(eventProperty -> { + String imageDocId = UUID.randomUUID().toString(); + String image = event.getFieldByRuntimeName(eventProperty.getRuntimeName()).getAsPrimitive().getAsString(); + + byte[] data = Base64.decodeBase64(image); + storeImage(data, imageDocId); + event.updateFieldBySelector("s0::" + eventProperty.getRuntimeName(), imageDocId); + }); + } + + public void storeImage(byte[] imageBytes, + String imageDocId) { + this.couchDbClient.saveAttachment( + new ByteArrayInputStream(imageBytes), + imageDocId, + "image/jpeg", + imageDocId, + null); + + } + + public void close() throws IOException { + this.couchDbClient.close(); + } + + private static CouchDbProperties from(SpConfig config) { + String couchDbProtocol = config.getString(CouchDbEnvKeys.COUCHDB_PROTOCOL); + String couchDbHost = config.getString(CouchDbEnvKeys.COUCHDB_HOST); + int couchDbPort = config.getInteger(CouchDbEnvKeys.COUCHDB_PORT); + + return new CouchDbProperties(DB_NAME, true, couchDbProtocol, + couchDbHost, couchDbPort, null, null); + } +}
diff --git a/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/image/ImageStoreUtils.java b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/image/ImageStoreUtils.java new file mode 100644 index 0000000..ba3ab6c --- /dev/null +++ b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/image/ImageStoreUtils.java
@@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.dataexplorer.commons.image; + +import org.apache.streampipes.model.datalake.DataLakeMeasure; +import org.apache.streampipes.model.schema.EventProperty; +import org.apache.streampipes.vocabulary.SPSensor; + +import java.util.List; +import java.util.stream.Collectors; + +public class ImageStoreUtils { + + public static List<EventProperty> getImageProperties(DataLakeMeasure measure) { + return measure.getEventSchema().getEventProperties().stream() + .filter(eventProperty -> eventProperty.getDomainProperties() != null && + eventProperty.getDomainProperties().size() > 0 && + eventProperty.getDomainProperties().get(0).toString().equals(SPSensor.IMAGE)) + .collect(Collectors.toList()); + } +}
diff --git a/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/influx/InfluxConnectionSettings.java b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/influx/InfluxConnectionSettings.java new file mode 100644 index 0000000..a6c1538 --- /dev/null +++ b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/influx/InfluxConnectionSettings.java
@@ -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. + * + */ + +package org.apache.streampipes.dataexplorer.commons.influx; + +import org.apache.streampipes.dataexplorer.commons.configs.DataExplorerEnvKeys; +import org.apache.streampipes.model.datalake.DataLakeMeasure; +import org.apache.streampipes.svcdiscovery.api.SpConfig; + +public class InfluxConnectionSettings { + + private final Integer influxDbPort; + private final String influxDbHost; + private final String databaseName; + private final String user; + private final String password; + + public static InfluxConnectionSettings from(SpConfig configStore) { + + return new InfluxConnectionSettings( + configStore.getString(DataExplorerEnvKeys.DATA_LAKE_PROTOCOL) + "://" + configStore.getString(DataExplorerEnvKeys.DATA_LAKE_HOST), + configStore.getInteger(DataExplorerEnvKeys.DATA_LAKE_PORT), + configStore.getString(DataExplorerEnvKeys.DATA_LAKE_DATABASE_NAME), + configStore.getString(DataExplorerEnvKeys.DATA_LAKE_USERNAME), + configStore.getString(DataExplorerEnvKeys.DATA_LAKE_PASSWORD)); + } + + + private InfluxConnectionSettings(String influxDbHost, + Integer influxDbPort, + String databaseName, + String user, + String password) { + this.influxDbHost = influxDbHost; + this.influxDbPort = influxDbPort; + this.databaseName = databaseName; + this.user = user; + this.password = password; + } + + public Integer getInfluxDbPort() { + return influxDbPort; + } + + public String getInfluxDbHost() { + return influxDbHost; + } + + public String getDatabaseName() { + return databaseName; + } + + public String getUser() { + return user; + } + + public String getPassword() { + return password; + } +}
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/InfluxDbReservedKeywords.java b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/influx/InfluxDbReservedKeywords.java similarity index 97% rename from streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/InfluxDbReservedKeywords.java rename to streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/influx/InfluxDbReservedKeywords.java index 26e7a14..754fc7c 100644 --- a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/InfluxDbReservedKeywords.java +++ b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/influx/InfluxDbReservedKeywords.java
@@ -16,7 +16,7 @@ * */ -package org.apache.streampipes.sinks.internal.jvm.datalake; +package org.apache.streampipes.dataexplorer.commons.influx; import java.util.Arrays; import java.util.List;
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/OperationDivide.java b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/influx/InfluxNameSanitizer.java similarity index 68% copy from streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/OperationDivide.java copy to streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/influx/InfluxNameSanitizer.java index b648a20..302ea45 100644 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/OperationDivide.java +++ b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/influx/InfluxNameSanitizer.java
@@ -16,12 +16,16 @@ * */ -package org.apache.streampipes.processors.enricher.flink.processor.math.operation; +package org.apache.streampipes.dataexplorer.commons.influx; -public class OperationDivide implements Operation { +public class InfluxNameSanitizer { - @Override - public Double operate(Double valLeft, Double valRight) { - return valLeft / valRight; + public static String renameReservedKeywords(String runtimeName) { + if (InfluxDbReservedKeywords.keywordList.stream().anyMatch(k -> k.equalsIgnoreCase(runtimeName))) { + return runtimeName + "_"; + } else { + return runtimeName; + } } + }
diff --git a/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/influx/InfluxStore.java b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/influx/InfluxStore.java new file mode 100644 index 0000000..429f62e --- /dev/null +++ b/streampipes-data-explorer-commons/src/main/java/org/apache/streampipes/dataexplorer/commons/influx/InfluxStore.java
@@ -0,0 +1,221 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.dataexplorer.commons.influx; + +import org.apache.streampipes.commons.exceptions.SpRuntimeException; +import org.apache.streampipes.model.datalake.DataLakeMeasure; +import org.apache.streampipes.model.runtime.Event; +import org.apache.streampipes.model.runtime.field.PrimitiveField; +import org.apache.streampipes.model.schema.EventProperty; +import org.apache.streampipes.model.schema.EventPropertyPrimitive; +import org.apache.streampipes.model.schema.PropertyScope; +import org.apache.streampipes.svcdiscovery.api.SpConfig; +import org.apache.streampipes.vocabulary.XSD; +import org.influxdb.InfluxDB; +import org.influxdb.InfluxDBFactory; +import org.influxdb.dto.Point; +import org.influxdb.dto.Pong; +import org.influxdb.dto.Query; +import org.influxdb.dto.QueryResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class InfluxStore { + + private static final Logger LOG = LoggerFactory.getLogger(InfluxStore.class); + + private InfluxDB influxDb = null; + DataLakeMeasure measure; + + Map<String, String> sanitizedRuntimeNames = new HashMap<>(); + + public InfluxStore(DataLakeMeasure measure, + SpConfig configStore) throws SpRuntimeException { + + this.measure = measure; + InfluxConnectionSettings settings = InfluxConnectionSettings.from(configStore); + + // store sanitized target property runtime names in local variable + measure.getEventSchema() + .getEventProperties() + .forEach(ep -> sanitizedRuntimeNames.put(ep.getRuntimeName(), + InfluxNameSanitizer.renameReservedKeywords(ep.getRuntimeName()))); + + connect(settings); + } + + /** + * Connects to the InfluxDB Server, sets the database and initializes the batch-behaviour + * + * @throws SpRuntimeException If not connection can be established or if the database could not + * be found + */ + private void connect(InfluxConnectionSettings settings) throws SpRuntimeException { + // Connecting to the server + // "http://" must be in front + String urlAndPort = settings.getInfluxDbHost() + ":" + settings.getInfluxDbPort(); + influxDb = InfluxDBFactory.connect(urlAndPort, settings.getUser(), settings.getPassword()); + + // Checking, if server is available + Pong response = influxDb.ping(); + if (response.getVersion().equalsIgnoreCase("unknown")) { + throw new SpRuntimeException("Could not connect to InfluxDb Server: " + urlAndPort); + } + + String databaseName = settings.getDatabaseName(); + // Checking whether the database exists + if (!databaseExists(databaseName)) { + LOG.info("Database '" + databaseName + "' not found. Gets created ..."); + createDatabase(databaseName); + } + + // setting up the database + influxDb.setDatabase(databaseName); + int batchSize = 2000; + int flushDuration = 500; + influxDb.enableBatch(batchSize, flushDuration, TimeUnit.MILLISECONDS); + } + + private boolean databaseExists(String dbName) { + QueryResult queryResult = influxDb.query(new Query("SHOW DATABASES", "")); + for (List<Object> a : queryResult.getResults().get(0).getSeries().get(0).getValues()) { + if (a.get(0).equals(dbName)) { + return true; + } + } + return false; + } + + /** + * Creates a new database with the given name + * + * @param dbName The name of the database which should be created + */ + private void createDatabase(String dbName) throws SpRuntimeException { + if (!dbName.matches("^[a-zA-Z_]\\w*$")) { + throw new SpRuntimeException( + "Database name '" + dbName + "' not allowed. Allowed names: ^[a-zA-Z_][a-zA-Z0-9_]*$"); + } + influxDb.query(new Query("CREATE DATABASE \"" + dbName + "\"", "")); + } + + /** + * Saves an event to the connected InfluxDB database + * + * @param event The event which should be saved + * @throws SpRuntimeException If the column name (key-value of the event map) is not allowed + */ + public void onEvent(Event event) throws SpRuntimeException { + if (event == null) { + throw new SpRuntimeException("event is null"); + } + + Long timestampValue = event.getFieldBySelector(measure.getTimestampField()).getAsPrimitive().getAsLong(); + Point.Builder point = + Point.measurement(measure.getMeasureName()).time((long) timestampValue, TimeUnit.MILLISECONDS); + + for (EventProperty ep : measure.getEventSchema().getEventProperties()) { + if (ep instanceof EventPropertyPrimitive) { + String runtimeName = ep.getRuntimeName(); + + // timestamp should not be added as a field + if (!measure.getTimestampField().endsWith(runtimeName)) { + String sanitizedRuntimeName = sanitizedRuntimeNames.get(runtimeName); + + try { + PrimitiveField eventPropertyPrimitiveField = event.getFieldByRuntimeName(runtimeName).getAsPrimitive(); + if (eventPropertyPrimitiveField.getRawValue() == null) { + LOG.warn("Field value for {} is null, ignoring value.", sanitizedRuntimeName); + } else { + + // store property as tag when the field is a dimension property + if (PropertyScope.DIMENSION_PROPERTY.name().equals(ep.getPropertyScope())) { + point.tag(sanitizedRuntimeName, eventPropertyPrimitiveField.getAsString()); + } else { + handleMeasurementProperty( + point, + (EventPropertyPrimitive) ep, + sanitizedRuntimeName, + eventPropertyPrimitiveField); + } + } + } catch (SpRuntimeException iae) { + LOG.warn("Field {} was missing in event and will be ignored", runtimeName, iae); + } + + } + + } + } + + influxDb.write(point.build()); + } + + private void handleMeasurementProperty(Point.Builder p, + EventPropertyPrimitive ep, + String preparedRuntimeName, + PrimitiveField eventPropertyPrimitiveField) { + try { + // Store property according to property type + String runtimeType = ep.getRuntimeType(); + if (XSD._integer.toString().equals(runtimeType)) { + try { + p.addField(preparedRuntimeName, eventPropertyPrimitiveField.getAsInt()); + } catch (NumberFormatException ef) { + p.addField(preparedRuntimeName, eventPropertyPrimitiveField.getAsFloat()); + } + } else if (XSD._float.toString().equals(runtimeType)) { + p.addField(preparedRuntimeName, eventPropertyPrimitiveField.getAsFloat()); + } else if (XSD._double.toString().equals(runtimeType)) { + p.addField(preparedRuntimeName, eventPropertyPrimitiveField.getAsDouble()); + } else if (XSD._boolean.toString().equals(runtimeType)) { + p.addField(preparedRuntimeName, eventPropertyPrimitiveField.getAsBoolean()); + } else if (XSD._long.toString().equals(runtimeType)) { + try { + p.addField(preparedRuntimeName, eventPropertyPrimitiveField.getAsLong()); + } catch (NumberFormatException ef) { + p.addField(preparedRuntimeName, eventPropertyPrimitiveField.getAsFloat()); + } + } else { + p.addField(preparedRuntimeName, eventPropertyPrimitiveField.getAsString()); + } + } catch (NumberFormatException e) { + LOG.warn("Wrong number format for field {}, ignoring.", preparedRuntimeName); + } + } + + /** + * Shuts down the connection to the InfluxDB server + */ + public void close() throws SpRuntimeException { + influxDb.flush(); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new SpRuntimeException(e); + } + influxDb.close(); + } + +}
diff --git a/streampipes-data-explorer/pom.xml b/streampipes-data-explorer/pom.xml index 4079bfe..78d1676 100644 --- a/streampipes-data-explorer/pom.xml +++ b/streampipes-data-explorer/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -31,17 +31,17 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-config</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-storage-management</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency>
diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataLakeManagementV4.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataLakeManagementV4.java index b5c68df..f9918fc 100644 --- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataLakeManagementV4.java +++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataLakeManagementV4.java
@@ -36,7 +36,13 @@ import org.apache.streampipes.model.datalake.DataLakeMeasure; import org.apache.streampipes.model.datalake.DataLakeRetentionPolicy; import org.apache.streampipes.model.datalake.SpQueryResult; +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.storage.api.IDataLakeStorage; import org.apache.streampipes.storage.couchdb.utils.Utils; +import org.apache.streampipes.storage.management.StorageDispatcher; import org.influxdb.InfluxDB; import org.influxdb.dto.Query; import org.influxdb.dto.QueryResult; @@ -53,16 +59,15 @@ import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalAccessor; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; import static org.apache.streampipes.dataexplorer.v4.SupportedDataLakeQueryParameters.*; public class DataLakeManagementV4 { + public static final String FOR_ID_KEY = "forId"; + private static final DateTimeFormatter formatter = new DateTimeFormatterBuilder() .appendPattern("uuuu[-MM[-dd]]['T'HH[:mm[:ss[.SSSSSSSSS][.SSSSSSSS][.SSSSSSS][.SSSSSS][.SSSSS][.SSSS][.SSS][.SS][.S]]]][XXX]") .parseDefaulting(ChronoField.NANO_OF_SECOND, 0) @@ -73,6 +78,10 @@ return DataExplorerUtils.getInfos(); } + public DataLakeMeasure getById(String measureId) { + return getDataLakeStorage().findOne(measureId); + } + public SpQueryResult getData(ProvidedQueryParams queryParams) throws IllegalArgumentException { if (queryParams.has(QP_AUTO_AGGREGATE)) { queryParams = new AutoAggregationHandler(queryParams).makeAutoAggregationQueryParams(); @@ -84,7 +93,12 @@ return new DataExplorerQueryV4(queryParts, maximumAmountOfEvents).executeQuery(); } - return new DataExplorerQueryV4(queryParts).executeQuery(); + if (queryParams.getProvidedParams().containsKey(FOR_ID_KEY)) { + String forWidgetId = queryParams.getProvidedParams().get(FOR_ID_KEY); + return new DataExplorerQueryV4(queryParts, forWidgetId).executeQuery(); + } else { + return new DataExplorerQueryV4(queryParts).executeQuery(); + } } public void getDataAsStream(ProvidedQueryParams params, String format, OutputStream outputStream) throws IOException { @@ -148,6 +162,11 @@ } boolean isFirstDataObject = true; + String delimiter = ","; + + if (params.has(QP_CSV_DELIMITER)) { + delimiter = params.getAsString(QP_CSV_DELIMITER).equals("comma") ? "," : ";"; + } do { params.update(SupportedDataLakeQueryParameters.QP_PAGE, String.valueOf(i)); @@ -158,7 +177,7 @@ boolean isFirst = true; for (int i1 = 0; i1 < dataResult.getHeaders().size(); i1++) { if (!isFirst) { - outputStream.write(toBytes(";")); + outputStream.write(toBytes(delimiter)); } isFirst = false; outputStream.write(toBytes(dataResult.getHeaders().get(i1))); @@ -174,7 +193,7 @@ for (int i1 = 0; i1 < row.size(); i1++) { Object element = row.get(i1); if (!isFirstInRow) { - outputStream.write(toBytes(";")); + outputStream.write(toBytes(delimiter)); } isFirstInRow = false; if (i1 == 0) { @@ -307,9 +326,10 @@ String fields) { InfluxDB influxDB = DataExplorerUtils.getInfluxDBClient(); Map<String, Object> tags = new HashMap<>(); - List<String> fieldList = Arrays.asList(fields.split(",")); - fieldList.forEach(f -> { - String q = "SHOW TAG VALUES ON \"" + BackendConfig.INSTANCE.getInfluxDatabaseName() + "\" FROM \"" +measurementId + "\" WITH KEY = \"" +f + "\""; + if (fields != null && !("".equals(fields))) { + List<String> fieldList = Arrays.asList(fields.split(",")); + fieldList.forEach(f -> { + String q = "SHOW TAG VALUES ON \"" + BackendConfig.INSTANCE.getInfluxDatabaseName() + "\" FROM \"" + measurementId + "\" WITH KEY = \"" + f + "\""; Query query = new Query(q); QueryResult queryResult = influxDB.query(query); if (queryResult.getResults() != null) { @@ -323,8 +343,69 @@ }); }); } - }); + }); + } return tags; } + + + // TODO validate method + public DataLakeMeasure addDataLake(DataLakeMeasure measure) { + List<DataLakeMeasure> dataLakeMeasureList = getDataLakeStorage().getAllDataLakeMeasures(); + Optional<DataLakeMeasure> optional = dataLakeMeasureList.stream().filter(entry -> entry.getMeasureName().equals(measure.getMeasureName())).findFirst(); + + if (optional.isPresent()) { + DataLakeMeasure oldEntry = optional.get(); + if (!compareEventProperties(oldEntry.getEventSchema().getEventProperties(), measure.getEventSchema().getEventProperties())) { + return oldEntry; + } + } else { + measure.setSchemaVersion(DataLakeMeasure.CURRENT_SCHEMA_VERSION); + getDataLakeStorage().storeDataLakeMeasure(measure); + return measure; + } + + return measure; + } + + private boolean compareEventProperties(List<EventProperty> prop1, List<EventProperty> prop2) { + if (prop1.size() != prop2.size()) { + return false; + } + + return prop1.stream().allMatch(prop -> { + + for (EventProperty property : prop2) { + if (prop.getRuntimeName().equals(property.getRuntimeName())) { + + //primitive + if (prop instanceof EventPropertyPrimitive && property instanceof EventPropertyPrimitive) { + if (((EventPropertyPrimitive) prop) + .getRuntimeType() + .equals(((EventPropertyPrimitive) property).getRuntimeType())) { + return true; + } + + //list + } else if (prop instanceof EventPropertyList && property instanceof EventPropertyList) { + return compareEventProperties(Collections.singletonList(((EventPropertyList) prop).getEventProperty()), + Collections.singletonList(((EventPropertyList) property).getEventProperty())); + + //nested + } else if (prop instanceof EventPropertyNested && property instanceof EventPropertyNested) { + return compareEventProperties(((EventPropertyNested) prop).getEventProperties(), + ((EventPropertyNested) property).getEventProperties()); + } + } + } + return false; + + }); + } + + + private IDataLakeStorage getDataLakeStorage() { + return StorageDispatcher.INSTANCE.getNoSqlStore().getDataLakeStorage(); + } }
diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataLakeNoUserManagementV3.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataLakeNoUserManagementV3.java index 3f9c7bd..5b411a0 100644 --- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataLakeNoUserManagementV3.java +++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataLakeNoUserManagementV3.java
@@ -28,8 +28,11 @@ import java.util.Optional; +@Deprecated public class DataLakeNoUserManagementV3 { + + @Deprecated public boolean addDataLake(String measure, EventSchema eventSchema) { List<DataLakeMeasure> dataLakeMeasureList = getDataLakeStorage().getAllDataLakeMeasures(); Optional<DataLakeMeasure> optional = dataLakeMeasureList.stream().filter(entry -> entry.getMeasureName().equals(measure)).findFirst(); @@ -39,7 +42,9 @@ return false; } } else { - getDataLakeStorage().storeDataLakeMeasure(new DataLakeMeasure(measure, eventSchema)); + DataLakeMeasure dataLakeMeasure = new DataLakeMeasure(measure, eventSchema); + dataLakeMeasure.setSchemaVersion(DataLakeMeasure.CURRENT_SCHEMA_VERSION); + getDataLakeStorage().storeDataLakeMeasure(dataLakeMeasure); } return true; }
diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/query/DeleteDataQuery.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/query/DeleteDataQuery.java index 73d6be6..4570927 100644 --- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/query/DeleteDataQuery.java +++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/query/DeleteDataQuery.java
@@ -30,7 +30,7 @@ @Override protected void getQuery(DataExplorerQueryBuilder queryBuilder) { - queryBuilder.add("DROP MEASUREMENT " + measure.getMeasureName()); + queryBuilder.add("DROP MEASUREMENT \"" + measure.getMeasureName() + "\""); } @Override
diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/sdk/DataLakeQueryBuilder.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/sdk/DataLakeQueryBuilder.java new file mode 100644 index 0000000..b4ea310 --- /dev/null +++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/sdk/DataLakeQueryBuilder.java
@@ -0,0 +1,181 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.dataexplorer.sdk; + +import org.apache.streampipes.config.backend.BackendConfig; +import org.apache.streampipes.dataexplorer.v4.params.ColumnFunction; +import org.influxdb.dto.Query; +import org.influxdb.querybuilder.Ordering; +import org.influxdb.querybuilder.SelectionQueryImpl; +import org.influxdb.querybuilder.clauses.*; + +import java.util.ArrayList; +import java.util.List; + +import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.*; + +public class DataLakeQueryBuilder { + + private final String measurementId; + private final SelectionQueryImpl selectionQuery; + private final List<Clause> whereClauses; + private final List<Clause> groupByClauses; + private Ordering ordering; + private int limit = Integer.MIN_VALUE; + + public static DataLakeQueryBuilder create(String measurementId) { + return new DataLakeQueryBuilder(measurementId); + } + + private DataLakeQueryBuilder(String measurementId) { + this.measurementId = measurementId; + this.selectionQuery = select(); + this.whereClauses = new ArrayList<>(); + this.groupByClauses = new ArrayList<>(); + } + + public DataLakeQueryBuilder withSimpleColumn(String columnName) { + this.selectionQuery.column(columnName); + + return this; + } + + public DataLakeQueryBuilder withAggregatedColumn(String columnName, + ColumnFunction columnFunction, + String targetName) { + if (columnFunction == ColumnFunction.COUNT) { + this.selectionQuery.count(columnName).as(targetName); + } else if (columnFunction == ColumnFunction.MEAN) { + this.selectionQuery.mean(columnName).as(targetName); + } else if (columnFunction == ColumnFunction.MIN) { + this.selectionQuery.min(columnName).as(targetName); + } else if (columnFunction == ColumnFunction.MAX) { + this.selectionQuery.max(columnName).as(targetName); + } else if (columnFunction == ColumnFunction.FIRST) { + this.selectionQuery.function("FIRST", columnName).as(targetName); + } else if (columnFunction == ColumnFunction.LAST) { + this.selectionQuery.function("LAST", columnName).as(targetName); + } + + // TODO implement all column functions + + return this; + } + + public DataLakeQueryBuilder withStartTime(long startTime) { + this.whereClauses.add(new SimpleClause("time", ">=", startTime * 1000000)); + return this; + } + + + public DataLakeQueryBuilder withEndTime(long endTime) { + return withEndTime(endTime, true); + } + + public DataLakeQueryBuilder withEndTime(long endTime, + boolean includeEndTime) { + String operator = includeEndTime ? "<=" : "<"; + this.whereClauses.add(new SimpleClause("time", operator, endTime * 1000000)); + return this; + } + + public DataLakeQueryBuilder withTimeBoundary(long startTime, + long endTime) { + this.withStartTime(startTime); + this.withEndTime(endTime); + + return this; + } + + public DataLakeQueryBuilder withFilter(String field, + String operator, + Object value) { + this.whereClauses.add(new SimpleClause(field, operator, value)); + return this; + } + + public DataLakeQueryBuilder withExclusiveFilter(String field, + String operator, + List<?> values) { + List<ConjunctionClause> or = new ArrayList<>(); + values.forEach(value -> { + or.add(new OrConjunction(new SimpleClause(field, operator, value))); + }); + + NestedClause nestedClause = new NestedClause(or); + this.whereClauses.add(nestedClause); + + return this; + } + + public DataLakeQueryBuilder withFilter(NestedClause clause) { + this.whereClauses.add(clause); + + return this; + } + + public DataLakeQueryBuilder withGroupByTime(String timeInterval) { + + this.groupByClauses.add(new RawTextClause("time(" + timeInterval + ")")); + + return this; + } + + public DataLakeQueryBuilder withGroupBy(String column) { + + this.groupByClauses.add(new RawTextClause(column)); + + return this; + } + + public DataLakeQueryBuilder withOrderBy(DataLakeQueryOrdering ordering) { + if (DataLakeQueryOrdering.ASC.equals(ordering)) { + this.ordering = asc(); + } else { + this.ordering = desc(); + } + + return this; + } + + public DataLakeQueryBuilder withLimit(int limit) { + this.limit = limit; + + return this; + } + + public Query build() { + var selectQuery = this.selectionQuery.from(BackendConfig.INSTANCE.getInfluxDatabaseName(), "\"" +measurementId + "\""); + this.whereClauses.forEach(selectQuery::where); + + if (this.groupByClauses.size() > 0) { + selectQuery.groupBy(this.groupByClauses.toArray()); + } + + if (this.ordering != null) { + selectQuery.orderBy(this.ordering); + } + + if (this.limit != Integer.MIN_VALUE) { + selectQuery.limit(this.limit); + } + + return selectQuery; + } +}
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/sdk/DataLakeQueryConstants.java similarity index 70% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/sdk/DataLakeQueryConstants.java index 58ba04b..f6664f4 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/sdk/DataLakeQueryConstants.java
@@ -16,3 +16,15 @@ * */ +package org.apache.streampipes.dataexplorer.sdk; + +public class DataLakeQueryConstants { + + public static final String GE = ">="; + public static final String LE = "<="; + public static final String LT = "<"; + public static final String GT = ">"; + public static final String EQ = "="; + public static final String NEQ = "!="; + +}
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.scss b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/sdk/DataLakeQueryOrdering.java similarity index 88% copy from ui/src/app/pipeline-details/pipeline-details.component.scss copy to streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/sdk/DataLakeQueryOrdering.java index a375af7..6952d0d 100644 --- a/ui/src/app/pipeline-details/pipeline-details.component.scss +++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/sdk/DataLakeQueryOrdering.java
@@ -16,7 +16,8 @@ * */ -.md-padding { - padding: 10px; -} +package org.apache.streampipes.dataexplorer.sdk; +public enum DataLakeQueryOrdering { + ASC, DESC +}
diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/SupportedDataLakeQueryParameters.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/SupportedDataLakeQueryParameters.java index 3a08624..1eadd81 100644 --- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/SupportedDataLakeQueryParameters.java +++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/SupportedDataLakeQueryParameters.java
@@ -33,6 +33,7 @@ public static final String QP_AGGREGATION_FUNCTION = "aggregationFunction"; public static final String QP_TIME_INTERVAL = "timeInterval"; public static final String QP_FORMAT = "format"; + public static final String QP_CSV_DELIMITER = "delimiter"; public static final String QP_COUNT_ONLY = "countOnly"; public static final String QP_AUTO_AGGREGATE = "autoAggregate"; public static final String QP_FILTER = "filter"; @@ -50,6 +51,7 @@ QP_AGGREGATION_FUNCTION, QP_TIME_INTERVAL, QP_FORMAT, + QP_CSV_DELIMITER, QP_COUNT_ONLY, QP_AUTO_AGGREGATE, QP_FILTER,
diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/params/SelectColumn.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/params/SelectColumn.java index 3b2a5f4..d2d0ba9 100644 --- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/params/SelectColumn.java +++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/params/SelectColumn.java
@@ -71,16 +71,16 @@ private String makeField() { if (this.simpleField) { - return this.originalField; + return "\"" + this.originalField + "\""; } else { - return this.columnFunction.toDbName() + "(" + this.originalField + ")"; + return this.columnFunction.toDbName() + "(\"" + this.originalField + "\")"; } } public String toQueryString() { String field = makeField(); if (this.rename) { - return field + " AS " + this.targetField; + return field + " AS \"" + this.targetField + "\""; } else { return field; }
diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/params/WhereStatementParams.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/params/WhereStatementParams.java index e3dbd84..a0af420 100644 --- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/params/WhereStatementParams.java +++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/params/WhereStatementParams.java
@@ -103,6 +103,8 @@ private String returnCondition(String inputCondition) { if (NumberUtils.isCreatable(inputCondition) || Boolean.parseBoolean(inputCondition)) { return inputCondition; + } else if (inputCondition.equals("\"\"")) { + return inputCondition; } else { return "'" + inputCondition + "'"; }
diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/query/DataExplorerQueryV4.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/query/DataExplorerQueryV4.java index c1a5121..30a87d4 100644 --- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/query/DataExplorerQueryV4.java +++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/query/DataExplorerQueryV4.java
@@ -44,6 +44,20 @@ protected int maximumAmountOfEvents; + private boolean appendId = false; + private String forId; + + public DataExplorerQueryV4() { + + } + + public DataExplorerQueryV4(Map<String, QueryParamsV4> params, + String forId) { + this(params); + this.appendId = true; + this.forId = forId; + } + public DataExplorerQueryV4(Map<String, QueryParamsV4> params) { this.params = params; this.maximumAmountOfEvents = -1; @@ -61,7 +75,8 @@ if (this.maximumAmountOfEvents != -1) { QueryBuilder countQueryBuilder = QueryBuilder.create(BackendConfig.INSTANCE.getInfluxDatabaseName()); Query countQuery = countQueryBuilder.build(queryElements, true); - Double amountOfQueryResults = getAmountOfResults(influxDB.query(countQuery)); + QueryResult countQueryResult = influxDB.query(countQuery); + Double amountOfQueryResults = getAmountOfResults(countQueryResult); if (amountOfQueryResults > this.maximumAmountOfEvents) { SpQueryResult tooMuchData = new SpQueryResult(); tooMuchData.setSpQueryStatus(SpQueryStatus.TOO_MUCH_DATA); @@ -84,6 +99,15 @@ return dataResult; } + public SpQueryResult executeQuery(Query query) { + InfluxDB influxDB = DataExplorerUtils.getInfluxDBClient(); + QueryResult result = influxDB.query(query); + SpQueryResult dataResult = postQuery(result); + influxDB.close(); + + return dataResult; + } + private double getAmountOfResults(QueryResult countQueryResult) { if (countQueryResult.getResults().get(0).getSeries() != null && countQueryResult.getResults().get(0).getSeries().get(0).getValues() != null) { @@ -120,6 +144,11 @@ result.addDataResult(series); }); } + + if (this.appendId) { + result.setForId(this.forId); + } + return result; }
diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/query/elements/SelectFromStatement.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/query/elements/SelectFromStatement.java index 731d348..9630367 100644 --- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/query/elements/SelectFromStatement.java +++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/query/elements/SelectFromStatement.java
@@ -23,6 +23,7 @@ import java.util.StringJoiner; public class SelectFromStatement extends QueryElement<SelectFromStatementParams> { + public SelectFromStatement(SelectFromStatementParams selectFromStatementParams) { super(selectFromStatementParams); } @@ -30,11 +31,11 @@ @Override protected String buildStatement(SelectFromStatementParams params) { if (params.isSelectWildcard()) { - return "SELECT * FROM " + params.getIndex(); + return "SELECT * FROM " + escapeIndex(params.getIndex()); } else { StringJoiner joiner = new StringJoiner(","); String queryPrefix = "SELECT "; - String queryAppendix = " FROM " +params.getIndex(); + String queryAppendix = " FROM " +escapeIndex(params.getIndex()); params.getSelectedColumns().forEach(column -> { joiner.add(column.toQueryString()); @@ -42,12 +43,9 @@ return queryPrefix + joiner + queryAppendix; } -// if (selectFromStatementParams.isCountOnly()) { -// return QueryTemplatesV4.selectCountFrom(selectFromStatementParams.getIndex(), selectFromStatementParams.getSelectedColumns()); -// } else if (selectFromStatementParams.getAggregationFunction() == null) { -// return QueryTemplatesV4.selectFrom(selectFromStatementParams.getIndex(), selectFromStatementParams.getSelectedColumns()); -// } else { -// return QueryTemplatesV4.selectAggregationFrom(selectFromStatementParams.getIndex(), selectFromStatementParams.getSelectedColumns(), selectFromStatementParams.getAggregationFunction()); -// } + } + + private String escapeIndex(String index) { + return "\"" + index + "\""; } }
diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/template/QueryTemplatesV4.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/template/QueryTemplatesV4.java index 0023cc2..dd681d6 100644 --- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/template/QueryTemplatesV4.java +++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/template/QueryTemplatesV4.java
@@ -42,11 +42,11 @@ joiner.add(builder); } - return "SELECT " + joiner + " FROM " + index; + return "SELECT " + joiner + " FROM \"" + index + "\""; } public static String deleteFrom(String index) { - return "DELETE FROM " + index; + return "DELETE FROM \"" + index + "\""; } public static String whereTimeWithin(long startDate, long endDate) {
diff --git a/streampipes-data-export/pom.xml b/streampipes-data-export/pom.xml new file mode 100644 index 0000000..8dc44bf --- /dev/null +++ b/streampipes-data-export/pom.xml
@@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ 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. + ~ + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>streampipes-parent</artifactId> + <groupId>org.apache.streampipes</groupId> + <version>0.71.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>streampipes-data-export</artifactId> + + <dependencies> + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-model</artifactId> + <version>0.71.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-pipeline-management</artifactId> + <version>0.71.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-resource-management</artifactId> + <version>0.71.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-storage-management</artifactId> + <version>0.71.0-SNAPSHOT</version> + </dependency> + </dependencies> + +</project>
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/AssetLinkCollector.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/AssetLinkCollector.java new file mode 100644 index 0000000..ba3e16d --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/AssetLinkCollector.java
@@ -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. + * + */ + +package org.apache.streampipes.export; + +import org.apache.streampipes.model.assets.AssetLink; +import org.apache.streampipes.model.assets.SpAsset; +import org.apache.streampipes.model.assets.SpAssetModel; + +import java.util.HashSet; +import java.util.Set; + +public class AssetLinkCollector { + + private SpAssetModel assetModel; + + public AssetLinkCollector(SpAssetModel assetModel) { + this.assetModel = assetModel; + } + + public Set<AssetLink> collectAssetLinks() { + var assetLinks = new HashSet<>(assetModel.getAssetLinks()); + assetModel.getAssets().forEach(asset -> addLinks(assetLinks, asset)); + + return assetLinks; + } + + private void addLinks(HashSet<AssetLink> assetLinks, + SpAsset asset) { + assetLinks.addAll(asset.getAssetLinks()); + if (asset.getAssets() != null) { + asset.getAssets().forEach(a -> addLinks(assetLinks, a)); + } + } +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/AssetLinkResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/AssetLinkResolver.java new file mode 100644 index 0000000..fb24122 --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/AssetLinkResolver.java
@@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.export; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.streampipes.export.constants.ResolvableAssetLinks; +import org.apache.streampipes.export.resolver.*; +import org.apache.streampipes.export.utils.SerializationUtils; +import org.apache.streampipes.model.assets.AssetLink; +import org.apache.streampipes.model.assets.SpAssetModel; +import org.apache.streampipes.model.export.AssetExportConfiguration; +import org.apache.streampipes.storage.management.StorageDispatcher; + +import java.io.IOException; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class AssetLinkResolver { + + private final String assetId; + private final ObjectMapper mapper; + + public AssetLinkResolver(String assetId) { + this.assetId = assetId; + this.mapper = SerializationUtils.getDefaultObjectMapper(); + } + + public AssetExportConfiguration resolveResources() { + + try { + var asset = getAsset(); + var assetLinks = new AssetLinkCollector(asset).collectAssetLinks(); + var exportConfig = new AssetExportConfiguration(); + exportConfig.setAssetId(this.assetId); + exportConfig.setAssetName(asset.getAssetName()); + exportConfig.setAdapters(new AdapterResolver().resolve(getLinks(assetLinks, ResolvableAssetLinks.ADAPTER))); + exportConfig.setDashboards(new DashboardResolver().resolve(getLinks(assetLinks, ResolvableAssetLinks.DASHBOARD))); + exportConfig.setDataViews(new DataViewResolver().resolve(getLinks(assetLinks, ResolvableAssetLinks.DATA_VIEW))); + exportConfig.setDataSources(new DataSourceResolver().resolve(getLinks(assetLinks, ResolvableAssetLinks.DATA_SOURCE))); + exportConfig.setPipelines(new PipelineResolver().resolve(getLinks(assetLinks, ResolvableAssetLinks.PIPELINE))); + exportConfig.setDataLakeMeasures(new MeasurementResolver().resolve(getLinks(assetLinks, ResolvableAssetLinks.MEASUREMENT))); + exportConfig.setFiles(new FileResolver().resolve(getLinks(assetLinks, ResolvableAssetLinks.FILE))); + + return exportConfig; + } catch (IOException e) { + e.printStackTrace(); + return new AssetExportConfiguration(); + } + } + + private Set<AssetLink> getLinks(Set<AssetLink> assetLinks, + String queryHint) { + return assetLinks + .stream() + .filter(link -> link.getQueryHint().equals(queryHint)) + .collect(Collectors.toSet()); + } + + private SpAssetModel getAsset() throws IOException { + return deserialize(StorageDispatcher.INSTANCE.getNoSqlStore().getGenericStorage().findOne(this.assetId)); + } + + private SpAssetModel deserialize(Map<String, Object> asset) { + return this.mapper.convertValue(asset, SpAssetModel.class); + } + +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/ExportManager.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/ExportManager.java new file mode 100644 index 0000000..1ceaa54 --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/ExportManager.java
@@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.export; + +import org.apache.streampipes.export.generator.ExportPackageGenerator; +import org.apache.streampipes.model.export.ExportConfiguration; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +public class ExportManager { + + public static ExportConfiguration getExportPreview(List<String> selectedAssetIds) { + var exportConfig = new ExportConfiguration(); + var assetExportConfigurations = selectedAssetIds + .stream() + .map(assetId -> new AssetLinkResolver(assetId).resolveResources()) + .collect(Collectors.toList()); + + exportConfig.setAssetExportConfiguration(assetExportConfigurations); + + return exportConfig; + } + + public static byte[] getExportPackage(ExportConfiguration exportConfiguration) throws IOException { + return new ExportPackageGenerator(exportConfiguration).generateExportPackage(); + } + +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/ImportManager.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/ImportManager.java new file mode 100644 index 0000000..58bfe95 --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/ImportManager.java
@@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.export; + +import org.apache.streampipes.export.dataimport.PerformImportGenerator; +import org.apache.streampipes.export.dataimport.PreviewImportGenerator; +import org.apache.streampipes.model.export.AssetExportConfiguration; + +import java.io.IOException; +import java.io.InputStream; + +public class ImportManager { + + public static AssetExportConfiguration getImportPreview(InputStream packageZipStream) throws IOException { + return new PreviewImportGenerator().generate(packageZipStream); + } + + public static void performImport(InputStream packageZipStream, + AssetExportConfiguration exportConfiguration, + String ownerSid) throws IOException { + new PerformImportGenerator(exportConfiguration, ownerSid).generate(packageZipStream); + } +}
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.scss b/streampipes-data-export/src/main/java/org/apache/streampipes/export/constants/ExportConstants.java similarity index 85% copy from ui/src/app/pipeline-details/pipeline-details.component.scss copy to streampipes-data-export/src/main/java/org/apache/streampipes/export/constants/ExportConstants.java index a375af7..80ec171 100644 --- a/ui/src/app/pipeline-details/pipeline-details.component.scss +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/constants/ExportConstants.java
@@ -16,7 +16,9 @@ * */ -.md-padding { - padding: 10px; -} +package org.apache.streampipes.export.constants; +public class ExportConstants { + + public static final String MANIFEST = "manifest"; +}
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/streampipes-data-export/src/main/java/org/apache/streampipes/export/constants/ResolvableAssetLinks.java similarity index 63% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to streampipes-data-export/src/main/java/org/apache/streampipes/export/constants/ResolvableAssetLinks.java index 58ba04b..35588da 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/constants/ResolvableAssetLinks.java
@@ -16,3 +16,15 @@ * */ +package org.apache.streampipes.export.constants; + +public class ResolvableAssetLinks { + + public static final String DATA_VIEW = "data-view"; + public static final String DASHBOARD = "dashboard"; + public static final String MEASUREMENT = "measurement"; + public static final String ADAPTER = "adapter"; + public static final String DATA_SOURCE = "data-source"; + public static final String PIPELINE = "pipeline"; + public static final String FILE = "file"; +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/ImportGenerator.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/ImportGenerator.java new file mode 100644 index 0000000..23bd41d --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/ImportGenerator.java
@@ -0,0 +1,170 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.export.dataimport; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.streampipes.commons.zip.ZipFileExtractor; +import org.apache.streampipes.export.constants.ExportConstants; +import org.apache.streampipes.export.utils.SerializationUtils; +import org.apache.streampipes.model.export.StreamPipesApplicationPackage; +import org.lightcouch.DocumentConflictException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Map; + +public abstract class ImportGenerator<T> { + + private static final Logger LOG = LoggerFactory.getLogger(ImportGenerator.class); + + protected ObjectMapper spMapper; + protected ObjectMapper defaultMapper; + + public ImportGenerator() { + this.spMapper = SerializationUtils.getSpObjectMapper(); + this.defaultMapper = SerializationUtils.getDefaultObjectMapper(); + } + + public T generate(InputStream inputStream) throws IOException { + Map<String, byte[]> previewFiles = new ZipFileExtractor(inputStream).extractZipToMap(); + + var manifest = getManifest(previewFiles); + + for (String assetId : manifest.getAssets()) { + try { + handleAsset(previewFiles, assetId); + } catch (DocumentConflictException | IOException e) { + LOG.warn("Skipping import of asset model {} (already present with the same id)", assetId); + } + } + + for (String adapterId : manifest.getAdapters()) { + try { + handleAdapter(asString(previewFiles.get(adapterId)), adapterId); + } catch (DocumentConflictException e) { + LOG.warn("Skipping import of adapter {} (already present with the same id)", adapterId); + } + } + + for (String dashboardId : manifest.getDashboards()) { + try { + handleDashboard(asString(previewFiles.get(dashboardId)), dashboardId); + } catch (DocumentConflictException e) { + LOG.warn("Skipping import of dashboard {} (already present with the same id)", dashboardId); + } + } + + for (String dataViewId : manifest.getDataViews()) { + try { + handleDataView(asString(previewFiles.get(dataViewId)), dataViewId); + } catch (DocumentConflictException e) { + LOG.warn("Skipping import of data view {} (already present with the same id)", dataViewId); + } + } + + for (String dataSourceId : manifest.getDataSources()) { + try { + handleDataSource(asString(previewFiles.get(dataSourceId)), dataSourceId); + } catch (DocumentConflictException e) { + LOG.warn("Skipping import of data source {} (already present with the same id)", dataSourceId); + } + } + + for (String pipelineId : manifest.getPipelines()) { + try { + handlePipeline(asString(previewFiles.get(pipelineId)), pipelineId); + } catch (DocumentConflictException e) { + LOG.warn("Skipping import of pipeline {} (already present with the same id)", pipelineId); + } + } + + for (String measurementId : manifest.getDataLakeMeasures()) { + try { + handleDataLakeMeasure(asString(previewFiles.get(measurementId)), measurementId); + } catch (DocumentConflictException e) { + LOG.warn("Skipping import of data lake measure {} (already present with the same id)", measurementId); + } + } + + for (String dashboardWidgetId : manifest.getDashboardWidgets()) { + try { + handleDashboardWidget(asString(previewFiles.get(dashboardWidgetId)), dashboardWidgetId); + } catch (DocumentConflictException e) { + LOG.warn("Skipping import of dashboard widget {} (already present with the same id)", dashboardWidgetId); + } + } + + for (String dataViewWidgetId : manifest.getDataViewWidgets()) { + try { + handleDataViewWidget(asString(previewFiles.get(dataViewWidgetId)), dataViewWidgetId); + } catch (DocumentConflictException e) { + LOG.warn("Skipping import of data view widget {} (already present with the same id)", dataViewWidgetId); + } + } + + for (String fileMetadataId : manifest.getFiles()) { + try { + handleFile(asString(previewFiles.get(fileMetadataId)), fileMetadataId, previewFiles); + } catch (DocumentConflictException e) { + LOG.warn("Skipping import of file {} (already present with the same id)", fileMetadataId); + } + } + + afterResourcesCreated(); + + return getReturnObject(); + } + + protected String asString(byte[] bytes) { + return new String(bytes, StandardCharsets.UTF_8); + } + + private StreamPipesApplicationPackage getManifest(Map<String, byte[]> previewFiles) throws JsonProcessingException { + return this.defaultMapper.readValue(asString(previewFiles.get(ExportConstants.MANIFEST)), StreamPipesApplicationPackage.class); + } + + protected abstract void handleAsset(Map<String, byte[]> previewFiles, String assetId) throws IOException; + + protected abstract void handleAdapter(String document, String adapterId) throws JsonProcessingException; + + protected abstract void handleDashboard(String document, String dashboardId) throws JsonProcessingException; + + protected abstract void handleDataView(String document, String dataViewId) throws JsonProcessingException; + + protected abstract void handleDataSource(String document, String dataSourceId) throws JsonProcessingException; + + protected abstract void handlePipeline(String document, String pipelineId) throws JsonProcessingException; + + protected abstract void handleDataLakeMeasure(String document, String dataLakeMeasureId) throws JsonProcessingException; + + protected abstract void handleDashboardWidget(String document, String dashboardWidgetId) throws JsonProcessingException; + + protected abstract void handleDataViewWidget(String document, String dataViewWidgetId) throws JsonProcessingException; + + protected abstract void handleFile(String document, String fileMetadataId, Map<String, byte[]> zipContent) throws IOException; + + protected abstract T getReturnObject(); + + protected abstract void afterResourcesCreated(); + +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/PerformImportGenerator.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/PerformImportGenerator.java new file mode 100644 index 0000000..f4345f9 --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/PerformImportGenerator.java
@@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.export.dataimport; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.apache.streampipes.export.model.PermissionInfo; +import org.apache.streampipes.export.resolver.*; +import org.apache.streampipes.manager.file.FileHandler; +import org.apache.streampipes.model.SpDataStream; +import org.apache.streampipes.model.connect.adapter.AdapterDescription; +import org.apache.streampipes.model.dashboard.DashboardModel; +import org.apache.streampipes.model.datalake.DataLakeMeasure; +import org.apache.streampipes.model.export.AssetExportConfiguration; +import org.apache.streampipes.model.export.ExportItem; +import org.apache.streampipes.model.pipeline.Pipeline; +import org.apache.streampipes.resource.management.PermissionResourceManager; +import org.apache.streampipes.storage.api.INoSqlStorage; +import org.apache.streampipes.storage.management.StorageDispatcher; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class PerformImportGenerator extends ImportGenerator<Void> { + + private AssetExportConfiguration config; + private INoSqlStorage storage; + private Set<PermissionInfo> permissionsToStore = new HashSet<>(); + private String ownerSid; + + public PerformImportGenerator(AssetExportConfiguration config, + String ownerSid) { + this.config = config; + this.storage = StorageDispatcher.INSTANCE.getNoSqlStore(); + this.ownerSid = ownerSid; + } + + @Override + protected void handleAsset(Map<String, byte[]> previewFiles, String assetId) throws IOException { + storage.getGenericStorage().create(asString(previewFiles.get(assetId))); + } + + @Override + protected void handleAdapter(String document, String adapterId) throws JsonProcessingException { + if (shouldStore(adapterId, config.getAdapters())) { + new AdapterResolver().writeDocument(document, config.isOverrideBrokerSettings()); + permissionsToStore.add(new PermissionInfo(adapterId, AdapterDescription.class)); + } + } + + @Override + protected void handleDashboard(String document, String dashboardId) throws JsonProcessingException { + if (shouldStore(dashboardId, config.getDashboards())) { + new DashboardResolver().writeDocument(document); + permissionsToStore.add(new PermissionInfo(dashboardId, DashboardModel.class)); + } + } + + @Override + protected void handleDataView(String document, String dataViewId) throws JsonProcessingException { + if (shouldStore(dataViewId, config.getDataViews())) { + new DataViewResolver().writeDocument(document); + permissionsToStore.add(new PermissionInfo(dataViewId, DashboardModel.class)); + } + } + + @Override + protected void handleDataSource(String document, String dataSourceId) throws JsonProcessingException { + if (shouldStore(dataSourceId, config.getDataSources())) { + new DataSourceResolver().writeDocument(document, config.isOverrideBrokerSettings()); + permissionsToStore.add(new PermissionInfo(dataSourceId, SpDataStream.class)); + } + } + + @Override + protected void handlePipeline(String document, String pipelineId) throws JsonProcessingException { + if (shouldStore(pipelineId, config.getPipelines())) { + new PipelineResolver().writeDocument(document, config.isOverrideBrokerSettings()); + permissionsToStore.add(new PermissionInfo(pipelineId, Pipeline.class)); + } + } + + @Override + protected void handleDataLakeMeasure(String document, String dataLakeMeasureId) throws JsonProcessingException { + if (shouldStore(dataLakeMeasureId, config.getDataLakeMeasures())) { + new MeasurementResolver().writeDocument(document); + permissionsToStore.add(new PermissionInfo(dataLakeMeasureId, DataLakeMeasure.class)); + } + } + + @Override + protected void handleDashboardWidget(String document, String dashboardWidgetId) throws JsonProcessingException { + new DashboardWidgetResolver().writeDocument(document); + } + + @Override + protected void handleDataViewWidget(String document, String dataViewWidget) throws JsonProcessingException { + new DataViewWidgetResolver().writeDocument(document); + } + + @Override + protected void handleFile(String document, + String fileMetadataId, + Map<String, byte[]> zipContent) throws IOException { + var resolver = new FileResolver(); + var fileMetadata = resolver.readDocument(document); + resolver.writeDocument(document); + byte[] file = zipContent.get(fileMetadata.getInternalFilename().substring(0, fileMetadata.getInternalFilename().lastIndexOf("."))); + new FileHandler().storeFile(fileMetadata.getInternalFilename(), new ByteArrayInputStream(file)); + } + + @Override + protected Void getReturnObject() { + return null; + } + + @Override + protected void afterResourcesCreated() { + var resourceManager = new PermissionResourceManager(); + this.permissionsToStore + .forEach(info -> resourceManager.createDefault( + info.getInstanceId(), + info.getInstanceClass(), + this.ownerSid, + true)); + } + + private boolean shouldStore(String adapterId, + Set<ExportItem> adapters) { + return adapters + .stream() + .filter(item -> item.getResourceId().equals(adapterId)) + .allMatch(ExportItem::isSelected); + } + +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/PreviewImportGenerator.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/PreviewImportGenerator.java new file mode 100644 index 0000000..80c4894 --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/PreviewImportGenerator.java
@@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.export.dataimport; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import org.apache.streampipes.export.resolver.*; +import org.apache.streampipes.model.export.AssetExportConfiguration; +import org.apache.streampipes.model.export.ExportItem; + +import java.util.Map; +import java.util.function.Consumer; + +public class PreviewImportGenerator extends ImportGenerator<AssetExportConfiguration> { + + private AssetExportConfiguration importConfig; + + public PreviewImportGenerator() { + super(); + this.importConfig = new AssetExportConfiguration(); + + } + + private void addExportItem(String id, + String name, + Consumer<ExportItem> addAdapter) { + var item = new ExportItem(id, name, true); + addAdapter.accept(item); + } + + + @Override + protected void handleAsset(Map<String, byte[]> previewFiles, String assetId) throws JsonProcessingException { + Map<String, Object> assetDescription = this.defaultMapper.readValue(asString(previewFiles.get(assetId)), new TypeReference<Map<String, Object>>() {}); + importConfig.addAsset(new ExportItem(assetId, String.valueOf(assetDescription.get("assetName")), true)); + } + + @Override + protected void handleAdapter(String document, String adapterId) throws JsonProcessingException { + addExportItem(adapterId, new AdapterResolver().readDocument(document).getName(), importConfig::addAdapter); + } + + @Override + protected void handleDashboard(String document, String dashboardId) throws JsonProcessingException { + addExportItem(dashboardId, new DashboardResolver().readDocument(document).getName(), importConfig::addDashboard); + } + + @Override + protected void handleDataView(String document, String dataViewId) throws JsonProcessingException { + addExportItem(dataViewId, new DataViewResolver().readDocument(document).getName(), importConfig::addDataView); + } + + @Override + protected void handleDataSource(String document, String dataSourceId) throws JsonProcessingException { + addExportItem(dataSourceId, new DataSourceResolver().readDocument(document).getName(), importConfig::addDataSource); + } + + @Override + protected void handlePipeline(String document, String pipelineId) throws JsonProcessingException { + addExportItem(pipelineId, new PipelineResolver().readDocument(document).getName(), importConfig::addPipeline); + } + + @Override + protected void handleDataLakeMeasure(String document, String measurementId) throws JsonProcessingException { + addExportItem(measurementId, new MeasurementResolver().readDocument(document).getMeasureName(), importConfig::addDataLakeMeasure); + } + + @Override + protected void handleDashboardWidget(String document, String dashboardWidgetId) { + + } + + @Override + protected void handleDataViewWidget(String document, String dataViewWidget) { + + } + + @Override + protected void handleFile(String document, + String fileMetadataId, + Map<String, byte[]> zipContent) throws JsonProcessingException { + addExportItem(fileMetadataId, new FileResolver().readDocument(document).getOriginalFilename(), importConfig::addFile); + } + + @Override + protected AssetExportConfiguration getReturnObject() { + return this.importConfig; + } + + @Override + protected void afterResourcesCreated() { + } +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/generator/ExportPackageGenerator.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/generator/ExportPackageGenerator.java new file mode 100644 index 0000000..8073dd5 --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/generator/ExportPackageGenerator.java
@@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.export.generator; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.streampipes.commons.exceptions.ElementNotFoundException; +import org.apache.streampipes.export.resolver.*; +import org.apache.streampipes.export.utils.SerializationUtils; +import org.apache.streampipes.manager.file.FileManager; +import org.apache.streampipes.model.export.AssetExportConfiguration; +import org.apache.streampipes.model.export.ExportConfiguration; +import org.apache.streampipes.model.export.ExportItem; +import org.apache.streampipes.model.export.StreamPipesApplicationPackage; +import org.apache.streampipes.storage.management.StorageDispatcher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.file.Files; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +public class ExportPackageGenerator { + + private static final Logger LOG = LoggerFactory.getLogger(ExportPackageGenerator.class); + + private final ExportConfiguration exportConfiguration; + private ObjectMapper defaultMapper; + private ObjectMapper spMapper; + + public ExportPackageGenerator(ExportConfiguration exportConfiguration) { + this.exportConfiguration = exportConfiguration; + this.defaultMapper = SerializationUtils.getDefaultObjectMapper(); + this.spMapper = SerializationUtils.getSpObjectMapper(); + } + + public byte[] generateExportPackage() throws IOException { + ZipFileBuilder builder = ZipFileBuilder.create(); + var manifest = new StreamPipesApplicationPackage(); + + addAssets(builder, exportConfiguration + .getAssetExportConfiguration() + .stream() + .map(AssetExportConfiguration::getAssetId) + .collect(Collectors.toList()), manifest); + + this.exportConfiguration.getAssetExportConfiguration().forEach(config -> { + + config.getAdapters().forEach(item -> addDoc(builder, + item, + new AdapterResolver(), + manifest::addAdapter)); + + config.getDashboards().forEach(item -> { + var resolver = new DashboardResolver(); + addDoc(builder, + item, + resolver, + manifest::addDashboard); + + var widgets = resolver.getWidgets(item.getResourceId()); + var widgetResolver = new DashboardWidgetResolver(); + widgets.forEach(widgetId -> addDoc(builder, widgetId, widgetResolver, manifest::addDashboardWidget)); + }); + + config.getDataSources().forEach(item -> addDoc(builder, + item, + new DataSourceResolver(), + manifest::addDataSource)); + + config.getDataLakeMeasures().forEach(item -> addDoc(builder, + item, + new MeasurementResolver(), + manifest::addDataLakeMeasure)); + + config.getPipelines().forEach(item -> addDoc(builder, + item, + new PipelineResolver(), + manifest::addPipeline)); + + config.getDataViews().forEach(item -> { + var resolver = new DataViewResolver(); + addDoc(builder, + item, + resolver, + manifest::addDataView); + + var widgets = resolver.getWidgets(item.getResourceId()); + var widgetResolver = new DataViewWidgetResolver(); + widgets.forEach(widgetId -> addDoc(builder, widgetId, widgetResolver, manifest::addDataViewWidget)); + }); + + config.getFiles().forEach(item -> { + var fileResolver = new FileResolver(); + String filename = fileResolver.findDocument(item.getResourceId()).getInternalFilename(); + addDoc(builder, item, new FileResolver(), manifest::addFile); + try { + builder.addBinary(filename, Files.readAllBytes(FileManager.getFile(filename).toPath())); + } catch (IOException e) { + e.printStackTrace(); + } + }); + }); + + builder.addManifest(defaultMapper.writeValueAsString(manifest)); + + + return builder.buildZip(); + } + + private void addDoc(ZipFileBuilder builder, + String resourceId, + AbstractResolver<?> resolver, + Consumer<String> function) { + addDoc(builder, new ExportItem(resourceId, "", true), resolver, function); + } + + private void addDoc(ZipFileBuilder builder, + ExportItem exportItem, + AbstractResolver<?> resolver, + Consumer<String> function) { + try { + var resourceId = exportItem.getResourceId(); + var sanitizedResourceId = sanitize(resourceId); + builder.addText(sanitizedResourceId, resolver.getSerializedDocument(resourceId)); + function.accept(sanitizedResourceId); + } catch (JsonProcessingException | ElementNotFoundException e) { + LOG.warn( + "Could not find document with resource id {} with resolver {}", + exportItem.getResourceId(), + resolver.getClass().getCanonicalName(), + e); + } + } + + private String sanitize(String resourceId) { + return resourceId.replaceAll(":", "").replaceAll("\\.", ""); + } + + private void addAssets(ZipFileBuilder builder, + List<String> assetIds, + StreamPipesApplicationPackage manifest) { + assetIds.forEach(assetId -> { + try { + var asset = getAsset(assetId); + asset.remove("_rev"); + builder.addText(String.valueOf(asset.get("_id")), this.defaultMapper.writeValueAsString(asset)); + manifest.addAsset(String.valueOf(asset.get("_id"))); + } catch (IOException e) { + e.printStackTrace(); + } + }); + } + + private Map<String, Object> getAsset(String assetId) throws IOException { + return StorageDispatcher.INSTANCE.getNoSqlStore().getGenericStorage().findOne(assetId); + } +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/generator/ZipFileBuilder.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/generator/ZipFileBuilder.java new file mode 100644 index 0000000..59edaa8 --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/generator/ZipFileBuilder.java
@@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.export.generator; + +import org.apache.streampipes.export.constants.ExportConstants; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +public class ZipFileBuilder { + + private final Map<String, byte[]> binaryEntries; + private final Map<String, String> textEntries; + private final Map<String, File> fileEntries; + private String manifest; + + public static ZipFileBuilder create() { + return new ZipFileBuilder(); + } + + private ZipFileBuilder() { + this.binaryEntries = new HashMap<>(); + this.fileEntries = new HashMap<>(); + this.textEntries = new HashMap<>(); + } + + public ZipFileBuilder addText(String filename, + String content) { + this.textEntries.put(filename, content); + + return this; + } + + public ZipFileBuilder addBinary(String filename, + byte[] content) { + this.binaryEntries.put(filename, content); + + return this; + } + + public ZipFileBuilder addFile(String filename, + File file) { + this.fileEntries.put(filename, file); + + return this; + } + + public ZipFileBuilder addManifest(String manifest) { + this.manifest = manifest; + + return this; + } + + public byte[] buildZip() throws IOException { + return makeZip(); + } + + private byte[] makeZip() throws IOException { + byte[] buffer = new byte[1024]; + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ZipOutputStream out = new ZipOutputStream(outputStream); + + for (String documentKey : this.textEntries.keySet()) { + byte[] document = asBytes(this.textEntries.get(documentKey)); + addZipEntry(documentKey + ".json", document, out, buffer); + } + + for(String binary : this.binaryEntries.keySet()) { + addZipEntry(binary, this.binaryEntries.get(binary), out, buffer); + } + + addZipEntry(ExportConstants.MANIFEST + ".json", asBytes(manifest), out, buffer); + out.closeEntry(); + out.close(); + return outputStream.toByteArray(); + } + + private byte[] asBytes(String document) { + return document.getBytes(StandardCharsets.UTF_8); + } + + private void addZipEntry(String filename, + byte[] document, + ZipOutputStream out, + byte[] buffer) throws IOException { + ZipEntry ze = new ZipEntry(filename); + out.putNextEntry(ze); + + try (InputStream in = new ByteArrayInputStream(document)) { + int len; + while ((len = in.read(buffer)) > 0) { + out.write(buffer, 0, len); + } + } catch (Exception e) { + e.printStackTrace(); + } + } +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/model/PermissionInfo.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/model/PermissionInfo.java new file mode 100644 index 0000000..5bf2c8b --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/model/PermissionInfo.java
@@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.export.model; + +public class PermissionInfo { + + private String instanceId; + private Class<?> instanceClass; + + public PermissionInfo(String instanceId, Class<?> className) { + this.instanceId = instanceId; + this.instanceClass = className; + } + + public String getInstanceId() { + return instanceId; + } + + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + public Class<?> getInstanceClass() { + return instanceClass; + } + + public void setInstanceClass(Class<?> instanceClass) { + this.instanceClass = instanceClass; + } +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AbstractResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AbstractResolver.java new file mode 100644 index 0000000..d4e0ed2 --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AbstractResolver.java
@@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.export.resolver; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.streampipes.commons.exceptions.ElementNotFoundException; +import org.apache.streampipes.export.utils.SerializationUtils; +import org.apache.streampipes.model.assets.AssetLink; +import org.apache.streampipes.model.export.ExportItem; +import org.apache.streampipes.storage.api.INoSqlStorage; +import org.apache.streampipes.storage.management.StorageDispatcher; +import org.lightcouch.DocumentConflictException; + +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +public abstract class AbstractResolver<T> { + + protected ObjectMapper spMapper; + protected ObjectMapper defaultMapper; + + public AbstractResolver() { + this.spMapper = SerializationUtils.getSpObjectMapper(); + this.defaultMapper = SerializationUtils.getDefaultObjectMapper(); + } + + public Set<ExportItem> resolve(Set<AssetLink> assetLinks) { + return assetLinks + .stream() + .map(link -> findDocument(link.getResourceId())) + .filter(this::existsDoc) + .map(this::convert) + .collect(Collectors.toSet()); + } + + protected boolean existsDoc(T doc) { + return Objects.nonNull(doc); + } + + public String getSerializedDocument(String resourceId) throws JsonProcessingException, ElementNotFoundException { + var document = findDocument(resourceId); + if (document != null) { + return SerializationUtils.getSpObjectMapper().writeValueAsString(modifyDocumentForExport(document)); + } else { + throw new ElementNotFoundException("Could not find element with resource id " + resourceId); + } + } + + protected INoSqlStorage getNoSqlStore() { + return StorageDispatcher.INSTANCE.getNoSqlStore(); + } + + public abstract T findDocument(String resourceId); + + public abstract T modifyDocumentForExport(T doc); + + public abstract T readDocument(String serializedDoc) throws JsonProcessingException; + + public abstract ExportItem convert(T document); + + public abstract void writeDocument(String document) throws JsonProcessingException, DocumentConflictException; + + protected abstract T deserializeDocument(String document) throws JsonProcessingException; +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AdapterResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AdapterResolver.java new file mode 100644 index 0000000..d3b7b2c --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AdapterResolver.java
@@ -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. + * + */ + + +package org.apache.streampipes.export.resolver; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.apache.streampipes.export.utils.EventGroundingProcessor; +import org.apache.streampipes.export.utils.SerializationUtils; +import org.apache.streampipes.model.connect.adapter.AdapterDescription; +import org.apache.streampipes.model.connect.adapter.AdapterStreamDescription; +import org.apache.streampipes.model.export.ExportItem; + +public class AdapterResolver extends AbstractResolver<AdapterDescription> { + + @Override + public AdapterDescription findDocument(String resourceId) { + return getNoSqlStore().getAdapterInstanceStorage().getAdapter(resourceId); + } + + @Override + public AdapterDescription modifyDocumentForExport(AdapterDescription doc) { + doc.setRev(null); + doc.setSelectedEndpointUrl(null); + if (doc instanceof AdapterStreamDescription) { + ((AdapterStreamDescription) doc).setRunning(false); + } + + return doc; + } + + @Override + public AdapterDescription readDocument(String serializedDoc) throws JsonProcessingException { + return SerializationUtils.getSpObjectMapper().readValue(serializedDoc, AdapterDescription.class); + } + + @Override + public ExportItem convert(AdapterDescription document) { + return new ExportItem(document.getElementId(), document.getName(), true); + } + + @Override + public void writeDocument(String document) throws JsonProcessingException { + getNoSqlStore().getAdapterInstanceStorage().storeAdapter(deserializeDocument(document)); + } + + public void writeDocument(String document, + boolean overrideDocument) throws JsonProcessingException { + var adapterDescription = deserializeDocument(document); + if (overrideDocument) { + EventGroundingProcessor.applyOverride(adapterDescription.getEventGrounding().getTransportProtocol()); + } + getNoSqlStore().getAdapterInstanceStorage().storeAdapter(adapterDescription); + } + + @Override + protected AdapterDescription deserializeDocument(String document) throws JsonProcessingException { + return this.spMapper.readValue(document, AdapterDescription.class); + } + +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DashboardResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DashboardResolver.java new file mode 100644 index 0000000..a756c03 --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DashboardResolver.java
@@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.export.resolver; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.apache.streampipes.export.utils.SerializationUtils; +import org.apache.streampipes.model.dashboard.DashboardItem; +import org.apache.streampipes.model.dashboard.DashboardModel; +import org.apache.streampipes.model.export.ExportItem; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public class DashboardResolver extends AbstractResolver<DashboardModel> { + + @Override + public DashboardModel findDocument(String resourceId) { + return getNoSqlStore().getDashboardStorage().getDashboard(resourceId); + } + + @Override + public DashboardModel modifyDocumentForExport(DashboardModel doc) { + doc.setCouchDbRev(null); + return doc; + } + + @Override + protected boolean existsDoc(DashboardModel doc) { + return Objects.nonNull(doc) && doc.getCouchDbId() != null; + } + + @Override + public DashboardModel readDocument(String serializedDoc) throws JsonProcessingException { + return SerializationUtils.getSpObjectMapper().readValue(serializedDoc, DashboardModel.class); + } + + @Override + public ExportItem convert(DashboardModel document) { + return new ExportItem(document.getCouchDbId(), document.getName(), true); + } + + @Override + public void writeDocument(String document) throws JsonProcessingException { + getNoSqlStore().getDashboardStorage().storeDashboard(deserializeDocument(document)); + } + + @Override + protected DashboardModel deserializeDocument(String document) throws JsonProcessingException { + return this.spMapper.readValue(document, DashboardModel.class); + } + + public List<String> getWidgets(String resourceId) { + var document = findDocument(resourceId); + return document.getWidgets().stream().map(DashboardItem::getId).collect(Collectors.toList()); + } +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DashboardWidgetResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DashboardWidgetResolver.java new file mode 100644 index 0000000..91d4876 --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DashboardWidgetResolver.java
@@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.export.resolver; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.apache.streampipes.export.utils.SerializationUtils; +import org.apache.streampipes.model.dashboard.DashboardWidgetModel; +import org.apache.streampipes.model.export.ExportItem; + +public class DashboardWidgetResolver extends AbstractResolver<DashboardWidgetModel> { + + @Override + public DashboardWidgetModel findDocument(String resourceId) { + return getNoSqlStore().getDashboardWidgetStorage().getDashboardWidget(resourceId); + } + + @Override + public DashboardWidgetModel modifyDocumentForExport(DashboardWidgetModel doc) { + doc.setRev(null); + return doc; + } + + @Override + public DashboardWidgetModel readDocument(String serializedDoc) throws JsonProcessingException { + return SerializationUtils.getSpObjectMapper().readValue(serializedDoc, DashboardWidgetModel.class); + } + + @Override + public ExportItem convert(DashboardWidgetModel document) { + return new ExportItem(document.getId(), document.getVisualizationName(), true); + } + + @Override + public void writeDocument(String document) throws JsonProcessingException { + getNoSqlStore().getDashboardWidgetStorage().storeDashboardWidget(deserializeDocument(document)); + } + + @Override + protected DashboardWidgetModel deserializeDocument(String document) throws JsonProcessingException { + return this.spMapper.readValue(document, DashboardWidgetModel.class); + } +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataSourceResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataSourceResolver.java new file mode 100644 index 0000000..14effbb --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataSourceResolver.java
@@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.export.resolver; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.apache.streampipes.export.utils.EventGroundingProcessor; +import org.apache.streampipes.export.utils.SerializationUtils; +import org.apache.streampipes.model.SpDataStream; +import org.apache.streampipes.model.export.ExportItem; + +public class DataSourceResolver extends AbstractResolver<SpDataStream> { + + @Override + public SpDataStream findDocument(String resourceId) { + return getNoSqlStore().getDataStreamStorage().getElementById(resourceId); + } + + @Override + public SpDataStream modifyDocumentForExport(SpDataStream doc) { + doc.setRev(null); + return doc; + } + + @Override + public SpDataStream readDocument(String serializedDoc) throws JsonProcessingException { + return SerializationUtils.getSpObjectMapper().readValue(serializedDoc, SpDataStream.class); + } + + @Override + public ExportItem convert(SpDataStream document) { + return new ExportItem(document.getElementId(), document.getName(), true); + } + + @Override + public void writeDocument(String document) throws JsonProcessingException { + getNoSqlStore().getDataStreamStorage().createElement(deserializeDocument(document)); + } + + public void writeDocument(String document, + boolean overrideDocument) throws JsonProcessingException { + var dataStream = deserializeDocument(document); + if (overrideDocument) { + if (dataStream.getEventGrounding() != null) { + EventGroundingProcessor.applyOverride(dataStream.getEventGrounding().getTransportProtocol()); + } + } + getNoSqlStore().getDataStreamStorage().createElement(dataStream); + } + + @Override + protected SpDataStream deserializeDocument(String document) throws JsonProcessingException { + return this.spMapper.readValue(document, SpDataStream.class); + } +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataViewResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataViewResolver.java new file mode 100644 index 0000000..4c81c42 --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataViewResolver.java
@@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +package org.apache.streampipes.export.resolver; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.apache.streampipes.export.utils.SerializationUtils; +import org.apache.streampipes.model.dashboard.DashboardItem; +import org.apache.streampipes.model.dashboard.DashboardModel; +import org.apache.streampipes.model.export.ExportItem; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public class DataViewResolver extends AbstractResolver<DashboardModel> { + + @Override + public DashboardModel findDocument(String resourceId) { + return getNoSqlStore().getDataExplorerDashboardStorage().getDashboard(resourceId); + } + + @Override + public DashboardModel modifyDocumentForExport(DashboardModel doc) { + doc.setCouchDbRev(null); + return doc; + } + + @Override + protected boolean existsDoc(DashboardModel doc) { + return Objects.nonNull(doc) && doc.getCouchDbId() != null; + } + + @Override + public DashboardModel readDocument(String serializedDoc) throws JsonProcessingException { + return SerializationUtils.getSpObjectMapper().readValue(serializedDoc, DashboardModel.class); + } + + @Override + public ExportItem convert(DashboardModel document) { + return new ExportItem(document.getCouchDbId(), document.getName(), true); + } + + @Override + public void writeDocument(String document) throws JsonProcessingException { + getNoSqlStore().getDataExplorerDashboardStorage().storeDashboard(deserializeDocument(document)); + } + + @Override + protected DashboardModel deserializeDocument(String document) throws JsonProcessingException { + return this.spMapper.readValue(document, DashboardModel.class); + } + + public List<String> getWidgets(String resourceId) { + var document = findDocument(resourceId); + return document.getWidgets().stream().map(DashboardItem::getId).collect(Collectors.toList()); + } +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataViewWidgetResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataViewWidgetResolver.java new file mode 100644 index 0000000..0414b37 --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataViewWidgetResolver.java
@@ -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. + * + */ + +package org.apache.streampipes.export.resolver; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.apache.streampipes.export.utils.SerializationUtils; +import org.apache.streampipes.model.datalake.DataExplorerWidgetModel; +import org.apache.streampipes.model.export.ExportItem; + +public class DataViewWidgetResolver extends AbstractResolver<DataExplorerWidgetModel> { + + @Override + public DataExplorerWidgetModel findDocument(String resourceId) { + return getNoSqlStore().getDataExplorerWidgetStorage().getDataExplorerWidget(resourceId); + } + + @Override + public DataExplorerWidgetModel modifyDocumentForExport(DataExplorerWidgetModel doc) { + doc.setRev(null); + return doc; + } + + @Override + public DataExplorerWidgetModel readDocument(String serializedDoc) throws JsonProcessingException { + return SerializationUtils.getSpObjectMapper().readValue(serializedDoc, DataExplorerWidgetModel.class); + } + + @Override + public ExportItem convert(DataExplorerWidgetModel document) { + return new ExportItem(document.getId(), document.getWidgetId(), true); + } + + @Override + public void writeDocument(String document) throws JsonProcessingException { + getNoSqlStore().getDataExplorerWidgetStorage().storeDataExplorerWidget(deserializeDocument(document)); + } + + @Override + protected DataExplorerWidgetModel deserializeDocument(String document) throws JsonProcessingException { + return this.defaultMapper.readValue(document, DataExplorerWidgetModel.class); + } + +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/FileResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/FileResolver.java new file mode 100644 index 0000000..e0e2ae8 --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/FileResolver.java
@@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.export.resolver; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.apache.streampipes.export.utils.SerializationUtils; +import org.apache.streampipes.model.export.ExportItem; +import org.apache.streampipes.model.file.FileMetadata; + +public class FileResolver extends AbstractResolver<FileMetadata> { + + @Override + public FileMetadata findDocument(String resourceId) { + return getNoSqlStore().getFileMetadataStorage().getMetadataById(resourceId); + } + + @Override + public FileMetadata modifyDocumentForExport(FileMetadata doc) { + doc.setRev(null); + return doc; + } + + @Override + public FileMetadata readDocument(String serializedDoc) throws JsonProcessingException { + return SerializationUtils.getSpObjectMapper().readValue(serializedDoc, FileMetadata.class); + } + + @Override + public ExportItem convert(FileMetadata document) { + return new ExportItem(document.getFileId(), document.getOriginalFilename(), true); + } + + @Override + public void writeDocument(String document) throws JsonProcessingException { + getNoSqlStore().getFileMetadataStorage().addFileMetadata(deserializeDocument(document)); + } + + @Override + protected FileMetadata deserializeDocument(String document) throws JsonProcessingException { + return SerializationUtils.getSpObjectMapper().readValue(document, FileMetadata.class); + } +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/MeasurementResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/MeasurementResolver.java new file mode 100644 index 0000000..c5a86df --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/MeasurementResolver.java
@@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.export.resolver; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.apache.streampipes.export.utils.SerializationUtils; +import org.apache.streampipes.model.datalake.DataLakeMeasure; +import org.apache.streampipes.model.export.ExportItem; + +public class MeasurementResolver extends AbstractResolver<DataLakeMeasure> { + + @Override + public DataLakeMeasure findDocument(String resourceId) { + return getNoSqlStore().getDataLakeStorage().findOne(resourceId); + } + + @Override + public DataLakeMeasure modifyDocumentForExport(DataLakeMeasure doc) { + doc.setRev(null); + return doc; + } + + @Override + public DataLakeMeasure readDocument(String serializedDoc) throws JsonProcessingException { + return SerializationUtils.getSpObjectMapper().readValue(serializedDoc, DataLakeMeasure.class); + } + + @Override + public ExportItem convert(DataLakeMeasure document) { + return new ExportItem(document.getElementId(), document.getMeasureName(), true); + } + + @Override + public void writeDocument(String document) throws JsonProcessingException { + getNoSqlStore().getDataLakeStorage().storeDataLakeMeasure(deserializeDocument(document)); + } + + @Override + protected DataLakeMeasure deserializeDocument(String document) throws JsonProcessingException { + return this.spMapper.readValue(document, DataLakeMeasure.class); + } +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/PipelineResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/PipelineResolver.java new file mode 100644 index 0000000..2117f54 --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/PipelineResolver.java
@@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.export.resolver; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.apache.streampipes.export.utils.EventGroundingProcessor; +import org.apache.streampipes.export.utils.SerializationUtils; +import org.apache.streampipes.model.SpDataSet; +import org.apache.streampipes.model.export.ExportItem; +import org.apache.streampipes.model.pipeline.Pipeline; + +import java.util.stream.Collectors; + +public class PipelineResolver extends AbstractResolver<Pipeline> { + + @Override + public Pipeline findDocument(String resourceId) { + return getNoSqlStore().getPipelineStorageAPI().getPipeline(resourceId); + } + + @Override + public Pipeline modifyDocumentForExport(Pipeline doc) { + doc.setRev(null); + doc.setRestartOnSystemReboot(false); + doc.setRunning(false); + doc.setSepas(doc.getSepas().stream().peek(s -> s.setSelectedEndpointUrl(null)).collect(Collectors.toList())); + doc.setActions(doc.getActions().stream().peek(s -> s.setSelectedEndpointUrl(null)).collect(Collectors.toList())); + doc.setStreams(doc.getStreams() + .stream() + .filter(s -> s instanceof SpDataSet).peek(s -> ((SpDataSet) s).setSelectedEndpointUrl(null)) + .collect(Collectors.toList())); + return doc; + } + + @Override + public Pipeline readDocument(String serializedDoc) throws JsonProcessingException { + return SerializationUtils.getSpObjectMapper().readValue(serializedDoc, Pipeline.class); + } + + @Override + public ExportItem convert(Pipeline document) { + return new ExportItem(document.getPipelineId(), document.getName(), true); + } + + @Override + public void writeDocument(String document) throws JsonProcessingException { + getNoSqlStore().getPipelineStorageAPI().storePipeline(deserializeDocument(document)); + } + + public void writeDocument(String document, + boolean overrideDocument) throws JsonProcessingException { + var pipeline = deserializeDocument(document); + if (overrideDocument) { + pipeline.setSepas(pipeline.getSepas().stream().peek(processor -> { + processor.getInputStreams().forEach(is -> EventGroundingProcessor.applyOverride(is.getEventGrounding().getTransportProtocol())); + EventGroundingProcessor.applyOverride(processor.getOutputStream().getEventGrounding().getTransportProtocol()); + }).collect(Collectors.toList())); + + pipeline.setStreams(pipeline.getStreams().stream().peek(stream -> { + EventGroundingProcessor.applyOverride(stream.getEventGrounding().getTransportProtocol()); + }).collect(Collectors.toList())); + + pipeline.setActions(pipeline.getActions().stream().peek(sink -> { + sink.getInputStreams().forEach(is -> EventGroundingProcessor.applyOverride(is.getEventGrounding().getTransportProtocol())); + }).collect(Collectors.toList())); + + } + getNoSqlStore().getPipelineStorageAPI().storePipeline(pipeline); + } + + @Override + protected Pipeline deserializeDocument(String document) throws JsonProcessingException { + return this.spMapper.readValue(document, Pipeline.class); + } +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/utils/EventGroundingProcessor.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/utils/EventGroundingProcessor.java new file mode 100644 index 0000000..15578de --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/utils/EventGroundingProcessor.java
@@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.export.utils; + +import org.apache.streampipes.config.backend.BackendConfig; +import org.apache.streampipes.model.grounding.KafkaTransportProtocol; +import org.apache.streampipes.model.grounding.MqttTransportProtocol; +import org.apache.streampipes.model.grounding.TransportProtocol; + +public class EventGroundingProcessor { + + public static void applyOverride(TransportProtocol protocol) { + if (protocol instanceof KafkaTransportProtocol) { + protocol.setBrokerHostname(BackendConfig.INSTANCE.getKafkaHost()); + ((KafkaTransportProtocol) protocol).setKafkaPort(BackendConfig.INSTANCE.getKafkaPort()); + } else if (protocol instanceof MqttTransportProtocol) { + protocol.setBrokerHostname(BackendConfig.INSTANCE.getMqttHost()); + ((MqttTransportProtocol) protocol).setPort(BackendConfig.INSTANCE.getMqttPort()); + } + } +}
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/utils/SerializationUtils.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/utils/SerializationUtils.java new file mode 100644 index 0000000..44eae52 --- /dev/null +++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/utils/SerializationUtils.java
@@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.export.utils; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.streampipes.serializers.json.JacksonSerializer; + +public class SerializationUtils { + + public static ObjectMapper getSpObjectMapper() { + return JacksonSerializer.getObjectMapper(); + } + + public static ObjectMapper getDefaultObjectMapper() { + var mapper = new ObjectMapper(); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + return mapper; + } +}
diff --git a/streampipes-dataformat-cbor/pom.xml b/streampipes-dataformat-cbor/pom.xml index 604a3af..3c2658b 100644 --- a/streampipes-dataformat-cbor/pom.xml +++ b/streampipes-dataformat-cbor/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,12 +32,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-vocabulary</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-dataformat-fst/pom.xml b/streampipes-dataformat-fst/pom.xml index e6f74b0..519c4bf 100644 --- a/streampipes-dataformat-fst/pom.xml +++ b/streampipes-dataformat-fst/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,12 +32,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-vocabulary</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-dataformat-json/pom.xml b/streampipes-dataformat-json/pom.xml index 88357bd..3150e08 100644 --- a/streampipes-dataformat-json/pom.xml +++ b/streampipes-dataformat-json/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,12 +32,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-vocabulary</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-dataformat-smile/pom.xml b/streampipes-dataformat-smile/pom.xml index ac774c8..0fe2690 100644 --- a/streampipes-dataformat-smile/pom.xml +++ b/streampipes-dataformat-smile/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,12 +32,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-vocabulary</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-dataformat/pom.xml b/streampipes-dataformat/pom.xml index b573e54..80d1057 100644 --- a/streampipes-dataformat/pom.xml +++ b/streampipes-dataformat/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,7 +32,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> </dependencies>
diff --git a/streampipes-extensions/pom.xml b/streampipes-extensions/pom.xml index cfa8acf..33709e5 100644 --- a/streampipes-extensions/pom.xml +++ b/streampipes-extensions/pom.xml
@@ -17,49 +17,54 @@ ~ --> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <artifactId>streampipes-extensions</artifactId> <packaging>pom</packaging> <modules> - <module>streampipes-sinks-databases-jvm</module> - <module>streampipes-sinks-internal-jvm</module> - <module>streampipes-sinks-brokers-jvm</module> - <module>streampipes-processors-filters-jvm</module> - <module>streampipes-sinks-databases-flink</module> + <module>streampipes-connect-adapters</module> + <module>streampipes-connect-adapters-iiot</module> + + <module>streampipes-extensions-all-iiot</module> + <module>streampipes-extensions-all-jvm</module> + + <module>streampipes-pipeline-elements-all-jvm</module> + <module>streampipes-pipeline-elements-all-flink</module> + <module>streampipes-pipeline-elements-data-simulator</module> + <module>streampipes-pipeline-elements-shared</module> + <module>streampipes-processors-aggregation-flink</module> - <module>streampipes-processors-pattern-detection-flink</module> + <module>streampipes-processors-change-detection-jvm</module> <module>streampipes-processors-enricher-flink</module> <module>streampipes-processors-enricher-jvm</module> - <module>streampipes-sources-watertank-simulator</module> - <module>streampipes-sources-vehicle-simulator</module> - <module>streampipes-processors-transformation-flink</module> - <module>streampipes-processors-geo-jvm</module> - <module>streampipes-processors-statistics-flink</module> + <module>streampipes-processors-filters-jvm</module> <module>streampipes-processors-filters-siddhi</module> + <module>streampipes-processors-geo-flink</module> + <module>streampipes-processors-geo-jvm</module> + <module>streampipes-processors-image-processing-jvm</module> + <module>streampipes-processors-pattern-detection-flink</module> + <module>streampipes-processors-statistics-flink</module> + <module>streampipes-processors-transformation-flink</module> <module>streampipes-processors-text-mining-flink</module> <module>streampipes-processors-text-mining-jvm</module> - <module>streampipes-sinks-notifications-jvm</module> - <module>streampipes-pipeline-elements-shared</module> - <module>streampipes-processors-geo-flink</module> - <module>streampipes-processors-image-processing-jvm</module> <module>streampipes-processors-transformation-jvm</module> - <module>streampipes-pipeline-elements-all-jvm</module> - <module>streampipes-pipeline-elements-data-simulator</module> - <module>streampipes-connect-adapters</module> - <module>streampipes-pipeline-elements-all-flink</module> - <module>streampipes-processors-change-detection-jvm</module> - <module>streampipes-extensions-all-jvm</module> - <module>streampipes-connect-adapters-iiot</module> + + <module>streampipes-sinks-brokers-jvm</module> + <module>streampipes-sinks-databases-jvm</module> + <module>streampipes-sinks-internal-jvm</module> + <module>streampipes-sinks-databases-flink</module> + <module>streampipes-sinks-notifications-jvm</module> + + <module>streampipes-sources-watertank-simulator</module> + <module>streampipes-sources-vehicle-simulator</module> </modules> <properties> @@ -84,7 +89,7 @@ <google-maps-services.version>0.10.0</google-maps-services.version> <graalvm.js.version>21.3.0</graalvm.js.version> <iotdb.version>0.12.0</iotdb.version> - <java-websocket.version>1.4.0</java-websocket.version> + <java-websocket.version>1.5.0</java-websocket.version> <javax-websocket-client-api.version>1.1</javax-websocket-client-api.version> <jsrosbridge.version>0.2.0</jsrosbridge.version> <jedis.version>3.3.0</jedis.version> @@ -98,8 +103,8 @@ <netty-resolver.version>4.1.72.Final</netty-resolver.version> <okhttp.version>3.13.1</okhttp.version> <opennlp.version>1.9.0</opennlp.version> - <postgresql.version>42.3.3</postgresql.version> - <pulsar.version>2.9.1</pulsar.version> + <postgresql.version>42.4.1</postgresql.version> + <pulsar.version>2.10.1</pulsar.version> <quartz.version>2.3.2</quartz.version> <scala-lang.version>2.11.12</scala-lang.version> <scala-parser-combinators.version>1.1.1</scala-parser-combinators.version> @@ -125,12 +130,12 @@ <influxdb.java.version>2.14</influxdb.java.version> <eclipse.milo.version>0.6.3</eclipse.milo.version> <mysql-binlog-connector.version>0.18.1</mysql-binlog-connector.version> - <mysql-connector-java.version>8.0.16</mysql-connector-java.version> + <mysql-connector-java.version>8.0.28</mysql-connector-java.version> <netty.version>4.1.72.Final</netty.version> <nimbus-jose-jwt.version>7.9</nimbus-jose-jwt.version> <opencsv.version>5.5.2</opencsv.version> - <plc4x.version>0.8.0</plc4x.version> - <protobuf.version>3.16.1</protobuf.version> + <plc4x.version>0.9.1</plc4x.version> + <protobuf.version>3.16.3</protobuf.version> <nats.version>2.11.0</nats.version> </properties> @@ -616,7 +621,7 @@ <plugin> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-maven-plugin</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </plugin> </plugins> </build>
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/.idea/workspace.xml b/streampipes-extensions/streampipes-connect-adapters-iiot/.idea/workspace.xml deleted file mode 100644 index 5cfa370..0000000 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/.idea/workspace.xml +++ /dev/null
@@ -1,65 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project version="4"> - <component name="AutoImportSettings"> - <option name="autoReloadType" value="SELECTIVE" /> - </component> - <component name="ChangeListManager"> - <list default="true" id="d3e2227a-dba3-47e7-b123-6c9059538b23" name="Changes" comment=""> - <change afterPath="$PROJECT_DIR$/src/main/java/org/apache/streampipes/connect/iiot/adapters/PullAdapter.java" afterDir="false" /> - <change afterPath="$PROJECT_DIR$/src/main/java/org/apache/streampipes/connect/iiot/adapters/PullRestAdapter.java" afterDir="false" /> - <change beforePath="$PROJECT_DIR$/src/main/java/org/apache/streampipes/connect/iiot/ConnectAdapterIiotInit.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/org/apache/streampipes/connect/iiot/ConnectAdapterIiotInit.java" afterDir="false" /> - <change beforePath="$PROJECT_DIR$/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/NetioRestAdapter.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/NetioRestAdapter.java" afterDir="false" /> - <change beforePath="$PROJECT_DIR$/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaAdapter.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaAdapter.java" afterDir="false" /> - <change beforePath="$PROJECT_DIR$/src/main/java/org/apache/streampipes/connect/iiot/adapters/plc4x/modbus/Plc4xModbusAdapter.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/org/apache/streampipes/connect/iiot/adapters/plc4x/modbus/Plc4xModbusAdapter.java" afterDir="false" /> - <change beforePath="$PROJECT_DIR$/src/main/java/org/apache/streampipes/connect/iiot/adapters/plc4x/s7/Plc4xS7Adapter.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/org/apache/streampipes/connect/iiot/adapters/plc4x/s7/Plc4xS7Adapter.java" afterDir="false" /> - </list> - <option name="SHOW_DIALOG" value="false" /> - <option name="HIGHLIGHT_CONFLICTS" value="true" /> - <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> - <option name="LAST_RESOLUTION" value="IGNORE" /> - </component> - <component name="Git.Settings"> - <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." /> - </component> - <component name="ProjectId" id="1zENWGAsJxaiZwkmabyYBU9b1cM" /> - <component name="ProjectViewState"> - <option name="hideEmptyMiddlePackages" value="true" /> - <option name="showLibraryContents" value="true" /> - </component> - <component name="PropertiesComponent"> - <property name="RunOnceActivity.OpenProjectViewOnStart" value="true" /> - <property name="RunOnceActivity.ShowReadmeOnStart" value="true" /> - <property name="last_opened_file_path" value="$PROJECT_DIR$/.." /> - </component> - <component name="RunManager"> - <configuration name="ConnectAdapterIiotInit" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true"> - <option name="MAIN_CLASS_NAME" value="org.apache.streampipes.connect.iiot.ConnectAdapterIiotInit" /> - <module name="streampipes-connect-adapters-iiot" /> - <extension name="coverage"> - <pattern> - <option name="PATTERN" value="org.apache.streampipes.connect.iiot.*" /> - <option name="ENABLED" value="true" /> - </pattern> - </extension> - <method v="2"> - <option name="Make" enabled="true" /> - </method> - </configuration> - <recent_temporary> - <list> - <item itemvalue="Application.ConnectAdapterIiotInit" /> - </list> - </recent_temporary> - </component> - <component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" /> - <component name="TaskManager"> - <task active="true" id="Default" summary="Default task"> - <changelist id="d3e2227a-dba3-47e7-b123-6c9059538b23" name="Changes" comment="" /> - <created>1633709316229</created> - <option name="number" value="Default" /> - <option name="presentableId" value="Default" /> - <updated>1633709316229</updated> - </task> - <servers /> - </component> -</project> \ No newline at end of file
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/pom.xml b/streampipes-extensions/streampipes-connect-adapters-iiot/pom.xml index 5ed13be..71a318a 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/pom.xml +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/pom.xml
@@ -17,16 +17,14 @@ ~ --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-extensions</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <artifactId>streampipes-connect-adapters-iiot</artifactId> @@ -39,7 +37,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-connect-container-worker</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>org.graalvm.nativeimage</groupId> @@ -50,17 +48,17 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-pipeline-elements-shared</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-client</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-container-extensions</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies --> @@ -69,10 +67,6 @@ <artifactId>jackson-module-jaxb-annotations</artifactId> </dependency> <dependency> - <groupId>com.github.shyiko</groupId> - <artifactId>mysql-binlog-connector-java</artifactId> - </dependency> - <dependency> <groupId>org.influxdb</groupId> <artifactId>influxdb-java</artifactId> </dependency> @@ -268,5 +262,4 @@ </plugins> <finalName>streampipes-connect-adapters-iiot</finalName> </build> - </project>
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/ConnectAdapterIiotInit.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/ConnectAdapterIiotInit.java index 7298fab..97f0df0 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/ConnectAdapterIiotInit.java +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/ConnectAdapterIiotInit.java
@@ -20,20 +20,16 @@ import org.apache.streampipes.connect.iiot.adapters.influxdb.InfluxDbSetAdapter; import org.apache.streampipes.connect.iiot.adapters.influxdb.InfluxDbStreamAdapter; -import org.apache.streampipes.connect.iiot.adapters.mysql.MySqlSetAdapter; -import org.apache.streampipes.connect.iiot.adapters.mysql.MySqlStreamAdapter; -import org.apache.streampipes.connect.iiot.adapters.netio.NetioMQTTAdapter; -import org.apache.streampipes.connect.iiot.adapters.netio.NetioRestAdapter; import org.apache.streampipes.connect.iiot.adapters.opcua.OpcUaAdapter; import org.apache.streampipes.connect.iiot.adapters.plc4x.modbus.Plc4xModbusAdapter; import org.apache.streampipes.connect.iiot.adapters.plc4x.s7.Plc4xS7Adapter; import org.apache.streampipes.connect.iiot.adapters.ros.RosBridgeAdapter; import org.apache.streampipes.connect.iiot.adapters.simulator.machine.MachineDataStreamAdapter; -import org.apache.streampipes.container.extensions.ExtensionsModelSubmitter; import org.apache.streampipes.connect.iiot.protocol.set.FileProtocol; import org.apache.streampipes.connect.iiot.protocol.set.HttpProtocol; import org.apache.streampipes.connect.iiot.protocol.stream.*; import org.apache.streampipes.connect.iiot.protocol.stream.pulsar.PulsarProtocol; +import org.apache.streampipes.container.extensions.ExtensionsModelSubmitter; import org.apache.streampipes.container.model.SpServiceDefinition; import org.apache.streampipes.container.model.SpServiceDefinitionBuilder; @@ -48,15 +44,11 @@ "StreamPipes connect worker containing adapters relevant for the IIoT", "", 8001) - .registerAdapter(new MySqlStreamAdapter()) - .registerAdapter(new MySqlSetAdapter()) .registerAdapter(new MachineDataStreamAdapter()) .registerAdapter(new RosBridgeAdapter()) .registerAdapter(new OpcUaAdapter()) .registerAdapter(new InfluxDbStreamAdapter()) .registerAdapter(new InfluxDbSetAdapter()) - .registerAdapter(new NetioRestAdapter()) - .registerAdapter(new NetioMQTTAdapter()) .registerAdapter(new Plc4xS7Adapter()) .registerAdapter(new Plc4xModbusAdapter()) .registerAdapter(new FileProtocol())
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/PullAdapter.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/PullAdapter.java index 2e92cfb..02f1b58 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/PullAdapter.java +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/PullAdapter.java
@@ -51,9 +51,7 @@ public void startAdapter() throws AdapterException { before(); - final Runnable errorThread = () -> { - executeAdpaterLogic(); - }; + final Runnable errorThread = this::executeAdpaterLogic; scheduler = Executors.newScheduledThreadPool(1); scheduler.schedule(errorThread, 0, TimeUnit.MILLISECONDS); @@ -61,11 +59,7 @@ } private void executeAdpaterLogic() { - final Runnable task = () -> { - - pullData(); - - }; + final Runnable task = this::pullData; scheduler = Executors.newScheduledThreadPool(1); ScheduledFuture<?> handle = scheduler.scheduleAtFixedRate(task, 1,
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/mysql/Column.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/mysql/Column.java deleted file mode 100644 index 08ee0c5..0000000 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/mysql/Column.java +++ /dev/null
@@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.connect.iiot.adapters.mysql; - -import org.apache.streampipes.sdk.utils.Datatypes; -import org.apache.streampipes.vocabulary.SO; - -class Column { - private String name; - private Datatypes type; - private Object def; - private String domainProperty; - - Column(String name, String dataType, String columnType) { - this.name = name; - switch (dataType) { - case "tinyint": - case "smallint": - case "mediumint": - case "int": - case "bit": - this.type = Datatypes.Integer; - def = 0; - break; - case "bigint": - this.type = Datatypes.Long; - def = 0L; - break; - case "float": - case "decimal": // Watch out for loss of precision - case "double": - this.type = Datatypes.Float; - def = 0.0f; - break; - case "text": - case "varchar": - case "char": - this.type = Datatypes.String; - def = ""; - break; - case "date": - case "datetime": - case "time": - case "timestamp": - case "year": - this.type = Datatypes.Float; - def = System.currentTimeMillis(); - this.domainProperty = SO.DateTime; - break; - default: - throw new IllegalArgumentException("Type " + type + " not supported."); - } - if (columnType.equals("tinyint(1)") || columnType.equals("bit(1)")) { - this.type = Datatypes.Boolean; - def = Boolean.FALSE; - } - System.out.println("Found column: " + name + ", type: " + this.type + " (sql-type: " - + dataType + ", column-tpye: " + columnType + ")"); - } - - public String getName() { - return name; - } - public Datatypes getType() { - return type; - } - public Object getDefault() { - return def; - } - - public String getDomainProperty() { - return domainProperty; - } -}
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/mysql/MySqlAdapter.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/mysql/MySqlAdapter.java deleted file mode 100644 index 59fecb9..0000000 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/mysql/MySqlAdapter.java +++ /dev/null
@@ -1,269 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.connect.iiot.adapters.mysql; - -import com.github.shyiko.mysql.binlog.BinaryLogClient; -import com.github.shyiko.mysql.binlog.event.*; -import com.github.shyiko.mysql.binlog.event.deserialization.EventDeserializer; -import org.apache.streampipes.connect.adapter.Adapter; -import org.apache.streampipes.connect.api.exception.AdapterException; -import org.apache.streampipes.connect.api.exception.ParseException; -import org.apache.streampipes.connect.adapter.model.specific.SpecificDataStreamAdapter; -import org.apache.streampipes.connect.adapter.sdk.ParameterExtractor; -import org.apache.streampipes.model.connect.adapter.SpecificAdapterStreamDescription; -import org.apache.streampipes.model.connect.guess.GuessSchema; -import org.apache.streampipes.model.schema.EventProperty; -import org.apache.streampipes.model.schema.EventSchema; -import org.apache.streampipes.sdk.builder.adapter.SpecificDataStreamAdapterBuilder; -import org.apache.streampipes.sdk.builder.PrimitivePropertyBuilder; -import org.apache.streampipes.sdk.helpers.Labels; -import org.apache.streampipes.vocabulary.SO; - -import java.io.IOException; -import java.io.Serializable; -import java.sql.*; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -public class MySqlAdapter extends SpecificDataStreamAdapter { - - public static final String ID = "http://streampipes.org/adapter/specific/mysql"; - - private static String MYSQL_HOST = "MYSQL_HOST"; - private static String MYSQL_USER = "MYSQL_USER"; - private static String MYSQL_PASS = "MYSQL_PASS"; - private static String MYSQL_DB = "MYSQL_DB"; - private static String MYSQL_TABLE = "MYSQL_TABLE"; - private static String MYSQL_PORT = "MYSQL_PORT"; - - private String host; - private String user; - private String pass; - private String database; - private String table; - private String port; - - private boolean dataComing = false; - private List<Column> tableSchema; - private BinaryLogClient client; - - public MySqlAdapter() { - } - - public MySqlAdapter(SpecificAdapterStreamDescription adapterDescription) { - super(adapterDescription); - - getConfigurations(adapterDescription); - } - - @Override - public SpecificAdapterStreamDescription declareModel() { - //TODO: Add Icon - SpecificAdapterStreamDescription description = SpecificDataStreamAdapterBuilder.create(ID, - "MySql Adapter", - "Creates a data stream for a SQL table") - .iconUrl("sql.png") - .requiredTextParameter(Labels.from(MYSQL_HOST, "Hostname", "Hostname of the MySql Server")) - .requiredTextParameter(Labels.from(MYSQL_USER, "Username", "Username of the user")) - .requiredTextParameter(Labels.from(MYSQL_PASS, "Password", "Password of the user")) - .requiredTextParameter(Labels.from(MYSQL_DB, "Database", "Database in which the table is located")) - .requiredTextParameter(Labels.from(MYSQL_TABLE, "Table", "Table which should be watched")) - .requiredIntegerParameter(Labels.from(MYSQL_PORT, "Port", "Port of the MySql Server. Default: 3306"), 3306) - .build(); - - description.setAppId(ID); - return description; - } - - @Override - public void startAdapter() throws AdapterException { - checkJdbcDriver(); - extractTableInformation(); - - // Connect BinaryLogClient - client = new BinaryLogClient(host, Integer.parseInt(port), user, pass); - EventDeserializer eventDeserializer = new EventDeserializer(); - eventDeserializer.setCompatibilityMode( - EventDeserializer.CompatibilityMode.DATE_AND_TIME_AS_LONG, - EventDeserializer.CompatibilityMode.CHAR_AND_BINARY_AS_BYTE_ARRAY - ); - client.setEventDeserializer(eventDeserializer); - client.registerEventListener(event -> sendEvent(event)); - try { - client.connect(); - } catch (IOException e) { - throw new AdapterException(e.getMessage()); - } - } - - private void sendEvent(Event event) { - // An event can contain multiple insertions/updates - if (event.getHeader().getEventType() == EventType.TABLE_MAP) { - // Check table and database, if the next event should be streamed - if (((TableMapEventData) event.getData()).getDatabase().equals(database) - && ((TableMapEventData) event.getData()).getTable().equals((table))) { - dataComing = true; - } - } - if (dataComing) { - if (EventType.isUpdate(event.getHeader().getEventType())) { - for (Entry<Serializable[], Serializable[]> en : ((UpdateRowsEventData) event.getData()).getRows()) { - sendChange(en.getValue()); - } - dataComing = false; - } else if (EventType.isWrite(event.getHeader().getEventType())) { - for (Serializable[] s : ((WriteRowsEventData) event.getData()).getRows()) { - sendChange(s); - } - dataComing = false; - } - } - } - - private void sendChange(Serializable[] rows) { - Map<String, Object> out = new HashMap<>(); - for (int i = 0; i < rows.length; i++) { - if (rows[i] != null) { - if (rows[i] instanceof byte[]) { - // Strings are sent in byte arrays and have to be converted. TODO: Check that encoding is correct - out.put(tableSchema.get(i).getName(), new String((byte[])rows[i])); - } else { - out.put(tableSchema.get(i).getName(), rows[i]); - } - } else { - out.put(tableSchema.get(i).getName(), tableSchema.get(i).getDefault()); - } - } - adapterPipeline.process(out); - } - - @Override - public void stopAdapter() throws AdapterException { - try { - client.disconnect(); - } catch (IOException e) { - throw new AdapterException("Thrown exception: " + e.getMessage()); - } - } - - @Override - public Adapter getInstance(SpecificAdapterStreamDescription adapterDescription) { - return new MySqlAdapter(adapterDescription); - } - - @Override - public GuessSchema getSchema(SpecificAdapterStreamDescription adapterDescription) - throws AdapterException, ParseException { - // Load JDBC Driver, connect JDBC Driver, Extract information, disconnect JDBC Driver - EventSchema eventSchema = new EventSchema(); - GuessSchema guessSchema = new GuessSchema(); - List<EventProperty> allProperties = new ArrayList<>(); - - getConfigurations(adapterDescription); - - checkJdbcDriver(); - extractTableInformation(); - - for (Column column : tableSchema) { - if (SO.DateTime.equals(column.getDomainProperty())) { - allProperties.add(PrimitivePropertyBuilder - .create(column.getType(), column.getName()) - .label(column.getName()) - .domainProperty(SO.DateTime) - .build()); - } else { - allProperties.add(PrimitivePropertyBuilder - .create(column.getType(), column.getName()) - .label(column.getName()) - .build()); - } - - } - - eventSchema.setEventProperties(allProperties); - guessSchema.setEventSchema(eventSchema); - - return guessSchema; - } - - @Override - public String getId() { - return ID; - } - - private void getConfigurations(SpecificAdapterStreamDescription adapterDescription) { - ParameterExtractor extractor = new ParameterExtractor(adapterDescription.getConfig()); - - this.host = extractor.singleValue(MYSQL_HOST, String.class); - this.user = extractor.singleValue(MYSQL_USER, String.class); - this.pass = extractor.singleValue(MYSQL_PASS, String.class); - this.database = extractor.singleValue(MYSQL_DB, String.class); - this.table = extractor.singleValue(MYSQL_TABLE, String.class); - this.port = extractor.singleValue(MYSQL_PORT, String.class); - } - - private void checkJdbcDriver() throws AdapterException { - try { - Class.forName("com.mysql.cj.jdbc.Driver"); - } catch (ClassNotFoundException e) { - throw new AdapterException("MySql Driver not found."); - } - } - - private void extractTableInformation() throws AdapterException { - String server = "jdbc:mysql://" + host + ":" + port + "/" + "?sslMode=DISABLED&allowPublicKeyRetrieval=true"; - ResultSet resultSet = null; - tableSchema = new ArrayList<>(); - - String query = "SELECT COLUMN_NAME, DATA_TYPE, COLUMN_TYPE FROM " - + "INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ? AND TABLE_SCHEMA = ? ORDER BY " - + "ORDINAL_POSITION ASC;"; - - try (Connection con = DriverManager.getConnection(server, user, pass); - PreparedStatement statement = con.prepareStatement(query)) { - - statement.setString(1, table); - statement.setString(2, database); - resultSet = statement.executeQuery(); - - if (resultSet.next()) { - do { - String name = resultSet.getString("COLUMN_NAME"); - String dataType = resultSet.getString("DATA_TYPE"); - String columnType = resultSet.getString("COLUMN_TYPE"); - tableSchema.add(new Column(name, dataType, columnType)); - } while(resultSet.next()); - } else { - // No columns found -> Table/Database does not exist - throw new IllegalArgumentException("Database/table not found"); - } - } catch (SQLException e) { - throw new AdapterException("SqlException: " + e.getMessage() - + ", Error code: " + e.getErrorCode() - + ", SqlState: " + e.getSQLState()); - } finally { - try { - resultSet.close(); - } catch (Exception e) {} - } - } -}
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/mysql/MySqlClient.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/mysql/MySqlClient.java deleted file mode 100644 index 251f16a..0000000 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/mysql/MySqlClient.java +++ /dev/null
@@ -1,215 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.connect.iiot.adapters.mysql; - -import org.apache.streampipes.connect.api.exception.AdapterException; -import org.apache.streampipes.model.connect.guess.GuessSchema; -import org.apache.streampipes.model.schema.EventProperty; -import org.apache.streampipes.model.schema.EventSchema; -import org.apache.streampipes.sdk.builder.PrimitivePropertyBuilder; -import org.apache.streampipes.vocabulary.SO; - -import java.sql.*; -import java.util.ArrayList; -import java.util.List; - -public class MySqlClient { - - public static final String ID = "http://streampipes.org/adapter/specific/mysql"; - - static final String HOST = "mysqlHost"; - static final String PORT = "mysqlPort"; - static final String DATABASE = "mysqlDatabase"; - static final String TABLE = "mysqlTable"; - static final String USER = "mysqlUser"; - static final String PASSWORD = "mysqlPassword"; - - static final String REPLACE_NULL_VALUES = "replaceNullValues"; - static final String DO_REPLACE_NULL_VALUES = "doReplaceNullValues"; - static final String DO_NOT_REPLACE_NULL_VALUES = "doNotReplaceNullValues"; - - private String host; - private Integer port; - private String database; - private String table; - - private String username; - private String password; - - - private List<Column> columns; - - Connection connection; - - MySqlClient(String host, - int port, - String database, - String table, - String username, - String password) { - this.host = host; - this.port = port; - this.database = database; - this.table = table; - this.username = username; - this.password = password; - - connection = null; - } - - public void connect() throws AdapterException { - checkJdbcDriver(); - String server = "jdbc:mysql://" + host + ":" + port + "/" + "?sslMode=DISABLED&allowPublicKeyRetrieval=true"; - try { - connection = DriverManager.getConnection(server, username, password); - } catch (SQLException e) { - throw new AdapterException("Could not connect to server: " + e.getMessage()); - } - } - - public void disconnect() throws AdapterException { - if (connection != null) { - try { - connection.close(); - } catch (SQLException e) { - throw new AdapterException("Error while disconnecting: " + e.getMessage()); - } - connection = null; - } - } - - public GuessSchema getSchema() throws AdapterException { - connect(); - loadColumns(); - - EventSchema eventSchema = new EventSchema(); - GuessSchema guessSchema = new GuessSchema(); - List<EventProperty> allProperties = new ArrayList<>(); - - for (Column column : columns) { - if (SO.DateTime.equals(column.getDomainProperty())) { - allProperties.add(PrimitivePropertyBuilder - .create(column.getType(), column.getName()) - .label(column.getName()) - .domainProperty(SO.DateTime) - .build()); - } else { - allProperties.add(PrimitivePropertyBuilder - .create(column.getType(), column.getName()) - .label(column.getName()) - .build()); - } - } - - eventSchema.setEventProperties(allProperties); - guessSchema.setEventSchema(eventSchema); - - disconnect(); - return guessSchema; - } - - /** - * Checks that the MySql-JDBC-Driver is "installed". Throws an AdapterException otherwise - */ - private void checkJdbcDriver() throws AdapterException { - try { - Class.forName("com.mysql.cj.jdbc.Driver"); - } catch (ClassNotFoundException e) { - throw new AdapterException("MySql Driver not found."); - } - } - - /** - * Fills the columns with the columns from the SQL Table - */ - public void loadColumns() throws AdapterException { - if (connection == null) { - throw new AdapterException("Client must be connected in order to load the columns"); - } - ResultSet resultSet = null; - columns = new ArrayList<>(); - - String query = "SELECT COLUMN_NAME, DATA_TYPE, COLUMN_TYPE FROM " - + "INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ? AND TABLE_SCHEMA = ? ORDER BY " - + "ORDINAL_POSITION ASC;"; - - try (PreparedStatement statement = connection.prepareStatement(query)) { - - statement.setString(1, table); - statement.setString(2, database); - resultSet = statement.executeQuery(); - - if (resultSet.next()) { - do { - String name = resultSet.getString("COLUMN_NAME"); - String dataType = resultSet.getString("DATA_TYPE"); - String columnType = resultSet.getString("COLUMN_TYPE"); - columns.add(new Column(name, dataType, columnType)); - } while(resultSet.next()); - } else { - // No columns found -> Table/Database does not exist - throw new IllegalArgumentException("Database/table not found"); - } - } catch (SQLException e) { - throw new AdapterException("SqlException while loading columns: " + e.getMessage() - + ", Error code: " + e.getErrorCode() - + ", SqlState: " + e.getSQLState()); - } finally { - try { - resultSet.close(); - } catch (Exception e) {} - } - } - - public String getHost() { - return host; - } - - public Integer getPort() { - return port; - } - - public String getDatabase() { - return database; - } - - public String getTable() { - return table; - } - - public String getUsername() { - return username; - } - - public String getPassword() { - return password; - } - - public List<Column> getColumns() { - return columns; - } - - public boolean isConnected() { - return connection != null; - } - - Connection getConnection() { - return connection; - } -}
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/mysql/MySqlSetAdapter.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/mysql/MySqlSetAdapter.java deleted file mode 100644 index 87769ee..0000000 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/mysql/MySqlSetAdapter.java +++ /dev/null
@@ -1,203 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.connect.iiot.adapters.mysql; - -import org.apache.streampipes.connect.adapter.Adapter; -import org.apache.streampipes.connect.api.exception.AdapterException; -import org.apache.streampipes.connect.api.exception.ParseException; -import org.apache.streampipes.connect.adapter.model.specific.SpecificDataSetAdapter; -import org.apache.streampipes.connect.adapter.sdk.ParameterExtractor; -import org.apache.streampipes.model.connect.adapter.SpecificAdapterSetDescription; -import org.apache.streampipes.model.connect.guess.GuessSchema; -import org.apache.streampipes.sdk.builder.adapter.SpecificDataSetAdapterBuilder; -import org.apache.streampipes.sdk.helpers.Labels; -import org.apache.streampipes.sdk.helpers.Locales; -import org.apache.streampipes.sdk.helpers.Options; -import org.apache.streampipes.sdk.helpers.Tuple2; -import org.apache.streampipes.sdk.utils.Assets; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.HashMap; -import java.util.Map; - -public class MySqlSetAdapter extends SpecificDataSetAdapter { - - public static final String ID = "org.apache.streampipes.connect.iiot.adapters.mysql.set"; - - private MySqlClient mySqlClient; - private Thread fetchDataThread; - - private boolean replaceNullValues; - - public static class FetchDataThread implements Runnable { - - MySqlSetAdapter mySqlSetAdapter; - MySqlClient mySqlClient; - - public FetchDataThread(MySqlSetAdapter mySqlSetAdapter) throws AdapterException { - this.mySqlSetAdapter = mySqlSetAdapter; - this.mySqlClient = mySqlSetAdapter.getMySqlClient(); - - mySqlClient.connect(); - mySqlClient.loadColumns(); - } - - @Override - public void run() { - if (!mySqlClient.isConnected()) { - System.out.println("Cannot start PollingThread, when the client is not connected"); - return; - } - // No batch approach like in the influx adapter due to the lack of a unique key in the table - // Create the columnString: - StringBuilder sb = new StringBuilder(); - for (Column column : mySqlClient.getColumns()) { - sb.append(column.getName()).append(", "); - } - sb.setLength(Math.max(0, sb.length() - 2)); - - String query = "SELECT " + sb.toString() + " FROM " + mySqlClient.getDatabase() + "." + mySqlClient.getTable(); - - try (Statement statement = mySqlClient.getConnection().createStatement()) { - boolean executed = statement.execute(query); - if (executed) { - ResultSet resultSet = statement.getResultSet(); - while (resultSet.next()) { - - // Retrieve by column name - Map<String, Object> event = new HashMap<>(); - for (Column column : mySqlClient.getColumns()) { - Object in = resultSet.getObject(column.getName()); - if (in == null) { - if (mySqlSetAdapter.replaceNullValues) { - in = column.getDefault(); - } else { - // We do not want to send this event (replaceNullValues == false) - event = null; - break; - } - } - event.put(column.getName(), in); - } - if (event != null) { - mySqlSetAdapter.send(event); - } - } - resultSet.close(); - } - } catch (SQLException e) { - System.out.println(e.getMessage()); - } - - try { - mySqlClient.disconnect(); - } catch (AdapterException e) { - e.printStackTrace(); - } - } - } - - public MySqlSetAdapter() { - } - - public MySqlSetAdapter(SpecificAdapterSetDescription adapterDescription) { - super(adapterDescription); - - getConfigurations(adapterDescription); - } - - - @Override - public SpecificAdapterSetDescription declareModel() { - SpecificAdapterSetDescription description = SpecificDataSetAdapterBuilder.create(ID) - .withAssets(Assets.DOCUMENTATION, Assets.ICON) - .withLocales(Locales.EN) - .requiredTextParameter(Labels.withId(MySqlClient.HOST)) - .requiredIntegerParameter(Labels.withId(MySqlClient.PORT), 3306) - .requiredTextParameter(Labels.withId(MySqlClient.DATABASE)) - .requiredTextParameter(Labels.withId(MySqlClient.TABLE)) - .requiredTextParameter(Labels.withId(MySqlClient.USER)) - .requiredSecret(Labels.withId(MySqlClient.PASSWORD)) - .requiredSingleValueSelection(Labels.withId(MySqlClient.REPLACE_NULL_VALUES), - Options.from( - new Tuple2<>("Yes", MySqlClient.DO_REPLACE_NULL_VALUES), - new Tuple2<>("No", MySqlClient.DO_NOT_REPLACE_NULL_VALUES))) - .build(); - - description.setAppId(ID); - return description; - } - - @Override - public void startAdapter() throws AdapterException { - fetchDataThread = new Thread(new FetchDataThread(this)); - fetchDataThread.start(); - } - - @Override - public void stopAdapter() throws AdapterException { - fetchDataThread.interrupt(); - try { - fetchDataThread.join(); - } catch (InterruptedException e) { - throw new AdapterException("Unexpected Error while joining polling thread: " + e.getMessage()); - } - } - - @Override - public Adapter getInstance(SpecificAdapterSetDescription adapterDescription) { - return new MySqlSetAdapter(adapterDescription); - } - - @Override - public GuessSchema getSchema(SpecificAdapterSetDescription adapterDescription) throws AdapterException, ParseException { - getConfigurations(adapterDescription); - return mySqlClient.getSchema(); - } - - @Override - public String getId() { - return ID; - } - - private void send(Map<String, Object> map) { - adapterPipeline.process(map); - } - - private void getConfigurations(SpecificAdapterSetDescription adapterDescription) { - ParameterExtractor extractor = new ParameterExtractor(adapterDescription.getConfig()); - - String replace = extractor.selectedSingleValueInternalName(MySqlClient.REPLACE_NULL_VALUES); - replaceNullValues = replace.equals(MySqlClient.DO_REPLACE_NULL_VALUES); - - mySqlClient = new MySqlClient( - extractor.singleValue(MySqlClient.HOST, String.class), - extractor.singleValue(MySqlClient.PORT, Integer.class), - extractor.singleValue(MySqlClient.DATABASE, String.class), - extractor.singleValue(MySqlClient.TABLE, String.class), - extractor.singleValue(MySqlClient.USER, String.class), - extractor.secretValue(MySqlClient.PASSWORD)); - } - - public MySqlClient getMySqlClient() { - return mySqlClient; - } -}
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/mysql/MySqlStreamAdapter.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/mysql/MySqlStreamAdapter.java deleted file mode 100644 index c36e14a..0000000 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/mysql/MySqlStreamAdapter.java +++ /dev/null
@@ -1,201 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.connect.iiot.adapters.mysql; - -import com.github.shyiko.mysql.binlog.BinaryLogClient; -import com.github.shyiko.mysql.binlog.event.*; -import com.github.shyiko.mysql.binlog.event.deserialization.EventDeserializer; -import org.apache.streampipes.connect.adapter.Adapter; -import org.apache.streampipes.connect.api.exception.AdapterException; -import org.apache.streampipes.connect.api.exception.ParseException; -import org.apache.streampipes.connect.adapter.model.specific.SpecificDataStreamAdapter; -import org.apache.streampipes.connect.adapter.sdk.ParameterExtractor; -import org.apache.streampipes.model.connect.adapter.SpecificAdapterStreamDescription; -import org.apache.streampipes.model.connect.guess.GuessSchema; -import org.apache.streampipes.sdk.builder.adapter.SpecificDataStreamAdapterBuilder; -import org.apache.streampipes.sdk.helpers.Labels; -import org.apache.streampipes.sdk.helpers.Locales; -import org.apache.streampipes.sdk.helpers.Options; -import org.apache.streampipes.sdk.helpers.Tuple2; -import org.apache.streampipes.sdk.utils.Assets; - -import java.io.IOException; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -public class MySqlStreamAdapter extends SpecificDataStreamAdapter { - - public static final String ID = "org.apache.streampipes.connect.iiot.adapters.mysql.stream"; - - private MySqlClient mySqlClient; - private BinaryLogClient binaryLogClient; - - private Thread subscriptionThread = new Thread(()-> { - try { - binaryLogClient.connect(); - } catch (IOException e) { - e.printStackTrace(); - } - }); - - private boolean replaceNullValues; - private boolean dataComing = false; - - public MySqlStreamAdapter() { - } - - public MySqlStreamAdapter(SpecificAdapterStreamDescription adapterDescription) { - super(adapterDescription); - - getConfigurations(adapterDescription); - } - - @Override - public SpecificAdapterStreamDescription declareModel() { - SpecificAdapterStreamDescription description = SpecificDataStreamAdapterBuilder.create(ID) - .withAssets(Assets.DOCUMENTATION, Assets.ICON) - .withLocales(Locales.EN) - .requiredTextParameter(Labels.withId(MySqlClient.HOST)) - .requiredIntegerParameter(Labels.withId(MySqlClient.PORT), 3306) - .requiredTextParameter(Labels.withId(MySqlClient.DATABASE)) - .requiredTextParameter(Labels.withId(MySqlClient.TABLE)) - .requiredTextParameter(Labels.withId(MySqlClient.USER)) - .requiredSecret(Labels.withId(MySqlClient.PASSWORD)) - .requiredSingleValueSelection(Labels.withId(MySqlClient.REPLACE_NULL_VALUES), - Options.from( - new Tuple2<>("Yes", MySqlClient.DO_REPLACE_NULL_VALUES), - new Tuple2<>("No", MySqlClient.DO_NOT_REPLACE_NULL_VALUES))) - .build(); - - description.setAppId(ID); - return description; - } - - @Override - public void startAdapter() throws AdapterException { - // Making sure, that the columns are all loaded - mySqlClient.connect(); - mySqlClient.loadColumns(); - mySqlClient.disconnect(); - - // Connect BinaryLogClient - binaryLogClient = new BinaryLogClient( - mySqlClient.getHost(), - mySqlClient.getPort(), - mySqlClient.getUsername(), - mySqlClient.getPassword()); - - EventDeserializer eventDeserializer = new EventDeserializer(); - eventDeserializer.setCompatibilityMode( - EventDeserializer.CompatibilityMode.DATE_AND_TIME_AS_LONG, - EventDeserializer.CompatibilityMode.CHAR_AND_BINARY_AS_BYTE_ARRAY - ); - binaryLogClient.setEventDeserializer(eventDeserializer); - binaryLogClient.registerEventListener(event -> sendEvent(event)); - subscriptionThread.start(); - } - - - private void sendEvent(Event event) { - // An event can contain multiple insertions/updates - if (event.getHeader().getEventType() == EventType.TABLE_MAP) { - // Check table and database, if the next event should be streamed - if (((TableMapEventData) event.getData()).getDatabase().equals(mySqlClient.getDatabase()) - && ((TableMapEventData) event.getData()).getTable().equals((mySqlClient.getTable()))) { - dataComing = true; - } - } - if (dataComing) { - if (EventType.isUpdate(event.getHeader().getEventType())) { - for (Map.Entry<Serializable[], Serializable[]> en : ((UpdateRowsEventData) event.getData()).getRows()) { - sendChange(en.getValue()); - } - dataComing = false; - } else if (EventType.isWrite(event.getHeader().getEventType())) { - for (Serializable[] s : ((WriteRowsEventData) event.getData()).getRows()) { - sendChange(s); - } - dataComing = false; - } - } - } - - private void sendChange(Serializable[] rows) { - Map<String, Object> out = new HashMap<>(); - for (int i = 0; i < rows.length; i++) { - if (rows[i] != null) { - if (rows[i] instanceof byte[]) { - // Strings are sent in byte arrays and have to be converted. - //TODO: Check that encoding is correct - out.put(mySqlClient.getColumns().get(i).getName(), new String((byte[])rows[i])); - } else { - out.put(mySqlClient.getColumns().get(i).getName(), rows[i]); - } - } else if (replaceNullValues) { - out.put(mySqlClient.getColumns().get(i).getName(), mySqlClient.getColumns().get(i).getDefault()); - } else { - // We should skip events with null values - return; - } - } - adapterPipeline.process(out); - } - - @Override - public void stopAdapter() throws AdapterException { - try { - binaryLogClient.disconnect(); - subscriptionThread.join(); - } catch (IOException | InterruptedException e) { - throw new AdapterException("Thrown exception: " + e.getMessage()); - } - } - - @Override - public Adapter getInstance(SpecificAdapterStreamDescription adapterDescription) { - return new MySqlStreamAdapter(adapterDescription); - } - - @Override - public GuessSchema getSchema(SpecificAdapterStreamDescription adapterDescription) throws AdapterException, ParseException { - getConfigurations(adapterDescription); - return mySqlClient.getSchema(); - } - - @Override - public String getId() { - return ID; - } - - private void getConfigurations(SpecificAdapterStreamDescription adapterDescription) { - ParameterExtractor extractor = new ParameterExtractor(adapterDescription.getConfig()); - - String replace = extractor.selectedSingleValueInternalName(MySqlClient.REPLACE_NULL_VALUES); - replaceNullValues = replace.equals(MySqlClient.DO_REPLACE_NULL_VALUES); - - mySqlClient = new MySqlClient( - extractor.singleValue(MySqlClient.HOST, String.class), - extractor.singleValue(MySqlClient.PORT, Integer.class), - extractor.singleValue(MySqlClient.DATABASE, String.class), - extractor.singleValue(MySqlClient.TABLE, String.class), - extractor.singleValue(MySqlClient.USER, String.class), - extractor.secretValue(MySqlClient.PASSWORD)); - } -}
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/MiloOpcUaConfigurationProvider.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/MiloOpcUaConfigurationProvider.java index e4336d8..7145858 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/MiloOpcUaConfigurationProvider.java +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/MiloOpcUaConfigurationProvider.java
@@ -18,6 +18,7 @@ package org.apache.streampipes.connect.iiot.adapters.opcua; +import org.apache.streampipes.commons.exceptions.SpConfigurationException; import org.apache.streampipes.connect.iiot.adapters.opcua.configuration.SpOpcUaConfig; import org.eclipse.milo.opcua.sdk.client.api.config.OpcUaClientConfig; import org.eclipse.milo.opcua.sdk.client.api.config.OpcUaClientConfigBuilder; @@ -31,10 +32,11 @@ import java.net.URISyntaxException; import java.util.Collections; import java.util.List; +import java.util.concurrent.ExecutionException; public class MiloOpcUaConfigurationProvider { - public OpcUaClientConfig makeClientConfig(SpOpcUaConfig spOpcConfig) throws Exception { + public OpcUaClientConfig makeClientConfig(SpOpcUaConfig spOpcConfig) throws ExecutionException, InterruptedException, SpConfigurationException, URISyntaxException { String opcServerUrl = spOpcConfig.getOpcServerURL(); List<EndpointDescription> endpoints = DiscoveryClient.getEndpoints(opcServerUrl).get(); String host = opcServerUrl.split("://")[1].split(":")[0]; @@ -43,7 +45,7 @@ .stream() .filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri())) .findFirst() - .orElseThrow(() -> new Exception("No endpoint with security policy none")); + .orElseThrow(() -> new SpConfigurationException("No endpoint with security policy none")); tmpEndpoint = updateEndpointUrl(tmpEndpoint, host); endpoints = Collections.singletonList(tmpEndpoint); @@ -51,7 +53,7 @@ EndpointDescription endpoint = endpoints .stream() .filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri())) - .findFirst().orElseThrow(() -> new Exception("no desired endpoints returned")); + .findFirst().orElseThrow(() -> new SpConfigurationException("no desired endpoints returned")); return buildConfig(endpoint, spOpcConfig); }
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaAdapter.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaAdapter.java index 525ca38..34016cb 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaAdapter.java +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaAdapter.java
@@ -18,6 +18,7 @@ package org.apache.streampipes.connect.iiot.adapters.opcua; +import org.apache.streampipes.commons.exceptions.SpConfigurationException; import org.apache.streampipes.connect.adapter.Adapter; import org.apache.streampipes.connect.adapter.util.PollingSettings; import org.apache.streampipes.connect.api.exception.AdapterException; @@ -30,6 +31,7 @@ import org.apache.streampipes.model.AdapterType; import org.apache.streampipes.model.connect.adapter.SpecificAdapterStreamDescription; import org.apache.streampipes.model.connect.guess.GuessSchema; +import org.apache.streampipes.model.connect.rules.schema.DeleteRuleDescription; import org.apache.streampipes.model.staticproperty.StaticProperty; import org.apache.streampipes.sdk.StaticProperties; import org.apache.streampipes.sdk.builder.adapter.SpecificDataStreamAdapterBuilder; @@ -41,49 +43,69 @@ import org.eclipse.milo.opcua.sdk.client.api.subscriptions.UaMonitoredItem; import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.*; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.stream.Collectors; public class OpcUaAdapter extends PullAdapter implements SupportsRuntimeConfig { public static final String ID = "org.apache.streampipes.connect.iiot.adapters.opcua"; + private static final Logger LOG = LoggerFactory.getLogger(OpcUaAdapter.class); private int pullingIntervalMilliSeconds; private SpOpcUaClient spOpcUaClient; private List<OpcNode> allNodes; private List<NodeId> allNodeIds; private int numberProperties; - private Map<String, Object> event; + private final Map<String, Object> event; + + /** + * This variable is used to map the node ids during the subscription to the labels of the nodes + */ + private final Map<String, String> nodeIdToLabelMapping; public OpcUaAdapter() { super(); this.numberProperties = 0; this.event = new HashMap<>(); + this.nodeIdToLabelMapping = new HashMap<>(); } public OpcUaAdapter(SpecificAdapterStreamDescription adapterStreamDescription) { super(adapterStreamDescription); this.numberProperties = 0; this.event = new HashMap<>(); + this.nodeIdToLabelMapping = new HashMap<>(); } @Override protected void before() throws AdapterException { this.allNodeIds = new ArrayList<>(); + List<String> deleteKeys = this.adapterDescription + .getSchemaRules() + .stream() + .filter(rule -> rule instanceof DeleteRuleDescription) + .map(rule -> ((DeleteRuleDescription) rule).getRuntimeKey()) + .collect(Collectors.toList()); + try { this.spOpcUaClient.connect(); - OpcUaNodeBrowser browserClient = new OpcUaNodeBrowser(this.spOpcUaClient.getClient(), this.spOpcUaClient.getSpOpcConfig()); - this.allNodes = browserClient.findNodes(); + OpcUaNodeBrowser browserClient = + new OpcUaNodeBrowser(this.spOpcUaClient.getClient(), this.spOpcUaClient.getSpOpcConfig()); + this.allNodes = browserClient.findNodes(deleteKeys); - for (OpcNode node : this.allNodes) { - this.allNodeIds.add(node.nodeId); - } + for (OpcNode node : this.allNodes) { + this.allNodeIds.add(node.nodeId); + } if (spOpcUaClient.inPullMode()) { this.pullingIntervalMilliSeconds = spOpcUaClient.getPullIntervalMilliSeconds(); @@ -92,13 +114,15 @@ this.spOpcUaClient.createListSubscription(this.allNodeIds, this); } + this.allNodes.forEach(node -> this.nodeIdToLabelMapping.put(node.getNodeId().toString(), node.getLabel())); + } catch (Exception e) { - throw new AdapterException("The Connection to the OPC UA server could not be established."); + throw new AdapterException("The Connection to the OPC UA server could not be established.", e.getCause()); } } - @Override + @Override public void startAdapter() throws AdapterException { this.spOpcUaClient = new SpOpcUaClient(SpOpcUaConfigBuilder.from(this.adapterDescription)); @@ -115,49 +139,67 @@ // close connection this.spOpcUaClient.disconnect(); - if (this.spOpcUaClient.inPullMode()){ + if (this.spOpcUaClient.inPullMode()) { super.stopAdapter(); } } @Override protected void pullData() { - CompletableFuture<List<DataValue>> response = this.spOpcUaClient.getClient().readValues(0, TimestampsToReturn.Both, this.allNodeIds); + var response = + this.spOpcUaClient.getClient().readValues(0, TimestampsToReturn.Both, this.allNodeIds); + boolean badStatusCodeReceived = false; + boolean emptyValueReceived = false; try { - List<DataValue> returnValues = response.get(); - for (int i = 0; i<returnValues.size(); i++) { - - Object value = returnValues.get(i).getValue().getValue(); - this.event.put(this.allNodes.get(i).getLabel(), value); - + List<DataValue> returnValues = response.get(this.getPollingInterval().getValue(), this.getPollingInterval().getTimeUnit()); + if (returnValues.size() == 0) { + emptyValueReceived = true; + LOG.warn("Empty value object returned - event will not be sent"); + } else { + for (int i = 0; i < returnValues.size(); i++) { + var status = returnValues.get(i).getStatusCode(); + if (StatusCode.GOOD.equals(status)) { + Object value = returnValues.get(i).getValue().getValue(); + this.event.put(this.allNodes.get(i).getLabel(), value); + } else { + badStatusCodeReceived = true; + LOG.warn("Received status code {} for node label: {} - event will not be sent", + status, + this.allNodes.get(i).getLabel()); + } + } } - } catch (InterruptedException | ExecutionException ie) { - ie.printStackTrace(); - } - - adapterPipeline.process(this.event); - + if (!badStatusCodeReceived && !emptyValueReceived) { + adapterPipeline.process(this.event); + } + } catch (InterruptedException | ExecutionException | TimeoutException ie) { + LOG.error("Exception while reading data", ie); + } } public void onSubscriptionValue(UaMonitoredItem item, DataValue value) { - String key = OpcUaUtil.getRuntimeNameOfNode(item.getReadValueId().getNodeId()); + String key = this.nodeIdToLabelMapping.get(item.getReadValueId().getNodeId().toString()); OpcNode currNode = this.allNodes.stream() - .filter(node -> key.equals(node.getNodeId().getIdentifier().toString())) + .filter(node -> key.equals(node.getLabel())) .findFirst() .orElse(null); - event.put(currNode.getLabel(), value.getValue().getValue()); + if (currNode != null) { + event.put(currNode.getLabel(), value.getValue().getValue()); - // ensure that event is complete and all opc ua subscriptions transmitted at least one value - if (event.keySet().size() >= this.numberProperties) { - Map <String, Object> newEvent = new HashMap<>(); - // deep copy of event to prevent preprocessor error - for (String k : event.keySet()) { - newEvent.put(k, event.get(k)); + // ensure that event is complete and all opc ua subscriptions transmitted at least one value + if (event.keySet().size() >= this.numberProperties) { + Map<String, Object> newEvent = new HashMap<>(); + // deep copy of event to prevent preprocessor error + for (String k : event.keySet()) { + newEvent.put(k, event.get(k)); + } + adapterPipeline.process(newEvent); } - adapterPipeline.process(newEvent); + } else { + LOG.error("No event is produced, because subscription item {} could not be found within all nodes", item); } } @@ -176,27 +218,32 @@ .category(AdapterType.Generic, AdapterType.Manufacturing) .requiredAlternatives(Labels.withId(OpcUaLabels.ADAPTER_TYPE.name()), Alternatives.from(Labels.withId(OpcUaLabels.PULL_MODE.name()), - StaticProperties.integerFreeTextProperty(Labels.withId(OpcUaLabels.PULLING_INTERVAL.name()))), + StaticProperties.integerFreeTextProperty( + Labels.withId(OpcUaLabels.PULLING_INTERVAL.name()))), Alternatives.from(Labels.withId(OpcUaLabels.SUBSCRIPTION_MODE.name()))) .requiredAlternatives(Labels.withId(OpcUaLabels.ACCESS_MODE.name()), Alternatives.from(Labels.withId(OpcUaLabels.UNAUTHENTICATED.name())), Alternatives.from(Labels.withId(OpcUaLabels.USERNAME_GROUP.name()), StaticProperties.group( Labels.withId(OpcUaLabels.USERNAME_GROUP.name()), - StaticProperties.stringFreeTextProperty(Labels.withId(OpcUaLabels.USERNAME.name())), + StaticProperties.stringFreeTextProperty( + Labels.withId(OpcUaLabels.USERNAME.name())), StaticProperties.secretValue(Labels.withId(OpcUaLabels.PASSWORD.name())) )) ) .requiredAlternatives(Labels.withId(OpcUaLabels.OPC_HOST_OR_URL.name()), Alternatives.from( Labels.withId(OpcUaLabels.OPC_URL.name()), - StaticProperties.stringFreeTextProperty(Labels.withId(OpcUaLabels.OPC_SERVER_URL.name()))) + StaticProperties.stringFreeTextProperty( + Labels.withId(OpcUaLabels.OPC_SERVER_URL.name()), "opc.tcp://localhost:4840")) , Alternatives.from(Labels.withId(OpcUaLabels.OPC_HOST.name()), StaticProperties.group( Labels.withId("host-port"), - StaticProperties.stringFreeTextProperty(Labels.withId(OpcUaLabels.OPC_SERVER_HOST.name())), - StaticProperties.stringFreeTextProperty(Labels.withId(OpcUaLabels.OPC_SERVER_PORT.name())) + StaticProperties.stringFreeTextProperty( + Labels.withId(OpcUaLabels.OPC_SERVER_HOST.name())), + StaticProperties.stringFreeTextProperty( + Labels.withId(OpcUaLabels.OPC_SERVER_PORT.name())) )) ) .requiredTextParameter(Labels.withId(OpcUaLabels.NAMESPACE_INDEX.name())) @@ -218,7 +265,8 @@ } @Override - public GuessSchema getSchema(SpecificAdapterStreamDescription adapterDescription) throws AdapterException, ParseException { + public GuessSchema getSchema(SpecificAdapterStreamDescription adapterDescription) + throws AdapterException, ParseException { return OpcUaUtil.getSchema(adapterDescription); } @@ -228,7 +276,8 @@ } @Override - public StaticProperty resolveConfiguration(String staticPropertyInternalName, StaticPropertyExtractor extractor) { + public StaticProperty resolveConfiguration(String staticPropertyInternalName, + StaticPropertyExtractor extractor) throws SpConfigurationException { return OpcUaUtil.resolveConfiguration(staticPropertyInternalName, extractor); } }
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaNodeBrowser.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaNodeBrowser.java index 5a9f2fb..c1cbc20 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaNodeBrowser.java +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaNodeBrowser.java
@@ -23,13 +23,15 @@ import org.apache.streampipes.model.staticproperty.TreeInputNode; import org.eclipse.milo.opcua.sdk.client.AddressSpace; import org.eclipse.milo.opcua.sdk.client.OpcUaClient; -import org.eclipse.milo.opcua.sdk.client.model.nodes.variables.BaseDataVariableTypeNode; import org.eclipse.milo.opcua.sdk.client.nodes.UaNode; +import org.eclipse.milo.opcua.sdk.client.nodes.UaVariableNode; import org.eclipse.milo.opcua.stack.core.UaException; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; @@ -43,21 +45,30 @@ private final OpcUaClient client; private final SpOpcUaConfig spOpcConfig; + private static final Logger LOG = LoggerFactory.getLogger(OpcUaNodeBrowser.class); + public OpcUaNodeBrowser(OpcUaClient client, SpOpcUaConfig spOpcUaClientConfig) { this.client = client; this.spOpcConfig = spOpcUaClientConfig; } - public List<OpcNode> findNodes() { - return this.spOpcConfig.getSelectedNodeNames().stream().map(n -> { - try { - return toOpcNode(n); - } catch (UaException e) { - e.printStackTrace(); - return null; - } - }).collect(Collectors.toList()); + public List<OpcNode> findNodes() throws UaException { + var opcNodes = new ArrayList<OpcNode>(); + for(String selectedNodeName: this.spOpcConfig.getSelectedNodeNames()) { + opcNodes.add(toOpcNode(selectedNodeName)); + } + + return opcNodes; + } + + public List<OpcNode> findNodes(List<String> runtimeNameFilters) throws UaException { + return findNodes() + .stream() + .filter(node -> runtimeNameFilters + .stream() + .noneMatch(f -> f.equals(node.getLabel()))) + .collect(Collectors.toList()); } public List<TreeInputNode> buildNodeTreeFromOrigin() throws UaException, ExecutionException, InterruptedException { @@ -80,11 +91,15 @@ NodeId nodeId = NodeId.parse(nodeName); UaNode node = addressSpace.getNode(nodeId); - if (node instanceof BaseDataVariableTypeNode) { - UInteger value = (UInteger) ((BaseDataVariableTypeNode) node).getDataType().getIdentifier(); + LOG.info("Using node of type {}", node.getNodeClass().toString() ); + + if (node instanceof UaVariableNode) { + UInteger value = (UInteger) ((UaVariableNode) node).getDataType().getIdentifier(); return new OpcNode(node.getDisplayName().getText(), OpcUaTypes.getType(value), node.getNodeId()); } + LOG.warn("Node {} not of type UaVariableNode", node.getDisplayName()); + throw new UaException(StatusCode.BAD, "Node is not of type BaseDataVariableTypeNode"); } @@ -112,6 +127,6 @@ } private boolean isDataNode(UaNode node) { - return node.getNodeClass().equals(NodeClass.Variable) && node instanceof BaseDataVariableTypeNode; + return (node.getNodeClass().equals(NodeClass.Variable) || (node.getNodeClass().equals(NodeClass.VariableType))) && node instanceof UaVariableNode; } }
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/SpOpcUaClient.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/SpOpcUaClient.java index da00cbf..299c4f0 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/SpOpcUaClient.java +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/SpOpcUaClient.java
@@ -19,15 +19,19 @@ package org.apache.streampipes.connect.iiot.adapters.opcua; +import org.apache.streampipes.commons.exceptions.SpConfigurationException; import org.apache.streampipes.connect.iiot.adapters.opcua.configuration.SpOpcUaConfig; import org.eclipse.milo.opcua.sdk.client.OpcUaClient; import org.eclipse.milo.opcua.sdk.client.api.config.OpcUaClientConfig; import org.eclipse.milo.opcua.sdk.client.api.subscriptions.UaMonitoredItem; import org.eclipse.milo.opcua.sdk.client.api.subscriptions.UaSubscription; +import org.eclipse.milo.opcua.sdk.client.api.subscriptions.UaSubscriptionManager; import org.eclipse.milo.opcua.stack.core.AttributeId; +import org.eclipse.milo.opcua.stack.core.UaException; import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; import org.eclipse.milo.opcua.stack.core.types.enumerated.MonitoringMode; import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn; @@ -37,9 +41,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicLong; import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; @@ -71,9 +77,9 @@ /*** * Establishes appropriate connection to OPC UA endpoint depending on the {@link SpOpcUaClient} instance * - * @throws Exception An exception occurring during OPC connection + * @throws UaException An exception occurring during OPC connection */ - public void connect() throws Exception { + public void connect() throws UaException, ExecutionException, InterruptedException, SpConfigurationException, URISyntaxException { OpcUaClientConfig clientConfig = new MiloOpcUaConfigurationProvider().makeClientConfig(spOpcConfig); this.client = OpcUaClient.create(clientConfig); client.connect().get(); @@ -89,7 +95,25 @@ * @param opcUaAdapter current instance of {@link OpcUaAdapter} * @throws Exception */ - public void createListSubscription(List<NodeId> nodes, OpcUaAdapter opcUaAdapter) throws Exception { + public void createListSubscription(List<NodeId> nodes, + OpcUaAdapter opcUaAdapter) throws Exception { + client.getSubscriptionManager().addSubscriptionListener(new UaSubscriptionManager.SubscriptionListener() { + @Override + public void onSubscriptionTransferFailed(UaSubscription subscription, StatusCode statusCode) { + LOG.warn("Transfer for subscriptionId={} failed: {}", subscription.getSubscriptionId(), statusCode); + try { + initSubscription(nodes, opcUaAdapter); + } catch (Exception e) { + LOG.error("Re-creating the subscription failed", e); + } + } + }); + + initSubscription(nodes, opcUaAdapter); + } + + + public void initSubscription(List<NodeId> nodes, OpcUaAdapter opcUaAdapter) throws Exception { /* * create a subscription @ 1000ms */
diff --git a/ui/src/app/connect/components/format-item-json/format-item-json.component.scss b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/utils/ExceptionMessageExtractor.java similarity index 62% copy from ui/src/app/connect/components/format-item-json/format-item-json.component.scss copy to streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/utils/ExceptionMessageExtractor.java index 30123c0..7c1b453 100644 --- a/ui/src/app/connect/components/format-item-json/format-item-json.component.scss +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/utils/ExceptionMessageExtractor.java
@@ -16,32 +16,23 @@ * */ +package org.apache.streampipes.connect.iiot.adapters.opcua.utils; -.format-label { - line-height:50px; - margin: auto; - text-align: center; - font-weight: bold; - font-size: 1.3em; +import org.eclipse.milo.opcua.stack.core.UaException; + +public class ExceptionMessageExtractor { + + public static String getDescription(UaException e) { + String[] parts = e.getMessage().split(", "); + if (parts.length > 1) { + String[] kv = parts[1].split("="); + if (kv.length > 1) { + return kv[1]; + } else { + return parts[1]; + } + } else { + return e.getMessage(); + } + } } - -.format-box { - min-height: 50px; - box-shadow: 1px 1px 2px #555; - border: 1px solid gray; - cursor: pointer; - padding: 10px; - opacity: 0.7; - margin: 10px; - background: #ffffff; -} - -.format-box:hover { - opacity: 1; -} - -.selectedItem { - opacity: 1; - background-color: grey; -} -
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/utils/OpcUaUtil.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/utils/OpcUaUtil.java index 38d4d4c..739dc19 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/utils/OpcUaUtil.java +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/utils/OpcUaUtil.java
@@ -18,6 +18,7 @@ package org.apache.streampipes.connect.iiot.adapters.opcua.utils; +import org.apache.streampipes.commons.exceptions.SpConfigurationException; import org.apache.streampipes.connect.api.exception.AdapterException; import org.apache.streampipes.connect.api.exception.ParseException; import org.apache.streampipes.connect.iiot.adapters.opcua.OpcNode; @@ -25,7 +26,9 @@ import org.apache.streampipes.connect.iiot.adapters.opcua.SpOpcUaClient; import org.apache.streampipes.connect.iiot.adapters.opcua.configuration.SpOpcUaConfigBuilder; import org.apache.streampipes.model.connect.adapter.SpecificAdapterStreamDescription; +import org.apache.streampipes.model.connect.guess.FieldStatusInfo; import org.apache.streampipes.model.connect.guess.GuessSchema; +import org.apache.streampipes.model.connect.guess.GuessTypeInfo; import org.apache.streampipes.model.schema.EventProperty; import org.apache.streampipes.model.schema.EventSchema; import org.apache.streampipes.model.staticproperty.RuntimeResolvableTreeInputStaticProperty; @@ -33,165 +36,220 @@ import org.apache.streampipes.sdk.extractor.StaticPropertyExtractor; import org.eclipse.milo.opcua.sdk.client.OpcUaClient; import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn; import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; /*** * Collection of several utility functions in context of OPC UA */ public class OpcUaUtil { - /*** - * Ensures server address starts with {@code opc.tcp://} - * @param serverAddress server address as given by user - * @return correctly formated server address - */ - public static String formatServerAddress(String serverAddress) { + /*** + * Ensures server address starts with {@code opc.tcp://} + * @param serverAddress server address as given by user + * @return correctly formated server address + */ + public static String formatServerAddress(String serverAddress) { - if (!serverAddress.startsWith("opc.tcp://")) { - serverAddress = "opc.tcp://" + serverAddress; - } - - return serverAddress; + if (!serverAddress.startsWith("opc.tcp://")) { + serverAddress = "opc.tcp://" + serverAddress; } - /*** - * OPC UA specific implementation of {@link org.apache.streampipes.connect.adapter.Adapter} - * @param adapterStreamDescription - * @return guess schema - * @throws AdapterException - * @throws ParseException - */ - public static GuessSchema getSchema(SpecificAdapterStreamDescription adapterStreamDescription) throws AdapterException, ParseException { - GuessSchema guessSchema = new GuessSchema(); - EventSchema eventSchema = new EventSchema(); - List<EventProperty> allProperties = new ArrayList<>(); + return serverAddress; + } - SpOpcUaClient spOpcUaClient = new SpOpcUaClient(SpOpcUaConfigBuilder.from(adapterStreamDescription)); + /*** + * OPC UA specific implementation of {@link org.apache.streampipes.connect.adapter.Adapter} + * @param adapterStreamDescription + * @return guess schema + * @throws AdapterException + * @throws ParseException + */ + public static GuessSchema getSchema(SpecificAdapterStreamDescription adapterStreamDescription) + throws AdapterException, ParseException { + GuessSchema guessSchema = new GuessSchema(); + EventSchema eventSchema = new EventSchema(); + List<Map<String, GuessTypeInfo>> eventPreview = new ArrayList<>(); + Map<String, FieldStatusInfo> fieldStatusInfos = new HashMap<>(); + List<EventProperty> allProperties = new ArrayList<>(); - try { - spOpcUaClient.connect(); - OpcUaNodeBrowser nodeBrowser = new OpcUaNodeBrowser(spOpcUaClient.getClient(), spOpcUaClient.getSpOpcConfig()); - List<OpcNode> selectedNodes = nodeBrowser.findNodes(); + SpOpcUaClient spOpcUaClient = new SpOpcUaClient(SpOpcUaConfigBuilder.from(adapterStreamDescription)); - if (!selectedNodes.isEmpty()) { - for (OpcNode opcNode : selectedNodes) { - if (opcNode.hasUnitId()) { - allProperties.add(PrimitivePropertyBuilder - .create(opcNode.getType(), opcNode.getLabel()) - .label(opcNode.getLabel()) - .measurementUnit(new URI(opcNode.getQudtURI())) - .build()); - } else { - allProperties.add(PrimitivePropertyBuilder - .create(opcNode.getType(), opcNode.getLabel()) - .label(opcNode.getLabel()) - .build()); - } + try { + spOpcUaClient.connect(); + OpcUaNodeBrowser nodeBrowser = + new OpcUaNodeBrowser(spOpcUaClient.getClient(), spOpcUaClient.getSpOpcConfig()); + List<OpcNode> selectedNodes = nodeBrowser.findNodes(); - } - } - - spOpcUaClient.disconnect(); - - } catch (Exception e) { - throw new AdapterException("Could not guess schema for opc node! " + e.getMessage()); + if (!selectedNodes.isEmpty()) { + for (OpcNode opcNode : selectedNodes) { + if (opcNode.hasUnitId()) { + allProperties.add(PrimitivePropertyBuilder + .create(opcNode.getType(), opcNode.getLabel()) + .label(opcNode.getLabel()) + .measurementUnit(new URI(opcNode.getQudtURI())) + .build()); + } else { + allProperties.add(PrimitivePropertyBuilder + .create(opcNode.getType(), opcNode.getLabel()) + .label(opcNode.getLabel()) + .build()); + } } + } - eventSchema.setEventProperties(allProperties); - guessSchema.setEventSchema(eventSchema); + var nodeIds = selectedNodes.stream().map(OpcNode::getNodeId).collect(Collectors.toList()); + var response = spOpcUaClient.getClient().readValues(0, TimestampsToReturn.Both, nodeIds); - return guessSchema; + var returnValues = response.get(); + + makeEventPreview(selectedNodes, eventPreview, fieldStatusInfos, returnValues); + + + } catch (Exception e) { + throw new AdapterException("Could not guess schema for opc node: " + e.getMessage(), e); + } finally { + spOpcUaClient.disconnect(); } + eventSchema.setEventProperties(allProperties); + guessSchema.setEventSchema(eventSchema); + guessSchema.setEventPreview(eventPreview); + guessSchema.setFieldStatusInfo(fieldStatusInfos); - /*** - * OPC UA specific implementation of {@link org.apache.streampipes.container.api.ResolvesContainerProvidedOptions#resolveOptions(String, StaticPropertyExtractor)}. } - * @param internalName The internal name of the Static Property - * @param parameterExtractor - * @return {@code List<Option>} with available node names for the given OPC UA configuration - */ - public static RuntimeResolvableTreeInputStaticProperty resolveConfiguration (String internalName, - StaticPropertyExtractor parameterExtractor) { + return guessSchema; + } - RuntimeResolvableTreeInputStaticProperty config = parameterExtractor - .getStaticPropertyByName(internalName, RuntimeResolvableTreeInputStaticProperty.class); - // access mode and host/url have to be selected - try { - parameterExtractor.selectedAlternativeInternalId(OpcUaLabels.OPC_HOST_OR_URL.name()); - parameterExtractor.selectedAlternativeInternalId(OpcUaLabels.ACCESS_MODE.name()); - } catch (NullPointerException nullPointerException) { - return config; - } + private static void makeEventPreview(List<OpcNode> selectedNodes, + List<Map<String, GuessTypeInfo>> eventPreview, + Map<String, FieldStatusInfo> fieldStatusInfos, + List<DataValue> dataValues) { + var singlePreview = new HashMap<String, GuessTypeInfo>(); - SpOpcUaClient spOpcUaClient = new SpOpcUaClient(SpOpcUaConfigBuilder.from(parameterExtractor)); - try{ - spOpcUaClient.connect(); - OpcUaNodeBrowser nodeBrowser = new OpcUaNodeBrowser(spOpcUaClient.getClient(), spOpcUaClient.getSpOpcConfig()); - config.setNodes(nodeBrowser.buildNodeTreeFromOrigin()); - spOpcUaClient.disconnect(); - } catch (Exception e) { - e.printStackTrace(); - } - - return config; + for (int i = 0; i < dataValues.size(); i++) { + var dv = dataValues.get(i); + String label = selectedNodes.get(i).getLabel(); + if (StatusCode.GOOD.equals(dv.getStatusCode())) { + var value = dv.getValue().getValue(); + singlePreview.put(label, new GuessTypeInfo(value.getClass().getCanonicalName(), value)); + fieldStatusInfos.put(label, FieldStatusInfo.good()); + } else { + String additionalInfo = dv.getStatusCode() != null ? dv.getStatusCode().toString() : "Status code is null"; + fieldStatusInfos.put(label, FieldStatusInfo.bad(additionalInfo, false)); + } } - public static String getRuntimeNameOfNode(NodeId nodeId) { - String[] keys = nodeId.getIdentifier().toString().split("\\."); - String key; + eventPreview.add(singlePreview); + } - if (keys.length > 0) { - key = keys[keys.length - 1]; - } else { - key = nodeId.getIdentifier().toString(); - } - return key; + /*** + * OPC UA specific implementation of {@link + * org.apache.streampipes.container.api.ResolvesContainerProvidedOptions# + * resolveOptions(String, StaticPropertyExtractor)}. + * @param internalName The internal name of the Static Property + * @param parameterExtractor to extract parameters from the OPC UA config + * @return {@code List<Option>} with available node names for the given OPC UA configuration + */ + public static RuntimeResolvableTreeInputStaticProperty resolveConfiguration(String internalName, + StaticPropertyExtractor parameterExtractor) throws SpConfigurationException { + + RuntimeResolvableTreeInputStaticProperty config = parameterExtractor + .getStaticPropertyByName(internalName, RuntimeResolvableTreeInputStaticProperty.class); + // access mode and host/url have to be selected + try { + parameterExtractor.selectedAlternativeInternalId(OpcUaLabels.OPC_HOST_OR_URL.name()); + parameterExtractor.selectedAlternativeInternalId(OpcUaLabels.ACCESS_MODE.name()); + } catch (NullPointerException nullPointerException) { + return config; } - /** - * connects to each node individually and updates the data type in accordance to the data from the server. - * @param opcNodes List of opcNodes where the data type is not determined appropriately - */ - public static void retrieveDataTypesFromServer(OpcUaClient client, List<OpcNode> opcNodes) throws AdapterException { + SpOpcUaClient spOpcUaClient = new SpOpcUaClient(SpOpcUaConfigBuilder.from(parameterExtractor)); - for (OpcNode opcNode : opcNodes) { - try { - UInteger dataTypeId = (UInteger) client.getAddressSpace().getVariableNode(opcNode.getNodeId()).getDataType().getIdentifier(); - OpcUaTypes.getType(dataTypeId); - opcNode.setType(OpcUaTypes.getType(dataTypeId)); - } catch (UaException e) { - throw new AdapterException("Could not guess schema for opc node! " + e.getMessage()); - } - } + try { + spOpcUaClient.connect(); + OpcUaNodeBrowser nodeBrowser = + new OpcUaNodeBrowser(spOpcUaClient.getClient(), spOpcUaClient.getSpOpcConfig()); + config.setNodes(nodeBrowser.buildNodeTreeFromOrigin()); + + return config; + } catch (UaException e) { + throw new SpConfigurationException(ExceptionMessageExtractor.getDescription(e), e); + } catch (ExecutionException | InterruptedException | URISyntaxException e) { + throw new SpConfigurationException("Could not connect to the OPC UA server with the provided settings", e); + } finally { + if (spOpcUaClient.getClient() != null) { + spOpcUaClient.disconnect(); + } + } + } + + public static String getRuntimeNameOfNode(NodeId nodeId) { + String[] keys = nodeId.getIdentifier().toString().split("\\."); + String key; + + if (keys.length > 0) { + key = keys[keys.length - 1]; + } else { + key = nodeId.getIdentifier().toString(); } - /*** - * Enum for all possible labels in the context of OPC UA adapters - */ - public enum OpcUaLabels { - OPC_HOST_OR_URL, - OPC_URL, - OPC_HOST, - OPC_SERVER_URL, - OPC_SERVER_HOST, - OPC_SERVER_PORT, - NAMESPACE_INDEX, - NODE_ID, - ACCESS_MODE, - USERNAME_GROUP, - USERNAME, - PASSWORD, - UNAUTHENTICATED, - AVAILABLE_NODES, - PULLING_INTERVAL, - ADAPTER_TYPE, - PULL_MODE, - SUBSCRIPTION_MODE; + return key; + } + + /** + * connects to each node individually and updates the data type in accordance to the data from the server. + * + * @param opcNodes List of opcNodes where the data type is not determined appropriately + */ + public static void retrieveDataTypesFromServer(OpcUaClient client, List<OpcNode> opcNodes) throws AdapterException { + + for (OpcNode opcNode : opcNodes) { + try { + UInteger dataTypeId = + (UInteger) client.getAddressSpace().getVariableNode(opcNode.getNodeId()).getDataType() + .getIdentifier(); + OpcUaTypes.getType(dataTypeId); + opcNode.setType(OpcUaTypes.getType(dataTypeId)); + } catch (UaException e) { + throw new AdapterException("Could not guess schema for opc node! " + e.getMessage()); + } } + } + + /*** + * Enum for all possible labels in the context of OPC UA adapters + */ + public enum OpcUaLabels { + OPC_HOST_OR_URL, + OPC_URL, + OPC_HOST, + OPC_SERVER_URL, + OPC_SERVER_HOST, + OPC_SERVER_PORT, + NAMESPACE_INDEX, + NODE_ID, + ACCESS_MODE, + USERNAME_GROUP, + USERNAME, + PASSWORD, + UNAUTHENTICATED, + AVAILABLE_NODES, + PULLING_INTERVAL, + ADAPTER_TYPE, + PULL_MODE, + SUBSCRIPTION_MODE; + } }
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/plc4x/s7/Plc4xS7Adapter.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/plc4x/s7/Plc4xS7Adapter.java index 04ece8a..227054b 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/plc4x/s7/Plc4xS7Adapter.java +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/plc4x/s7/Plc4xS7Adapter.java
@@ -27,11 +27,12 @@ import org.apache.plc4x.java.utils.connectionpool.PooledPlcDriverManager; import org.apache.streampipes.connect.adapter.Adapter; import org.apache.streampipes.connect.adapter.util.PollingSettings; -import org.apache.streampipes.connect.iiot.adapters.PullAdapter; import org.apache.streampipes.connect.api.exception.AdapterException; +import org.apache.streampipes.connect.iiot.adapters.PullAdapter; import org.apache.streampipes.model.AdapterType; import org.apache.streampipes.model.connect.adapter.SpecificAdapterStreamDescription; import org.apache.streampipes.model.connect.guess.GuessSchema; +import org.apache.streampipes.model.connect.guess.GuessTypeInfo; import org.apache.streampipes.model.schema.EventProperty; import org.apache.streampipes.model.schema.EventSchema; import org.apache.streampipes.model.staticproperty.CollectionStaticProperty; @@ -54,10 +55,10 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; -public class Plc4xS7Adapter extends PullAdapter { +public class Plc4xS7Adapter extends PullAdapter implements PlcReadResponseHandler { /** * A unique id to identify the Plc4xS7Adapter @@ -133,31 +134,45 @@ public GuessSchema getSchema(SpecificAdapterStreamDescription adapterDescription) throws AdapterException { // Extract user input - getConfigurations(adapterDescription); + try { + getConfigurations(adapterDescription); - if (this.pollingInterval < 10) { - throw new AdapterException("Polling interval must be higher then 10. Current value: " + this.pollingInterval); + if (this.pollingInterval < 10) { + throw new AdapterException("Polling interval must be higher than 10. Current value: " + this.pollingInterval); + } + + GuessSchema guessSchema = new GuessSchema(); + + EventSchema eventSchema = new EventSchema(); + List<EventProperty> allProperties = new ArrayList<>(); + + for (Map<String, String> node : this.nodes) { + Datatypes datatype = getStreamPipesDataType(node.get(PLC_NODE_TYPE).toUpperCase().replaceAll(" ", "_")); + + allProperties.add( + PrimitivePropertyBuilder + .create(datatype, node.get(PLC_NODE_RUNTIME_NAME)) + .label(node.get(PLC_NODE_RUNTIME_NAME)) + .description("") + .build()); + } + + this.before(); + var event = readPlcDataSynchronized(); + var preview = event + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> + new GuessTypeInfo(e.getValue().getClass().getCanonicalName(), e.getValue()))); + + eventSchema.setEventProperties(allProperties); + guessSchema.setEventSchema(eventSchema); + guessSchema.setEventPreview(List.of(preview)); + + return guessSchema; + } catch (Exception e) { + throw new AdapterException(e.getMessage(), e); } - - GuessSchema guessSchema = new GuessSchema(); - - EventSchema eventSchema = new EventSchema(); - List<EventProperty> allProperties = new ArrayList<>(); - - for (Map<String, String> node : this.nodes) { - Datatypes datatype = getStreamPipesDataType(node.get(PLC_NODE_TYPE).toUpperCase().replaceAll(" ", "_")); - - allProperties.add( - PrimitivePropertyBuilder - .create(datatype, node.get(PLC_NODE_RUNTIME_NAME)) - .label(node.get(PLC_NODE_RUNTIME_NAME)) - .description("") - .build()); - } - - eventSchema.setEventProperties(allProperties); - guessSchema.setEventSchema(eventSchema); - return guessSchema; } /** @@ -171,7 +186,6 @@ this.driverManager = new PooledPlcDriverManager(); try (PlcConnection plcConnection = this.driverManager.getConnection("s7://" + this.ip)) { - if (!plcConnection.getMetadata().canRead()) { this.LOG.error("The S7 on IP: " + this.ip + " does not support reading data"); } @@ -188,47 +202,36 @@ */ @Override protected void pullData() { - // Create PLC read request - try (PlcConnection plcConnection = this.driverManager.getConnection("s7://" + this.ip)) { - PlcReadRequest.Builder builder = plcConnection.readRequestBuilder(); - for (Map<String, String> node : this.nodes) { - builder.addItem(node.get(PLC_NODE_NAME), node.get(PLC_NODE_NAME) + ":" + node.get(PLC_NODE_TYPE).toUpperCase().replaceAll(" ", "_")); - } - PlcReadRequest readRequest = builder.build(); - - // Execute the request - CompletableFuture<? extends PlcReadResponse> asyncResponse = readRequest.execute(); - - asyncResponse.whenComplete((response, throwable) -> { - // Create an event containing the value of the PLC - if (throwable != null) { - throwable.printStackTrace(); - this.LOG.error(throwable.getMessage()); - } else { - Map<String, Object> event = new HashMap<>(); - for (Map<String, String> node : this.nodes) { - if (response.getResponseCode(node.get(PLC_NODE_NAME)) == PlcResponseCode.OK) { - event.put(node.get(PLC_NODE_RUNTIME_NAME), response.getObject(node.get(PLC_NODE_NAME))); - } else { - this.LOG.error("Error[" + node.get(PLC_NODE_NAME) + "]: " + - response.getResponseCode(node.get(PLC_NODE_NAME)).name()); - } - } - - // publish the final event - adapterPipeline.process(event); - } - }); - - } catch (InterruptedException | ExecutionException e) { - this.LOG.error(e.getMessage()); - e.printStackTrace(); + try(PlcConnection plcConnection = this.driverManager.getConnection("s7://" + this.ip)) { + readPlcData(plcConnection, this); } catch (Exception e) { - this.LOG.error("Could not establish connection to S7 with ip " + this.ip, e); - e.printStackTrace(); + LOG.error("Error while reading from PLC with IP {} ", this.ip, e); } + } + private PlcReadRequest makeReadRequest(PlcConnection plcConnection) throws PlcConnectionException { + PlcReadRequest.Builder builder = plcConnection.readRequestBuilder(); + for (Map<String, String> node : this.nodes) { + builder.addItem(node.get(PLC_NODE_NAME), node.get(PLC_NODE_NAME) + ":" + node.get(PLC_NODE_TYPE).toUpperCase().replaceAll(" ", "_")); + } + return builder.build(); + } + + private void readPlcData(PlcConnection plcConnection, PlcReadResponseHandler handler) throws PlcConnectionException { + var readRequest = makeReadRequest(plcConnection); + // Execute the request + CompletableFuture<? extends PlcReadResponse> asyncResponse = readRequest.execute(); + asyncResponse.whenComplete(handler::onReadResult); + } + + private Map<String, Object> readPlcDataSynchronized() throws Exception { + try (PlcConnection plcConnection = this.driverManager.getConnection("s7://" + this.ip)) { + var readRequest = makeReadRequest(plcConnection); + // Execute the request + var readResponse = readRequest.execute().get(5000, TimeUnit.MILLISECONDS); + return makeEvent(readResponse); + } } /** @@ -315,4 +318,28 @@ } } + @Override + public void onReadResult(PlcReadResponse response, Throwable throwable) { + if (throwable != null) { + throwable.printStackTrace(); + this.LOG.error(throwable.getMessage()); + } else { + var event = makeEvent(response); + // publish the final event + adapterPipeline.process(event); + } + } + + private Map<String, Object> makeEvent(PlcReadResponse response) { + Map<String, Object> event = new HashMap<>(); + for (Map<String, String> node : this.nodes) { + if (response.getResponseCode(node.get(PLC_NODE_NAME)) == PlcResponseCode.OK) { + event.put(node.get(PLC_NODE_RUNTIME_NAME), response.getObject(node.get(PLC_NODE_NAME))); + } else { + this.LOG.error("Error[" + node.get(PLC_NODE_NAME) + "]: " + + response.getResponseCode(node.get(PLC_NODE_NAME)).name()); + } + } + return event; + } }
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/plc4x/s7/PlcReadResponseHandler.java similarity index 75% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/plc4x/s7/PlcReadResponseHandler.java index 58ba04b..b9b8f1b 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/plc4x/s7/PlcReadResponseHandler.java
@@ -16,3 +16,12 @@ * */ +package org.apache.streampipes.connect.iiot.adapters.plc4x.s7; + +import org.apache.plc4x.java.api.messages.PlcReadResponse; + +public interface PlcReadResponseHandler { + + void onReadResult(PlcReadResponse response, + Throwable throwable); +}
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataSimulatorUtils.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataSimulatorUtils.java index 0d7b2af..f157bab 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataSimulatorUtils.java +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataSimulatorUtils.java
@@ -30,123 +30,137 @@ public class MachineDataSimulatorUtils { - // Vocabulary - public static final String NS = "https://streampipes.org/vocabulary/examples/watertank/v1/"; - public static final String HAS_SENSOR_ID = NS + "hasSensorId"; + // Vocabulary + public static final String NS = "https://streampipes.org/vocabulary/examples/watertank/v1/"; + public static final String HAS_SENSOR_ID = NS + "hasSensorId"; - private static final String TIMESTAMP = "timestamp"; - private static final String SENSOR_ID = "sensorId"; - private static final String MASS_FLOW = "mass_flow"; - private static final String TEMPERATURE = "temperature"; + private static final String TIMESTAMP = "timestamp"; + private static final String SENSOR_ID = "sensorId"; + private static final String MASS_FLOW = "mass_flow"; + private static final String TEMPERATURE = "temperature"; - public static GuessSchema getSchema(String selectedSimulatorOption) throws AdapterException { - switch(selectedSimulatorOption) { - case "flowrate": - return getFlowrateSchema(); - case "pressure": - return getPressureSchema(); - case "waterlevel": - return getWaterlevelSchema(); - default: - throw new AdapterException("resource not found"); - } + public static GuessSchema getSchema(String selectedSimulatorOption) throws AdapterException { + switch (selectedSimulatorOption) { + case "flowrate": + return getFlowrateSchema(); + case "pressure": + return getPressureSchema(); + case "waterlevel": + return getWaterlevelSchema(); + default: + throw new AdapterException("resource not found"); } + } - private static GuessSchema getWaterlevelSchema() { - return GuessSchemaBuilder.create() - .property(timestampProperty(TIMESTAMP)) - .property(PrimitivePropertyBuilder - .create(Datatypes.String, "sensorId") - .label("Sensor ID") - .description("The ID of the sensor") - .domainProperty(HAS_SENSOR_ID) - .scope(PropertyScope.DIMENSION_PROPERTY) - .build()) - .property(PrimitivePropertyBuilder - .create(Datatypes.Float, "level") - .label("Water Level") - .description("Denotes the current water level in the container") - .domainProperty(SO.Number) - .scope(PropertyScope.MEASUREMENT_PROPERTY) - .build()) - .property(PrimitivePropertyBuilder - .create(Datatypes.Boolean, "overflow") - .label("Overflow") - .description("Indicates whether the tank overflows") - .domainProperty(SO.Number) - .scope(PropertyScope.MEASUREMENT_PROPERTY) - .build()) - .build(); - } + private static GuessSchema getWaterlevelSchema() { + return GuessSchemaBuilder.create() + .property(timestampProperty(TIMESTAMP)) + .sample(TIMESTAMP, System.currentTimeMillis()) + .property(PrimitivePropertyBuilder + .create(Datatypes.String, "sensorId") + .label("Sensor ID") + .description("The ID of the sensor") + .domainProperty(HAS_SENSOR_ID) + .scope(PropertyScope.DIMENSION_PROPERTY) + .build()) + .sample("sensorId", "sensor01") + .property(PrimitivePropertyBuilder + .create(Datatypes.Float, "level") + .label("Water Level") + .description("Denotes the current water level in the container") + .domainProperty(SO.Number) + .scope(PropertyScope.MEASUREMENT_PROPERTY) + .build()) + .sample("level", 5.25f) + .property(PrimitivePropertyBuilder + .create(Datatypes.Boolean, "overflow") + .label("Overflow") + .description("Indicates whether the tank overflows") + .domainProperty(SO.Number) + .scope(PropertyScope.MEASUREMENT_PROPERTY) + .build()) + .sample("overflow", true) + .build(); + } - private static GuessSchema getPressureSchema() { - return GuessSchemaBuilder.create() - .property(timestampProperty(TIMESTAMP)) - .property(PrimitivePropertyBuilder - .create(Datatypes.String, "sensorId") - .label("Sensor ID") - .description("The ID of the sensor") - .domainProperty(HAS_SENSOR_ID) - .scope(PropertyScope.DIMENSION_PROPERTY) - .build()) - .property(PrimitivePropertyBuilder - .create(Datatypes.Float, "pressure") - .label("Pressure") - .description("Denotes the current pressure in the pressure tank") - .domainProperty(SO.Number) - .valueSpecification(0.0f, 100.0f, 0.5f) - .scope(PropertyScope.MEASUREMENT_PROPERTY) - .build()) - .build(); - } + private static GuessSchema getPressureSchema() { + return GuessSchemaBuilder.create() + .property(timestampProperty(TIMESTAMP)) + .sample(TIMESTAMP, System.currentTimeMillis()) + .property(PrimitivePropertyBuilder + .create(Datatypes.String, "sensorId") + .label("Sensor ID") + .description("The ID of the sensor") + .domainProperty(HAS_SENSOR_ID) + .scope(PropertyScope.DIMENSION_PROPERTY) + .build()) + .sample("sensorId", "sensor01") + .property(PrimitivePropertyBuilder + .create(Datatypes.Float, "pressure") + .label("Pressure") + .description("Denotes the current pressure in the pressure tank") + .domainProperty(SO.Number) + .valueSpecification(0.0f, 100.0f, 0.5f) + .scope(PropertyScope.MEASUREMENT_PROPERTY) + .build()) + .sample("pressure", 85.22f) + .build(); + } - public static GuessSchema getFlowrateSchema() { - return GuessSchemaBuilder.create() - .property(timestampProperty(TIMESTAMP)) - .property(PrimitivePropertyBuilder - .create(Datatypes.String, SENSOR_ID) - .label("Sensor ID") - .description("The ID of the sensor") - .domainProperty(HAS_SENSOR_ID) - .scope(PropertyScope.DIMENSION_PROPERTY) - .build()) - .property(PrimitivePropertyBuilder - .create(Datatypes.Float, MASS_FLOW) - .label("Mass Flow") - .description("Denotes the current mass flow in the sensor") - .domainProperty(SO.Number) - .scope(PropertyScope.MEASUREMENT_PROPERTY) - .build()) - .property(PrimitivePropertyBuilder - .create(Datatypes.Float, "volume_flow") - .label("Volume Flow") - .description("Denotes the current volume flow") - .domainProperty(SO.Number) - .scope(PropertyScope.MEASUREMENT_PROPERTY) - .build()) - .property(PrimitivePropertyBuilder - .create(Datatypes.Float, TEMPERATURE) - .label("Temperature") - .description("Denotes the current temperature in degrees celsius") - .domainProperty(SO.Number) - .scope(PropertyScope.MEASUREMENT_PROPERTY) - .measurementUnit(URI.create("http://codes.wmo.int/common/unit/degC")) - .valueSpecification(0.0f, 100.0f, 0.1f) - .build()) - .property(PrimitivePropertyBuilder - .create(Datatypes.Float, "density") - .label("Density") - .description("Denotes the current density of the fluid") - .domainProperty(SO.Number) - .scope(PropertyScope.MEASUREMENT_PROPERTY) - .build()) - .property(PrimitivePropertyBuilder - .create(Datatypes.Boolean, "sensor_fault_flags") - .label("Sensor Fault Flags") - .description("Any fault flags of the sensors") - .domainProperty(SO.Boolean) - .scope(PropertyScope.MEASUREMENT_PROPERTY) - .build()) - .build(); - } + public static GuessSchema getFlowrateSchema() { + return GuessSchemaBuilder.create() + .property(timestampProperty(TIMESTAMP)) + .sample(TIMESTAMP, System.currentTimeMillis()) + .property(PrimitivePropertyBuilder + .create(Datatypes.String, SENSOR_ID) + .label("Sensor ID") + .description("The ID of the sensor") + .domainProperty(HAS_SENSOR_ID) + .scope(PropertyScope.DIMENSION_PROPERTY) + .build()) + .sample("sensorId", "sensor01") + .property(PrimitivePropertyBuilder + .create(Datatypes.Float, MASS_FLOW) + .label("Mass Flow") + .description("Denotes the current mass flow in the sensor") + .domainProperty(SO.Number) + .scope(PropertyScope.MEASUREMENT_PROPERTY) + .build()) + .sample(MASS_FLOW, 5.76f) + .property(PrimitivePropertyBuilder + .create(Datatypes.Float, "volume_flow") + .label("Volume Flow") + .description("Denotes the current volume flow") + .domainProperty(SO.Number) + .scope(PropertyScope.MEASUREMENT_PROPERTY) + .build()) + .sample("volume_flow", 3.34f) + .property(PrimitivePropertyBuilder + .create(Datatypes.Float, TEMPERATURE) + .label("Temperature") + .description("Denotes the current temperature in degrees celsius") + .domainProperty(SO.Number) + .scope(PropertyScope.MEASUREMENT_PROPERTY) + .measurementUnit(URI.create("http://codes.wmo.int/common/unit/degC")) + .valueSpecification(0.0f, 100.0f, 0.1f) + .build()) + .sample(TEMPERATURE, 33.221f) + .property(PrimitivePropertyBuilder + .create(Datatypes.Float, "density") + .label("Density") + .description("Denotes the current density of the fluid") + .domainProperty(SO.Number) + .scope(PropertyScope.MEASUREMENT_PROPERTY) + .build()) + .sample("density", 5.0f) + .property(PrimitivePropertyBuilder + .create(Datatypes.Boolean, "sensor_fault_flags") + .label("Sensor Fault Flags") + .description("Any fault flags of the sensors") + .domainProperty(SO.Boolean) + .scope(PropertyScope.MEASUREMENT_PROPERTY) + .build()) + .sample("sensor_fault_flags", true) + .build(); + } }
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataStreamAdapter.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataStreamAdapter.java index e661a7c..aaf7a90 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataStreamAdapter.java +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataStreamAdapter.java
@@ -59,7 +59,7 @@ .withAssets(Assets.DOCUMENTATION, Assets.ICON) .withLocales(Locales.EN) .category(AdapterType.Debugging) - .requiredIntegerParameter(Labels.withId(WAIT_TIME_MS)) + .requiredIntegerParameter(Labels.withId(WAIT_TIME_MS), 1000) .requiredSingleValueSelection(Labels.withId(SELECTED_SIMULATOR_OPTION), Options.from( "flowrate", "pressure", "waterlevel")) .build();
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/set/FileProtocol.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/set/FileProtocol.java index 25976de..8dcb342 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/set/FileProtocol.java +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/set/FileProtocol.java
@@ -121,11 +121,12 @@ InputStream targetStream = FileProtocolUtils.getFileInputStream(this.selectedFilename); List<byte[]> dataByte = parser.parseNEvents(targetStream, 20); - EventSchema eventSchema = parser.getEventSchema(dataByte); - - GuessSchema result = SchemaGuesser.guessSchma(eventSchema); - - return result; + if (parser.supportsPreview()) { + return SchemaGuesser.guessSchema(parser.getSchemaAndSample(dataByte)); + } else { + EventSchema eventSchema = parser.getEventSchema(dataByte); + return SchemaGuesser.guessSchema(eventSchema); + } } catch (FileNotFoundException e) { throw new ParseException("Could not read local file"); }
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/set/HttpProtocol.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/set/HttpProtocol.java index 1feb4cc..eca0f25 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/set/HttpProtocol.java +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/set/HttpProtocol.java
@@ -116,7 +116,7 @@ EventSchema eventSchema= parser.getEventSchema(dataByte); - GuessSchema result = SchemaGuesser.guessSchma(eventSchema); + GuessSchema result = SchemaGuesser.guessSchema(eventSchema); return result; }
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/BrokerProtocol.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/BrokerProtocol.java index 835fffc..e34d7f9 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/BrokerProtocol.java +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/BrokerProtocol.java
@@ -23,7 +23,6 @@ import org.apache.streampipes.connect.api.IParser; import org.apache.streampipes.connect.api.exception.ParseException; import org.apache.streampipes.model.connect.guess.GuessSchema; -import org.apache.streampipes.model.schema.EventSchema; import java.util.ArrayList; import java.util.List; @@ -48,9 +47,12 @@ public GuessSchema getGuessSchema() throws ParseException { List<byte[]> eventByte = getNByteElements(1); - EventSchema eventSchema = parser.getEventSchema(eventByte); - return SchemaGuesser.guessSchma(eventSchema); + if (parser.supportsPreview()) { + return SchemaGuesser.guessSchema(parser.getSchemaAndSample(eventByte)); + } else { + return SchemaGuesser.guessSchema(parser.getEventSchema(eventByte)); + } } @Override
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/FileStreamProtocol.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/FileStreamProtocol.java index 4b9368b..f88f5c5 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/FileStreamProtocol.java +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/FileStreamProtocol.java
@@ -211,11 +211,12 @@ List<byte[]> dataByte = parser.parseNEvents(dataInputStream, 2); - EventSchema eventSchema = parser.getEventSchema(dataByte); - - GuessSchema result = SchemaGuesser.guessSchma(eventSchema); - - return result; + if (parser.supportsPreview()) { + return SchemaGuesser.guessSchema(parser.getSchemaAndSample(dataByte)); + } else { + EventSchema eventSchema = parser.getEventSchema(dataByte); + return SchemaGuesser.guessSchema(eventSchema); + } } @Override
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/HttpStreamProtocol.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/HttpStreamProtocol.java index 39a5dad..be68829 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/HttpStreamProtocol.java +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/HttpStreamProtocol.java
@@ -112,7 +112,7 @@ dataByte.addAll(dataByte); } EventSchema eventSchema= parser.getEventSchema(dataByte); - GuessSchema result = SchemaGuesser.guessSchma(eventSchema); + GuessSchema result = SchemaGuesser.guessSchema(eventSchema); return result; }
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/KafkaProtocol.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/KafkaProtocol.java index 502aa7c..cdc8cb4 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/KafkaProtocol.java +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/KafkaProtocol.java
@@ -20,9 +20,11 @@ import org.apache.commons.io.IOUtils; import org.apache.kafka.clients.consumer.*; +import org.apache.kafka.common.KafkaException; import org.apache.kafka.common.TopicPartition; import org.apache.kafka.common.serialization.ByteArrayDeserializer; import org.apache.streampipes.commons.constants.GlobalStreamPipesConstants; +import org.apache.streampipes.commons.exceptions.SpConfigurationException; import org.apache.streampipes.commons.exceptions.SpRuntimeException; import org.apache.streampipes.connect.SendToPipeline; import org.apache.streampipes.connect.adapter.model.generic.Protocol; @@ -30,7 +32,7 @@ import org.apache.streampipes.connect.api.IFormat; import org.apache.streampipes.connect.api.IParser; import org.apache.streampipes.connect.api.exception.ParseException; -import org.apache.streampipes.container.api.ResolvesContainerProvidedOptions; +import org.apache.streampipes.container.api.SupportsRuntimeConfig; import org.apache.streampipes.messaging.InternalEventProcessor; import org.apache.streampipes.messaging.kafka.SpKafkaConsumer; import org.apache.streampipes.model.AdapterType; @@ -38,6 +40,8 @@ import org.apache.streampipes.model.grounding.KafkaTransportProtocol; import org.apache.streampipes.model.grounding.SimpleTopicDefinition; import org.apache.streampipes.model.staticproperty.Option; +import org.apache.streampipes.model.staticproperty.RuntimeResolvableOneOfStaticProperty; +import org.apache.streampipes.model.staticproperty.StaticProperty; import org.apache.streampipes.pe.shared.config.kafka.KafkaConfig; import org.apache.streampipes.pe.shared.config.kafka.KafkaConnectUtils; import org.apache.streampipes.sdk.builder.adapter.ProtocolDescriptionBuilder; @@ -45,7 +49,6 @@ import org.apache.streampipes.sdk.helpers.AdapterSourceType; import org.apache.streampipes.sdk.helpers.Labels; import org.apache.streampipes.sdk.helpers.Locales; -import org.apache.streampipes.sdk.helpers.Options; import org.apache.streampipes.sdk.utils.Assets; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,7 +58,7 @@ import java.util.*; import java.util.stream.Collectors; -public class KafkaProtocol extends BrokerProtocol implements ResolvesContainerProvidedOptions { +public class KafkaProtocol extends BrokerProtocol implements SupportsRuntimeConfig { Logger logger = LoggerFactory.getLogger(KafkaProtocol.class); KafkaConfig config; @@ -154,7 +157,7 @@ return resultEventsByte; } - private Consumer<byte[], byte[]> createConsumer(KafkaConfig kafkaConfig) { + private Consumer<byte[], byte[]> createConsumer(KafkaConfig kafkaConfig) throws KafkaException { final Properties props = new Properties(); kafkaConfig.getSecurityConfig().appendConfig(props); @@ -165,6 +168,8 @@ props.put(ConsumerConfig.GROUP_ID_CONFIG, "KafkaExampleConsumer" + System.currentTimeMillis()); + props.put(ConsumerConfig.DEFAULT_API_TIMEOUT_MS_CONFIG, 6000); + props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class.getName()); props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, @@ -214,22 +219,30 @@ } @Override - public List<Option> resolveOptions(String requestId, StaticPropertyExtractor extractor) { + public StaticProperty resolveConfiguration(String staticPropertyInternalName, StaticPropertyExtractor extractor) throws SpConfigurationException { + RuntimeResolvableOneOfStaticProperty config = extractor + .getStaticPropertyByName(KafkaConnectUtils.TOPIC_KEY, RuntimeResolvableOneOfStaticProperty.class); KafkaConfig kafkaConfig = KafkaConnectUtils.getConfig(extractor, false); boolean hideInternalTopics = extractor.slideToggleValue(KafkaConnectUtils.getHideInternalTopicsKey()); - Consumer<byte[], byte[]> consumer = createConsumer(kafkaConfig); + try { + Consumer<byte[], byte[]> consumer = createConsumer(kafkaConfig); + Set<String> topics = consumer.listTopics().keySet(); + consumer.close(); - Set<String> topics = consumer.listTopics().keySet(); - consumer.close(); + if (hideInternalTopics) { + topics = topics + .stream() + .filter(t -> !t.startsWith(GlobalStreamPipesConstants.INTERNAL_TOPIC_PREFIX)) + .collect(Collectors.toSet()); + } - if (hideInternalTopics) { - topics = topics - .stream() - .filter(t -> !t.startsWith(GlobalStreamPipesConstants.INTERNAL_TOPIC_PREFIX)) - .collect(Collectors.toSet()); + config.setOptions(topics.stream().map(Option::new).collect(Collectors.toList())); + + return config; + } catch (KafkaException e) { + throw new SpConfigurationException(e.getMessage(), e); } - return topics.stream().map(Option::new).collect(Collectors.toList()); }
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/pulsar/PulsarProtocol.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/pulsar/PulsarProtocol.java index 197456a..4f431c5 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/pulsar/PulsarProtocol.java +++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/pulsar/PulsarProtocol.java
@@ -17,8 +17,10 @@ */ package org.apache.streampipes.connect.iiot.protocol.stream.pulsar; +import java.io.IOException; import org.apache.pulsar.client.api.PulsarClient; import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.client.api.Reader; import org.apache.streampipes.connect.SendToPipeline; import org.apache.streampipes.connect.adapter.model.generic.Protocol; import org.apache.streampipes.connect.adapter.sdk.ParameterExtractor; @@ -68,18 +70,17 @@ @Override protected List<byte[]> getNByteElements(int n) throws ParseException { List<byte[]> elements = new ArrayList<>(); - InternalEventProcessor<byte[]> eventProcessor = elements::add; - PulsarConsumer consumer = new PulsarConsumer(this.brokerUrl, this.topic, eventProcessor, n); - - Thread thread = new Thread(consumer); - thread.start(); - - while (consumer.getMessageCount() < n) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); + try (PulsarClient pulsarClient = PulsarUtils.makePulsarClient(brokerUrl); + Reader<byte[]> reader = pulsarClient.newReader() + .topic(topic) + .create()) { + for (int i = 0; i < n; i++) { + if (reader.hasMessageAvailable()) { + elements.add(reader.readNext().getValue()); + } } + } catch (IOException e) { + throw new ParseException("Failed to fetch messages.", e); } return elements; }
diff --git a/streampipes-extensions/streampipes-connect-adapters/pom.xml b/streampipes-extensions/streampipes-connect-adapters/pom.xml index 713a33c..40c2f3f 100644 --- a/streampipes-extensions/streampipes-connect-adapters/pom.xml +++ b/streampipes-extensions/streampipes-connect-adapters/pom.xml
@@ -23,7 +23,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-extensions</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <artifactId>streampipes-connect-adapters</artifactId> @@ -37,7 +37,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-connect-container-worker</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>org.graalvm.nativeimage</groupId> @@ -48,12 +48,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-pipeline-elements-shared</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-container-extensions</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies --> @@ -215,5 +215,4 @@ </plugins> <finalName>streampipes-connect-adapters</finalName> </build> - </project>
diff --git a/streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/ConnectAdapterInit.java b/streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/ConnectAdapterInit.java index 78423b8..624b9e2 100644 --- a/streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/ConnectAdapterInit.java +++ b/streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/ConnectAdapterInit.java
@@ -26,6 +26,8 @@ import org.apache.streampipes.connect.adapters.image.set.ImageSetAdapter; import org.apache.streampipes.connect.adapters.image.stream.ImageStreamAdapter; import org.apache.streampipes.connect.adapters.iss.IssAdapter; +import org.apache.streampipes.connect.adapters.netio.NetioMQTTAdapter; +import org.apache.streampipes.connect.adapters.netio.NetioRestAdapter; import org.apache.streampipes.connect.adapters.simulator.random.RandomDataSetAdapter; import org.apache.streampipes.connect.adapters.simulator.random.RandomDataStreamAdapter; import org.apache.streampipes.connect.adapters.slack.SlackAdapter; @@ -45,23 +47,25 @@ @Override public SpServiceDefinition provideServiceDefinition() { return SpServiceDefinitionBuilder.create("connect-adapter", - "StreamPipes Connect Worker Main", - "",8001) - .registerAdapter(new GdeltAdapter()) - .registerAdapter(new CoindeskBitcoinAdapter()) - .registerAdapter(new IexCloudNewsAdapter()) - .registerAdapter(new IexCloudStockAdapter()) - .registerAdapter(new RandomDataSetAdapter()) - .registerAdapter(new RandomDataStreamAdapter()) - .registerAdapter(new SlackAdapter()) - .registerAdapter(new WikipediaEditedArticlesAdapter()) - .registerAdapter(new WikipediaNewArticlesAdapter()) - .registerAdapter(new ImageStreamAdapter()) - .registerAdapter(new ImageSetAdapter()) - .registerAdapter(new IssAdapter()) - .registerAdapter(new FlicMQTTAdapter()) - .registerAdapter(new TISensorTag()) - .build(); + "StreamPipes Connect Worker Main", + "", 8001) + .registerAdapter(new GdeltAdapter()) + .registerAdapter(new CoindeskBitcoinAdapter()) + .registerAdapter(new NetioRestAdapter()) + .registerAdapter(new NetioMQTTAdapter()) + .registerAdapter(new IexCloudNewsAdapter()) + .registerAdapter(new IexCloudStockAdapter()) + .registerAdapter(new RandomDataSetAdapter()) + .registerAdapter(new RandomDataStreamAdapter()) + .registerAdapter(new SlackAdapter()) + .registerAdapter(new WikipediaEditedArticlesAdapter()) + .registerAdapter(new WikipediaNewArticlesAdapter()) + .registerAdapter(new ImageStreamAdapter()) + .registerAdapter(new ImageSetAdapter()) + .registerAdapter(new IssAdapter()) + .registerAdapter(new FlicMQTTAdapter()) + .registerAdapter(new TISensorTag()) + .build(); } }
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/NetioMQTTAdapter.java b/streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/adapters/netio/NetioMQTTAdapter.java similarity index 95% rename from streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/NetioMQTTAdapter.java rename to streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/adapters/netio/NetioMQTTAdapter.java index d692cd7..f2686c8 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/NetioMQTTAdapter.java +++ b/streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/adapters/netio/NetioMQTTAdapter.java
@@ -16,7 +16,7 @@ * */ -package org.apache.streampipes.connect.iiot.adapters.netio; +package org.apache.streampipes.connect.adapters.netio; import com.google.gson.Gson; @@ -24,8 +24,8 @@ import org.apache.streampipes.connect.api.exception.AdapterException; import org.apache.streampipes.connect.adapter.model.pipeline.AdapterPipeline; import org.apache.streampipes.connect.adapter.model.specific.SpecificDataStreamAdapter; -import org.apache.streampipes.connect.iiot.adapters.netio.model.NetioAllPowerOutputs; -import org.apache.streampipes.connect.iiot.adapters.netio.model.NetioPowerOutput; +import org.apache.streampipes.connect.adapters.netio.model.NetioAllPowerOutputs; +import org.apache.streampipes.connect.adapters.netio.model.NetioPowerOutput; import org.apache.streampipes.pe.shared.config.mqtt.*; import org.apache.streampipes.messaging.InternalEventProcessor; import org.apache.streampipes.model.AdapterType;
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/NetioRestAdapter.java b/streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/adapters/netio/NetioRestAdapter.java similarity index 95% rename from streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/NetioRestAdapter.java rename to streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/adapters/netio/NetioRestAdapter.java index 7d7a5d3..4b4c9f4 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/NetioRestAdapter.java +++ b/streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/adapters/netio/NetioRestAdapter.java
@@ -16,7 +16,7 @@ * */ -package org.apache.streampipes.connect.iiot.adapters.netio; +package org.apache.streampipes.connect.adapters.netio; import com.google.gson.Gson; import org.apache.http.HttpHost; @@ -24,12 +24,12 @@ import org.apache.http.client.fluent.Executor; import org.apache.http.client.fluent.Request; import org.apache.streampipes.connect.adapter.Adapter; -import org.apache.streampipes.connect.api.exception.AdapterException; import org.apache.streampipes.connect.adapter.sdk.ParameterExtractor; import org.apache.streampipes.connect.adapter.util.PollingSettings; -import org.apache.streampipes.connect.iiot.adapters.PullAdapter; -import org.apache.streampipes.connect.iiot.adapters.netio.model.NetioAllPowerOutputs; -import org.apache.streampipes.connect.iiot.adapters.netio.model.NetioPowerOutput; +import org.apache.streampipes.connect.adapters.PullAdapter; +import org.apache.streampipes.connect.adapters.netio.model.NetioAllPowerOutputs; +import org.apache.streampipes.connect.adapters.netio.model.NetioPowerOutput; +import org.apache.streampipes.connect.api.exception.AdapterException; import org.apache.streampipes.model.AdapterType; import org.apache.streampipes.model.connect.adapter.SpecificAdapterStreamDescription; import org.apache.streampipes.model.connect.guess.GuessSchema;
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/NetioUtils.java b/streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/adapters/netio/NetioUtils.java similarity index 96% rename from streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/NetioUtils.java rename to streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/adapters/netio/NetioUtils.java index b7da893..2a47cc1 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/NetioUtils.java +++ b/streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/adapters/netio/NetioUtils.java
@@ -16,10 +16,10 @@ * */ -package org.apache.streampipes.connect.iiot.adapters.netio; +package org.apache.streampipes.connect.adapters.netio; -import org.apache.streampipes.connect.iiot.adapters.netio.model.NetioGlobalMeasure; -import org.apache.streampipes.connect.iiot.adapters.netio.model.NetioPowerOutput; +import org.apache.streampipes.connect.adapters.netio.model.NetioGlobalMeasure; +import org.apache.streampipes.connect.adapters.netio.model.NetioPowerOutput; import org.apache.streampipes.model.connect.guess.GuessSchema; import org.apache.streampipes.model.schema.EventProperty; import org.apache.streampipes.model.schema.EventSchema;
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/model/NetioAllPowerOutputs.java b/streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/adapters/netio/model/NetioAllPowerOutputs.java similarity index 95% rename from streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/model/NetioAllPowerOutputs.java rename to streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/adapters/netio/model/NetioAllPowerOutputs.java index c816ca4..1b4e5ac 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/model/NetioAllPowerOutputs.java +++ b/streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/adapters/netio/model/NetioAllPowerOutputs.java
@@ -16,7 +16,7 @@ * */ -package org.apache.streampipes.connect.iiot.adapters.netio.model; +package org.apache.streampipes.connect.adapters.netio.model; import com.google.gson.annotations.SerializedName;
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/model/NetioGlobalMeasure.java b/streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/adapters/netio/model/NetioGlobalMeasure.java similarity index 96% rename from streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/model/NetioGlobalMeasure.java rename to streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/adapters/netio/model/NetioGlobalMeasure.java index 0a6c9a6..34c0d22 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/model/NetioGlobalMeasure.java +++ b/streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/adapters/netio/model/NetioGlobalMeasure.java
@@ -16,7 +16,7 @@ * */ -package org.apache.streampipes.connect.iiot.adapters.netio.model; +package org.apache.streampipes.connect.adapters.netio.model; import com.google.gson.annotations.SerializedName;
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/model/NetioPowerOutput.java b/streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/adapters/netio/model/NetioPowerOutput.java similarity index 97% rename from streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/model/NetioPowerOutput.java rename to streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/adapters/netio/model/NetioPowerOutput.java index f2b75eb..2b2c6ae 100644 --- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/netio/model/NetioPowerOutput.java +++ b/streampipes-extensions/streampipes-connect-adapters/src/main/java/org/apache/streampipes/connect/adapters/netio/model/NetioPowerOutput.java
@@ -16,7 +16,7 @@ * */ -package org.apache.streampipes.connect.iiot.adapters.netio.model; +package org.apache.streampipes.connect.adapters.netio.model; import com.google.gson.annotations.SerializedName;
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.mqtt/documentation.md b/streampipes-extensions/streampipes-connect-adapters/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.mqtt/documentation.md similarity index 100% rename from streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.mqtt/documentation.md rename to streampipes-extensions/streampipes-connect-adapters/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.mqtt/documentation.md
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.mqtt/icon.png b/streampipes-extensions/streampipes-connect-adapters/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.mqtt/icon.png similarity index 100% rename from streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.mqtt/icon.png rename to streampipes-extensions/streampipes-connect-adapters/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.mqtt/icon.png Binary files differ
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.mqtt/strings.en b/streampipes-extensions/streampipes-connect-adapters/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.mqtt/strings.en similarity index 100% rename from streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.mqtt/strings.en rename to streampipes-extensions/streampipes-connect-adapters/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.mqtt/strings.en
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.rest/documentation.md b/streampipes-extensions/streampipes-connect-adapters/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.rest/documentation.md similarity index 100% rename from streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.rest/documentation.md rename to streampipes-extensions/streampipes-connect-adapters/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.rest/documentation.md
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.rest/icon.png b/streampipes-extensions/streampipes-connect-adapters/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.rest/icon.png similarity index 100% rename from streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.rest/icon.png rename to streampipes-extensions/streampipes-connect-adapters/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.rest/icon.png Binary files differ
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.rest/strings.en b/streampipes-extensions/streampipes-connect-adapters/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.rest/strings.en similarity index 100% rename from streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.rest/strings.en rename to streampipes-extensions/streampipes-connect-adapters/src/main/resources/org.apache.streampipes.connect.iiot.adapters.netio.rest/strings.en
diff --git a/streampipes-extensions/streampipes-processors-image-processing-jvm/Dockerfile b/streampipes-extensions/streampipes-extensions-all-iiot/Dockerfile similarity index 73% rename from streampipes-extensions/streampipes-processors-image-processing-jvm/Dockerfile rename to streampipes-extensions/streampipes-extensions-all-iiot/Dockerfile index e64e6d1..99ba527 100644 --- a/streampipes-extensions/streampipes-processors-image-processing-jvm/Dockerfile +++ b/streampipes-extensions/streampipes-extensions-all-iiot/Dockerfile
@@ -13,16 +13,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -ARG BASE_IMAGE=adoptopenjdk/openjdk8-openj9:alpine -FROM $BASE_IMAGE +FROM eclipse-temurin:11-jre-focal ENV CONSUL_LOCATION consul EXPOSE 8090 -# needed pkgs processors-image-processing-jvm -RUN apk --update add --no-cache \ - fontconfig \ - ttf-dejavu -COPY target/streampipes-processors-image-processing-jvm.jar /streampipes-processing-element-container.jar -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"] +# needed pkgs processors-image-processing-jvm +RUN apt-get update && apt-get install ttf-dejavu-core && apt-get install fontconfig + +COPY target/streampipes-extensions-all-iiot.jar /streampipes-extensions-all-iiot.jar + +ENTRYPOINT ["java", "-jar", "/streampipes-extensions-all-iiot.jar"]
diff --git a/streampipes-extensions/streampipes-extensions-all-iiot/pom.xml b/streampipes-extensions/streampipes-extensions-all-iiot/pom.xml new file mode 100644 index 0000000..74511fa --- /dev/null +++ b/streampipes-extensions/streampipes-extensions-all-iiot/pom.xml
@@ -0,0 +1,137 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ 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. + ~ + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>streampipes-extensions</artifactId> + <groupId>org.apache.streampipes</groupId> + <version>0.71.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>streampipes-extensions-all-iiot</artifactId> + + <dependencies> + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-container-extensions</artifactId> + <version>0.71.0-SNAPSHOT</version> + <exclusions> + <exclusion> + <groupId>org.graalvm.nativeimage</groupId> + <artifactId>svm</artifactId> + </exclusion> + </exclusions> + </dependency> + + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-processors-filters-jvm</artifactId> + <version>0.71.0-SNAPSHOT</version> + <exclusions> + <exclusion> + <groupId>org.graalvm.nativeimage</groupId> + <artifactId>svm</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-processors-filters-siddhi</artifactId> + <version>0.71.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-processors-transformation-jvm</artifactId> + <version>0.71.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-sinks-brokers-jvm</artifactId> + <version>0.71.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-sinks-databases-jvm</artifactId> + <version>0.71.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-sinks-internal-jvm</artifactId> + <version>0.71.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-sinks-notifications-jvm</artifactId> + <version>0.71.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-processors-enricher-jvm</artifactId> + <version>0.71.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-processors-change-detection-jvm</artifactId> + <version>0.71.0-SNAPSHOT</version> + </dependency> + + <!-- 3rd party dependencies to avoid convergence errors --> + <dependency> + <groupId>io.dropwizard.metrics</groupId> + <artifactId>metrics-core</artifactId> + </dependency> + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty-handler</artifactId> + </dependency> + <dependency> + <groupId>org.atteo.classindex</groupId> + <artifactId>classindex</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-connect-adapters-iiot</artifactId> + <version>0.71.0-SNAPSHOT</version> + <classifier>embed</classifier> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>repackage</goal> + </goals> + <configuration> + <mainClass>org.apache.streampipes.extensions.all.iiot.AllExtensionsIIoTInit</mainClass> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + <finalName>streampipes-extensions-all-iiot</finalName> + </build> +</project>
diff --git a/streampipes-extensions/streampipes-extensions-all-iiot/src/main/java/org/apache/streampipes/extensions/all/iiot/AllExtensionsIIoTInit.java b/streampipes-extensions/streampipes-extensions-all-iiot/src/main/java/org/apache/streampipes/extensions/all/iiot/AllExtensionsIIoTInit.java new file mode 100644 index 0000000..d58da6e --- /dev/null +++ b/streampipes-extensions/streampipes-extensions-all-iiot/src/main/java/org/apache/streampipes/extensions/all/iiot/AllExtensionsIIoTInit.java
@@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.extensions.all.iiot; + +import org.apache.streampipes.connect.iiot.ConnectAdapterIiotInit; +import org.apache.streampipes.container.extensions.ExtensionsModelSubmitter; +import org.apache.streampipes.container.model.SpServiceDefinition; +import org.apache.streampipes.container.model.SpServiceDefinitionBuilder; +import org.apache.streampipes.dataformat.cbor.CborDataFormatFactory; +import org.apache.streampipes.dataformat.fst.FstDataFormatFactory; +import org.apache.streampipes.dataformat.json.JsonDataFormatFactory; +import org.apache.streampipes.dataformat.smile.SmileDataFormatFactory; +import org.apache.streampipes.messaging.jms.SpJmsProtocolFactory; +import org.apache.streampipes.messaging.kafka.SpKafkaProtocolFactory; +import org.apache.streampipes.messaging.mqtt.SpMqttProtocolFactory; +import org.apache.streampipes.processors.changedetection.jvm.ChangeDetectionJvmInit; +import org.apache.streampipes.processors.enricher.jvm.EnricherJvmInit; +import org.apache.streampipes.processors.filters.jvm.FiltersJvmInit; +import org.apache.streampipes.processors.siddhi.FiltersSiddhiInit; +import org.apache.streampipes.processors.transformation.jvm.TransformationJvmInit; +import org.apache.streampipes.sinks.brokers.jvm.BrokersJvmInit; +import org.apache.streampipes.sinks.databases.jvm.DatabasesJvmInit; +import org.apache.streampipes.sinks.internal.jvm.SinksInternalJvmInit; +import org.apache.streampipes.sinks.notifications.jvm.SinksNotificationsJvmInit; + +public class AllExtensionsIIoTInit extends ExtensionsModelSubmitter { + + public static void main (String[] args) { + new AllExtensionsIIoTInit().init(); + } + + @Override + public SpServiceDefinition provideServiceDefinition() { + return SpServiceDefinitionBuilder.create("org.apache.streampipes.extensions.all.iiot", + "StreamPipes Extensions (IIoT only)", + "", 8090) + .merge(new ConnectAdapterIiotInit().provideServiceDefinition()) + .merge(new SinksInternalJvmInit().provideServiceDefinition()) + .merge(new FiltersJvmInit().provideServiceDefinition()) + .merge(new ChangeDetectionJvmInit().provideServiceDefinition()) + .merge(new EnricherJvmInit().provideServiceDefinition()) + .merge(new FiltersSiddhiInit().provideServiceDefinition()) + .merge(new TransformationJvmInit().provideServiceDefinition()) + .merge(new BrokersJvmInit().provideServiceDefinition()) + .merge(new DatabasesJvmInit().provideServiceDefinition()) + .merge(new SinksNotificationsJvmInit().provideServiceDefinition()) + .registerMessagingFormats( + new JsonDataFormatFactory(), + new CborDataFormatFactory(), + new SmileDataFormatFactory(), + new FstDataFormatFactory()) + .registerMessagingProtocols( + new SpKafkaProtocolFactory(), + new SpJmsProtocolFactory(), + new SpMqttProtocolFactory()) + .build(); + } +}
diff --git a/streampipes-extensions/streampipes-extensions-all-jvm/pom.xml b/streampipes-extensions/streampipes-extensions-all-jvm/pom.xml index 68151b8..a904a84 100644 --- a/streampipes-extensions/streampipes-extensions-all-jvm/pom.xml +++ b/streampipes-extensions/streampipes-extensions-all-jvm/pom.xml
@@ -20,7 +20,7 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -34,7 +34,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-container-extensions</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>org.graalvm.nativeimage</groupId> @@ -46,7 +46,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-pipeline-elements-all-jvm</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <classifier>embed</classifier> </dependency> @@ -54,13 +54,13 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-connect-adapters</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <classifier>embed</classifier> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-connect-adapters-iiot</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <classifier>embed</classifier> </dependency> @@ -90,5 +90,4 @@ </plugins> <finalName>streampipes-extensions-all-jvm</finalName> </build> - </project>
diff --git a/streampipes-extensions/streampipes-pipeline-elements-all-flink/pom.xml b/streampipes-extensions/streampipes-pipeline-elements-all-flink/pom.xml index b722ff1..e2a091f 100644 --- a/streampipes-extensions/streampipes-pipeline-elements-all-flink/pom.xml +++ b/streampipes-extensions/streampipes-pipeline-elements-all-flink/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -35,43 +35,43 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-processors-aggregation-flink</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <classifier>embed</classifier> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-processors-enricher-flink</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-processors-geo-flink</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-processors-pattern-detection-flink</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-processors-statistics-flink</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-processors-text-mining-flink</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-processors-transformation-flink</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sinks-databases-flink</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- 3rd party dependencies to avoid convergence errors -->
diff --git a/streampipes-extensions/streampipes-pipeline-elements-all-jvm/pom.xml b/streampipes-extensions/streampipes-pipeline-elements-all-jvm/pom.xml index 9feec84..133905e 100644 --- a/streampipes-extensions/streampipes-pipeline-elements-all-jvm/pom.xml +++ b/streampipes-extensions/streampipes-pipeline-elements-all-jvm/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -35,8 +35,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-processors-filters-jvm</artifactId> - <version>0.70.0-SNAPSHOT</version> - <classifier>embed</classifier> + <version>0.71.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>org.graalvm.nativeimage</groupId> @@ -47,68 +46,57 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-processors-image-processing-jvm</artifactId> - <version>0.70.0-SNAPSHOT</version> - <classifier>embed</classifier> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-processors-filters-siddhi</artifactId> - <version>0.70.0-SNAPSHOT</version> - <classifier>embed</classifier> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-processors-text-mining-jvm</artifactId> - <version>0.70.0-SNAPSHOT</version> - <classifier>embed</classifier> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-processors-transformation-jvm</artifactId> - <version>0.70.0-SNAPSHOT</version> - <classifier>embed</classifier> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sinks-brokers-jvm</artifactId> - <version>0.70.0-SNAPSHOT</version> - <classifier>embed</classifier> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sinks-databases-jvm</artifactId> - <version>0.70.0-SNAPSHOT</version> - <classifier>embed</classifier> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sinks-internal-jvm</artifactId> - <version>0.70.0-SNAPSHOT</version> - <classifier>embed</classifier> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sinks-notifications-jvm</artifactId> - <version>0.70.0-SNAPSHOT</version> - <classifier>embed</classifier> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-processors-enricher-jvm</artifactId> - <version>0.70.0-SNAPSHOT</version> - <classifier>embed</classifier> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-processors-geo-jvm</artifactId> - <version>0.70.0-SNAPSHOT</version> - <classifier>embed</classifier> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-processors-change-detection-jvm</artifactId> - <version>0.70.0-SNAPSHOT</version> - <classifier>embed</classifier> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- 3rd party dependencies to avoid convergence errors -->
diff --git a/streampipes-extensions/streampipes-pipeline-elements-data-simulator/pom.xml b/streampipes-extensions/streampipes-pipeline-elements-data-simulator/pom.xml index cb40a4a..7bb7d9a 100644 --- a/streampipes-extensions/streampipes-pipeline-elements-data-simulator/pom.xml +++ b/streampipes-extensions/streampipes-pipeline-elements-data-simulator/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -75,5 +75,4 @@ </exclusions> </dependency> </dependencies> - </project>
diff --git a/streampipes-extensions/streampipes-pipeline-elements-shared/pom.xml b/streampipes-extensions/streampipes-pipeline-elements-shared/pom.xml index a5cead8..643d091 100644 --- a/streampipes-extensions/streampipes-pipeline-elements-shared/pom.xml +++ b/streampipes-extensions/streampipes-pipeline-elements-shared/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -39,12 +39,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <scope>compile</scope> </dependency> <dependency> @@ -54,12 +54,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging-kafka</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> </dependencies> </project>
diff --git a/streampipes-extensions/streampipes-processors-aggregation-flink/Dockerfile b/streampipes-extensions/streampipes-processors-aggregation-flink/Dockerfile deleted file mode 100644 index 695eae0..0000000 --- a/streampipes-extensions/streampipes-processors-aggregation-flink/Dockerfile +++ /dev/null
@@ -1,25 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=adoptopenjdk/openjdk8-openj9:alpine -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY target/streampipes-processors-aggregation-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-aggregation-flink/aarch64.Dockerfile b/streampipes-extensions/streampipes-processors-aggregation-flink/aarch64.Dockerfile deleted file mode 100644 index 2e3fc3c..0000000 --- a/streampipes-extensions/streampipes-processors-aggregation-flink/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-processors-aggregation-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-aggregation-flink/arm.Dockerfile b/streampipes-extensions/streampipes-processors-aggregation-flink/arm.Dockerfile deleted file mode 100644 index 7fe7fb9..0000000 --- a/streampipes-extensions/streampipes-processors-aggregation-flink/arm.Dockerfile +++ /dev/null
@@ -1,27 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim - -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-processors-aggregation-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-aggregation-flink/development/env b/streampipes-extensions/streampipes-processors-aggregation-flink/development/env deleted file mode 100644 index 5b3c9da..0000000 --- a/streampipes-extensions/streampipes-processors-aggregation-flink/development/env +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Those parameters are used by IntelliJ to set the default consul parameters for development -SP_PORT=6005 -SP_HOST=host.docker.internal -SP_DEBUG=true -SP_FLINK_DEBUG=true
diff --git a/streampipes-extensions/streampipes-processors-aggregation-flink/pom.xml b/streampipes-extensions/streampipes-processors-aggregation-flink/pom.xml index f1ff41f..d0fe1ac 100644 --- a/streampipes-extensions/streampipes-processors-aggregation-flink/pom.xml +++ b/streampipes-extensions/streampipes-processors-aggregation-flink/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -36,12 +36,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-flink</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies --> @@ -112,7 +112,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-test-utils</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <scope>test</scope> </dependency> <dependency>
diff --git a/streampipes-extensions/streampipes-processors-change-detection-jvm/development/env b/streampipes-extensions/streampipes-processors-change-detection-jvm/development/env deleted file mode 100644 index 2e01490..0000000 --- a/streampipes-extensions/streampipes-processors-change-detection-jvm/development/env +++ /dev/null
@@ -1,19 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Those parameters are used by IntelliJ to set the default consul parameters for development -SP_PORT=6018 -SP_HOST=localhost -SP_DEBUG=true
diff --git a/streampipes-extensions/streampipes-processors-change-detection-jvm/pom.xml b/streampipes-extensions/streampipes-processors-change-detection-jvm/pom.xml index 88b4c64..725fcef 100644 --- a/streampipes-extensions/streampipes-processors-change-detection-jvm/pom.xml +++ b/streampipes-extensions/streampipes-processors-change-detection-jvm/pom.xml
@@ -21,60 +21,23 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>streampipes-processors-change-detection-jvm</artifactId> - <properties> - <maven.deploy.skip>true</maven.deploy.skip> - </properties> - <dependencies> <!-- StreamPipes dependencies --> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-standalone</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>jar</goal> - </goals> - <phase>package</phase> - <configuration> - <classifier>embed</classifier> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-maven-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>repackage</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - <finalName>streampipes-processors-change-detection-jvm</finalName> - </build> - </project>
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/Dockerfile b/streampipes-extensions/streampipes-processors-enricher-flink/Dockerfile deleted file mode 100644 index b0c8a48..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-flink/Dockerfile +++ /dev/null
@@ -1,25 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=adoptopenjdk/openjdk8-openj9:alpine -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY target/streampipes-processors-enricher-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/aarch64.Dockerfile b/streampipes-extensions/streampipes-processors-enricher-flink/aarch64.Dockerfile deleted file mode 100644 index 938661d..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-flink/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-processors-enricher-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/arm.Dockerfile b/streampipes-extensions/streampipes-processors-enricher-flink/arm.Dockerfile deleted file mode 100644 index 4d26bd7..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-flink/arm.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-processors-enricher-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/development/env b/streampipes-extensions/streampipes-processors-enricher-flink/development/env deleted file mode 100644 index e33bec4..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-flink/development/env +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Those parameters are used by IntelliJ to set the default consul parameters for development -SP_PORT=6010 -SP_HOST=host.docker.internal -SP_DEBUG=true -SP_FLINK_DEBUG=true \ No newline at end of file
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/pom.xml b/streampipes-extensions/streampipes-processors-enricher-flink/pom.xml index dfc7b03..7ffcf7e 100644 --- a/streampipes-extensions/streampipes-processors-enricher-flink/pom.xml +++ b/streampipes-extensions/streampipes-processors-enricher-flink/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -37,12 +37,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-flink</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/EnricherFlinkInit.java b/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/EnricherFlinkInit.java index 2d36358a..28d7803 100644 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/EnricherFlinkInit.java +++ b/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/EnricherFlinkInit.java
@@ -29,10 +29,7 @@ import org.apache.streampipes.messaging.kafka.SpKafkaProtocolFactory; import org.apache.streampipes.messaging.mqtt.SpMqttProtocolFactory; import org.apache.streampipes.processors.enricher.flink.config.ConfigKeys; -import org.apache.streampipes.processors.enricher.flink.processor.math.mathop.MathOpController; -import org.apache.streampipes.processors.enricher.flink.processor.math.staticmathop.StaticMathOpController; import org.apache.streampipes.processors.enricher.flink.processor.timestamp.TimestampController; -import org.apache.streampipes.processors.enricher.flink.processor.trigonometry.TrigonometryController; import org.apache.streampipes.processors.enricher.flink.processor.urldereferencing.UrlDereferencingController; public class EnricherFlinkInit extends StandaloneModelSubmitter { @@ -48,10 +45,7 @@ "", 8090) .registerPipelineElements(new TimestampController(), - new MathOpController(), - new StaticMathOpController(), - new UrlDereferencingController(), - new TrigonometryController()) + new UrlDereferencingController()) .registerMessagingFormats( new JsonDataFormatFactory(), new CborDataFormatFactory(),
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/mathop/MathOp.java b/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/mathop/MathOp.java deleted file mode 100644 index 13ce569..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/mathop/MathOp.java +++ /dev/null
@@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.processors.enricher.flink.processor.math.mathop; - -import org.apache.flink.api.common.functions.FlatMapFunction; -import org.apache.flink.util.Collector; -import org.apache.streampipes.model.runtime.Event; -import org.apache.streampipes.processors.enricher.flink.processor.math.operation.Operation; - -public class MathOp implements FlatMapFunction<Event, Event> { - - private Operation operation; - private String leftOperand; - private String rightOperand; - private String resulField; - - public MathOp(Operation operation, String leftOperand, String rightOperand, String resulField) { - this.operation = operation; - this.leftOperand = leftOperand; - this.rightOperand = rightOperand; - this.resulField = resulField; - } - - @Override - public void flatMap(Event in, Collector<Event> out) throws Exception { - Double leftValue = in.getFieldBySelector(leftOperand).getAsPrimitive().getAsDouble(); - Double rightValue = in.getFieldBySelector(rightOperand).getAsPrimitive().getAsDouble(); - - Double result = operation.operate(leftValue, rightValue); - in.addField(resulField, result); - - out.collect(in); - } -}
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/mathop/MathOpController.java b/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/mathop/MathOpController.java deleted file mode 100644 index f5c4f2e..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/mathop/MathOpController.java +++ /dev/null
@@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.processors.enricher.flink.processor.math.mathop; - -import org.apache.streampipes.client.StreamPipesClient; -import org.apache.streampipes.container.config.ConfigExtractor; -import org.apache.streampipes.model.DataProcessorType; -import org.apache.streampipes.model.graph.DataProcessorDescription; -import org.apache.streampipes.model.graph.DataProcessorInvocation; -import org.apache.streampipes.model.schema.PropertyScope; -import org.apache.streampipes.processors.enricher.flink.processor.math.operation.*; -import org.apache.streampipes.sdk.builder.ProcessingElementBuilder; -import org.apache.streampipes.sdk.builder.StreamRequirementsBuilder; -import org.apache.streampipes.sdk.extractor.ProcessingElementParameterExtractor; -import org.apache.streampipes.sdk.helpers.*; -import org.apache.streampipes.sdk.utils.Assets; -import org.apache.streampipes.vocabulary.SO; -import org.apache.streampipes.wrapper.flink.FlinkDataProcessorDeclarer; -import org.apache.streampipes.wrapper.flink.FlinkDataProcessorRuntime; - -public class MathOpController extends FlinkDataProcessorDeclarer<MathOpParameters> { - - private final String RESULT_FIELD = "calculationResult"; - private final String LEFT_OPERAND = "leftOperand"; - private final String RIGHT_OPERAND = "rightOperand"; - private final String OPERATION = "operation"; - - @Override - public DataProcessorDescription declareModel() { - return ProcessingElementBuilder.create("org.apache.streampipes.processors.enricher.flink.processor.math.mathop") - .withAssets(Assets.DOCUMENTATION, Assets.ICON) - .withLocales(Locales.EN) - .category(DataProcessorType.ALGORITHM) - .requiredStream(StreamRequirementsBuilder - .create() - .requiredPropertyWithUnaryMapping(EpRequirements.numberReq(), - Labels.withId(LEFT_OPERAND), - PropertyScope.NONE) - .requiredPropertyWithUnaryMapping(EpRequirements.numberReq(), - Labels.withId(RIGHT_OPERAND), - PropertyScope.NONE) - .build()) - .outputStrategy( - OutputStrategies.append( - EpProperties.numberEp(Labels.empty(), RESULT_FIELD, SO.Number))) - .requiredSingleValueSelection(Labels.withId(OPERATION), Options.from("+", "-", "/", - "*", "%")) - .build(); - } - - @Override - public FlinkDataProcessorRuntime<MathOpParameters> getRuntime(DataProcessorInvocation graph, - ProcessingElementParameterExtractor extractor, - ConfigExtractor configExtractor, - StreamPipesClient streamPipesClient) { - String leftOperand = extractor.mappingPropertyValue(LEFT_OPERAND); - String rightOperand = extractor.mappingPropertyValue(RIGHT_OPERAND); - String operation = extractor.selectedSingleValue(OPERATION, String.class); - - Operation arithmeticOperation = null; - switch (operation) { - case "+": - arithmeticOperation = new OperationAddition(); - break; - case "-": - arithmeticOperation = new OperationSubtracting(); - break; - case "*": - arithmeticOperation = new OperationMultiply(); - break; - case "/": - arithmeticOperation = new OperationDivide(); - break; - case "%": - arithmeticOperation = new OperationModulo(); - } - - MathOpParameters parameters = new MathOpParameters(graph, arithmeticOperation, leftOperand, rightOperand, RESULT_FIELD); - - return new MathOpProgram(parameters, configExtractor, streamPipesClient); - } -}
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/mathop/MathOpParameters.java b/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/mathop/MathOpParameters.java deleted file mode 100644 index 228a0ed..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/mathop/MathOpParameters.java +++ /dev/null
@@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.processors.enricher.flink.processor.math.mathop; - -import org.apache.streampipes.model.graph.DataProcessorInvocation; -import org.apache.streampipes.processors.enricher.flink.processor.math.operation.Operation; -import org.apache.streampipes.wrapper.params.binding.EventProcessorBindingParams; - -public class MathOpParameters extends EventProcessorBindingParams { - - private Operation operation; - private String leftOperand; - private String rightOperand; - private String resultField; - - public MathOpParameters(DataProcessorInvocation graph, Operation operation, String leftOperand, String rightOperand, String resultField) { - super(graph); - this.operation = operation; - this.leftOperand = leftOperand; - this.rightOperand = rightOperand; - this.resultField = resultField; - } - - public Operation getOperation() { - return operation; - } - - public String getLeftOperand() { - return leftOperand; - } - - public String getRightOperand() { - return rightOperand; - } - - public String getResultField() { - return resultField; - } -}
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/mathop/MathOpProgram.java b/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/mathop/MathOpProgram.java deleted file mode 100644 index bb61a3e..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/mathop/MathOpProgram.java +++ /dev/null
@@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.processors.enricher.flink.processor.math.mathop; - -import org.apache.flink.streaming.api.datastream.DataStream; -import org.apache.streampipes.client.StreamPipesClient; -import org.apache.streampipes.container.config.ConfigExtractor; -import org.apache.streampipes.model.runtime.Event; -import org.apache.streampipes.processors.enricher.flink.AbstractEnricherProgram; - -public class MathOpProgram extends AbstractEnricherProgram<MathOpParameters> { - - public MathOpProgram(MathOpParameters params, - ConfigExtractor configExtractor, - StreamPipesClient streamPipesClient) { - super(params, configExtractor, streamPipesClient); - } - - @Override - protected DataStream<Event> getApplicationLogic(DataStream<Event>... dataStreams) { - return dataStreams[0] - .flatMap(new MathOp(params.getOperation(), params.getLeftOperand(), - params.getRightOperand(), params.getResultField())); - } -}
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/staticmathop/StaticMathOp.java b/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/staticmathop/StaticMathOp.java deleted file mode 100644 index 60e68df..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/staticmathop/StaticMathOp.java +++ /dev/null
@@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.processors.enricher.flink.processor.math.staticmathop; - -import org.apache.flink.api.common.functions.FlatMapFunction; -import org.apache.flink.util.Collector; -import org.apache.streampipes.model.runtime.Event; -import org.apache.streampipes.processors.enricher.flink.processor.math.operation.Operation; - -public class StaticMathOp implements FlatMapFunction<Event, Event> { - - private Operation operation; - private String leftOperand; - private double rightOperandValue; - private String resulField; - - public StaticMathOp(Operation operation, String leftOperand, double rightOperandValue, String resultField) { - this.operation = operation; - this.leftOperand = leftOperand; - this.rightOperandValue = rightOperandValue; - this.resulField = resultField; - } - - @Override - public void flatMap(Event in, Collector<Event> out) throws Exception { - Double leftValue = Double.parseDouble(String.valueOf(in.getFieldBySelector(leftOperand) - .getAsPrimitive().getAsDouble())); - - Double result = operation.operate(leftValue, rightOperandValue); - in.updateFieldBySelector(leftOperand, result); - - out.collect(in); - } -}
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/staticmathop/StaticMathOpController.java b/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/staticmathop/StaticMathOpController.java deleted file mode 100644 index 6cf6bbd..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/staticmathop/StaticMathOpController.java +++ /dev/null
@@ -1,95 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.processors.enricher.flink.processor.math.staticmathop; - -import org.apache.streampipes.client.StreamPipesClient; -import org.apache.streampipes.container.config.ConfigExtractor; -import org.apache.streampipes.model.DataProcessorType; -import org.apache.streampipes.model.graph.DataProcessorDescription; -import org.apache.streampipes.model.graph.DataProcessorInvocation; -import org.apache.streampipes.model.schema.PropertyScope; -import org.apache.streampipes.processors.enricher.flink.processor.math.operation.*; -import org.apache.streampipes.sdk.builder.ProcessingElementBuilder; -import org.apache.streampipes.sdk.builder.StreamRequirementsBuilder; -import org.apache.streampipes.sdk.extractor.ProcessingElementParameterExtractor; -import org.apache.streampipes.sdk.helpers.*; -import org.apache.streampipes.sdk.utils.Assets; -import org.apache.streampipes.wrapper.flink.FlinkDataProcessorDeclarer; -import org.apache.streampipes.wrapper.flink.FlinkDataProcessorRuntime; - -public class StaticMathOpController extends FlinkDataProcessorDeclarer<StaticMathOpParameters> { - - private final String RESULT_FIELD = "calculationResultStatic"; - private final String LEFT_OPERAND = "leftOperand"; - private final String RIGHT_OPERAND_VALUE = "rightOperandValue"; - private final String OPERATION = "operation"; - - @Override - public DataProcessorDescription declareModel() { - return ProcessingElementBuilder.create("org.apache.streampipes.processors.enricher.flink.processor.math.staticmathop") - .withAssets(Assets.DOCUMENTATION, Assets.ICON) - .withLocales(Locales.EN) - .category(DataProcessorType.ALGORITHM) - .requiredStream(StreamRequirementsBuilder - .create() - .requiredPropertyWithUnaryMapping(EpRequirements.numberReq(), - Labels.withId(LEFT_OPERAND), - PropertyScope.NONE) - .build()) - .requiredFloatParameter(Labels.withId(RIGHT_OPERAND_VALUE)) - .outputStrategy( - OutputStrategies.keep()) - .requiredSingleValueSelection(Labels.withId(OPERATION), - Options.from("+", "-", "/", "*", "%")) - .build(); - } - - @Override - public FlinkDataProcessorRuntime<StaticMathOpParameters> getRuntime(DataProcessorInvocation graph, - ProcessingElementParameterExtractor extractor, - ConfigExtractor configExtractor, - StreamPipesClient streamPipesClient) { - String leftOperand = extractor.mappingPropertyValue(LEFT_OPERAND); - double rightOperand = extractor.singleValueParameter(RIGHT_OPERAND_VALUE, Double.class); - String operation = extractor.selectedSingleValue(OPERATION, String.class); - - Operation arithmeticOperation = null; - switch (operation) { - case "+": - arithmeticOperation = new OperationAddition(); - break; - case "-": - arithmeticOperation = new OperationSubtracting(); - break; - case "*": - arithmeticOperation = new OperationMultiply(); - break; - case "/": - arithmeticOperation = new OperationDivide(); - break; - case "%": - arithmeticOperation = new OperationModulo(); - } - - StaticMathOpParameters parameters = new StaticMathOpParameters(graph, arithmeticOperation, leftOperand, rightOperand, RESULT_FIELD); - - return new StaticMathOpProgram(parameters, configExtractor, streamPipesClient); - - } -}
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/staticmathop/StaticMathOpParameters.java b/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/staticmathop/StaticMathOpParameters.java deleted file mode 100644 index b8466d2..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/staticmathop/StaticMathOpParameters.java +++ /dev/null
@@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.processors.enricher.flink.processor.math.staticmathop; - -import org.apache.streampipes.model.graph.DataProcessorInvocation; -import org.apache.streampipes.processors.enricher.flink.processor.math.operation.Operation; -import org.apache.streampipes.wrapper.params.binding.EventProcessorBindingParams; - -public class StaticMathOpParameters extends EventProcessorBindingParams { - - private Operation operation; - private String leftOperand; - private double rightOperandValue; - private String resultField; - - public StaticMathOpParameters(DataProcessorInvocation graph, Operation operation, String leftOperand, double rightOperandValue, String resultField) { - super(graph); - this.operation = operation; - this.leftOperand = leftOperand; - this.rightOperandValue = rightOperandValue; - this.resultField = resultField; - } - - public Operation getOperation() { - return operation; - } - - public String getLeftOperand() { - return leftOperand; - } - - public double getRightOperandValue() { - return rightOperandValue; - } - - public String getResultField() { - return resultField; - } -}
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/staticmathop/StaticMathOpProgram.java b/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/staticmathop/StaticMathOpProgram.java deleted file mode 100644 index 57c0dcf..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/staticmathop/StaticMathOpProgram.java +++ /dev/null
@@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.processors.enricher.flink.processor.math.staticmathop; - -import org.apache.flink.streaming.api.datastream.DataStream; -import org.apache.streampipes.client.StreamPipesClient; -import org.apache.streampipes.container.config.ConfigExtractor; -import org.apache.streampipes.model.runtime.Event; -import org.apache.streampipes.processors.enricher.flink.AbstractEnricherProgram; - -public class StaticMathOpProgram extends AbstractEnricherProgram<StaticMathOpParameters> { - - public StaticMathOpProgram(StaticMathOpParameters params, - ConfigExtractor configExtractor, - StreamPipesClient streamPipesClient) { - super(params, configExtractor, streamPipesClient); - } - - @Override - protected DataStream<Event> getApplicationLogic(DataStream<Event>... dataStreams) { - return dataStreams[0] - .flatMap(new StaticMathOp(params.getOperation(), params.getLeftOperand(), - params.getRightOperandValue(), params.getResultField())); - } -}
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/trigonometry/Trigonometry.java b/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/trigonometry/Trigonometry.java deleted file mode 100644 index e7fd00f..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/trigonometry/Trigonometry.java +++ /dev/null
@@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.processors.enricher.flink.processor.trigonometry; - -import org.apache.flink.api.common.functions.FlatMapFunction; -import org.apache.flink.util.Collector; -import org.apache.streampipes.model.runtime.Event; - -public class Trigonometry implements FlatMapFunction<Event, Event> { - - private String operand; - private Operation operation; - private String resultField; - - public Trigonometry(String operand, Operation operation, String resultField) { - this.operand = operand; - this.operation = operation; - this.resultField = resultField; - } - - @Override - public void flatMap(Event in, Collector<Event> out) throws Exception { - double value = in.getFieldBySelector(operand).getAsPrimitive().getAsDouble(); - double result; - - if (operation == Operation.SIN) { - result = Math.sin(value); - } else if (operation == Operation.COS) { - result = Math.cos(value); - } else { - result = Math.tan(value); - } - in.addField(resultField, result); - - out.collect(in); - } -}
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/trigonometry/TrigonometryController.java b/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/trigonometry/TrigonometryController.java deleted file mode 100644 index 29735c8..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/trigonometry/TrigonometryController.java +++ /dev/null
@@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.processors.enricher.flink.processor.trigonometry; - -import org.apache.streampipes.client.StreamPipesClient; -import org.apache.streampipes.container.config.ConfigExtractor; -import org.apache.streampipes.model.DataProcessorType; -import org.apache.streampipes.model.graph.DataProcessorDescription; -import org.apache.streampipes.model.graph.DataProcessorInvocation; -import org.apache.streampipes.model.schema.PropertyScope; -import org.apache.streampipes.sdk.builder.ProcessingElementBuilder; -import org.apache.streampipes.sdk.builder.StreamRequirementsBuilder; -import org.apache.streampipes.sdk.extractor.ProcessingElementParameterExtractor; -import org.apache.streampipes.sdk.helpers.*; -import org.apache.streampipes.sdk.utils.Assets; -import org.apache.streampipes.vocabulary.SO; -import org.apache.streampipes.wrapper.flink.FlinkDataProcessorDeclarer; -import org.apache.streampipes.wrapper.flink.FlinkDataProcessorRuntime; - -public class TrigonometryController extends FlinkDataProcessorDeclarer<TrigonometryParameters> { - - private final String OPERAND = "operand"; - private final String OPERATION = "operation"; - private final String RESULT_FIELD = "trigonometryResult"; - - - @Override - public DataProcessorDescription declareModel() { - return ProcessingElementBuilder.create("org.apache.streampipes.processors.enricher.flink.processor.trigonometry") - .withAssets(Assets.DOCUMENTATION, Assets.ICON) - .withLocales(Locales.EN) - .category(DataProcessorType.ALGORITHM) - .requiredStream(StreamRequirementsBuilder - .create() - .requiredPropertyWithUnaryMapping(EpRequirements.numberReq(), - Labels.withId(OPERAND), - PropertyScope.NONE) - .build()) - .outputStrategy( - OutputStrategies.append( - EpProperties.numberEp(Labels.empty(), RESULT_FIELD, SO.Number))) - .requiredSingleValueSelection(Labels.withId(OPERATION), - Options.from("sin(a)", "cos(a)", "tan(a)" )) - .build(); - } - - @Override - public FlinkDataProcessorRuntime<TrigonometryParameters> getRuntime(DataProcessorInvocation graph, - ProcessingElementParameterExtractor extractor, - ConfigExtractor configExtractor, - StreamPipesClient streamPipesClient) { - String operand = extractor.mappingPropertyValue(OPERAND); - String operation = extractor.selectedSingleValue(OPERATION, String.class); - - Operation trigonometryFunction = null; - switch (operation) { - case "sin(a)": trigonometryFunction = Operation.SIN; - break; - case "cos(a)": trigonometryFunction = Operation.COS; - break; - case "tan(a)": trigonometryFunction = Operation.TAN; - - } - - - TrigonometryParameters parameters = new TrigonometryParameters(graph, operand, trigonometryFunction, RESULT_FIELD); - - return new TrigonometryProgram(parameters, configExtractor, streamPipesClient); - } -}
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/trigonometry/TrigonometryParameters.java b/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/trigonometry/TrigonometryParameters.java deleted file mode 100644 index 5c0d80c..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/trigonometry/TrigonometryParameters.java +++ /dev/null
@@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.processors.enricher.flink.processor.trigonometry; - -import org.apache.streampipes.model.graph.DataProcessorInvocation; -import org.apache.streampipes.wrapper.params.binding.EventProcessorBindingParams; - -public class TrigonometryParameters extends EventProcessorBindingParams { - - private String operand; - private Operation operation; - private String resultField; - - public TrigonometryParameters(DataProcessorInvocation graph, String operand, Operation operation, String resultField) { - super(graph); - this.operand = operand; - this.operation = operation; - this.resultField = resultField; - } - - public String getOperand() { - return operand; - } - - public Operation getOperation() { - return operation; - } - - public String getResultField() { - return resultField; - } -}
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/trigonometry/TrigonometryProgram.java b/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/trigonometry/TrigonometryProgram.java deleted file mode 100644 index ceb2d83..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/trigonometry/TrigonometryProgram.java +++ /dev/null
@@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.processors.enricher.flink.processor.trigonometry; - -import org.apache.flink.streaming.api.datastream.DataStream; -import org.apache.streampipes.client.StreamPipesClient; -import org.apache.streampipes.container.config.ConfigExtractor; -import org.apache.streampipes.model.runtime.Event; -import org.apache.streampipes.processors.enricher.flink.AbstractEnricherProgram; - -public class TrigonometryProgram extends AbstractEnricherProgram<TrigonometryParameters> { - - public TrigonometryProgram(TrigonometryParameters params, - ConfigExtractor configExtractor, - StreamPipesClient streamPipesClient) { - super(params, configExtractor, streamPipesClient); - } - - @Override - protected DataStream<Event> getApplicationLogic(DataStream<Event>... dataStreams) { - return dataStreams[0].flatMap(new Trigonometry(params.getOperand(), params.getOperation(), params.getResultField())); - } -}
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.math.mathop/strings.en b/streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.math.mathop/strings.en deleted file mode 100644 index 877a15a..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.math.mathop/strings.en +++ /dev/null
@@ -1,11 +0,0 @@ -org.apache.streampipes.processors.enricher.flink.processor.math.mathop.title=Math -org.apache.streampipes.processors.enricher.flink.processor.math.mathop.description=Performs calculations on event properties (+, -, *, /, %) - -leftOperand.title=Left operand -leftOperand.description=Select left operand - -rightOperand.title=Right operand -rightOperand.description=Select right operand - -operation.title=Select Operation -operation.description= \ No newline at end of file
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.math.staticmathop/strings.en b/streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.math.staticmathop/strings.en deleted file mode 100644 index 3825f6e..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.math.staticmathop/strings.en +++ /dev/null
@@ -1,10 +0,0 @@ -org.apache.streampipes.processors.enricher.flink.processor.math.staticmathop.title=Static Math -org.apache.streampipes.processors.enricher.flink.processor.math.staticmathop.description=Performs calculation on an event property with a static value (+, -, *, /, %) - -leftOperand.title=Left operand -leftOperand.description=Select left operand - -rightOperandValue.title=Right operand value -rightOperandValue.description=Specify the value of the right operand. - -operation.title=Select operation \ No newline at end of file
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.trigonometry/strings.en b/streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.trigonometry/strings.en deleted file mode 100644 index 051c848..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.trigonometry/strings.en +++ /dev/null
@@ -1,9 +0,0 @@ -org.apache.streampipes.processors.enricher.flink.processor.trigonometry.title=Trigonometry Functions -org.apache.streampipes.processors.enricher.flink.processor.trigonometry.description=Performs Trigonometric functions on event properties - -operand.title=Alpha -operand.description=Select the alpha parameter - -operation.title=Operation -operation.description= -
diff --git a/streampipes-extensions/streampipes-processors-enricher-jvm/Dockerfile b/streampipes-extensions/streampipes-processors-enricher-jvm/Dockerfile deleted file mode 100644 index 63fe799..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-jvm/Dockerfile +++ /dev/null
@@ -1,25 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=adoptopenjdk/openjdk9-openj9:alpine -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY target/streampipes-processors-enricher-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-enricher-jvm/aarch64.Dockerfile b/streampipes-extensions/streampipes-processors-enricher-jvm/aarch64.Dockerfile deleted file mode 100644 index dd6f1a3..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-jvm/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-processors-enricher-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-enricher-jvm/arm.Dockerfile b/streampipes-extensions/streampipes-processors-enricher-jvm/arm.Dockerfile deleted file mode 100644 index 28cba17..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-jvm/arm.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-processors-enricher-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-enricher-jvm/development/.env b/streampipes-extensions/streampipes-processors-enricher-jvm/development/.env deleted file mode 100644 index db69c0d..0000000 --- a/streampipes-extensions/streampipes-processors-enricher-jvm/development/.env +++ /dev/null
@@ -1,19 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Those parameters are used by IntelliJ to set the default consul parameters for development -SP_PORT=6015 -SP_HOST=host.docker.internal -SP_DEBUG=true
diff --git a/streampipes-extensions/streampipes-processors-enricher-jvm/pom.xml b/streampipes-extensions/streampipes-processors-enricher-jvm/pom.xml index f383bba..0b4c4b4 100644 --- a/streampipes-extensions/streampipes-processors-enricher-jvm/pom.xml +++ b/streampipes-extensions/streampipes-processors-enricher-jvm/pom.xml
@@ -20,26 +20,22 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>streampipes-processors-enricher-jvm</artifactId> - <properties> - <maven.deploy.skip>true</maven.deploy.skip> - </properties> - <dependencies> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-standalone</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.graalvm.js</groupId> @@ -50,37 +46,4 @@ <artifactId>js-scriptengine</artifactId> </dependency> </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>jar</goal> - </goals> - <phase>package</phase> - <configuration> - <classifier>embed</classifier> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-maven-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>repackage</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - <finalName>streampipes-processors-enricher-jvm</finalName> - - </build> </project>
diff --git a/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/EnricherJvmInit.java b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/EnricherJvmInit.java index d022600..d18ece8 100644 --- a/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/EnricherJvmInit.java +++ b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/EnricherJvmInit.java
@@ -29,7 +29,10 @@ import org.apache.streampipes.messaging.kafka.SpKafkaProtocolFactory; import org.apache.streampipes.messaging.mqtt.SpMqttProtocolFactory; import org.apache.streampipes.processors.enricher.jvm.processor.jseval.JSEvalController; +import org.apache.streampipes.processors.enricher.jvm.processor.math.MathOpProcessor; +import org.apache.streampipes.processors.enricher.jvm.processor.math.staticmathop.StaticMathOpProcessor; import org.apache.streampipes.processors.enricher.jvm.processor.sizemeasure.SizeMeasureController; +import org.apache.streampipes.processors.enricher.jvm.processor.trigonometry.TrigonometryProcessor; import org.apache.streampipes.processors.enricher.jvm.processor.valueChange.ValueChangeProcessor; public class EnricherJvmInit extends StandaloneModelSubmitter { @@ -46,6 +49,9 @@ 8090) .registerPipelineElements(new SizeMeasureController(), new JSEvalController(), + new MathOpProcessor(), + new StaticMathOpProcessor(), + new TrigonometryProcessor(), new ValueChangeProcessor()) .registerMessagingFormats( new JsonDataFormatFactory(),
diff --git a/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/MathOpProcessor.java b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/MathOpProcessor.java new file mode 100644 index 0000000..0c54e49 --- /dev/null +++ b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/MathOpProcessor.java
@@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +package org.apache.streampipes.processors.enricher.jvm.processor.math; + +import org.apache.streampipes.commons.exceptions.SpRuntimeException; +import org.apache.streampipes.model.DataProcessorType; +import org.apache.streampipes.model.graph.DataProcessorDescription; +import org.apache.streampipes.model.runtime.Event; +import org.apache.streampipes.model.schema.PropertyScope; +import org.apache.streampipes.processors.enricher.jvm.processor.math.operation.*; +import org.apache.streampipes.sdk.builder.ProcessingElementBuilder; +import org.apache.streampipes.sdk.builder.StreamRequirementsBuilder; +import org.apache.streampipes.sdk.helpers.*; +import org.apache.streampipes.sdk.utils.Assets; +import org.apache.streampipes.vocabulary.SO; +import org.apache.streampipes.wrapper.context.EventProcessorRuntimeContext; +import org.apache.streampipes.wrapper.routing.SpOutputCollector; +import org.apache.streampipes.wrapper.standalone.ProcessorParams; +import org.apache.streampipes.wrapper.standalone.StreamPipesDataProcessor; + +public class MathOpProcessor extends StreamPipesDataProcessor { + + private final String RESULT_FIELD = "calculationResult"; + private final String LEFT_OPERAND = "leftOperand"; + private final String RIGHT_OPERAND = "rightOperand"; + private final String OPERATION = "operation"; + + Operation arithmeticOperation = null; + String leftOperand; + String rightOperand; + + @Override + public DataProcessorDescription declareModel() { + return ProcessingElementBuilder.create("org.apache.streampipes.processors.enricher.jvm.processor.math.mathop") + .withAssets(Assets.DOCUMENTATION, Assets.ICON) + .withLocales(Locales.EN) + .category(DataProcessorType.ALGORITHM) + .requiredStream(StreamRequirementsBuilder + .create() + .requiredPropertyWithUnaryMapping(EpRequirements.numberReq(), + Labels.withId(LEFT_OPERAND), + PropertyScope.NONE) + .requiredPropertyWithUnaryMapping(EpRequirements.numberReq(), + Labels.withId(RIGHT_OPERAND), + PropertyScope.NONE) + .build()) + .outputStrategy( + OutputStrategies.append( + EpProperties.numberEp(Labels.empty(), RESULT_FIELD, SO.Number))) + .requiredSingleValueSelection(Labels.withId(OPERATION), Options.from("+", "-", "/", + "*", "%")) + .build(); + } + + @Override + public void onInvocation(ProcessorParams parameters, SpOutputCollector spOutputCollector, EventProcessorRuntimeContext runtimeContext) throws SpRuntimeException { + this.leftOperand = parameters.extractor().mappingPropertyValue(LEFT_OPERAND); + this.rightOperand = parameters.extractor().mappingPropertyValue(RIGHT_OPERAND); + String operation = parameters.extractor().selectedSingleValue(OPERATION, String.class); + + switch (operation) { + case "+": + arithmeticOperation = new OperationAddition(); + break; + case "-": + arithmeticOperation = new OperationSubtracting(); + break; + case "*": + arithmeticOperation = new OperationMultiply(); + break; + case "/": + arithmeticOperation = new OperationDivide(); + break; + case "%": + arithmeticOperation = new OperationModulo(); + } + } + + @Override + public void onEvent(Event in, SpOutputCollector out) throws SpRuntimeException { + Double leftValue = in.getFieldBySelector(leftOperand).getAsPrimitive().getAsDouble(); + Double rightValue = in.getFieldBySelector(rightOperand).getAsPrimitive().getAsDouble(); + + Double result = arithmeticOperation.operate(leftValue, rightValue); + in.addField(RESULT_FIELD, result); + + out.collect(in); + } + + @Override + public void onDetach() throws SpRuntimeException { + + } +}
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/Operation.java b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/operation/Operation.java similarity index 91% rename from streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/Operation.java rename to streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/operation/Operation.java index e9cd593..f3d71bc 100644 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/Operation.java +++ b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/operation/Operation.java
@@ -16,7 +16,7 @@ * */ -package org.apache.streampipes.processors.enricher.flink.processor.math.operation; +package org.apache.streampipes.processors.enricher.jvm.processor.math.operation; import java.io.Serializable;
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/OperationAddition.java b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/operation/OperationAddition.java similarity index 91% rename from streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/OperationAddition.java rename to streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/operation/OperationAddition.java index 8a19293..b3e8507 100644 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/OperationAddition.java +++ b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/operation/OperationAddition.java
@@ -16,7 +16,7 @@ * */ -package org.apache.streampipes.processors.enricher.flink.processor.math.operation; +package org.apache.streampipes.processors.enricher.jvm.processor.math.operation; public class OperationAddition implements Operation {
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/OperationDivide.java b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/operation/OperationDivide.java similarity index 91% rename from streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/OperationDivide.java rename to streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/operation/OperationDivide.java index b648a20..e60c610 100644 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/OperationDivide.java +++ b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/operation/OperationDivide.java
@@ -16,7 +16,7 @@ * */ -package org.apache.streampipes.processors.enricher.flink.processor.math.operation; +package org.apache.streampipes.processors.enricher.jvm.processor.math.operation; public class OperationDivide implements Operation {
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/OperationModulo.java b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/operation/OperationModulo.java similarity index 91% rename from streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/OperationModulo.java rename to streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/operation/OperationModulo.java index ab50adf..0561722 100644 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/OperationModulo.java +++ b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/operation/OperationModulo.java
@@ -16,7 +16,7 @@ * */ -package org.apache.streampipes.processors.enricher.flink.processor.math.operation; +package org.apache.streampipes.processors.enricher.jvm.processor.math.operation; public class OperationModulo implements Operation {
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/OperationMultiply.java b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/operation/OperationMultiply.java similarity index 91% rename from streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/OperationMultiply.java rename to streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/operation/OperationMultiply.java index e359244..f8d121e 100644 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/OperationMultiply.java +++ b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/operation/OperationMultiply.java
@@ -16,7 +16,7 @@ * */ -package org.apache.streampipes.processors.enricher.flink.processor.math.operation; +package org.apache.streampipes.processors.enricher.jvm.processor.math.operation; public class OperationMultiply implements Operation{
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/OperationSubtracting.java b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/operation/OperationSubtracting.java similarity index 91% rename from streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/OperationSubtracting.java rename to streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/operation/OperationSubtracting.java index 27163a4..d8ed36d 100644 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/OperationSubtracting.java +++ b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/operation/OperationSubtracting.java
@@ -16,7 +16,7 @@ * */ -package org.apache.streampipes.processors.enricher.flink.processor.math.operation; +package org.apache.streampipes.processors.enricher.jvm.processor.math.operation; public class OperationSubtracting implements Operation {
diff --git a/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/staticmathop/StaticMathOpProcessor.java b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/staticmathop/StaticMathOpProcessor.java new file mode 100644 index 0000000..3fe76bc --- /dev/null +++ b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/math/staticmathop/StaticMathOpProcessor.java
@@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.processors.enricher.jvm.processor.math.staticmathop; + +import org.apache.streampipes.commons.exceptions.SpRuntimeException; +import org.apache.streampipes.model.DataProcessorType; +import org.apache.streampipes.model.graph.DataProcessorDescription; +import org.apache.streampipes.model.runtime.Event; +import org.apache.streampipes.model.schema.PropertyScope; +import org.apache.streampipes.processors.enricher.jvm.processor.math.operation.*; +import org.apache.streampipes.sdk.builder.ProcessingElementBuilder; +import org.apache.streampipes.sdk.builder.StreamRequirementsBuilder; +import org.apache.streampipes.sdk.helpers.*; +import org.apache.streampipes.sdk.utils.Assets; +import org.apache.streampipes.wrapper.context.EventProcessorRuntimeContext; +import org.apache.streampipes.wrapper.routing.SpOutputCollector; +import org.apache.streampipes.wrapper.standalone.ProcessorParams; +import org.apache.streampipes.wrapper.standalone.StreamPipesDataProcessor; + +public class StaticMathOpProcessor extends StreamPipesDataProcessor { + + private final String RESULT_FIELD = "calculationResultStatic"; + private final String LEFT_OPERAND = "leftOperand"; + private final String RIGHT_OPERAND_VALUE = "rightOperandValue"; + private final String OPERATION = "operation"; + + Operation arithmeticOperation; + String leftOperand; + double rightOperandValue; + + + @Override + public DataProcessorDescription declareModel() { + return ProcessingElementBuilder.create("org.apache.streampipes.processors.enricher.jvm.processor.math.staticmathop") + .withAssets(Assets.DOCUMENTATION, Assets.ICON) + .withLocales(Locales.EN) + .category(DataProcessorType.ALGORITHM) + .requiredStream(StreamRequirementsBuilder + .create() + .requiredPropertyWithUnaryMapping(EpRequirements.numberReq(), + Labels.withId(LEFT_OPERAND), + PropertyScope.NONE) + .build()) + .requiredFloatParameter(Labels.withId(RIGHT_OPERAND_VALUE)) + .outputStrategy( + OutputStrategies.keep()) + .requiredSingleValueSelection(Labels.withId(OPERATION), + Options.from("+", "-", "/", "*", "%")) + .build(); + } + + @Override + public void onInvocation(ProcessorParams parameters, SpOutputCollector spOutputCollector, EventProcessorRuntimeContext runtimeContext) throws SpRuntimeException { + this.leftOperand = parameters.extractor().mappingPropertyValue(LEFT_OPERAND); + this.rightOperandValue = parameters.extractor().singleValueParameter(RIGHT_OPERAND_VALUE, Double.class); + String operation = parameters.extractor().selectedSingleValue(OPERATION, String.class); + + switch (operation) { + case "+": + arithmeticOperation = new OperationAddition(); + break; + case "-": + arithmeticOperation = new OperationSubtracting(); + break; + case "*": + arithmeticOperation = new OperationMultiply(); + break; + case "/": + arithmeticOperation = new OperationDivide(); + break; + case "%": + arithmeticOperation = new OperationModulo(); + } + } + + @Override + public void onEvent(Event in, SpOutputCollector out) throws SpRuntimeException { + Double leftValue = Double.parseDouble(String.valueOf(in.getFieldBySelector(leftOperand) + .getAsPrimitive().getAsDouble())); + + Double result = arithmeticOperation.operate(leftValue, rightOperandValue); + in.updateFieldBySelector(leftOperand, result); + + out.collect(in); + } + + @Override + public void onDetach() throws SpRuntimeException { + + } +}
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/trigonometry/Operation.java b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/trigonometry/Operation.java similarity index 91% rename from streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/trigonometry/Operation.java rename to streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/trigonometry/Operation.java index 794a000..c2c179a 100644 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/trigonometry/Operation.java +++ b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/trigonometry/Operation.java
@@ -16,7 +16,7 @@ * */ -package org.apache.streampipes.processors.enricher.flink.processor.trigonometry; +package org.apache.streampipes.processors.enricher.jvm.processor.trigonometry; public enum Operation { SIN,
diff --git a/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/trigonometry/TrigonometryProcessor.java b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/trigonometry/TrigonometryProcessor.java new file mode 100644 index 0000000..3067168 --- /dev/null +++ b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/java/org/apache/streampipes/processors/enricher/jvm/processor/trigonometry/TrigonometryProcessor.java
@@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.processors.enricher.jvm.processor.trigonometry; + +import org.apache.streampipes.commons.exceptions.SpRuntimeException; +import org.apache.streampipes.model.DataProcessorType; +import org.apache.streampipes.model.graph.DataProcessorDescription; +import org.apache.streampipes.model.runtime.Event; +import org.apache.streampipes.model.schema.PropertyScope; +import org.apache.streampipes.sdk.builder.ProcessingElementBuilder; +import org.apache.streampipes.sdk.builder.StreamRequirementsBuilder; +import org.apache.streampipes.sdk.helpers.*; +import org.apache.streampipes.sdk.utils.Assets; +import org.apache.streampipes.vocabulary.SO; +import org.apache.streampipes.wrapper.context.EventProcessorRuntimeContext; +import org.apache.streampipes.wrapper.routing.SpOutputCollector; +import org.apache.streampipes.wrapper.standalone.ProcessorParams; +import org.apache.streampipes.wrapper.standalone.StreamPipesDataProcessor; + +public class TrigonometryProcessor extends StreamPipesDataProcessor { + + private final String OPERAND = "operand"; + private final String OPERATION = "operation"; + private final String RESULT_FIELD = "trigonometryResult"; + + private Operation operation; + private String operand; + + + @Override + public DataProcessorDescription declareModel() { + return ProcessingElementBuilder.create("org.apache.streampipes.processors.enricher.jvm.processor.trigonometry") + .withAssets(Assets.DOCUMENTATION, Assets.ICON) + .withLocales(Locales.EN) + .category(DataProcessorType.ALGORITHM) + .requiredStream(StreamRequirementsBuilder + .create() + .requiredPropertyWithUnaryMapping(EpRequirements.numberReq(), + Labels.withId(OPERAND), + PropertyScope.NONE) + .build()) + .outputStrategy( + OutputStrategies.append( + EpProperties.numberEp(Labels.empty(), RESULT_FIELD, SO.Number))) + .requiredSingleValueSelection(Labels.withId(OPERATION), + Options.from("sin", "cos", "tan" )) + .build(); + } + + @Override + public void onInvocation(ProcessorParams parameters, + SpOutputCollector spOutputCollector, + EventProcessorRuntimeContext runtimeContext) throws SpRuntimeException { + + this.operand = parameters.extractor().mappingPropertyValue(OPERAND); + String stringOperation = parameters.extractor().selectedSingleValue(OPERATION, String.class); + + switch (stringOperation) { + case "sin": operation = Operation.SIN; + break; + case "cos": operation = Operation.COS; + break; + case "tan": operation = Operation.TAN; + + } + } + + @Override + public void onEvent(Event in, SpOutputCollector out) throws SpRuntimeException { + double value = in.getFieldBySelector(operand).getAsPrimitive().getAsDouble(); + double result; + + if (operation == Operation.SIN) { + result = Math.sin(value); + } else if (operation == Operation.COS) { + result = Math.cos(value); + } else { + result = Math.tan(value); + } + in.addField(RESULT_FIELD, result); + + out.collect(in); + } + + @Override + public void onDetach() throws SpRuntimeException { + + } +}
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.math.mathop/documentation.md b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.math.mathop/documentation.md similarity index 100% rename from streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.math.mathop/documentation.md rename to streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.math.mathop/documentation.md
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.math.mathop/icon.png b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.math.mathop/icon.png similarity index 100% rename from streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.math.mathop/icon.png rename to streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.math.mathop/icon.png Binary files differ
diff --git a/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.math.mathop/strings.en b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.math.mathop/strings.en new file mode 100644 index 0000000..d55af60 --- /dev/null +++ b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.math.mathop/strings.en
@@ -0,0 +1,11 @@ +org.apache.streampipes.processors.enricher.jvm.processor.math.mathop.title=Math +org.apache.streampipes.processors.enricher.jvm.processor.math.mathop.description=Performs calculations on event properties (+, -, *, /, %) + +leftOperand.title=Left operand +leftOperand.description=Select left operand + +rightOperand.title=Right operand +rightOperand.description=Select right operand + +operation.title=Select Operation +operation.description=
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.math.staticmathop/documentation.md b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.math.staticmathop/documentation.md similarity index 100% rename from streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.math.staticmathop/documentation.md rename to streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.math.staticmathop/documentation.md
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.math.staticmathop/icon.png b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.math.staticmathop/icon.png similarity index 100% rename from streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.math.staticmathop/icon.png rename to streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.math.staticmathop/icon.png Binary files differ
diff --git a/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.math.staticmathop/strings.en b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.math.staticmathop/strings.en new file mode 100644 index 0000000..8c3c82b --- /dev/null +++ b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.math.staticmathop/strings.en
@@ -0,0 +1,10 @@ +org.apache.streampipes.processors.enricher.jvm.processor.math.staticmathop.title=Static Math +org.apache.streampipes.processors.enricher.jvm.processor.math.staticmathop.description=Performs calculation on an event property with a static value (+, -, *, /, %) + +leftOperand.title=Left operand +leftOperand.description=Select left operand + +rightOperandValue.title=Right operand value +rightOperandValue.description=Specify the value of the right operand. + +operation.title=Select operation
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.trigonometry/documentation.md b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.trigonometry/documentation.md similarity index 100% rename from streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.trigonometry/documentation.md rename to streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.trigonometry/documentation.md
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.trigonometry/icon.png b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.trigonometry/icon.png similarity index 100% rename from streampipes-extensions/streampipes-processors-enricher-flink/src/main/resources/org.apache.streampipes.processors.enricher.flink.processor.trigonometry/icon.png rename to streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.trigonometry/icon.png Binary files differ
diff --git a/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.trigonometry/strings.en b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.trigonometry/strings.en new file mode 100644 index 0000000..7280fa9 --- /dev/null +++ b/streampipes-extensions/streampipes-processors-enricher-jvm/src/main/resources/org.apache.streampipes.processors.enricher.jvm.processor.trigonometry/strings.en
@@ -0,0 +1,9 @@ +org.apache.streampipes.processors.enricher.jvm.processor.trigonometry.title=Trigonometry Functions +org.apache.streampipes.processors.enricher.jvm.processor.trigonometry.description=Performs Trigonometric functions on event properties + +operand.title=Alpha +operand.description=Select the alpha parameter + +operation.title=Operation +operation.description= +
diff --git a/streampipes-extensions/streampipes-processors-filters-jvm/Dockerfile b/streampipes-extensions/streampipes-processors-filters-jvm/Dockerfile deleted file mode 100644 index f2b8798..0000000 --- a/streampipes-extensions/streampipes-processors-filters-jvm/Dockerfile +++ /dev/null
@@ -1,25 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=adoptopenjdk/openjdk8-openj9:alpine -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY target/streampipes-processors-filters-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-filters-jvm/aarch64.Dockerfile b/streampipes-extensions/streampipes-processors-filters-jvm/aarch64.Dockerfile deleted file mode 100644 index e835ef3..0000000 --- a/streampipes-extensions/streampipes-processors-filters-jvm/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-processors-filters-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-filters-jvm/arm.Dockerfile b/streampipes-extensions/streampipes-processors-filters-jvm/arm.Dockerfile deleted file mode 100644 index 692ddb3..0000000 --- a/streampipes-extensions/streampipes-processors-filters-jvm/arm.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-processors-filters-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-filters-jvm/development/env b/streampipes-extensions/streampipes-processors-filters-jvm/development/env deleted file mode 100644 index 28f3dca..0000000 --- a/streampipes-extensions/streampipes-processors-filters-jvm/development/env +++ /dev/null
@@ -1,19 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Those parameters are used by IntelliJ to set the default consul parameters for development -SP_PORT=6015 -#SP_HOST=localhost -SP_DEBUG=true
diff --git a/streampipes-extensions/streampipes-processors-filters-jvm/pom.xml b/streampipes-extensions/streampipes-processors-filters-jvm/pom.xml index 9d12a29..c0a63ed 100644 --- a/streampipes-extensions/streampipes-processors-filters-jvm/pom.xml +++ b/streampipes-extensions/streampipes-processors-filters-jvm/pom.xml
@@ -21,64 +21,27 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>streampipes-processors-filters-jvm</artifactId> - <properties> - <maven.deploy.skip>true</maven.deploy.skip> - </properties> - <dependencies> <!-- StreamPipes dependencies --> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-standalone</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> </dependency> </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>jar</goal> - </goals> - <phase>package</phase> - <configuration> - <classifier>embed</classifier> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-maven-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>repackage</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - <finalName>streampipes-processors-filters-jvm</finalName> - - </build> </project>
diff --git a/streampipes-extensions/streampipes-processors-filters-jvm/src/main/java/org/apache/streampipes/processors/filters/jvm/processor/numericaltextfilter/NumericalTextFilterProcessor.java b/streampipes-extensions/streampipes-processors-filters-jvm/src/main/java/org/apache/streampipes/processors/filters/jvm/processor/numericaltextfilter/NumericalTextFilterProcessor.java index a41ef2d..dad2e6a 100644 --- a/streampipes-extensions/streampipes-processors-filters-jvm/src/main/java/org/apache/streampipes/processors/filters/jvm/processor/numericaltextfilter/NumericalTextFilterProcessor.java +++ b/streampipes-extensions/streampipes-processors-filters-jvm/src/main/java/org/apache/streampipes/processors/filters/jvm/processor/numericaltextfilter/NumericalTextFilterProcessor.java
@@ -71,7 +71,7 @@ .requiredFloatParameter(Labels.withId(NUMBER_VALUE), NUMBER_MAPPING) .requiredSingleValueSelection(Labels.withId(TEXT_OPERATION), Options.from("MATCHES", "CONTAINS")) - .requiredTextParameter(Labels.withId(TEXT_KEYWORD), "text") + .requiredTextParameterWithLink(Labels.withId(TEXT_KEYWORD), "text") .outputStrategy(OutputStrategies.keep()) .build();
diff --git a/streampipes-extensions/streampipes-processors-filters-jvm/src/main/java/org/apache/streampipes/processors/filters/jvm/processor/textfilter/TextFilterProcessor.java b/streampipes-extensions/streampipes-processors-filters-jvm/src/main/java/org/apache/streampipes/processors/filters/jvm/processor/textfilter/TextFilterProcessor.java index 855fba9..8e29c45 100644 --- a/streampipes-extensions/streampipes-processors-filters-jvm/src/main/java/org/apache/streampipes/processors/filters/jvm/processor/textfilter/TextFilterProcessor.java +++ b/streampipes-extensions/streampipes-processors-filters-jvm/src/main/java/org/apache/streampipes/processors/filters/jvm/processor/textfilter/TextFilterProcessor.java
@@ -59,7 +59,7 @@ .build()) .requiredSingleValueSelection(Labels.withId(OPERATION_ID), Options.from("MATCHES", "CONTAINS")) - .requiredTextParameter(Labels.withId(KEYWORD_ID), "text") + .requiredTextParameterWithLink(Labels.withId(KEYWORD_ID), "text") .outputStrategy(OutputStrategies.keep()) .build(); }
diff --git a/streampipes-extensions/streampipes-processors-filters-siddhi/Dockerfile b/streampipes-extensions/streampipes-processors-filters-siddhi/Dockerfile deleted file mode 100644 index 806bb28..0000000 --- a/streampipes-extensions/streampipes-processors-filters-siddhi/Dockerfile +++ /dev/null
@@ -1,25 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=adoptopenjdk/openjdk8-openj9:alpine -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY target/streampipes-processors-filters-siddhi.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-filters-siddhi/aarch64.Dockerfile b/streampipes-extensions/streampipes-processors-filters-siddhi/aarch64.Dockerfile deleted file mode 100644 index 58bc359..0000000 --- a/streampipes-extensions/streampipes-processors-filters-siddhi/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-processors-filters-siddhi.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-filters-siddhi/arm.Dockerfile b/streampipes-extensions/streampipes-processors-filters-siddhi/arm.Dockerfile deleted file mode 100644 index ce43076..0000000 --- a/streampipes-extensions/streampipes-processors-filters-siddhi/arm.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-processors-filters-siddhi.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-filters-siddhi/development/env b/streampipes-extensions/streampipes-processors-filters-siddhi/development/env index dfa6559..869b1d3 100644 --- a/streampipes-extensions/streampipes-processors-filters-siddhi/development/env +++ b/streampipes-extensions/streampipes-processors-filters-siddhi/development/env
@@ -16,4 +16,4 @@ # Those parameters are used by IntelliJ to set the default consul parameters for development SP_PORT=6020 SP_HOST=host.docker.internal -SP_DEBUG=true +SP_DEBUG=true \ No newline at end of file
diff --git a/streampipes-extensions/streampipes-processors-filters-siddhi/pom.xml b/streampipes-extensions/streampipes-processors-filters-siddhi/pom.xml index f09400b..0a7c7ca 100644 --- a/streampipes-extensions/streampipes-processors-filters-siddhi/pom.xml +++ b/streampipes-extensions/streampipes-processors-filters-siddhi/pom.xml
@@ -21,27 +21,23 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>streampipes-processors-filters-siddhi</artifactId> - <properties> - <maven.deploy.skip>true</maven.deploy.skip> - </properties> - <dependencies> <!-- StreamPipes dependencies --> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-siddhi</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>org.slf4j</groupId> @@ -70,43 +66,8 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-test-utils</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <scope>test</scope> </dependency> </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>jar</goal> - </goals> - <phase>package</phase> - <configuration> - <classifier>embed</classifier> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-maven-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>repackage</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - <finalName>streampipes-processors-filters-siddhi</finalName> - - </build> - - </project>
diff --git a/streampipes-extensions/streampipes-processors-filters-siddhi/src/main/java/org/apache/streampipes/processors/siddhi/count/CountAggregation.java b/streampipes-extensions/streampipes-processors-filters-siddhi/src/main/java/org/apache/streampipes/processors/siddhi/count/CountAggregation.java index 1842a58..9bf37f5 100644 --- a/streampipes-extensions/streampipes-processors-filters-siddhi/src/main/java/org/apache/streampipes/processors/siddhi/count/CountAggregation.java +++ b/streampipes-extensions/streampipes-processors-filters-siddhi/src/main/java/org/apache/streampipes/processors/siddhi/count/CountAggregation.java
@@ -40,6 +40,7 @@ public class CountAggregation extends StreamPipesSiddhiProcessor { private static final String TIME_WINDOW_KEY = "time-window"; + private static final String TIMESTAMP_MAPPING_KEY = "timestamp-mapping"; private static final String SCALE_KEY = "scale"; private static final String COUNT_MAPPING = "count-mapping"; @@ -55,8 +56,14 @@ .withLocales(Locales.EN) .requiredStream(StreamRequirementsBuilder .create() - .requiredPropertyWithUnaryMapping(EpRequirements.anyProperty(), - Labels.withId(COUNT_MAPPING), PropertyScope.DIMENSION_PROPERTY) + .requiredPropertyWithUnaryMapping( + EpRequirements.timestampReq(), + Labels.withId(TIMESTAMP_MAPPING_KEY), + PropertyScope.NONE) + .requiredPropertyWithUnaryMapping( + EpRequirements.anyProperty(), + Labels.withId(COUNT_MAPPING), + PropertyScope.DIMENSION_PROPERTY) .build()) .outputStrategy(OutputStrategies.fixed( EpProperties.timestampProperty("timestamp"), @@ -76,12 +83,14 @@ Integer timeWindowSize = siddhiParams.getParams().extractor().singleValueParameter(TIME_WINDOW_KEY, Integer.class); String scale = siddhiParams.getParams().extractor().selectedSingleValueInternalName(SCALE_KEY, String.class); String fieldToCount = siddhiParams.getParams().extractor().mappingPropertyValue(COUNT_MAPPING); + String timestampField = siddhiParams.getParams().extractor().mappingPropertyValue(TIMESTAMP_MAPPING_KEY); + FromClause fromClause = FromClause.create(); fromClause.add(Expressions.stream(siddhiParams.getInputStreamNames().get(0), Expressions.timeWindow(timeWindowSize, toTimeUnit(scale)))); SelectClause selectClause = SelectClause.create( - Expressions.as(Expressions.property("currentTimeMillis()"), "timestamp"), + Expressions.as(Expressions.property(timestampField), "timestamp"), Expressions.as(Expressions.property(fieldToCount), "value"), Expressions.as(Expressions.count(Expressions.property(fieldToCount)), "count"));
diff --git a/streampipes-extensions/streampipes-processors-filters-siddhi/src/main/resources/org.apache.streampipes.processors.siddhi.count/strings.en b/streampipes-extensions/streampipes-processors-filters-siddhi/src/main/resources/org.apache.streampipes.processors.siddhi.count/strings.en index ce1c093..e5e690a 100644 --- a/streampipes-extensions/streampipes-processors-filters-siddhi/src/main/resources/org.apache.streampipes.processors.siddhi.count/strings.en +++ b/streampipes-extensions/streampipes-processors-filters-siddhi/src/main/resources/org.apache.streampipes.processors.siddhi.count/strings.en
@@ -9,3 +9,6 @@ scale.title=Time Window Scale scale.description= + +timestamp-mapping.title=Timestamp Field +timestamp-mapping.description=The value which contains a timestamp \ No newline at end of file
diff --git a/streampipes-extensions/streampipes-processors-geo-flink/Dockerfile b/streampipes-extensions/streampipes-processors-geo-flink/Dockerfile deleted file mode 100644 index ab39bee..0000000 --- a/streampipes-extensions/streampipes-processors-geo-flink/Dockerfile +++ /dev/null
@@ -1,25 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=adoptopenjdk/openjdk8-openj9:alpine -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY target/streampipes-processors-geo-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-geo-flink/aarch64.Dockerfile b/streampipes-extensions/streampipes-processors-geo-flink/aarch64.Dockerfile deleted file mode 100644 index f26c8d2..0000000 --- a/streampipes-extensions/streampipes-processors-geo-flink/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-processors-geo-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-geo-flink/arm.Dockerfile b/streampipes-extensions/streampipes-processors-geo-flink/arm.Dockerfile deleted file mode 100644 index 3730ca5..0000000 --- a/streampipes-extensions/streampipes-processors-geo-flink/arm.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-processors-geo-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-geo-flink/development/env b/streampipes-extensions/streampipes-processors-geo-flink/development/env deleted file mode 100644 index 4dfff09..0000000 --- a/streampipes-extensions/streampipes-processors-geo-flink/development/env +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Those parameters are used by IntelliJ to set the default consul parameters for development -SP_PORT=6025 -SP_HOST=host.docker.internal -SP_DEBUG=true -SP_FLINK_DEBUG=true
diff --git a/streampipes-extensions/streampipes-processors-geo-flink/pom.xml b/streampipes-extensions/streampipes-processors-geo-flink/pom.xml index 1a09e5a..d0fc406 100644 --- a/streampipes-extensions/streampipes-processors-geo-flink/pom.xml +++ b/streampipes-extensions/streampipes-processors-geo-flink/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -36,12 +36,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-flink</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> </dependencies>
diff --git a/streampipes-extensions/streampipes-processors-geo-jvm/Dockerfile b/streampipes-extensions/streampipes-processors-geo-jvm/Dockerfile deleted file mode 100644 index e66211b..0000000 --- a/streampipes-extensions/streampipes-processors-geo-jvm/Dockerfile +++ /dev/null
@@ -1,25 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=adoptopenjdk/openjdk8-openj9:alpine -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY target/streampipes-processors-geo-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-geo-jvm/aarch64.Dockerfile b/streampipes-extensions/streampipes-processors-geo-jvm/aarch64.Dockerfile deleted file mode 100644 index 9a33a1b..0000000 --- a/streampipes-extensions/streampipes-processors-geo-jvm/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-processors-geo-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-geo-jvm/arm.Dockerfile b/streampipes-extensions/streampipes-processors-geo-jvm/arm.Dockerfile deleted file mode 100644 index fc2707c..0000000 --- a/streampipes-extensions/streampipes-processors-geo-jvm/arm.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-processors-geo-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-geo-jvm/development/env b/streampipes-extensions/streampipes-processors-geo-jvm/development/env deleted file mode 100644 index 3e9e217..0000000 --- a/streampipes-extensions/streampipes-processors-geo-jvm/development/env +++ /dev/null
@@ -1,19 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Those parameters are used by IntelliJ to set the default consul parameters for development -SP_PORT=8005 -SP_HOST=172.17.0.1 -SP_DEBUG=true
diff --git a/streampipes-extensions/streampipes-processors-geo-jvm/pom.xml b/streampipes-extensions/streampipes-processors-geo-jvm/pom.xml index 861e1d9..19c70e4 100644 --- a/streampipes-extensions/streampipes-processors-geo-jvm/pom.xml +++ b/streampipes-extensions/streampipes-processors-geo-jvm/pom.xml
@@ -21,32 +21,28 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>streampipes-processors-geo-jvm</artifactId> - <properties> - <maven.deploy.skip>true</maven.deploy.skip> - </properties> - <dependencies> <!-- StreamPipes dependencies --> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-config</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-standalone</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies --> @@ -69,38 +65,4 @@ <version>1.16.1</version> </dependency> </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>jar</goal> - </goals> - <phase>package</phase> - <configuration> - <classifier>embed</classifier> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-maven-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>repackage</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - <finalName>streampipes-processors-geo-jvm</finalName> - - </build> - </project>
diff --git a/streampipes-extensions/streampipes-processors-geo-jvm/src/main/java/org/apache/streampipes/processors/geo/jvm/GeoJvmInit.java b/streampipes-extensions/streampipes-processors-geo-jvm/src/main/java/org/apache/streampipes/processors/geo/jvm/GeoJvmInit.java index 2d86d13..9498870 100644 --- a/streampipes-extensions/streampipes-processors-geo-jvm/src/main/java/org/apache/streampipes/processors/geo/jvm/GeoJvmInit.java +++ b/streampipes-extensions/streampipes-processors-geo-jvm/src/main/java/org/apache/streampipes/processors/geo/jvm/GeoJvmInit.java
@@ -41,10 +41,6 @@ public class GeoJvmInit extends StandaloneModelSubmitter { - public static void main(String[] args) { - new GeoJvmInit().init(); - } - @Override public SpServiceDefinition provideServiceDefinition() { return SpServiceDefinitionBuilder.create("org.apache.streampipes.processors.geo.jvm",
diff --git a/streampipes-extensions/streampipes-processors-image-processing-jvm/aarch64.Dockerfile b/streampipes-extensions/streampipes-processors-image-processing-jvm/aarch64.Dockerfile deleted file mode 100644 index 3659bbc..0000000 --- a/streampipes-extensions/streampipes-processors-image-processing-jvm/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-processors-image-processing-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-image-processing-jvm/arm.Dockerfile b/streampipes-extensions/streampipes-processors-image-processing-jvm/arm.Dockerfile deleted file mode 100644 index 14917a2..0000000 --- a/streampipes-extensions/streampipes-processors-image-processing-jvm/arm.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-processors-image-processing-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-image-processing-jvm/development/env b/streampipes-extensions/streampipes-processors-image-processing-jvm/development/env deleted file mode 100644 index 3e5fb41..0000000 --- a/streampipes-extensions/streampipes-processors-image-processing-jvm/development/env +++ /dev/null
@@ -1,19 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Those parameters are used by IntelliJ to set the default consul parameters for development -SP_PORT=6035 -SP_HOST=host.docker.internal -SP_DEBUG=true
diff --git a/streampipes-extensions/streampipes-processors-image-processing-jvm/pom.xml b/streampipes-extensions/streampipes-processors-image-processing-jvm/pom.xml index 6332393..e160301 100644 --- a/streampipes-extensions/streampipes-processors-image-processing-jvm/pom.xml +++ b/streampipes-extensions/streampipes-processors-image-processing-jvm/pom.xml
@@ -21,27 +21,23 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>streampipes-processors-image-processing-jvm</artifactId> - <properties> - <maven.deploy.skip>true</maven.deploy.skip> - </properties> - <dependencies> <!-- StreamPipes dependencies --> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-standalone</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies --> @@ -56,37 +52,4 @@ <artifactId>ddogleg</artifactId> </dependency> </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>jar</goal> - </goals> - <phase>package</phase> - <configuration> - <classifier>embed</classifier> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-maven-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>repackage</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - <finalName>streampipes-processors-image-processing-jvm</finalName> - </build> - </project>
diff --git a/streampipes-extensions/streampipes-processors-image-processing-jvm/src/main/java/org/apache/streampipes/processors/imageprocessing/jvm/ImageProcessingJvmInit.java b/streampipes-extensions/streampipes-processors-image-processing-jvm/src/main/java/org/apache/streampipes/processors/imageprocessing/jvm/ImageProcessingJvmInit.java index 0f0c136..22f9897 100644 --- a/streampipes-extensions/streampipes-processors-image-processing-jvm/src/main/java/org/apache/streampipes/processors/imageprocessing/jvm/ImageProcessingJvmInit.java +++ b/streampipes-extensions/streampipes-processors-image-processing-jvm/src/main/java/org/apache/streampipes/processors/imageprocessing/jvm/ImageProcessingJvmInit.java
@@ -35,10 +35,6 @@ public class ImageProcessingJvmInit extends StandaloneModelSubmitter { - public static void main(String[] args) { - new ImageProcessingJvmInit().init(); - } - @Override public SpServiceDefinition provideServiceDefinition() { return SpServiceDefinitionBuilder.create("org.apache.streampipes.processors.imageprocessing.jvm",
diff --git a/streampipes-extensions/streampipes-processors-pattern-detection-flink/Dockerfile b/streampipes-extensions/streampipes-processors-pattern-detection-flink/Dockerfile deleted file mode 100644 index 600ef8b..0000000 --- a/streampipes-extensions/streampipes-processors-pattern-detection-flink/Dockerfile +++ /dev/null
@@ -1,25 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=adoptopenjdk/openjdk8-openj9:alpine -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY target/streampipes-processors-pattern-detection-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-pattern-detection-flink/aarch64.Dockerfile b/streampipes-extensions/streampipes-processors-pattern-detection-flink/aarch64.Dockerfile deleted file mode 100644 index f5ac542..0000000 --- a/streampipes-extensions/streampipes-processors-pattern-detection-flink/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-processors-pattern-detection-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-pattern-detection-flink/arm.Dockerfile b/streampipes-extensions/streampipes-processors-pattern-detection-flink/arm.Dockerfile deleted file mode 100644 index 144c755..0000000 --- a/streampipes-extensions/streampipes-processors-pattern-detection-flink/arm.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-processors-pattern-detection-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-pattern-detection-flink/development/env b/streampipes-extensions/streampipes-processors-pattern-detection-flink/development/env deleted file mode 100644 index 7350282..0000000 --- a/streampipes-extensions/streampipes-processors-pattern-detection-flink/development/env +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Those parameters are used by IntelliJ to set the default consul parameters for development -SP_PORT=6040 -SP_HOST=host.docker.internal -SP_DEBUG=true -SP_FLINK_DEBUG=true
diff --git a/streampipes-extensions/streampipes-processors-pattern-detection-flink/pom.xml b/streampipes-extensions/streampipes-processors-pattern-detection-flink/pom.xml index f6c5b77..f917cf3 100644 --- a/streampipes-extensions/streampipes-processors-pattern-detection-flink/pom.xml +++ b/streampipes-extensions/streampipes-processors-pattern-detection-flink/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -37,12 +37,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-flink</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>log4j</groupId> @@ -112,7 +112,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-test-utils</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <scope>test</scope> </dependency> </dependencies> @@ -157,5 +157,4 @@ </plugins> <finalName>streampipes-processors-pattern-detection-flink</finalName> </build> - </project>
diff --git a/streampipes-extensions/streampipes-processors-statistics-flink/Dockerfile b/streampipes-extensions/streampipes-processors-statistics-flink/Dockerfile deleted file mode 100644 index f2fcb8e..0000000 --- a/streampipes-extensions/streampipes-processors-statistics-flink/Dockerfile +++ /dev/null
@@ -1,25 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=adoptopenjdk/openjdk8-openj9:alpine -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY target/streampipes-processors-statistics-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-statistics-flink/aarch64.Dockerfile b/streampipes-extensions/streampipes-processors-statistics-flink/aarch64.Dockerfile deleted file mode 100644 index 6fca3bf..0000000 --- a/streampipes-extensions/streampipes-processors-statistics-flink/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-processors-statistics-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-statistics-flink/arm.Dockerfile b/streampipes-extensions/streampipes-processors-statistics-flink/arm.Dockerfile deleted file mode 100644 index 4fe36a0..0000000 --- a/streampipes-extensions/streampipes-processors-statistics-flink/arm.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-processors-statistics-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-statistics-flink/development/.env b/streampipes-extensions/streampipes-processors-statistics-flink/development/.env deleted file mode 100644 index e5c610f..0000000 --- a/streampipes-extensions/streampipes-processors-statistics-flink/development/.env +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Those parameters are used by IntelliJ to set the default consul parameters for development -SP_PORT=6045 -SP_HOST=host.docker.internal -SP_DEBUG=true -SP_FLINK_DEBUG=true
diff --git a/streampipes-extensions/streampipes-processors-statistics-flink/pom.xml b/streampipes-extensions/streampipes-processors-statistics-flink/pom.xml index 5147355..c984827 100644 --- a/streampipes-extensions/streampipes-processors-statistics-flink/pom.xml +++ b/streampipes-extensions/streampipes-processors-statistics-flink/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -36,12 +36,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-flink</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-extensions/streampipes-processors-text-mining-flink/development/env b/streampipes-extensions/streampipes-processors-text-mining-flink/development/env deleted file mode 100644 index 3e94b17..0000000 --- a/streampipes-extensions/streampipes-processors-text-mining-flink/development/env +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Those parameters are used by IntelliJ to set the default consul parameters for development -SP_PORT=6050 -SP_HOST=host.docker.internal -SP_DEBUG=true -SP_FLINK_DEBUG=true
diff --git a/streampipes-extensions/streampipes-processors-text-mining-flink/pom.xml b/streampipes-extensions/streampipes-processors-text-mining-flink/pom.xml index bd95858..3411d6e 100644 --- a/streampipes-extensions/streampipes-processors-text-mining-flink/pom.xml +++ b/streampipes-extensions/streampipes-processors-text-mining-flink/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -36,12 +36,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-flink</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies --> @@ -89,7 +89,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-test-utils</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <scope>test</scope> </dependency> <dependency>
diff --git a/streampipes-extensions/streampipes-processors-text-mining-jvm/Dockerfile b/streampipes-extensions/streampipes-processors-text-mining-jvm/Dockerfile deleted file mode 100644 index 4a0eed6..0000000 --- a/streampipes-extensions/streampipes-processors-text-mining-jvm/Dockerfile +++ /dev/null
@@ -1,25 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=adoptopenjdk/openjdk8-openj9:alpine -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY target/streampipes-processors-text-mining-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-text-mining-jvm/aarch64.Dockerfile b/streampipes-extensions/streampipes-processors-text-mining-jvm/aarch64.Dockerfile deleted file mode 100644 index 302c873..0000000 --- a/streampipes-extensions/streampipes-processors-text-mining-jvm/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-processors-text-mining-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-text-mining-jvm/arm.Dockerfile b/streampipes-extensions/streampipes-processors-text-mining-jvm/arm.Dockerfile deleted file mode 100644 index 3e110c7..0000000 --- a/streampipes-extensions/streampipes-processors-text-mining-jvm/arm.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-processors-text-mining-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-text-mining-jvm/development/env b/streampipes-extensions/streampipes-processors-text-mining-jvm/development/env deleted file mode 100644 index fbb93b2..0000000 --- a/streampipes-extensions/streampipes-processors-text-mining-jvm/development/env +++ /dev/null
@@ -1,19 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Those parameters are used by IntelliJ to set the default consul parameters for development -SP_PORT=6065 -SP_HOST=host.docker.internal -SP_DEBUG=true
diff --git a/streampipes-extensions/streampipes-processors-text-mining-jvm/pom.xml b/streampipes-extensions/streampipes-processors-text-mining-jvm/pom.xml index f021fe0..8afccf5 100644 --- a/streampipes-extensions/streampipes-processors-text-mining-jvm/pom.xml +++ b/streampipes-extensions/streampipes-processors-text-mining-jvm/pom.xml
@@ -21,27 +21,23 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>streampipes-processors-text-mining-jvm</artifactId> - <properties> - <maven.deploy.skip>true</maven.deploy.skip> - </properties> - <dependencies> <!-- StreamPipes dependencies --> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-standalone</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies --> @@ -52,39 +48,8 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging-mqtt</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> </dependencies> - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>jar</goal> - </goals> - <phase>package</phase> - <configuration> - <classifier>embed</classifier> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-maven-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>repackage</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - <finalName>streampipes-processors-text-mining-jvm</finalName> - </build> </project>
diff --git a/streampipes-extensions/streampipes-processors-transformation-flink/Dockerfile b/streampipes-extensions/streampipes-processors-transformation-flink/Dockerfile deleted file mode 100644 index cbe76f3..0000000 --- a/streampipes-extensions/streampipes-processors-transformation-flink/Dockerfile +++ /dev/null
@@ -1,25 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=adoptopenjdk/openjdk8-openj9:alpine -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY target/streampipes-processors-transformation-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-transformation-flink/aarch64.Dockerfile b/streampipes-extensions/streampipes-processors-transformation-flink/aarch64.Dockerfile deleted file mode 100644 index 1eb794c..0000000 --- a/streampipes-extensions/streampipes-processors-transformation-flink/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-processors-transformation-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-transformation-flink/arm.Dockerfile b/streampipes-extensions/streampipes-processors-transformation-flink/arm.Dockerfile deleted file mode 100644 index f92454a..0000000 --- a/streampipes-extensions/streampipes-processors-transformation-flink/arm.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-processors-transformation-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-transformation-flink/development/env b/streampipes-extensions/streampipes-processors-transformation-flink/development/env deleted file mode 100644 index dc98a5d..0000000 --- a/streampipes-extensions/streampipes-processors-transformation-flink/development/env +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Those parameters are used by IntelliJ to set the default consul parameters for development -SP_PORT=6055 -SP_HOST=localhost -SP_FLINK_DEBUG=true -SP_DEBUG=true
diff --git a/streampipes-extensions/streampipes-processors-transformation-flink/pom.xml b/streampipes-extensions/streampipes-processors-transformation-flink/pom.xml index a4b4d59..a16d662 100644 --- a/streampipes-extensions/streampipes-processors-transformation-flink/pom.xml +++ b/streampipes-extensions/streampipes-processors-transformation-flink/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -36,17 +36,17 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-measurement-units</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-flink</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies --> @@ -82,7 +82,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-test-utils</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <scope>test</scope> </dependency> <dependency> @@ -132,5 +132,4 @@ </plugins> <finalName>streampipes-processors-transformation-flink</finalName> </build> - </project>
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/Dockerfile b/streampipes-extensions/streampipes-processors-transformation-jvm/Dockerfile deleted file mode 100644 index 55c3d34..0000000 --- a/streampipes-extensions/streampipes-processors-transformation-jvm/Dockerfile +++ /dev/null
@@ -1,25 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=adoptopenjdk/openjdk8-openj9:alpine -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY target/streampipes-processors-transformation-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/aarch64.Dockerfile b/streampipes-extensions/streampipes-processors-transformation-jvm/aarch64.Dockerfile deleted file mode 100644 index cde1ab7..0000000 --- a/streampipes-extensions/streampipes-processors-transformation-jvm/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-processors-transformation-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/arm.Dockerfile b/streampipes-extensions/streampipes-processors-transformation-jvm/arm.Dockerfile deleted file mode 100644 index 6f7f281..0000000 --- a/streampipes-extensions/streampipes-processors-transformation-jvm/arm.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-processors-transformation-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/development/env b/streampipes-extensions/streampipes-processors-transformation-jvm/development/env deleted file mode 100644 index 10821f4..0000000 --- a/streampipes-extensions/streampipes-processors-transformation-jvm/development/env +++ /dev/null
@@ -1,18 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -SP_PORT=6060 -SP_HOST=localhost -SP_DEBUG=true
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/pom.xml b/streampipes-extensions/streampipes-processors-transformation-jvm/pom.xml index 37f754e..db7e924 100644 --- a/streampipes-extensions/streampipes-processors-transformation-jvm/pom.xml +++ b/streampipes-extensions/streampipes-processors-transformation-jvm/pom.xml
@@ -21,16 +21,12 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>streampipes-processors-transformation-jvm</artifactId> - <properties> - <maven.deploy.skip>true</maven.deploy.skip> - </properties> - <dependencies> <!-- External dependencies --> <dependency> @@ -44,48 +40,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-standalone</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>jar</goal> - </goals> - <phase>package</phase> - <configuration> - <classifier>embed</classifier> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-maven-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>repackage</goal> - </goals> - <configuration> - <mainClass>org.apache.streampipes.processors.transformation.jvm.TransformationJvmInit</mainClass> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - <finalName>streampipes-processors-transformation-jvm</finalName> - - </build> </project>
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/TransformationJvmInit.java b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/TransformationJvmInit.java index a7d637d..f50421b 100644 --- a/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/TransformationJvmInit.java +++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/TransformationJvmInit.java
@@ -39,6 +39,9 @@ import org.apache.streampipes.processors.transformation.jvm.processor.booloperator.timer.BooleanTimerController; import org.apache.streampipes.processors.transformation.jvm.processor.csvmetadata.CsvMetadataEnrichmentController; import org.apache.streampipes.processors.transformation.jvm.processor.fieldrename.FiledRenameProcessor; +import org.apache.streampipes.processors.transformation.jvm.processor.hasher.FieldHasherProcessor; +import org.apache.streampipes.processors.transformation.jvm.processor.mapper.FieldMapperProcessor; +import org.apache.streampipes.processors.transformation.jvm.processor.measurementconverter.MeasurementUnitConverterProcessor; import org.apache.streampipes.processors.transformation.jvm.processor.state.labeler.number.NumberLabelerController; import org.apache.streampipes.processors.transformation.jvm.processor.stringoperator.counter.StringCounterController; import org.apache.streampipes.processors.transformation.jvm.processor.stringoperator.state.StringToStateController; @@ -72,6 +75,9 @@ new BooleanTimekeepingController(), new BooleanTimerController(), new CsvMetadataEnrichmentController(), + new FieldHasherProcessor(), + new FieldMapperProcessor(), + new MeasurementUnitConverterProcessor(), new TaskDurationController(), new TransformToBooleanController(), new StringTimerController(),
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/hasher/FieldHasherProcessor.java b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/hasher/FieldHasherProcessor.java new file mode 100644 index 0000000..e13decd --- /dev/null +++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/hasher/FieldHasherProcessor.java
@@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.processors.transformation.jvm.processor.hasher; + +import org.apache.streampipes.commons.exceptions.SpRuntimeException; +import org.apache.streampipes.model.graph.DataProcessorDescription; +import org.apache.streampipes.model.runtime.Event; +import org.apache.streampipes.model.schema.PropertyScope; +import org.apache.streampipes.processors.transformation.jvm.processor.hasher.algorithm.HashAlgorithm; +import org.apache.streampipes.processors.transformation.jvm.processor.hasher.algorithm.HashAlgorithmType; +import org.apache.streampipes.sdk.builder.ProcessingElementBuilder; +import org.apache.streampipes.sdk.builder.StreamRequirementsBuilder; +import org.apache.streampipes.sdk.helpers.*; +import org.apache.streampipes.sdk.utils.Assets; +import org.apache.streampipes.wrapper.context.EventProcessorRuntimeContext; +import org.apache.streampipes.wrapper.routing.SpOutputCollector; +import org.apache.streampipes.wrapper.standalone.ProcessorParams; +import org.apache.streampipes.wrapper.standalone.StreamPipesDataProcessor; + +public class FieldHasherProcessor extends StreamPipesDataProcessor { + + private static final String HASH_PROPERTIES = "property-mapping"; + private static final String HASH_ALGORITHM = "hash-algorithm"; + + private String propertyName; + private HashAlgorithm hashAlgorithm; + + @Override + public DataProcessorDescription declareModel() { + return ProcessingElementBuilder.create("org.apache.streampipes.processors.transformation.jvm.fieldhasher") + .withLocales(Locales.EN) + .withAssets(Assets.DOCUMENTATION, Assets.ICON) + .requiredStream(StreamRequirementsBuilder + .create() + .requiredPropertyWithUnaryMapping(EpRequirements.stringReq(), Labels.withId + (HASH_PROPERTIES), PropertyScope.NONE) + .build()) + .requiredSingleValueSelection(Labels.withId(HASH_ALGORITHM), + Options.from("SHA1", "SHA2", "MD5")) + .outputStrategy(OutputStrategies.keep()) + .build(); + } + + @Override + public void onInvocation(ProcessorParams parameters, + SpOutputCollector spOutputCollector, + EventProcessorRuntimeContext runtimeContext) throws SpRuntimeException { + var extractor = parameters.extractor(); + this.propertyName = extractor.mappingPropertyValue(HASH_PROPERTIES); + + this.hashAlgorithm = HashAlgorithmType.valueOf(extractor.selectedSingleValue(HASH_ALGORITHM, String.class)).hashAlgorithm(); + } + + @Override + public void onEvent(Event in, SpOutputCollector out) throws SpRuntimeException { + in.updateFieldBySelector(propertyName, + hashAlgorithm.toHashValue(in.getFieldBySelector(propertyName).getAsPrimitive().getAsString())); + out.collect(in); + } + + @Override + public void onDetach() throws SpRuntimeException { + + } +}
diff --git a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/Operation.java b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/hasher/algorithm/HashAlgorithm.java similarity index 81% copy from streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/Operation.java copy to streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/hasher/algorithm/HashAlgorithm.java index e9cd593..5ee1162 100644 --- a/streampipes-extensions/streampipes-processors-enricher-flink/src/main/java/org/apache/streampipes/processors/enricher/flink/processor/math/operation/Operation.java +++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/hasher/algorithm/HashAlgorithm.java
@@ -16,11 +16,11 @@ * */ -package org.apache.streampipes.processors.enricher.flink.processor.math.operation; +package org.apache.streampipes.processors.transformation.jvm.processor.hasher.algorithm; import java.io.Serializable; -public interface Operation extends Serializable { +public interface HashAlgorithm extends Serializable { - Double operate(Double valLeft, Double valRight); + String toHashValue(Object value); }
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/hasher/algorithm/HashAlgorithmType.java similarity index 65% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/hasher/algorithm/HashAlgorithmType.java index 58ba04b..943aa40 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/hasher/algorithm/HashAlgorithmType.java
@@ -16,3 +16,18 @@ * */ +package org.apache.streampipes.processors.transformation.jvm.processor.hasher.algorithm; + +public enum HashAlgorithmType { + MD5(new Md5HashAlgorithm()), SHA1(new Sha1HashAlgorithm()), SHA2(new Sha2HashAlgorithm()); + + private HashAlgorithm hashAlgorithm; + + HashAlgorithmType(HashAlgorithm hashAlgorithm) { + this.hashAlgorithm = hashAlgorithm; + } + + public HashAlgorithm hashAlgorithm() { + return hashAlgorithm; + } +}
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/hasher/algorithm/Md5HashAlgorithm.java similarity index 68% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/hasher/algorithm/Md5HashAlgorithm.java index 58ba04b..96accec 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/hasher/algorithm/Md5HashAlgorithm.java
@@ -16,3 +16,17 @@ * */ +package org.apache.streampipes.processors.transformation.jvm.processor.hasher.algorithm; + +import org.apache.commons.codec.digest.DigestUtils; + +public class Md5HashAlgorithm implements HashAlgorithm { + + private static final long serialVersionUID = 1L; + + @Override + public String toHashValue(Object value) { + return DigestUtils.md5Hex(String.valueOf(value)); + } + +}
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/hasher/algorithm/Sha1HashAlgorithm.java similarity index 68% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/hasher/algorithm/Sha1HashAlgorithm.java index 58ba04b..2eb3997 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/hasher/algorithm/Sha1HashAlgorithm.java
@@ -16,3 +16,17 @@ * */ +package org.apache.streampipes.processors.transformation.jvm.processor.hasher.algorithm; + +import org.apache.commons.codec.digest.DigestUtils; + +public class Sha1HashAlgorithm implements HashAlgorithm { + + private static final long serialVersionUID = 1L; + + @Override + public String toHashValue(Object value) { + return DigestUtils.shaHex(String.valueOf(value)); + } + +}
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.scss b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/hasher/algorithm/Sha2HashAlgorithm.java similarity index 68% copy from ui/src/app/pipeline-details/pipeline-details.component.scss copy to streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/hasher/algorithm/Sha2HashAlgorithm.java index a375af7..7cfef6e 100644 --- a/ui/src/app/pipeline-details/pipeline-details.component.scss +++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/hasher/algorithm/Sha2HashAlgorithm.java
@@ -16,7 +16,17 @@ * */ -.md-padding { - padding: 10px; -} +package org.apache.streampipes.processors.transformation.jvm.processor.hasher.algorithm; +import org.apache.commons.codec.digest.DigestUtils; + +public class Sha2HashAlgorithm implements HashAlgorithm { + + private static final long serialVersionUID = 1L; + + @Override + public String toHashValue(Object value) { + return DigestUtils.sha256Hex(String.valueOf(value)); + } + +}
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/mapper/FieldMapperProcessor.java b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/mapper/FieldMapperProcessor.java new file mode 100644 index 0000000..48c49c4 --- /dev/null +++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/mapper/FieldMapperProcessor.java
@@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.processors.transformation.jvm.processor.mapper; + +import org.apache.streampipes.commons.exceptions.SpRuntimeException; +import org.apache.streampipes.container.api.ResolvesContainerProvidedOutputStrategy; +import org.apache.streampipes.model.graph.DataProcessorDescription; +import org.apache.streampipes.model.graph.DataProcessorInvocation; +import org.apache.streampipes.model.runtime.Event; +import org.apache.streampipes.model.schema.EventProperty; +import org.apache.streampipes.model.schema.EventPropertyPrimitive; +import org.apache.streampipes.model.schema.EventSchema; +import org.apache.streampipes.model.schema.PropertyScope; +import org.apache.streampipes.processors.transformation.jvm.processor.hasher.algorithm.HashAlgorithmType; +import org.apache.streampipes.sdk.builder.PrimitivePropertyBuilder; +import org.apache.streampipes.sdk.builder.ProcessingElementBuilder; +import org.apache.streampipes.sdk.builder.StreamRequirementsBuilder; +import org.apache.streampipes.sdk.extractor.ProcessingElementParameterExtractor; +import org.apache.streampipes.sdk.helpers.EpRequirements; +import org.apache.streampipes.sdk.helpers.Labels; +import org.apache.streampipes.sdk.helpers.Locales; +import org.apache.streampipes.sdk.helpers.OutputStrategies; +import org.apache.streampipes.sdk.utils.Assets; +import org.apache.streampipes.sdk.utils.Datatypes; +import org.apache.streampipes.wrapper.context.EventProcessorRuntimeContext; +import org.apache.streampipes.wrapper.routing.SpOutputCollector; +import org.apache.streampipes.wrapper.standalone.ProcessorParams; +import org.apache.streampipes.wrapper.standalone.StreamPipesDataProcessor; + +import java.util.List; +import java.util.stream.Collectors; + +public class FieldMapperProcessor extends StreamPipesDataProcessor implements ResolvesContainerProvidedOutputStrategy<DataProcessorInvocation, ProcessingElementParameterExtractor> { + + private static final String REPLACE_PROPERTIES = "replaceProperties"; + private static final String FIELD_NAME = "fieldName"; + + private List<String> replacePropertyNames; + private String newFieldName; + + @Override + public DataProcessorDescription declareModel() { + return ProcessingElementBuilder.create("org.apache.streampipes.processors.transformation.jvm.field-mapper") + .withLocales(Locales.EN) + .withAssets(Assets.DOCUMENTATION, Assets.ICON) + .requiredStream(StreamRequirementsBuilder + .create() + .requiredPropertyWithNaryMapping(EpRequirements.anyProperty(), Labels.withId + (REPLACE_PROPERTIES), PropertyScope.NONE) + .build()) + .requiredTextParameter(Labels.withId(FIELD_NAME)) + .outputStrategy(OutputStrategies.customTransformation()) + .build(); + } + + @Override + public void onInvocation(ProcessorParams parameters, + SpOutputCollector spOutputCollector, + EventProcessorRuntimeContext runtimeContext) throws SpRuntimeException { + var extractor = parameters.extractor(); + this.replacePropertyNames = extractor.mappingPropertyValues(REPLACE_PROPERTIES); + this.newFieldName = extractor.singleValueParameter(FIELD_NAME, String.class); + } + + @Override + public void onEvent(Event in, SpOutputCollector out) throws SpRuntimeException { + Event event = new Event(); + StringBuilder hashValue = new StringBuilder(); + List<String> keys = in.getFields().keySet().stream().sorted().collect(Collectors.toList()); + for (String key : keys) { + if (replacePropertyNames.stream().noneMatch(r -> r.equals(key))) { + event.addField(in.getFieldBySelector(key)); + } else { + hashValue.append(in.getFieldBySelector((key)).getAsPrimitive().getAsString()); + } + } + + event.addField(newFieldName, HashAlgorithmType.MD5.hashAlgorithm().toHashValue(hashValue + .toString + ())); + out.collect(event); + } + + @Override + public void onDetach() throws SpRuntimeException { + + } + + @Override + public EventSchema resolveOutputStrategy(DataProcessorInvocation processingElement, + ProcessingElementParameterExtractor extractor) throws SpRuntimeException { + List<String> replacePropertyNames = extractor.mappingPropertyValues(REPLACE_PROPERTIES); + String newFieldName = extractor.singleValueParameter(FIELD_NAME, String.class); + + List<EventProperty> outProperties = extractor.getNoneInputStreamEventPropertySubset(replacePropertyNames); + + EventPropertyPrimitive newProperty = PrimitivePropertyBuilder.create(Datatypes.String, newFieldName).build(); + outProperties.add(newProperty); + return new EventSchema(outProperties); + } +}
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/measurementconverter/MeasurementUnitConverterProcessor.java b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/measurementconverter/MeasurementUnitConverterProcessor.java new file mode 100644 index 0000000..7090b68 --- /dev/null +++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/measurementconverter/MeasurementUnitConverterProcessor.java
@@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +package org.apache.streampipes.processors.transformation.jvm.processor.measurementconverter; + +import com.github.jqudt.Quantity; +import com.github.jqudt.Unit; +import org.apache.streampipes.commons.exceptions.SpRuntimeException; +import org.apache.streampipes.container.api.ResolvesContainerProvidedOptions; +import org.apache.streampipes.model.graph.DataProcessorDescription; +import org.apache.streampipes.model.runtime.Event; +import org.apache.streampipes.model.schema.EventProperty; +import org.apache.streampipes.model.schema.EventPropertyPrimitive; +import org.apache.streampipes.model.schema.PropertyScope; +import org.apache.streampipes.model.staticproperty.Option; +import org.apache.streampipes.model.staticproperty.RuntimeResolvableOneOfStaticProperty; +import org.apache.streampipes.sdk.builder.ProcessingElementBuilder; +import org.apache.streampipes.sdk.builder.PropertyRequirementsBuilder; +import org.apache.streampipes.sdk.builder.StreamRequirementsBuilder; +import org.apache.streampipes.sdk.extractor.StaticPropertyExtractor; +import org.apache.streampipes.sdk.helpers.Labels; +import org.apache.streampipes.sdk.helpers.Locales; +import org.apache.streampipes.sdk.helpers.OutputStrategies; +import org.apache.streampipes.sdk.helpers.TransformOperations; +import org.apache.streampipes.sdk.utils.Assets; +import org.apache.streampipes.units.UnitProvider; +import org.apache.streampipes.wrapper.context.EventProcessorRuntimeContext; +import org.apache.streampipes.wrapper.routing.SpOutputCollector; +import org.apache.streampipes.wrapper.standalone.ProcessorParams; +import org.apache.streampipes.wrapper.standalone.StreamPipesDataProcessor; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class MeasurementUnitConverterProcessor extends StreamPipesDataProcessor implements ResolvesContainerProvidedOptions { + + private static final String CONVERT_PROPERTY = "convert-property"; + private static final String OUTPUT_UNIT = "output-unit"; + + private Unit inputUnit; + private Unit outputUnit; + + private String convertProperty; + + @Override + public DataProcessorDescription declareModel() { + return ProcessingElementBuilder.create("org.apache.streampipes.processors.transformation.jvm.measurementunitconverter") + .withLocales(Locales.EN) + .withAssets(Assets.DOCUMENTATION, Assets.ICON) + .requiredStream(StreamRequirementsBuilder + .create() + .requiredPropertyWithUnaryMapping(PropertyRequirementsBuilder + .create() + .measurementUnitPresence() + .build(), + Labels.withId(CONVERT_PROPERTY), + PropertyScope.MEASUREMENT_PROPERTY) + .build()) + .requiredSingleValueSelectionFromContainer(Labels.withId(OUTPUT_UNIT)) + .outputStrategy(OutputStrategies.transform(TransformOperations + .dynamicMeasurementUnitTransformation(CONVERT_PROPERTY, OUTPUT_UNIT))) + .build(); + } + + @Override + public void onInvocation(ProcessorParams parameters, SpOutputCollector spOutputCollector, EventProcessorRuntimeContext runtimeContext) throws SpRuntimeException { + var extractor = parameters.extractor(); + + this.convertProperty = extractor.mappingPropertyValue(CONVERT_PROPERTY); + String runtimeName = extractor.getEventPropertyBySelector(this.convertProperty).getRuntimeName(); + String inputUnitId = extractor.measurementUnit(runtimeName, 0); + String outputUnitId = parameters.getGraph().getStaticProperties().stream().filter(sp -> sp + .getInternalName().equals(OUTPUT_UNIT)) + .map(sp -> + (RuntimeResolvableOneOfStaticProperty) sp) + .findFirst() + .get().getOptions() + .stream + ().filter(Option::isSelected).map(Option::getInternalName).findFirst().get(); + + this.inputUnit = UnitProvider.INSTANCE.getUnit(inputUnitId); + this.outputUnit = UnitProvider.INSTANCE.getUnit(outputUnitId); + } + + @Override + public void onEvent(Event in, SpOutputCollector out) throws SpRuntimeException { + double value = in.getFieldBySelector(convertProperty).getAsPrimitive().getAsDouble(); + + // transform old value to new unit + Quantity obs = new Quantity(value, inputUnit); + try { + Double newValue = obs.convertTo(outputUnit).getValue(); + in.updateFieldBySelector(convertProperty, newValue); + out.collect(in); + } catch (IllegalAccessException e) { + throw new SpRuntimeException("Could not convert measurement", e); + } + } + + @Override + public void onDetach() throws SpRuntimeException { + + } + + @Override + public List<Option> resolveOptions(String staticPropertyInternalName, StaticPropertyExtractor parameterExtractor) { + try { + String selector = parameterExtractor.mappingPropertyValue(CONVERT_PROPERTY); + EventProperty linkedEventProperty = parameterExtractor.getEventPropertyBySelector(selector); + if (linkedEventProperty instanceof EventPropertyPrimitive && ((EventPropertyPrimitive) linkedEventProperty) + .getMeasurementUnit() != null) { + Unit measurementUnit = UnitProvider.INSTANCE.getUnit(((EventPropertyPrimitive) linkedEventProperty) + .getMeasurementUnit().toString()); + URI type = measurementUnit.getType(); + List<Unit> availableUnits = UnitProvider.INSTANCE.getUnitsByType(type); + return availableUnits + .stream() + .filter(unit -> !(unit.getResource().toString().equals(measurementUnit.getResource().toString()))) + .map(unit -> new Option(unit.getLabel(), unit.getResource().toString())) + .collect(Collectors.toList()); + } else { + return new ArrayList<>(); + } + } catch (SpRuntimeException e) { + e.printStackTrace(); + return new ArrayList<>(); + } + } +}
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.field-mapper/documentation.md b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.field-mapper/documentation.md new file mode 100644 index 0000000..8babeef --- /dev/null +++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.field-mapper/documentation.md
@@ -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. + ~ + --> + +## Field Mapper + +<p align="center"> + <img src="icon.png" width="150px;" class="pe-image-documentation"/> +</p> + +*** + +## Description + +Replaces one or more fields with a new field and computes a hash value of these fields + +*** + +## Configuration + +* Fields: Fields that will be mapped into a property +* Name of the new field + +*** + +## Example +Merge two fields into a hash value +### Input event +``` +{ + "timestamp":1586380104915, + "mass_flow":4.3167, + "temperature":40.05, + "sensorId":"flowrate01" +} +``` + +### Configuration +* Fields: mass_flow, temperature +* Name of new field: demo + +### Output event +``` +{ + "timestamp":1586380104915, + "sensorId":"flowrate01" + "demo":"8ae11f5c83610104408d485b73120832", +} +``` \ No newline at end of file
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.field-mapper/icon.png b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.field-mapper/icon.png new file mode 100644 index 0000000..2eafc5f --- /dev/null +++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.field-mapper/icon.png Binary files differ
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.field-mapper/strings.en b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.field-mapper/strings.en new file mode 100644 index 0000000..cf570b5 --- /dev/null +++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.field-mapper/strings.en
@@ -0,0 +1,8 @@ +org.apache.streampipes.processors.transformation.jvm.field-mapper.title=Field Mapper +org.apache.streampipes.processors.transformation.jvm.field-mapper.description=Replaces one or more field with a new field and computes a hash value of these fields + +replaceProperties.title=Fields +replaceProperties.description=The fields to replace + +fieldName.title=New Field Name +fieldName.description=The name of the new field
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.fieldhasher/documentation.md b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.fieldhasher/documentation.md new file mode 100644 index 0000000..4049b6d --- /dev/null +++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.fieldhasher/documentation.md
@@ -0,0 +1,48 @@ +<!-- + ~ 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. + ~ + --> + +## Field Hasher + +<p align="center"> + <img src="icon.png" width="150px;" class="pe-image-documentation"/> +</p> + +*** + +## Description + +The Field Hasher uses an algorithm to encode values in a field. The Field Hasher can use MD5, SHA1 or SHA2 to hash field values. + +*** + +## Required input +This processor requires at least one field of type string. + +*** + +## Configuration + +### Field +Specifies the string field that will be encoded. + +### Hash Algorithm +Specifies the algorithm used to encode the string field. The following algorithms +are available: SHA2, MD5 or SHA1. + +## Output +The encoded string field. \ No newline at end of file
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.fieldhasher/icon.png b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.fieldhasher/icon.png new file mode 100644 index 0000000..f9fa3a2 --- /dev/null +++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.fieldhasher/icon.png Binary files differ
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.fieldhasher/strings.en b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.fieldhasher/strings.en new file mode 100644 index 0000000..561f434 --- /dev/null +++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.fieldhasher/strings.en
@@ -0,0 +1,8 @@ +org.apache.streampipes.processors.transformation.jvm.fieldhasher.title=Field Hasher +org.apache.streampipes.processors.transformation.jvm.fieldhasher.description=Hashes the value of a field using various hash functions. + +property-mapping.title=Field +property-mapping.description=The field the hash function should be applied on + +hash-algorithm.title=Hash Algorithm +hash-algorithm.description=The hash algorithm that should be used.
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-event-property-list/edit-event-property-list.component.html b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.measurementunitconverter/documentation.md similarity index 70% rename from ui/src/app/connect/dialog/edit-event-property/components/edit-event-property-list/edit-event-property-list.component.html rename to streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.measurementunitconverter/documentation.md index 92c744b..f9b8e88 100644 --- a/ui/src/app/connect/dialog/edit-event-property/components/edit-event-property-list/edit-event-property-list.component.html +++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.measurementunitconverter/documentation.md
@@ -16,6 +16,32 @@ ~ --> -<sp-edit-data-type - [cachedProperty]= "cachedProperty.eventProperty"> -</sp-edit-data-type> +## Measurement Unit Converter + +<p align="center"> + <img src="icon.png" width="150px;" class="pe-image-documentation"/> +</p> + +*** + +## Description + +Converts a unit of measurement to another one. + +*** + +## Required input + + +*** + +## Configuration + +Describe the configuration parameters here + +### 1st parameter + + +### 2nd parameter + +## Output \ No newline at end of file
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.measurementunitconverter/icon.png b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.measurementunitconverter/icon.png new file mode 100644 index 0000000..ebe9f3a --- /dev/null +++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.measurementunitconverter/icon.png Binary files differ
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.measurementunitconverter/strings.en b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.measurementunitconverter/strings.en new file mode 100644 index 0000000..754f04b --- /dev/null +++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/resources/org.apache.streampipes.processors.transformation.jvm.measurementunitconverter/strings.en
@@ -0,0 +1,8 @@ +org.apache.streampipes.processors.transformation.jvm.measurementunitconverter.title=Measurement Unit Converter +org.apache.streampipes.processors.transformation.jvm.measurementunitconverter.description=Converts a unit of measurement to another one + +convert-property.title=Field +convert-property.description=The field to convert + +output-unit.title=Output Unit +output-unit.description=The output type unit of measurement
diff --git a/streampipes-extensions/streampipes-sinks-brokers-jvm/Dockerfile b/streampipes-extensions/streampipes-sinks-brokers-jvm/Dockerfile deleted file mode 100644 index 630bd7b..0000000 --- a/streampipes-extensions/streampipes-sinks-brokers-jvm/Dockerfile +++ /dev/null
@@ -1,25 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=adoptopenjdk/openjdk8-openj9:alpine -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY target/streampipes-sinks-brokers-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-sinks-brokers-jvm/aarch64.Dockerfile b/streampipes-extensions/streampipes-sinks-brokers-jvm/aarch64.Dockerfile deleted file mode 100644 index 3fc0649..0000000 --- a/streampipes-extensions/streampipes-sinks-brokers-jvm/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-sinks-brokers-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-sinks-brokers-jvm/arm.Dockerfile b/streampipes-extensions/streampipes-sinks-brokers-jvm/arm.Dockerfile deleted file mode 100644 index 9ca1b46..0000000 --- a/streampipes-extensions/streampipes-sinks-brokers-jvm/arm.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-sinks-brokers-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-sinks-brokers-jvm/development/env b/streampipes-extensions/streampipes-sinks-brokers-jvm/development/env deleted file mode 100644 index f191f5a..0000000 --- a/streampipes-extensions/streampipes-sinks-brokers-jvm/development/env +++ /dev/null
@@ -1,19 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Those parameters are used by IntelliJ to set the default consul parameters for development -SP_PORT=7005 -SP_HOST=host.docker.internal -SP_DEBUG=true
diff --git a/streampipes-extensions/streampipes-sinks-brokers-jvm/pom.xml b/streampipes-extensions/streampipes-sinks-brokers-jvm/pom.xml index 1d3d526..9b8ef3e 100644 --- a/streampipes-extensions/streampipes-sinks-brokers-jvm/pom.xml +++ b/streampipes-extensions/streampipes-sinks-brokers-jvm/pom.xml
@@ -21,32 +21,28 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>streampipes-sinks-brokers-jvm</artifactId> - <properties> - <maven.deploy.skip>true</maven.deploy.skip> - </properties> - <dependencies> <!-- StreamPipes dependencies --> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-pipeline-elements-shared</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-standalone</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies --> @@ -106,37 +102,12 @@ <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> + + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <scope>test</scope> + </dependency> </dependencies> - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>jar</goal> - </goals> - <phase>package</phase> - <configuration> - <classifier>embed</classifier> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-maven-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>repackage</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - <finalName>streampipes-sinks-brokers-jvm</finalName> - </build> </project>
diff --git a/streampipes-extensions/streampipes-sinks-brokers-jvm/src/main/java/org/apache/streampipes/sinks/brokers/jvm/BrokersJvmInit.java b/streampipes-extensions/streampipes-sinks-brokers-jvm/src/main/java/org/apache/streampipes/sinks/brokers/jvm/BrokersJvmInit.java index 97dad40..9910a94 100644 --- a/streampipes-extensions/streampipes-sinks-brokers-jvm/src/main/java/org/apache/streampipes/sinks/brokers/jvm/BrokersJvmInit.java +++ b/streampipes-extensions/streampipes-sinks-brokers-jvm/src/main/java/org/apache/streampipes/sinks/brokers/jvm/BrokersJvmInit.java
@@ -33,7 +33,7 @@ import org.apache.streampipes.sinks.brokers.jvm.kafka.KafkaController; import org.apache.streampipes.sinks.brokers.jvm.mqtt.MqttPublisherSink; import org.apache.streampipes.sinks.brokers.jvm.nats.NatsController; -import org.apache.streampipes.sinks.brokers.jvm.pulsar.PulsarController; +import org.apache.streampipes.sinks.brokers.jvm.pulsar.PulsarPublisherSink; import org.apache.streampipes.sinks.brokers.jvm.rabbitmq.RabbitMqController; import org.apache.streampipes.sinks.brokers.jvm.rest.RestController; import org.apache.streampipes.sinks.brokers.jvm.websocket.WebsocketServerSink; @@ -58,7 +58,7 @@ new RabbitMqController(), new MqttPublisherSink(), new WebsocketServerSink(), - new PulsarController(), + new PulsarPublisherSink(), new NatsController()) .registerMessagingFormats( new JsonDataFormatFactory(),
diff --git a/streampipes-extensions/streampipes-sinks-brokers-jvm/src/main/java/org/apache/streampipes/sinks/brokers/jvm/pulsar/Pulsar.java b/streampipes-extensions/streampipes-sinks-brokers-jvm/src/main/java/org/apache/streampipes/sinks/brokers/jvm/pulsar/Pulsar.java deleted file mode 100644 index c51ce93..0000000 --- a/streampipes-extensions/streampipes-sinks-brokers-jvm/src/main/java/org/apache/streampipes/sinks/brokers/jvm/pulsar/Pulsar.java +++ /dev/null
@@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.streampipes.sinks.brokers.jvm.pulsar; - -import org.apache.pulsar.client.api.Producer; -import org.apache.pulsar.client.api.PulsarClient; -import org.apache.pulsar.client.api.PulsarClientException; -import org.apache.streampipes.commons.exceptions.SpRuntimeException; -import org.apache.streampipes.dataformat.SpDataFormatDefinition; -import org.apache.streampipes.dataformat.json.JsonDataFormatDefinition; -import org.apache.streampipes.model.runtime.Event; -import org.apache.streampipes.wrapper.context.EventSinkRuntimeContext; -import org.apache.streampipes.wrapper.runtime.EventSink; - -import java.util.Map; - -public class Pulsar implements EventSink<PulsarParameters> { - - private static final String PulsarScheme = "pulsar://"; - private static final String Colon = ":"; - - private Producer<byte[]> producer; - private PulsarClient pulsarClient; - private SpDataFormatDefinition spDataFormatDefinition; - - public Pulsar() { - this.spDataFormatDefinition = new JsonDataFormatDefinition(); - } - - @Override - public void onInvocation(PulsarParameters params, - EventSinkRuntimeContext eventSinkRuntimeContext) throws SpRuntimeException { - try { - this.pulsarClient = PulsarClient.builder() - .serviceUrl(makePulsarUrl(params.getPulsarHost(), params.getPulsarPort())) - .build(); - - this.producer = this.pulsarClient.newProducer() - .topic(params.getTopic()) - .create(); - } catch (PulsarClientException e) { - throw new SpRuntimeException(e); - } - } - - @Override - public void onEvent(Event event) throws SpRuntimeException { - Map<String, Object> rawMap = event.getRaw(); - byte[] jsonMessage = this.spDataFormatDefinition.fromMap(rawMap); - - try { - this.producer.send(jsonMessage); - } catch (PulsarClientException e) { - throw new SpRuntimeException(e); - } - } - - @Override - public void onDetach() throws SpRuntimeException { - try { - this.pulsarClient.close(); - } catch (PulsarClientException e) { - throw new SpRuntimeException(e); - } - } - - private String makePulsarUrl(String hostname, Integer port) { - return PulsarScheme + hostname + Colon + port; - } -}
diff --git a/streampipes-extensions/streampipes-sinks-brokers-jvm/src/main/java/org/apache/streampipes/sinks/brokers/jvm/pulsar/PulsarController.java b/streampipes-extensions/streampipes-sinks-brokers-jvm/src/main/java/org/apache/streampipes/sinks/brokers/jvm/pulsar/PulsarController.java deleted file mode 100644 index b79458c..0000000 --- a/streampipes-extensions/streampipes-sinks-brokers-jvm/src/main/java/org/apache/streampipes/sinks/brokers/jvm/pulsar/PulsarController.java +++ /dev/null
@@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.streampipes.sinks.brokers.jvm.pulsar; - -import org.apache.streampipes.model.DataSinkType; -import org.apache.streampipes.model.graph.DataSinkDescription; -import org.apache.streampipes.model.graph.DataSinkInvocation; -import org.apache.streampipes.sdk.builder.DataSinkBuilder; -import org.apache.streampipes.sdk.builder.StreamRequirementsBuilder; -import org.apache.streampipes.sdk.extractor.DataSinkParameterExtractor; -import org.apache.streampipes.sdk.helpers.EpRequirements; -import org.apache.streampipes.sdk.helpers.Labels; -import org.apache.streampipes.sdk.helpers.Locales; -import org.apache.streampipes.sdk.utils.Assets; -import org.apache.streampipes.wrapper.standalone.ConfiguredEventSink; -import org.apache.streampipes.wrapper.standalone.declarer.StandaloneEventSinkDeclarer; - -public class PulsarController extends StandaloneEventSinkDeclarer<PulsarParameters> { - - private static final String TOPIC_KEY = "topic"; - private static final String PULSAR_HOST_KEY = "pulsar-host"; - private static final String PULSAR_PORT_KEY = "pulsar-port"; - - @Override - public DataSinkDescription declareModel() { - return DataSinkBuilder.create("org.apache.streampipes.sinks.brokers.jvm.pulsar") - .category(DataSinkType.MESSAGING) - .withLocales(Locales.EN) - .withAssets(Assets.DOCUMENTATION, Assets.ICON) - .requiredStream(StreamRequirementsBuilder - .create() - .requiredProperty(EpRequirements.anyProperty()) - .build()) - .requiredTextParameter(Labels.withId(PULSAR_HOST_KEY)) - .requiredIntegerParameter(Labels.withId(PULSAR_PORT_KEY), 6650) - .requiredTextParameter(Labels.withId(TOPIC_KEY)) - .build(); - } - - @Override - public ConfiguredEventSink<PulsarParameters> onInvocation(DataSinkInvocation graph, - DataSinkParameterExtractor extractor) { - String pulsarHost = extractor.singleValueParameter(PULSAR_HOST_KEY, String.class); - Integer pulsarPort = extractor.singleValueParameter(PULSAR_PORT_KEY, Integer.class); - String topic = extractor.singleValueParameter(TOPIC_KEY, String.class); - - PulsarParameters params = new PulsarParameters(graph, pulsarHost, pulsarPort, topic); - - return new ConfiguredEventSink<>(params, Pulsar::new); - } - - -}
diff --git a/streampipes-extensions/streampipes-sinks-brokers-jvm/src/main/java/org/apache/streampipes/sinks/brokers/jvm/pulsar/PulsarParameters.java b/streampipes-extensions/streampipes-sinks-brokers-jvm/src/main/java/org/apache/streampipes/sinks/brokers/jvm/pulsar/PulsarParameters.java index 82351ee..0accba0 100644 --- a/streampipes-extensions/streampipes-sinks-brokers-jvm/src/main/java/org/apache/streampipes/sinks/brokers/jvm/pulsar/PulsarParameters.java +++ b/streampipes-extensions/streampipes-sinks-brokers-jvm/src/main/java/org/apache/streampipes/sinks/brokers/jvm/pulsar/PulsarParameters.java
@@ -17,21 +17,22 @@ */ package org.apache.streampipes.sinks.brokers.jvm.pulsar; -import org.apache.streampipes.model.graph.DataSinkInvocation; -import org.apache.streampipes.wrapper.params.binding.EventSinkBindingParams; +import org.apache.streampipes.sdk.extractor.DataSinkParameterExtractor; +import org.apache.streampipes.wrapper.standalone.SinkParams; -public class PulsarParameters extends EventSinkBindingParams { +import static org.apache.streampipes.sinks.brokers.jvm.pulsar.PulsarPublisherSink.*; +public class PulsarParameters { private String pulsarHost; private Integer pulsarPort; private String topic; - public PulsarParameters(DataSinkInvocation graph, String pulsarHost, Integer pulsarPort, - String topic) { - super(graph); - this.pulsarHost = pulsarHost; - this.pulsarPort = pulsarPort; - this.topic = topic; + public PulsarParameters(SinkParams parameters) { + DataSinkParameterExtractor extractor = parameters.extractor(); + + this.pulsarHost = extractor.singleValueParameter(PULSAR_HOST_KEY, String.class); + this.pulsarPort = extractor.singleValueParameter(PULSAR_PORT_KEY, Integer.class); + this.topic = extractor.singleValueParameter(TOPIC_KEY, String.class); } public String getPulsarHost() {
diff --git a/streampipes-extensions/streampipes-sinks-brokers-jvm/src/main/java/org/apache/streampipes/sinks/brokers/jvm/pulsar/PulsarPublisherSink.java b/streampipes-extensions/streampipes-sinks-brokers-jvm/src/main/java/org/apache/streampipes/sinks/brokers/jvm/pulsar/PulsarPublisherSink.java new file mode 100644 index 0000000..0eadc54 --- /dev/null +++ b/streampipes-extensions/streampipes-sinks-brokers-jvm/src/main/java/org/apache/streampipes/sinks/brokers/jvm/pulsar/PulsarPublisherSink.java
@@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.streampipes.sinks.brokers.jvm.pulsar; + +import com.google.common.annotations.VisibleForTesting; +import java.util.Map; +import org.apache.pulsar.client.api.ClientBuilder; +import org.apache.pulsar.client.api.Producer; +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.streampipes.commons.exceptions.SpRuntimeException; +import org.apache.streampipes.dataformat.SpDataFormatDefinition; +import org.apache.streampipes.dataformat.json.JsonDataFormatDefinition; +import org.apache.streampipes.model.DataSinkType; +import org.apache.streampipes.model.graph.DataSinkDescription; +import org.apache.streampipes.model.runtime.Event; +import org.apache.streampipes.sdk.builder.DataSinkBuilder; +import org.apache.streampipes.sdk.builder.StreamRequirementsBuilder; +import org.apache.streampipes.sdk.helpers.EpRequirements; +import org.apache.streampipes.sdk.helpers.Labels; +import org.apache.streampipes.sdk.helpers.Locales; +import org.apache.streampipes.sdk.utils.Assets; +import org.apache.streampipes.wrapper.context.EventSinkRuntimeContext; +import org.apache.streampipes.wrapper.standalone.SinkParams; +import org.apache.streampipes.wrapper.standalone.StreamPipesDataSink; + +public class PulsarPublisherSink extends StreamPipesDataSink { + + public static final String TOPIC_KEY = "topic"; + public static final String PULSAR_HOST_KEY = "pulsar-host"; + public static final String PULSAR_PORT_KEY = "pulsar-port"; + private static final String PulsarScheme = "pulsar://"; + private static final String Colon = ":"; + private final ClientBuilder clientBuilder; + private Producer<byte[]> producer; + private PulsarClient pulsarClient; + private SpDataFormatDefinition spDataFormatDefinition; + private PulsarParameters params; + + public PulsarPublisherSink() { + this.clientBuilder = PulsarClient.builder(); + } + + @VisibleForTesting + public PulsarPublisherSink(ClientBuilder pulsarClientBuilder) { + this.clientBuilder = pulsarClientBuilder; + } + + @Override + public DataSinkDescription declareModel() { + return DataSinkBuilder.create("org.apache.streampipes.sinks.brokers.jvm.pulsar") + .category(DataSinkType.MESSAGING) + .withLocales(Locales.EN) + .withAssets(Assets.DOCUMENTATION, Assets.ICON) + .requiredStream(StreamRequirementsBuilder + .create() + .requiredProperty(EpRequirements.anyProperty()) + .build()) + .requiredTextParameter(Labels.withId(PULSAR_HOST_KEY)) + .requiredIntegerParameter(Labels.withId(PULSAR_PORT_KEY), 6650) + .requiredTextParameter(Labels.withId(TOPIC_KEY)) + .build(); + } + + @Override + public void onInvocation(SinkParams parameters, EventSinkRuntimeContext runtimeContext) throws SpRuntimeException { + params = new PulsarParameters(parameters); + + this.spDataFormatDefinition = new JsonDataFormatDefinition(); + try { + this.pulsarClient = clientBuilder.serviceUrl(makePulsarUrl(params.getPulsarHost(), params.getPulsarPort())) + .build(); + + this.producer = this.pulsarClient.newProducer() + .topic(params.getTopic()) + .create(); + } catch (PulsarClientException e) { + throw new SpRuntimeException(e); + } + } + + @Override + public void onEvent(Event event) throws SpRuntimeException { + Map<String, Object> rawMap = event.getRaw(); + byte[] jsonMessage = this.spDataFormatDefinition.fromMap(rawMap); + + try { + this.producer.send(jsonMessage); + } catch (PulsarClientException e) { + throw new SpRuntimeException(e); + } + } + + @Override + public void onDetach() throws SpRuntimeException { + try { + this.pulsarClient.close(); + } catch (PulsarClientException e) { + throw new SpRuntimeException(e); + } + } + + private String makePulsarUrl(String hostname, Integer port) { + return PulsarScheme + hostname + Colon + port; + } +}
diff --git a/streampipes-extensions/streampipes-sinks-brokers-jvm/src/test/java/org/apache/streampipes/sinks/brokers/jvm/pulsar/TestPulsarParameters.java b/streampipes-extensions/streampipes-sinks-brokers-jvm/src/test/java/org/apache/streampipes/sinks/brokers/jvm/pulsar/TestPulsarParameters.java new file mode 100644 index 0000000..aaf4fd2 --- /dev/null +++ b/streampipes-extensions/streampipes-sinks-brokers-jvm/src/test/java/org/apache/streampipes/sinks/brokers/jvm/pulsar/TestPulsarParameters.java
@@ -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. + * + */ +package org.apache.streampipes.sinks.brokers.jvm.pulsar; + +import static org.apache.streampipes.sinks.brokers.jvm.pulsar.PulsarPublisherSink.PULSAR_HOST_KEY; +import static org.apache.streampipes.sinks.brokers.jvm.pulsar.PulsarPublisherSink.PULSAR_PORT_KEY; +import static org.apache.streampipes.sinks.brokers.jvm.pulsar.PulsarPublisherSink.TOPIC_KEY; +import static org.mockito.Mockito.mock; +import org.apache.streampipes.sdk.extractor.DataSinkParameterExtractor; +import org.apache.streampipes.wrapper.standalone.SinkParams; +import org.junit.Assert; +import org.mockito.Mockito; +import org.junit.Test; + +public class TestPulsarParameters { + @Test + public void testInitPulsarParameters() { + String pulsarHost = "localhost"; + Integer pulsarPort = 6650; + String topic = "test"; + + SinkParams params = mock(SinkParams.class); + DataSinkParameterExtractor extractor = mock(DataSinkParameterExtractor.class); + Mockito.when(params.extractor()).thenReturn(extractor); + Mockito.when(extractor.singleValueParameter(PULSAR_HOST_KEY, String.class)).thenReturn(pulsarHost); + Mockito.when(extractor.singleValueParameter(PULSAR_PORT_KEY, Integer.class)).thenReturn(pulsarPort); + Mockito.when(extractor.singleValueParameter(TOPIC_KEY, String.class)).thenReturn(topic); + + PulsarParameters pulsarParameters = new PulsarParameters(params); + + Assert.assertEquals(pulsarHost, pulsarParameters.getPulsarHost()); + Assert.assertEquals(pulsarPort, pulsarParameters.getPulsarPort()); + Assert.assertEquals(topic, pulsarParameters.getTopic()); + } +}
diff --git a/streampipes-extensions/streampipes-sinks-brokers-jvm/src/test/java/org/apache/streampipes/sinks/brokers/jvm/pulsar/TestPulsarPublisherSink.java b/streampipes-extensions/streampipes-sinks-brokers-jvm/src/test/java/org/apache/streampipes/sinks/brokers/jvm/pulsar/TestPulsarPublisherSink.java new file mode 100644 index 0000000..5e15a13 --- /dev/null +++ b/streampipes-extensions/streampipes-sinks-brokers-jvm/src/test/java/org/apache/streampipes/sinks/brokers/jvm/pulsar/TestPulsarPublisherSink.java
@@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.streampipes.sinks.brokers.jvm.pulsar; + +import static org.apache.streampipes.sinks.brokers.jvm.pulsar.PulsarPublisherSink.PULSAR_HOST_KEY; +import static org.apache.streampipes.sinks.brokers.jvm.pulsar.PulsarPublisherSink.PULSAR_PORT_KEY; +import static org.apache.streampipes.sinks.brokers.jvm.pulsar.PulsarPublisherSink.TOPIC_KEY; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashMap; +import java.util.Map; +import org.apache.pulsar.client.api.ClientBuilder; +import org.apache.pulsar.client.api.Producer; +import org.apache.pulsar.client.api.ProducerBuilder; +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.streampipes.model.runtime.Event; +import org.apache.streampipes.sdk.extractor.DataSinkParameterExtractor; +import org.apache.streampipes.wrapper.standalone.SinkParams; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +public class TestPulsarPublisherSink { + @Test + public void testSimpleEventSink() throws PulsarClientException { + String pulsarHost = "localhost"; + Integer pulsarPort = 6650; + String topic = "test"; + + Map<String, Object> rawMap = new HashMap<>(2); + + rawMap.put("key1", "value1"); + rawMap.put("key2", "value2"); + + SinkParams params = mock(SinkParams.class); + DataSinkParameterExtractor extractor = mock(DataSinkParameterExtractor.class); + when(params.extractor()).thenReturn(extractor); + when(extractor.singleValueParameter(PULSAR_HOST_KEY, String.class)).thenReturn(pulsarHost); + when(extractor.singleValueParameter(PULSAR_PORT_KEY, Integer.class)).thenReturn(pulsarPort); + when(extractor.singleValueParameter(TOPIC_KEY, String.class)).thenReturn(topic); + + ClientBuilder clientBuilder = mock(ClientBuilder.class); + PulsarClient pulsarClient = mock(PulsarClient.class); + ProducerBuilder<byte[]> producerBuilder = mock(ProducerBuilder.class); + Producer<byte[]> producer = mock(Producer.class); + when(clientBuilder.serviceUrl(anyString())).thenReturn(clientBuilder); + when(clientBuilder.build()).thenReturn(pulsarClient); + when(pulsarClient.newProducer()).thenReturn(producerBuilder); + when(producerBuilder.topic(topic)).thenReturn(producerBuilder); + when(producerBuilder.create()).thenReturn(producer); + when(producer.send(Mockito.any(byte[].class))).thenAnswer(data -> { + HashMap<String, String> map; + ObjectMapper mapper = new ObjectMapper(); + String json = new String((byte[]) data.getArgument(0)); + map = mapper.readValue(json, new TypeReference<>() { + }); + Assert.assertEquals(map, rawMap); + return null; + }); + + PulsarPublisherSink pulsarPublisherSink = new PulsarPublisherSink(clientBuilder); + + // Test invocation + pulsarPublisherSink.onInvocation(params, null); + + verify(clientBuilder).serviceUrl(String.format("pulsar://%s:%d", pulsarHost, pulsarPort)); + + // Test publish event + Event event = mock(Event.class); + when(event.getRaw()).thenReturn(rawMap); + + pulsarPublisherSink.onEvent(event); + + verify(producer, times(1)).send(Mockito.any(byte[].class)); + } +}
diff --git a/streampipes-extensions/streampipes-sinks-databases-flink/Dockerfile b/streampipes-extensions/streampipes-sinks-databases-flink/Dockerfile deleted file mode 100644 index 2402500..0000000 --- a/streampipes-extensions/streampipes-sinks-databases-flink/Dockerfile +++ /dev/null
@@ -1,25 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=adoptopenjdk/openjdk8-openj9:alpine -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY target/streampipes-sinks-databases-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-sinks-databases-flink/aarch64.Dockerfile b/streampipes-extensions/streampipes-sinks-databases-flink/aarch64.Dockerfile deleted file mode 100644 index e62b5a4..0000000 --- a/streampipes-extensions/streampipes-sinks-databases-flink/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-sinks-databases-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-sinks-databases-flink/arm.Dockerfile b/streampipes-extensions/streampipes-sinks-databases-flink/arm.Dockerfile deleted file mode 100644 index 7b2be61..0000000 --- a/streampipes-extensions/streampipes-sinks-databases-flink/arm.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-sinks-databases-flink.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-sinks-databases-flink/development/env b/streampipes-extensions/streampipes-sinks-databases-flink/development/env deleted file mode 100644 index c84aed9..0000000 --- a/streampipes-extensions/streampipes-sinks-databases-flink/development/env +++ /dev/null
@@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# Those parameters are used by IntelliJ to set the default consul parameters for development -SP_PORT=7010 -SP_HOST=host.docker.internal -SP_DEBUG=true -SP_FLINK_DEBUG=true -SP_ELASTICSEARCH_HOST=localhost
diff --git a/streampipes-extensions/streampipes-sinks-databases-flink/pom.xml b/streampipes-extensions/streampipes-sinks-databases-flink/pom.xml index 24e0d8c..f87c6d6 100644 --- a/streampipes-extensions/streampipes-sinks-databases-flink/pom.xml +++ b/streampipes-extensions/streampipes-sinks-databases-flink/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -36,12 +36,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-flink</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-extensions/streampipes-sinks-databases-jvm/Dockerfile b/streampipes-extensions/streampipes-sinks-databases-jvm/Dockerfile deleted file mode 100644 index 2ab40ee..0000000 --- a/streampipes-extensions/streampipes-sinks-databases-jvm/Dockerfile +++ /dev/null
@@ -1,25 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=adoptopenjdk/openjdk8-openj9:alpine -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY target/streampipes-sinks-databases-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-sinks-databases-jvm/aarch64.Dockerfile b/streampipes-extensions/streampipes-sinks-databases-jvm/aarch64.Dockerfile deleted file mode 100644 index 3da3590..0000000 --- a/streampipes-extensions/streampipes-sinks-databases-jvm/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-sinks-databases-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-sinks-databases-jvm/arm.Dockerfile b/streampipes-extensions/streampipes-sinks-databases-jvm/arm.Dockerfile deleted file mode 100644 index 200b0fe..0000000 --- a/streampipes-extensions/streampipes-sinks-databases-jvm/arm.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-sinks-databases-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-sinks-databases-jvm/development/env b/streampipes-extensions/streampipes-sinks-databases-jvm/development/env deleted file mode 100644 index 6a41c19..0000000 --- a/streampipes-extensions/streampipes-sinks-databases-jvm/development/env +++ /dev/null
@@ -1,19 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Those parameters are used by IntelliJ to set the default consul parameters for development -SP_PORT=7015 -SP_HOST=host.docker.internal -SP_DEBUG=true
diff --git a/streampipes-extensions/streampipes-sinks-databases-jvm/pom.xml b/streampipes-extensions/streampipes-sinks-databases-jvm/pom.xml index 4aa929b..2f4e1e4 100644 --- a/streampipes-extensions/streampipes-sinks-databases-jvm/pom.xml +++ b/streampipes-extensions/streampipes-sinks-databases-jvm/pom.xml
@@ -21,27 +21,23 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>streampipes-sinks-databases-jvm</artifactId> - <properties> - <maven.deploy.skip>true</maven.deploy.skip> - </properties> - <dependencies> <!-- StreamPipes dependencies --> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-standalone</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies --> @@ -79,10 +75,6 @@ <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency> - <dependency> - <groupId>mysql</groupId> - <artifactId>mysql-connector-java</artifactId> - </dependency> <!-- 3rd party dependencies to avoid convergence errors --> <dependency> @@ -120,39 +112,4 @@ <artifactId>jcl-over-slf4j</artifactId> </dependency> </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>jar</goal> - </goals> - <phase>package</phase> - <configuration> - <classifier>embed</classifier> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-maven-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>repackage</goal> - </goals> - <configuration> - <mainClass>org.apache.streampipes.sinks.databases.jvm.DatabasesJvmInit</mainClass> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - <finalName>streampipes-sinks-databases-jvm</finalName> - </build> </project>
diff --git a/streampipes-extensions/streampipes-sinks-databases-jvm/src/main/java/org/apache/streampipes/sinks/databases/jvm/DatabasesJvmInit.java b/streampipes-extensions/streampipes-sinks-databases-jvm/src/main/java/org/apache/streampipes/sinks/databases/jvm/DatabasesJvmInit.java index 528b538..cb1a38a 100644 --- a/streampipes-extensions/streampipes-sinks-databases-jvm/src/main/java/org/apache/streampipes/sinks/databases/jvm/DatabasesJvmInit.java +++ b/streampipes-extensions/streampipes-sinks-databases-jvm/src/main/java/org/apache/streampipes/sinks/databases/jvm/DatabasesJvmInit.java
@@ -32,7 +32,6 @@ import org.apache.streampipes.sinks.databases.jvm.ditto.DittoController; import org.apache.streampipes.sinks.databases.jvm.influxdb.InfluxDbController; import org.apache.streampipes.sinks.databases.jvm.iotdb.IotDbController; -import org.apache.streampipes.sinks.databases.jvm.mysql.MysqlController; import org.apache.streampipes.sinks.databases.jvm.opcua.UpcUaController; import org.apache.streampipes.sinks.databases.jvm.postgresql.PostgreSqlController; import org.apache.streampipes.sinks.databases.jvm.redis.RedisController; @@ -56,8 +55,7 @@ new PostgreSqlController(), new IotDbController(), new DittoController(), - new RedisController(), - new MysqlController()) + new RedisController()) .registerMessagingFormats( new JsonDataFormatFactory(), new CborDataFormatFactory(),
diff --git a/streampipes-extensions/streampipes-sinks-databases-jvm/src/main/java/org/apache/streampipes/sinks/databases/jvm/mysql/Mysql.java b/streampipes-extensions/streampipes-sinks-databases-jvm/src/main/java/org/apache/streampipes/sinks/databases/jvm/mysql/Mysql.java deleted file mode 100644 index 510d1fd..0000000 --- a/streampipes-extensions/streampipes-sinks-databases-jvm/src/main/java/org/apache/streampipes/sinks/databases/jvm/mysql/Mysql.java +++ /dev/null
@@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.sinks.databases.jvm.mysql; - -import org.apache.streampipes.commons.exceptions.SpRuntimeException; -import org.apache.streampipes.model.runtime.Event; -import org.apache.streampipes.logging.api.Logger; -import org.apache.streampipes.sinks.databases.jvm.jdbcclient.JdbcClient; -import org.apache.streampipes.sinks.databases.jvm.jdbcclient.model.SupportedDbEngines; -import org.apache.streampipes.wrapper.context.EventSinkRuntimeContext; -import org.apache.streampipes.wrapper.runtime.EventSink; - - -public class Mysql extends JdbcClient implements EventSink<MysqlParameters> { - - private MysqlParameters params; - private final SupportedDbEngines dbEngine = SupportedDbEngines.MY_SQL; - - @Override - public void onInvocation(MysqlParameters params, EventSinkRuntimeContext runtimeContext) throws SpRuntimeException { - - this.params = params; - Logger LOG = params.getGraph().getLogger(Mysql.class); - - initializeJdbc( - params.getGraph().getInputStreams().get(0).getEventSchema(), - params, - dbEngine, - LOG); - } - - - @Override - public void onEvent(Event inputEvent) { - try { - save(inputEvent); - } catch (SpRuntimeException e) { - e.printStackTrace(); - } - } - - - @Override - public void onDetach() throws SpRuntimeException { - closeAll(); - } - - - @Override - protected void ensureDatabaseExists(String databaseName) throws SpRuntimeException { - - String createStatement = "CREATE DATABASE IF NOT EXISTS "; - - ensureDatabaseExists(createStatement, databaseName); - - } - - @Override - protected void extractTableInformation() throws SpRuntimeException { - - String query = "SELECT COLUMN_NAME, DATA_TYPE, COLUMN_TYPE FROM " - + "INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ? AND TABLE_SCHEMA = ? ORDER BY " - + "ORDINAL_POSITION ASC;"; - - String[] queryParameter = new String[]{params.getDbTable(), params.getDbName()}; - - this.tableDescription.extractTableInformation( - this.statementHandler.preparedStatement, this.connection, - query, queryParameter); - } - - -} - -
diff --git a/streampipes-extensions/streampipes-sinks-databases-jvm/src/main/java/org/apache/streampipes/sinks/databases/jvm/mysql/MysqlController.java b/streampipes-extensions/streampipes-sinks-databases-jvm/src/main/java/org/apache/streampipes/sinks/databases/jvm/mysql/MysqlController.java deleted file mode 100644 index 927ac7d..0000000 --- a/streampipes-extensions/streampipes-sinks-databases-jvm/src/main/java/org/apache/streampipes/sinks/databases/jvm/mysql/MysqlController.java +++ /dev/null
@@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.sinks.databases.jvm.mysql; - -import org.apache.streampipes.model.DataSinkType; -import org.apache.streampipes.model.graph.DataSinkDescription; -import org.apache.streampipes.model.graph.DataSinkInvocation; -import org.apache.streampipes.sdk.builder.DataSinkBuilder; -import org.apache.streampipes.sdk.builder.StreamRequirementsBuilder; -import org.apache.streampipes.sdk.extractor.DataSinkParameterExtractor; -import org.apache.streampipes.sdk.helpers.EpRequirements; -import org.apache.streampipes.sdk.helpers.Labels; -import org.apache.streampipes.sdk.helpers.Locales; -import org.apache.streampipes.sdk.utils.Assets; -import org.apache.streampipes.wrapper.standalone.ConfiguredEventSink; -import org.apache.streampipes.wrapper.standalone.declarer.StandaloneEventSinkDeclarer; - -public class MysqlController extends StandaloneEventSinkDeclarer<MysqlParameters> { - - private static final String HOST_KEY = "host"; - private static final String USER_KEY = "user"; - private static final String PASSWORD_KEY = "password"; - private static final String DB_KEY = "db"; - private static final String TABLE_KEY = "table"; - private static final String PORT_KEY = "port"; - - @Override - public DataSinkDescription declareModel() { - return DataSinkBuilder.create("org.apache.streampipes.sinks.databases.jvm.mysql") - .category(DataSinkType.DATABASE) - .withLocales(Locales.EN) - .withAssets(Assets.DOCUMENTATION, Assets.ICON) - .requiredStream(StreamRequirementsBuilder - .create() - .requiredProperty(EpRequirements.anyProperty()) - .build()) - .requiredTextParameter(Labels.withId(HOST_KEY), false, false) - .requiredIntegerParameter(Labels.withId(PORT_KEY), 3306) - .requiredTextParameter(Labels.withId(USER_KEY), false, false) - .requiredSecret(Labels.withId(PASSWORD_KEY)) - .requiredTextParameter(Labels.withId(DB_KEY), false, false) - .requiredTextParameter(Labels.withId(TABLE_KEY), false, false) - .build(); - } - - @Override - public ConfiguredEventSink<MysqlParameters> onInvocation(DataSinkInvocation graph, - DataSinkParameterExtractor extractor) { - - String host = extractor.singleValueParameter(HOST_KEY, String.class); - String user = extractor.singleValueParameter(USER_KEY, String.class); - String password = extractor.secretValue(PASSWORD_KEY); - String db = extractor.singleValueParameter(DB_KEY, String.class); - String table = extractor.singleValueParameter(TABLE_KEY, String.class); - Integer port = extractor.singleValueParameter(PORT_KEY, Integer.class); - - // SSL connection is not yet implemented for MySQL client - MysqlParameters params = new MysqlParameters(graph, host, user, password, db, table, port, false); - return new ConfiguredEventSink<>(params, Mysql::new); - } - -}
diff --git a/streampipes-extensions/streampipes-sinks-databases-jvm/src/main/java/org/apache/streampipes/sinks/databases/jvm/mysql/MysqlParameters.java b/streampipes-extensions/streampipes-sinks-databases-jvm/src/main/java/org/apache/streampipes/sinks/databases/jvm/mysql/MysqlParameters.java deleted file mode 100644 index 40180ca..0000000 --- a/streampipes-extensions/streampipes-sinks-databases-jvm/src/main/java/org/apache/streampipes/sinks/databases/jvm/mysql/MysqlParameters.java +++ /dev/null
@@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.sinks.databases.jvm.mysql; - -import org.apache.streampipes.model.graph.DataSinkInvocation; -import org.apache.streampipes.sinks.databases.jvm.jdbcclient.model.JdbcConnectionParameters; - -public class MysqlParameters extends JdbcConnectionParameters { - - public MysqlParameters(DataSinkInvocation graph, String mySqlHost, String mySqlUser, String mySqlPassword, - String mySqlDb, String mySqlTable, Integer mySqlPort, boolean sslEnabled) { - super( - graph, - mySqlHost, - mySqlPort, - mySqlDb, - mySqlUser, - mySqlPassword, - mySqlTable, - sslEnabled, - null, - false - ); - } -}
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/aarch64.Dockerfile b/streampipes-extensions/streampipes-sinks-internal-jvm/aarch64.Dockerfile deleted file mode 100644 index b1d2f6e..0000000 --- a/streampipes-extensions/streampipes-sinks-internal-jvm/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-sinks-internal-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/arm.Dockerfile b/streampipes-extensions/streampipes-sinks-internal-jvm/arm.Dockerfile deleted file mode 100644 index 983eb89..0000000 --- a/streampipes-extensions/streampipes-sinks-internal-jvm/arm.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-sinks-internal-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/pom.xml b/streampipes-extensions/streampipes-sinks-internal-jvm/pom.xml index 1262f52..0ceb2d8 100644 --- a/streampipes-extensions/streampipes-sinks-internal-jvm/pom.xml +++ b/streampipes-extensions/streampipes-sinks-internal-jvm/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -30,28 +30,33 @@ <properties> <lightcouch.version>0.1.8</lightcouch.version> <influxdb.java.version>2.14</influxdb.java.version> - <maven.deploy.skip>true</maven.deploy.skip> </properties> <dependencies> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-pipeline-elements-shared</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- StreamPipes dependencies --> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-standalone</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-data-explorer-commons</artifactId> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies --> + <!-- TODO remove after refactoring --> <dependency> <groupId>org.lightcouch</groupId> <artifactId>lightcouch</artifactId> @@ -60,6 +65,8 @@ <groupId>org.influxdb</groupId> <artifactId>influxdb-java</artifactId> </dependency> + <!-- TODO remove after refactoring --> + <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> @@ -72,37 +79,6 @@ <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> - </dependencies> - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>jar</goal> - </goals> - <phase>package</phase> - <configuration> - <classifier>embed</classifier> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-maven-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>repackage</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - <finalName>streampipes-sinks-internal-jvm</finalName> - </build> + </dependencies> </project>
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/SinksInternalJvmInit.java b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/SinksInternalJvmInit.java index 53e3db7..421ab74 100644 --- a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/SinksInternalJvmInit.java +++ b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/SinksInternalJvmInit.java
@@ -21,6 +21,8 @@ import org.apache.streampipes.container.model.SpServiceDefinition; import org.apache.streampipes.container.model.SpServiceDefinitionBuilder; import org.apache.streampipes.container.standalone.init.StandaloneModelSubmitter; +import org.apache.streampipes.dataexplorer.commons.configs.CouchDbConfigurations; +import org.apache.streampipes.dataexplorer.commons.configs.DataExplorerConfigurations; import org.apache.streampipes.dataformat.cbor.CborDataFormatFactory; import org.apache.streampipes.dataformat.fst.FstDataFormatFactory; import org.apache.streampipes.dataformat.json.JsonDataFormatFactory; @@ -28,16 +30,11 @@ import org.apache.streampipes.messaging.jms.SpJmsProtocolFactory; import org.apache.streampipes.messaging.kafka.SpKafkaProtocolFactory; import org.apache.streampipes.messaging.mqtt.SpMqttProtocolFactory; -import org.apache.streampipes.sinks.internal.jvm.config.ConfigKeys; -import org.apache.streampipes.sinks.internal.jvm.datalake.DataLakeController; -import org.apache.streampipes.sinks.internal.jvm.notification.NotificationController; +import org.apache.streampipes.sinks.internal.jvm.datalake.DataLakeSink; +import org.apache.streampipes.sinks.internal.jvm.notification.NotificationProducer; public class SinksInternalJvmInit extends StandaloneModelSubmitter { - public static void main(String[] args) { - new SinksInternalJvmInit().init(); - } - @Override public SpServiceDefinition provideServiceDefinition() { return SpServiceDefinitionBuilder.create("org.apache.streampipes.sinks.internal.jvm", @@ -45,8 +42,8 @@ "", 8090) .registerPipelineElements( - new DataLakeController(), - new NotificationController()) + new DataLakeSink(), + new NotificationProducer()) .registerMessagingFormats( new JsonDataFormatFactory(), new CborDataFormatFactory(), @@ -56,15 +53,8 @@ new SpKafkaProtocolFactory(), new SpJmsProtocolFactory(), new SpMqttProtocolFactory()) - .addConfig(ConfigKeys.COUCHDB_HOST, "couchdb", "Hostname for CouchDB to store image blobs") - .addConfig(ConfigKeys.COUCHDB_PORT, 5984, "") - .addConfig(ConfigKeys.COUCHDB_PROTOCOL, "http", "") - .addConfig(ConfigKeys.DATA_LAKE_HOST, "influxdb", "Hostname for the StreamPipes data lake database") - .addConfig(ConfigKeys.DATA_LAKE_PROTOCOL, "http", "Protocol for the StreamPipes data lake database") - .addConfig(ConfigKeys.DATA_LAKE_PORT, 8086, "Port for the StreamPipes data lake database") - .addConfig(ConfigKeys.DATA_LAKE_USERNAME, "default", "Username for the StreamPipes data lake database") - .addConfig(ConfigKeys.DATA_LAKE_PASSWORD, "default", "Password for the StreamPipes data lake database") - .addConfig(ConfigKeys.DATA_LAKE_DATABASE_NAME, "sp", "Database name for the StreamPipes data lake database") + .addConfigs(DataExplorerConfigurations.getDefaults()) + .addConfigs(CouchDbConfigurations.getDefaults()) .build();
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLake.java b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLake.java deleted file mode 100644 index 83cbb3b..0000000 --- a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLake.java +++ /dev/null
@@ -1,150 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.sinks.internal.jvm.datalake; - -import org.apache.commons.codec.binary.Base64; -import org.apache.streampipes.client.StreamPipesClient; -import org.apache.streampipes.commons.exceptions.SpRuntimeException; -import org.apache.streampipes.logging.api.Logger; -import org.apache.streampipes.model.runtime.Event; -import org.apache.streampipes.model.schema.EventProperty; -import org.apache.streampipes.model.schema.EventSchema; -import org.apache.streampipes.sinks.internal.jvm.config.ConfigKeys; -import org.apache.streampipes.svcdiscovery.api.SpConfig; -import org.apache.streampipes.vocabulary.SPSensor; -import org.apache.streampipes.wrapper.context.EventSinkRuntimeContext; -import org.apache.streampipes.wrapper.runtime.EventSink; - -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; - -/** - * Code is the same as InfluxDB (org.apache.streampipes.sinks.databases.jvm.influxdb) sink. Changes applied here should also be applied in the InfluxDB sink - */ -public class DataLake implements EventSink<DataLakeParameters> { - - - private DataLakeInfluxDbClient influxDbClient; - - private static Logger LOG; - - private List<EventProperty> imageProperties; - private String timestampField; - - private EventSchema eventSchema; - private ImageStore imageStore; - - @Override - public void onInvocation(DataLakeParameters parameters, EventSinkRuntimeContext runtimeContext) throws SpRuntimeException { - LOG = parameters.getGraph().getLogger(DataLake.class); - - this.timestampField = parameters.getTimestampField(); - - SpConfig configStore = runtimeContext.getConfigStore().getConfig(); - - String influxHost = configStore.getString(ConfigKeys.DATA_LAKE_PROTOCOL) + "://" + configStore.getString(ConfigKeys.DATA_LAKE_HOST); - Integer influxPort = configStore.getInteger(ConfigKeys.DATA_LAKE_PORT); - String databaseName = configStore.getString(ConfigKeys.DATA_LAKE_DATABASE_NAME); - String user = configStore.getString(ConfigKeys.DATA_LAKE_USERNAME); - String password = configStore.getString(ConfigKeys.DATA_LAKE_PASSWORD); - - String couchDbProtocol = configStore.getString(ConfigKeys.COUCHDB_PROTOCOL); - String couchDbHost = configStore.getString(ConfigKeys.COUCHDB_HOST); - int couchDbPort = configStore.getInteger(ConfigKeys.COUCHDB_PORT); - - this.imageStore = new ImageStore(couchDbProtocol, couchDbHost, couchDbPort); - - EventSchema schema = runtimeContext.getInputSchemaInfo().get(0).getEventSchema(); - // Remove the timestamp field from the event schema - List<EventProperty> eventPropertiesWithoutTimestamp = schema.getEventProperties() - .stream() - .filter(eventProperty -> !this.timestampField.endsWith(eventProperty.getRuntimeName())) - .collect(Collectors.toList()); - schema.setEventProperties(eventPropertiesWithoutTimestamp); - - // deep copy of event schema. Event property runtime name is changed to lower case for the schema registration - this.eventSchema = new EventSchema(schema); - - schema.getEventProperties().forEach(eventProperty -> - eventProperty.setRuntimeName(DataLakeUtils.sanitizePropertyRuntimeName(eventProperty.getRuntimeName()))); - registerAtDataLake(parameters.getMeasurementName(), schema, runtimeContext.getStreamPipesClient()); - - imageProperties = schema.getEventProperties().stream() - .filter(eventProperty -> eventProperty.getDomainProperties() != null && - eventProperty.getDomainProperties().size() > 0 && - eventProperty.getDomainProperties().get(0).toString().equals(SPSensor.IMAGE)) - .collect(Collectors.toList()); - - InfluxDbConnectionSettings settings = InfluxDbConnectionSettings.from( - influxHost, influxPort, databaseName, parameters.getMeasurementName(), user, password); - - this.influxDbClient = new DataLakeInfluxDbClient( - settings, - parameters.getTimestampField(), - parameters.getBatchSize(), - parameters.getFlushDuration(), - this.eventSchema - ); - } - - @Override - public void onEvent(Event event) { - try { - - this.imageProperties.forEach(eventProperty -> { - String imageDocId = UUID.randomUUID().toString(); - String image = event.getFieldByRuntimeName(eventProperty.getRuntimeName()).getAsPrimitive().getAsString(); - - this.writeToImageFile(image, imageDocId); - event.updateFieldBySelector("s0::" + eventProperty.getRuntimeName(), imageDocId); - }); - - influxDbClient.save(event, this.eventSchema); - } catch (SpRuntimeException e) { - LOG.error(e.getMessage()); - } - } - - @Override - public void onDetach() throws SpRuntimeException { - influxDbClient.stop(); - } - - private void writeToImageFile(String image, String imageDocId) { - byte[] data = Base64.decodeBase64(image); - this.imageStore.storeImage(data, imageDocId); - } - - /** - * Adds a new measurement to the StreamPipes data lake - * @param measure - * @param eventSchema - * @throws SpRuntimeException - */ - private void registerAtDataLake(String measure, - EventSchema eventSchema, - StreamPipesClient client) throws SpRuntimeException { - client - .customRequest() - .sendPost("api/v3/datalake/measure/" + measure, eventSchema); - } - - -}
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeController.java b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeController.java deleted file mode 100644 index 6bdad66..0000000 --- a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeController.java +++ /dev/null
@@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.sinks.internal.jvm.datalake; - -import org.apache.streampipes.model.DataSinkType; -import org.apache.streampipes.model.graph.DataSinkDescription; -import org.apache.streampipes.model.graph.DataSinkInvocation; -import org.apache.streampipes.model.schema.PropertyScope; -import org.apache.streampipes.sdk.builder.DataSinkBuilder; -import org.apache.streampipes.sdk.builder.StreamRequirementsBuilder; -import org.apache.streampipes.sdk.extractor.DataSinkParameterExtractor; -import org.apache.streampipes.sdk.helpers.EpRequirements; -import org.apache.streampipes.sdk.helpers.Labels; -import org.apache.streampipes.sdk.helpers.Locales; -import org.apache.streampipes.sdk.utils.Assets; -import org.apache.streampipes.wrapper.standalone.ConfiguredEventSink; -import org.apache.streampipes.wrapper.standalone.declarer.StandaloneEventSinkDeclarer; - -public class DataLakeController extends StandaloneEventSinkDeclarer<DataLakeParameters> { - - private static final String DATABASE_MEASUREMENT_KEY = "db_measurement"; - private static final String TIMESTAMP_MAPPING_KEY = "timestamp_mapping"; - - - @Override - public DataSinkDescription declareModel() { - return DataSinkBuilder.create("org.apache.streampipes.sinks.internal.jvm.datalake") - .withLocales(Locales.EN) - .withAssets(Assets.DOCUMENTATION, Assets.ICON) - .category(DataSinkType.INTERNAL) - .requiredStream(StreamRequirementsBuilder.create().requiredPropertyWithUnaryMapping( - EpRequirements.timestampReq(), - Labels.withId(TIMESTAMP_MAPPING_KEY), - PropertyScope.NONE).build()) - .requiredTextParameter(Labels.withId(DATABASE_MEASUREMENT_KEY)) - .build(); - } - - @Override - public ConfiguredEventSink<DataLakeParameters> onInvocation(DataSinkInvocation graph, - DataSinkParameterExtractor extractor) { - - String measureName = extractor.singleValueParameter(DATABASE_MEASUREMENT_KEY, String.class); - measureName = DataLakeUtils.prepareString(measureName); - String timestampField = extractor.mappingPropertyValue(TIMESTAMP_MAPPING_KEY); - - Integer batch_size = 2000; - Integer flush_duration = 500; - - DataLakeParameters params = new DataLakeParameters(graph, - measureName, - timestampField, - batch_size, - flush_duration); - - - return new ConfiguredEventSink<>(params, DataLake::new); - } -}
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeInfluxDbClient.java b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeInfluxDbClient.java deleted file mode 100644 index 80c7214..0000000 --- a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeInfluxDbClient.java +++ /dev/null
@@ -1,207 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.sinks.internal.jvm.datalake; - -import org.apache.streampipes.commons.exceptions.SpRuntimeException; -import org.apache.streampipes.model.runtime.Event; -import org.apache.streampipes.model.runtime.field.PrimitiveField; -import org.apache.streampipes.model.schema.EventProperty; -import org.apache.streampipes.model.schema.EventPropertyPrimitive; -import org.apache.streampipes.model.schema.EventSchema; -import org.apache.streampipes.vocabulary.XSD; -import org.influxdb.InfluxDB; -import org.influxdb.InfluxDBFactory; -import org.influxdb.dto.Point; -import org.influxdb.dto.Pong; -import org.influxdb.dto.Query; -import org.influxdb.dto.QueryResult; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -/** - * Code is the same as InfluxDB (org.apache.streampipes.sinks.databases.jvm.influxdb) sink. Changes applied here should also be applied in the InfluxDB sink - */ -public class DataLakeInfluxDbClient { - - private static final Logger LOG = LoggerFactory.getLogger(DataLakeInfluxDbClient.class); - - private final String measureName; - private final String timestampField; - private final Integer batchSize; - private final Integer flushDuration; - - private InfluxDB influxDb = null; - private final InfluxDbConnectionSettings settings; - private final EventSchema originalEventSchema; - - Map<String, String> targetRuntimeNames = new HashMap<>(); - - DataLakeInfluxDbClient(InfluxDbConnectionSettings settings, - String timestampField, - Integer batchSize, - Integer flushDuration, - EventSchema originalEventSchema) throws SpRuntimeException { - this.settings = settings; - this.originalEventSchema = originalEventSchema; - this.timestampField = timestampField; - this.batchSize = batchSize; - this.flushDuration = flushDuration; - this.measureName = settings.getMeasureName(); - - prepareSchema(); - connect(); - } - - private void prepareSchema() { - originalEventSchema - .getEventProperties() - .forEach(ep -> targetRuntimeNames.put(ep.getRuntimeName(), DataLakeUtils.sanitizePropertyRuntimeName(ep.getRuntimeName()))); - } - - /** - * Connects to the InfluxDB Server, sets the database and initializes the batch-behaviour - * - * @throws SpRuntimeException If not connection can be established or if the database could not - * be found - */ - private void connect() throws SpRuntimeException { - // Connecting to the server - // "http://" must be in front - String urlAndPort = settings.getInfluxDbHost() + ":" + settings.getInfluxDbPort(); - influxDb = InfluxDBFactory.connect(urlAndPort, settings.getUser(), settings.getPassword()); - - // Checking, if server is available - Pong response = influxDb.ping(); - if (response.getVersion().equalsIgnoreCase("unknown")) { - throw new SpRuntimeException("Could not connect to InfluxDb Server: " + urlAndPort); - } - - String databaseName = settings.getDatabaseName(); - // Checking whether the database exists - if(!databaseExists(databaseName)) { - LOG.info("Database '" + databaseName + "' not found. Gets created ..."); - createDatabase(databaseName); - } - - // setting up the database - influxDb.setDatabase(databaseName); - influxDb.enableBatch(batchSize, flushDuration, TimeUnit.MILLISECONDS); - } - - /** - * Checks whether the given database exists. Needs a working connection to an InfluxDB Server - * ({@link DataLakeInfluxDbClient#influxDb} needs to be initialized) - * - * @param dbName The name of the database, the method should look for - * @return True if the database exists, false otherwise - */ - private boolean databaseExists(String dbName) { - QueryResult queryResult = influxDb.query(new Query("SHOW DATABASES", "")); - for(List<Object> a : queryResult.getResults().get(0).getSeries().get(0).getValues()) { - if(a.get(0).equals(dbName)) { - return true; - } - } - return false; - } - - /** - * Creates a new database with the given name - * - * @param dbName The name of the database which should be created - */ - private void createDatabase(String dbName) throws SpRuntimeException { - if(!dbName.matches("^[a-zA-Z_][a-zA-Z0-9_]*$")) { - throw new SpRuntimeException("Databasename '" + dbName + "' not allowed. Allowed names: ^[a-zA-Z_][a-zA-Z0-9_]*$"); - } - influxDb.query(new Query("CREATE DATABASE \"" + dbName + "\"", "")); - } - - /** - * Saves an event to the connnected InfluxDB database - * - * @param event The event which should be saved - * @throws SpRuntimeException If the column name (key-value of the event map) is not allowed - */ - void save(Event event, EventSchema schema) throws SpRuntimeException { - if (event == null) { - throw new SpRuntimeException("event is null"); - } - - Long timestampValue = event.getFieldBySelector(timestampField).getAsPrimitive().getAsLong(); - Point.Builder p = Point.measurement(measureName).time(timestampValue, TimeUnit.MILLISECONDS); - - for (EventProperty ep : schema.getEventProperties()) { - if (ep instanceof EventPropertyPrimitive) { - String runtimeName = ep.getRuntimeName(); - - if (!timestampField.endsWith(runtimeName)) { - String preparedRuntimeName = targetRuntimeNames.get(runtimeName); - PrimitiveField eventPropertyPrimitiveField = event.getFieldByRuntimeName(runtimeName).getAsPrimitive(); - - // store property as tag when the field is a dimension property - if ("DIMENSION_PROPERTY".equals(ep.getPropertyScope())) { - p.tag(preparedRuntimeName, eventPropertyPrimitiveField.getAsString()); - } else { - try { - // Store property according to property type - String runtimeType = ((EventPropertyPrimitive) ep).getRuntimeType(); - if (XSD._integer.toString().equals(runtimeType)) { - p.addField(preparedRuntimeName, eventPropertyPrimitiveField.getAsInt()); - } else if (XSD._float.toString().equals(runtimeType)) { - p.addField(preparedRuntimeName, eventPropertyPrimitiveField.getAsFloat()); - } else if (XSD._double.toString().equals(runtimeType)) { - p.addField(preparedRuntimeName, eventPropertyPrimitiveField.getAsDouble()); - } else if (XSD._boolean.toString().equals(runtimeType)) { - p.addField(preparedRuntimeName, eventPropertyPrimitiveField.getAsBoolean()); - } else if (XSD._long.toString().equals(runtimeType)) { - p.addField(preparedRuntimeName, eventPropertyPrimitiveField.getAsLong()); - } else { - p.addField(preparedRuntimeName, eventPropertyPrimitiveField.getAsString()); - } - } catch (NumberFormatException e) { - LOG.warn("Wrong number format for field {}, ignoring.", preparedRuntimeName); - } - } - } - } - } - - influxDb.write(p.build()); - } - - /** - * Shuts down the connection to the InfluxDB server - */ - void stop() { - influxDb.flush(); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - influxDb.close(); - } - -}
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeParameters.java b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeParameters.java deleted file mode 100644 index 61f8f3a..0000000 --- a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeParameters.java +++ /dev/null
@@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.sinks.internal.jvm.datalake; - -import org.apache.streampipes.model.graph.DataSinkInvocation; -import org.apache.streampipes.wrapper.params.binding.EventSinkBindingParams; - -/** - * Code is the same as InfluxDB (org.apache.streampipes.sinks.databases.jvm.influxdb) sink. Changes applied here should also be applied in the InfluxDB sink - */ -public class DataLakeParameters extends EventSinkBindingParams { - - private String measureName; - private String timestampField; - private Integer batchSize; - private Integer flushDuration; - - public DataLakeParameters(DataSinkInvocation graph, - String measureName, - String timestampField, - Integer batchSize, - Integer flushDuration) { - super(graph); - this.measureName = measureName; - this.timestampField = timestampField; - this.batchSize = batchSize; - this.flushDuration = flushDuration; - } - - public String getMeasurementName() { - return measureName; - } - - public String getTimestampField() { - return timestampField; - } - - public Integer getBatchSize() { - return batchSize; - } - - public Integer getFlushDuration() { - return flushDuration; - } - -}
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeSink.java b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeSink.java new file mode 100644 index 0000000..a62315b --- /dev/null +++ b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeSink.java
@@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.sinks.internal.jvm.datalake; + +import org.apache.streampipes.commons.exceptions.SpRuntimeException; +import org.apache.streampipes.dataexplorer.commons.TimeSeriesStore; +import org.apache.streampipes.logging.api.Logger; +import org.apache.streampipes.model.DataSinkType; +import org.apache.streampipes.model.datalake.DataLakeMeasure; +import org.apache.streampipes.model.graph.DataSinkDescription; +import org.apache.streampipes.model.runtime.Event; +import org.apache.streampipes.model.schema.EventSchema; +import org.apache.streampipes.model.schema.PropertyScope; +import org.apache.streampipes.sdk.builder.DataSinkBuilder; +import org.apache.streampipes.sdk.builder.StreamRequirementsBuilder; +import org.apache.streampipes.sdk.helpers.EpRequirements; +import org.apache.streampipes.sdk.helpers.Labels; +import org.apache.streampipes.sdk.helpers.Locales; +import org.apache.streampipes.sdk.utils.Assets; +import org.apache.streampipes.wrapper.context.EventSinkRuntimeContext; +import org.apache.streampipes.wrapper.standalone.SinkParams; +import org.apache.streampipes.wrapper.standalone.StreamPipesDataSink; + + +public class DataLakeSink extends StreamPipesDataSink { + private static Logger LOG; + + private static final String DATABASE_MEASUREMENT_KEY = "db_measurement"; + private static final String TIMESTAMP_MAPPING_KEY = "timestamp_mapping"; + + private TimeSeriesStore timeSeriesStore; + + + @Override + public DataSinkDescription declareModel() { + return DataSinkBuilder.create("org.apache.streampipes.sinks.internal.jvm.datalake") + .withLocales(Locales.EN) + .withAssets(Assets.DOCUMENTATION, Assets.ICON) + .category(DataSinkType.INTERNAL) + .requiredStream(StreamRequirementsBuilder.create() + .requiredPropertyWithUnaryMapping( + EpRequirements.timestampReq(), + Labels.withId(TIMESTAMP_MAPPING_KEY), + PropertyScope.NONE) + .build()) + .requiredTextParameter(Labels.withId(DATABASE_MEASUREMENT_KEY)) + .build(); + } + + @Override + public void onInvocation(SinkParams parameters, EventSinkRuntimeContext runtimeContext) throws SpRuntimeException { + + + LOG = parameters.getGraph().getLogger(DataLakeSink.class); + + String timestampField = parameters.extractor().mappingPropertyValue(TIMESTAMP_MAPPING_KEY); + String measureName = parameters.extractor().singleValueParameter(DATABASE_MEASUREMENT_KEY, String.class); + EventSchema eventSchema = runtimeContext.getInputSchemaInfo().get(0).getEventSchema(); + + DataLakeMeasure measure = new DataLakeMeasure(measureName, timestampField, eventSchema); + + this.timeSeriesStore = new TimeSeriesStore(runtimeContext.getConfigStore().getConfig(), + runtimeContext.getStreamPipesClient(), + measure, + true); + + } + + @Override + public void onEvent(Event event) throws SpRuntimeException { + this.timeSeriesStore.onEvent(event); + } + + @Override + public void onDetach() throws SpRuntimeException { + this.timeSeriesStore.close(); + } +}
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeUtils.java b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeUtils.java deleted file mode 100644 index 8fa1736..0000000 --- a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeUtils.java +++ /dev/null
@@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.sinks.internal.jvm.datalake; - -public class DataLakeUtils { - - public static String prepareString(String s) { - return s.toLowerCase().replaceAll(" ", "_"); - } - - private static String renameReservedKeywords(String runtimeName) { - if (InfluxDbReservedKeywords.keywordList.stream().anyMatch(k -> k.equalsIgnoreCase(runtimeName))) { - return runtimeName + "_"; - } else { - return runtimeName; - } - } - - public static String sanitizePropertyRuntimeName(String runtimeName) { - String sanitizedRuntimeName = prepareString(runtimeName); - return renameReservedKeywords(sanitizedRuntimeName); - } -}
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/ImageStore.java b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/ImageStore.java deleted file mode 100644 index cd946b4..0000000 --- a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/ImageStore.java +++ /dev/null
@@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.sinks.internal.jvm.datalake; - -import org.lightcouch.CouchDbClient; -import org.lightcouch.CouchDbProperties; - -import java.io.ByteArrayInputStream; - -public class ImageStore { - - private static final String DB_NAME = "images"; - - private CouchDbClient couchDbClient; - - public ImageStore(String couchDbProtocol, - String couchDbHost, - int couchDbPort) { - this.couchDbClient = new CouchDbClient(props(couchDbProtocol, couchDbHost, couchDbPort)); - } - - public void storeImage(byte[] imageBytes, - String imageDocId) { - this.couchDbClient.saveAttachment( - new ByteArrayInputStream(imageBytes), - imageDocId, - "image/jpeg", - imageDocId, - null); - } - - private static CouchDbProperties props(String couchDbProtocol, - String couchDbHost, - int couchDbPort) { - return new CouchDbProperties(DB_NAME, true, couchDbProtocol, - couchDbHost, couchDbPort, null, null); - } -}
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/InfluxDbConnectionSettings.java b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/InfluxDbConnectionSettings.java deleted file mode 100644 index 3be6b21..0000000 --- a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/InfluxDbConnectionSettings.java +++ /dev/null
@@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.sinks.internal.jvm.datalake; - -public class InfluxDbConnectionSettings { - - private final Integer influxDbPort; - private final String influxDbHost; - private final String databaseName; - private final String measureName; - private final String user; - private final String password; - - public static InfluxDbConnectionSettings from(String influxDbHost, - Integer influxDbPort, - String databaseName, - String measureName, - String user, - String password) { - return new InfluxDbConnectionSettings( - influxDbHost, - influxDbPort, - databaseName, - measureName, - user, - password); - } - - private InfluxDbConnectionSettings(String influxDbHost, - Integer influxDbPort, - String databaseName, - String measureName, - String user, - String password) { - this.influxDbHost = influxDbHost; - this.influxDbPort = influxDbPort; - this.databaseName = databaseName; - this.measureName = measureName; - this.user = user; - this.password = password; - } - - public Integer getInfluxDbPort() { - return influxDbPort; - } - - public String getInfluxDbHost() { - return influxDbHost; - } - - public String getDatabaseName() { - return databaseName; - } - - public String getMeasureName() { - return measureName; - } - - public String getUser() { - return user; - } - - public String getPassword() { - return password; - } -}
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/notification/NotificationController.java b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/notification/NotificationController.java deleted file mode 100644 index d9cd341..0000000 --- a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/notification/NotificationController.java +++ /dev/null
@@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.sinks.internal.jvm.notification; - -import org.apache.streampipes.model.DataSinkType; -import org.apache.streampipes.model.graph.DataSinkDescription; -import org.apache.streampipes.model.graph.DataSinkInvocation; -import org.apache.streampipes.sdk.builder.DataSinkBuilder; -import org.apache.streampipes.sdk.builder.StreamRequirementsBuilder; -import org.apache.streampipes.sdk.extractor.DataSinkParameterExtractor; -import org.apache.streampipes.sdk.helpers.EpRequirements; -import org.apache.streampipes.sdk.helpers.Labels; -import org.apache.streampipes.sdk.helpers.Locales; -import org.apache.streampipes.sdk.utils.Assets; -import org.apache.streampipes.wrapper.standalone.ConfiguredEventSink; -import org.apache.streampipes.wrapper.standalone.declarer.StandaloneEventSinkDeclarer; - -public class NotificationController extends StandaloneEventSinkDeclarer<NotificationParameters> { - - private static final String TITLE_KEY = "title"; - private static final String CONTENT_KEY = "content"; - - @Override - public DataSinkDescription declareModel() { - return DataSinkBuilder.create("org.apache.streampipes.sinks.internal.jvm.notification") - .withLocales(Locales.EN) - .withAssets(Assets.DOCUMENTATION, Assets.ICON) - .category(DataSinkType.INTERNAL, DataSinkType.NOTIFICATION) - .requiredStream(StreamRequirementsBuilder - .create() - .requiredProperty(EpRequirements.anyProperty()) - .build()) - .requiredTextParameter(Labels.withId(TITLE_KEY)) - .requiredHtmlInputParameter(Labels.withId(CONTENT_KEY)) - .build(); - } - - @Override - public ConfiguredEventSink<NotificationParameters> onInvocation(DataSinkInvocation graph, - DataSinkParameterExtractor extractor) { - - String title = extractor.singleValueParameter(TITLE_KEY, String.class); - String content = extractor.singleValueParameter(CONTENT_KEY, String.class); - - NotificationParameters params = new NotificationParameters(graph, title, content); - - return new ConfiguredEventSink<>(params, NotificationProducer::new); - } - -}
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/notification/NotificationParameters.java b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/notification/NotificationParameters.java deleted file mode 100644 index 2914433..0000000 --- a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/notification/NotificationParameters.java +++ /dev/null
@@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.sinks.internal.jvm.notification; - -import org.apache.streampipes.model.graph.DataSinkInvocation; -import org.apache.streampipes.wrapper.params.binding.EventSinkBindingParams; - -public class NotificationParameters extends EventSinkBindingParams { - - private String title; - private String content; - - public NotificationParameters(DataSinkInvocation graph, String title, String content) { - super(graph); - this.title = title; - this.content = content; - } - - public String getTitle() { - return title; - } - - public String getContent() { - return content; - } -}
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/notification/NotificationProducer.java b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/notification/NotificationProducer.java index c7bcad0..74ebd34 100644 --- a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/notification/NotificationProducer.java +++ b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/notification/NotificationProducer.java
@@ -21,21 +21,38 @@ import org.apache.streampipes.client.StreamPipesClient; import org.apache.streampipes.commons.exceptions.SpRuntimeException; +import org.apache.streampipes.model.DataSinkType; import org.apache.streampipes.model.Notification; +import org.apache.streampipes.model.graph.DataSinkDescription; import org.apache.streampipes.model.runtime.Event; import org.apache.streampipes.pe.shared.PlaceholderExtractor; +import org.apache.streampipes.sdk.builder.DataSinkBuilder; +import org.apache.streampipes.sdk.builder.StreamRequirementsBuilder; +import org.apache.streampipes.sdk.helpers.EpRequirements; +import org.apache.streampipes.sdk.helpers.Labels; +import org.apache.streampipes.sdk.helpers.Locales; +import org.apache.streampipes.sdk.utils.Assets; import org.apache.streampipes.wrapper.context.EventSinkRuntimeContext; -import org.apache.streampipes.wrapper.runtime.EventSink; +import org.apache.streampipes.wrapper.standalone.SinkParams; +import org.apache.streampipes.wrapper.standalone.StreamPipesDataSink; +import java.time.Instant; import java.util.Date; import java.util.UUID; -public class NotificationProducer implements EventSink<NotificationParameters> { +public class NotificationProducer extends StreamPipesDataSink { private static final String HASHTAG = "#"; + private static final String TITLE_KEY = "title"; + private static final String CONTENT_KEY = "content"; + private static final String SILENT_PERIOD = "silent-period"; private String title; private String content; + + private long silentPeriodInSeconds; + private long lastMessageEpochSecond = -1; + private String correspondingPipelineId; private String correspondingUser; @@ -43,10 +60,11 @@ @Override - public void onInvocation(NotificationParameters parameters, EventSinkRuntimeContext context) throws + public void onInvocation(SinkParams parameters, EventSinkRuntimeContext context) throws SpRuntimeException { - this.title = parameters.getTitle(); - this.content = parameters.getContent(); + this.title = parameters.extractor().singleValueParameter(TITLE_KEY, String.class); + this.content = parameters.extractor().singleValueParameter(CONTENT_KEY, String.class); + this.silentPeriodInSeconds = parameters.extractor().singleValueParameter(SILENT_PERIOD, Integer.class) * 60; this.correspondingPipelineId = parameters.getGraph().getCorrespondingPipeline(); this.correspondingUser = parameters.getGraph().getCorrespondingUser(); this.client = context.getStreamPipesClient(); @@ -54,20 +72,23 @@ @Override public void onEvent(Event inputEvent) { - Date currentDate = new Date(); - Notification notification = new Notification(); - notification.setId(UUID.randomUUID().toString()); - notification.setRead(false); - notification.setTitle(title); - notification.setMessage(PlaceholderExtractor.replacePlaceholders(inputEvent, content)); - notification.setCreatedAt(currentDate); - notification.setCreatedAtTimestamp(currentDate.getTime()); - notification.setCorrespondingPipelineId(correspondingPipelineId); - notification.setTargetedAt(correspondingUser); + if (shouldSendNotification()) { + Date currentDate = new Date(); + Notification notification = new Notification(); + notification.setId(UUID.randomUUID().toString()); + notification.setRead(false); + notification.setTitle(title); + notification.setMessage(PlaceholderExtractor.replacePlaceholders(inputEvent, content)); + notification.setCreatedAt(currentDate); + notification.setCreatedAtTimestamp(currentDate.getTime()); + notification.setCorrespondingPipelineId(correspondingPipelineId); + notification.setTargetedAt(correspondingUser); - // TODO add targeted user to notification object + // TODO add targeted user to notification object - client.notificationsApi().add(notification); + client.notificationsApi().add(notification); + this.lastMessageEpochSecond = Instant.now().getEpochSecond(); + } } @Override @@ -75,4 +96,27 @@ } + private boolean shouldSendNotification() { + if (this.lastMessageEpochSecond == -1) { + return true; + } else { + return Instant.now().getEpochSecond() >= (this.lastMessageEpochSecond + this.silentPeriodInSeconds); + } + } + + @Override + public DataSinkDescription declareModel() { + return DataSinkBuilder.create("org.apache.streampipes.sinks.internal.jvm.notification") + .withLocales(Locales.EN) + .withAssets(Assets.DOCUMENTATION, Assets.ICON) + .category(DataSinkType.INTERNAL, DataSinkType.NOTIFICATION) + .requiredStream(StreamRequirementsBuilder + .create() + .requiredProperty(EpRequirements.anyProperty()) + .build()) + .requiredTextParameter(Labels.withId(TITLE_KEY)) + .requiredHtmlInputParameter(Labels.withId(CONTENT_KEY)) + .requiredIntegerParameter(Labels.withId(SILENT_PERIOD), 10) + .build(); + } }
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/resources/org.apache.streampipes.sinks.internal.jvm.notification/strings.en b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/resources/org.apache.streampipes.sinks.internal.jvm.notification/strings.en index b64ef71..886235d 100644 --- a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/resources/org.apache.streampipes.sinks.internal.jvm.notification/strings.en +++ b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/resources/org.apache.streampipes.sinks.internal.jvm.notification/strings.en
@@ -6,3 +6,6 @@ content.title=Content content.description=Enter the notification text. You can use placeholders like #fieldName# to add the value of a stream variable. + +silent-period.title=Silent Period [min] +silent-period.description=The minimum number of minutes between two consecutive notifications that are sent.
diff --git a/streampipes-extensions/streampipes-sinks-notifications-jvm/Dockerfile b/streampipes-extensions/streampipes-sinks-notifications-jvm/Dockerfile deleted file mode 100644 index 0b594df..0000000 --- a/streampipes-extensions/streampipes-sinks-notifications-jvm/Dockerfile +++ /dev/null
@@ -1,25 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=adoptopenjdk/openjdk8-openj9:alpine -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY target/streampipes-sinks-notifications-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-sinks-notifications-jvm/aarch64.Dockerfile b/streampipes-extensions/streampipes-sinks-notifications-jvm/aarch64.Dockerfile deleted file mode 100644 index 499af11..0000000 --- a/streampipes-extensions/streampipes-sinks-notifications-jvm/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-sinks-notifications-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-sinks-notifications-jvm/arm.Dockerfile b/streampipes-extensions/streampipes-sinks-notifications-jvm/arm.Dockerfile deleted file mode 100644 index 2edc3d8..0000000 --- a/streampipes-extensions/streampipes-sinks-notifications-jvm/arm.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-sinks-notifications-jvm.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-sinks-notifications-jvm/development/env b/streampipes-extensions/streampipes-sinks-notifications-jvm/development/env deleted file mode 100644 index b575485..0000000 --- a/streampipes-extensions/streampipes-sinks-notifications-jvm/development/env +++ /dev/null
@@ -1,28 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Those parameters are used by IntelliJ to set the default consul parameters for development -SP_PORT=7025 -SP_HOST=host.docker.internal -SP_DEBUG=true -SLACK_TOKEN= -EMAIL_FROM= -EMAIL_USERNAME= -EMAIL_PASSWORD= -EMAIL_SMTP_HOST= -EMAIL_SMTP_PORT= -EMAIL_STARTTLS= -EMAIL_SLL= -WEBSOCKET_PROTOCOL=ws
diff --git a/streampipes-extensions/streampipes-sinks-notifications-jvm/pom.xml b/streampipes-extensions/streampipes-sinks-notifications-jvm/pom.xml index 0b1fb39..d21329f 100644 --- a/streampipes-extensions/streampipes-sinks-notifications-jvm/pom.xml +++ b/streampipes-extensions/streampipes-sinks-notifications-jvm/pom.xml
@@ -21,32 +21,28 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>streampipes-sinks-notifications-jvm</artifactId> - <properties> - <maven.deploy.skip>true</maven.deploy.skip> - </properties> - <dependencies> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-pipeline-elements-shared</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- StreamPipes dependencies --> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-standalone</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies --> @@ -64,36 +60,4 @@ </dependency> </dependencies> - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>jar</goal> - </goals> - <phase>package</phase> - <configuration> - <classifier>embed</classifier> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-maven-plugin</artifactId> - <executions> - <execution> - <goals> - <goal>repackage</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - <finalName>streampipes-sinks-notifications-jvm</finalName> - - </build> </project>
diff --git a/streampipes-extensions/streampipes-sinks-notifications-jvm/src/main/java/org/apache/streampipes/sinks/notifications/jvm/SinksNotificationsJvmInit.java b/streampipes-extensions/streampipes-sinks-notifications-jvm/src/main/java/org/apache/streampipes/sinks/notifications/jvm/SinksNotificationsJvmInit.java index 019cb4b..72a6dd4 100644 --- a/streampipes-extensions/streampipes-sinks-notifications-jvm/src/main/java/org/apache/streampipes/sinks/notifications/jvm/SinksNotificationsJvmInit.java +++ b/streampipes-extensions/streampipes-sinks-notifications-jvm/src/main/java/org/apache/streampipes/sinks/notifications/jvm/SinksNotificationsJvmInit.java
@@ -36,10 +36,6 @@ public class SinksNotificationsJvmInit extends StandaloneModelSubmitter { - public static void main(String[] args) { - new SinksNotificationsJvmInit().init(); - } - @Override public SpServiceDefinition provideServiceDefinition() { return SpServiceDefinitionBuilder.create("org.apache.streampipes.sinks.notifications.jvm",
diff --git a/streampipes-extensions/streampipes-sources-vehicle-simulator/Dockerfile b/streampipes-extensions/streampipes-sources-vehicle-simulator/Dockerfile index 924db56..c8f7b92 100644 --- a/streampipes-extensions/streampipes-sources-vehicle-simulator/Dockerfile +++ b/streampipes-extensions/streampipes-sources-vehicle-simulator/Dockerfile
@@ -13,8 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -ARG BASE_IMAGE=adoptopenjdk/openjdk8-openj9:alpine -FROM $BASE_IMAGE +FROM eclipse-temurin:11-jre-focal ENV CONSUL_LOCATION consul
diff --git a/streampipes-extensions/streampipes-sources-vehicle-simulator/aarch64.Dockerfile b/streampipes-extensions/streampipes-sources-vehicle-simulator/aarch64.Dockerfile deleted file mode 100644 index 97a15aa..0000000 --- a/streampipes-extensions/streampipes-sources-vehicle-simulator/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-sources-vehicle-simulator.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-sources-vehicle-simulator/arm.Dockerfile b/streampipes-extensions/streampipes-sources-vehicle-simulator/arm.Dockerfile deleted file mode 100644 index 0843e9e..0000000 --- a/streampipes-extensions/streampipes-sources-vehicle-simulator/arm.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-sources-vehicle-simulator.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-sources-vehicle-simulator/pom.xml b/streampipes-extensions/streampipes-sources-vehicle-simulator/pom.xml index 81c6eee..b559567 100644 --- a/streampipes-extensions/streampipes-sources-vehicle-simulator/pom.xml +++ b/streampipes-extensions/streampipes-sources-vehicle-simulator/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -35,7 +35,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-pipeline-elements-data-simulator</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>log4j</groupId> @@ -48,7 +48,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>org.graalvm.nativeimage</groupId> @@ -59,12 +59,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sources</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-standalone</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-extensions/streampipes-sources-watertank-simulator/Dockerfile b/streampipes-extensions/streampipes-sources-watertank-simulator/Dockerfile index 48b6778..12bee65 100644 --- a/streampipes-extensions/streampipes-sources-watertank-simulator/Dockerfile +++ b/streampipes-extensions/streampipes-sources-watertank-simulator/Dockerfile
@@ -13,8 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -ARG BASE_IMAGE=adoptopenjdk/openjdk8-openj9:alpine -FROM $BASE_IMAGE +FROM eclipse-temurin:11-jre-focal ENV CONSUL_LOCATION consul
diff --git a/streampipes-extensions/streampipes-sources-watertank-simulator/aarch64.Dockerfile b/streampipes-extensions/streampipes-sources-watertank-simulator/aarch64.Dockerfile deleted file mode 100644 index 77507a9..0000000 --- a/streampipes-extensions/streampipes-sources-watertank-simulator/aarch64.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm64v8/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-aarch64-static /usr/bin -COPY target/streampipes-sources-watertank-simulator.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-sources-watertank-simulator/arm.Dockerfile b/streampipes-extensions/streampipes-sources-watertank-simulator/arm.Dockerfile deleted file mode 100644 index 0367081..0000000 --- a/streampipes-extensions/streampipes-sources-watertank-simulator/arm.Dockerfile +++ /dev/null
@@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ARG BASE_IMAGE=arm32v7/openjdk:11-jre-slim -FROM $BASE_IMAGE - -ENV CONSUL_LOCATION consul - -EXPOSE 8090 - -COPY qemu-arm-static /usr/bin -COPY target/streampipes-sources-watertank-simulator.jar /streampipes-processing-element-container.jar - -ENTRYPOINT ["java", "-jar", "/streampipes-processing-element-container.jar"]
diff --git a/streampipes-extensions/streampipes-sources-watertank-simulator/pom.xml b/streampipes-extensions/streampipes-sources-watertank-simulator/pom.xml index 6e5da08..a1b8b40 100644 --- a/streampipes-extensions/streampipes-sources-watertank-simulator/pom.xml +++ b/streampipes-extensions/streampipes-sources-watertank-simulator/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-extensions</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -35,7 +35,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-pipeline-elements-data-simulator</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>log4j</groupId> @@ -48,7 +48,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk-bundle</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>org.graalvm.nativeimage</groupId> @@ -59,12 +59,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sources</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-standalone</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-logging/pom.xml b/streampipes-logging/pom.xml index 1e8f567..bec0929 100644 --- a/streampipes-logging/pom.xml +++ b/streampipes-logging/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/streampipes-mail/pom.xml b/streampipes-mail/pom.xml index 782ce9d..8b50f0f 100644 --- a/streampipes-mail/pom.xml +++ b/streampipes-mail/pom.xml
@@ -16,13 +16,11 @@ ~ limitations under the License. ~ --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,12 +30,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-config</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-user-management</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.simplejavamail</groupId>
diff --git a/streampipes-maven-plugin/pom.xml b/streampipes-maven-plugin/pom.xml index 3abf907..f711ab2 100644 --- a/streampipes-maven-plugin/pom.xml +++ b/streampipes-maven-plugin/pom.xml
@@ -20,7 +20,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -139,7 +139,7 @@ <dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> - <version>1.26</version> + <version>1.32</version> </dependency> <!-- dependency convergence -->
diff --git a/streampipes-measurement-units/pom.xml b/streampipes-measurement-units/pom.xml index d2e700b..fd17344 100644 --- a/streampipes-measurement-units/pom.xml +++ b/streampipes-measurement-units/pom.xml
@@ -21,7 +21,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <artifactId>streampipes-measurement-units</artifactId> @@ -31,7 +31,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-commons</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-messaging-jms/pom.xml b/streampipes-messaging-jms/pom.xml index 985aea4..3edcc5c 100644 --- a/streampipes-messaging-jms/pom.xml +++ b/streampipes-messaging-jms/pom.xml
@@ -21,7 +21,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,7 +32,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-messaging-kafka/pom.xml b/streampipes-messaging-kafka/pom.xml index 2bdae81..2948501 100644 --- a/streampipes-messaging-kafka/pom.xml +++ b/streampipes-messaging-kafka/pom.xml
@@ -21,7 +21,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,12 +32,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-commons</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-messaging-mqtt/pom.xml b/streampipes-messaging-mqtt/pom.xml index 67ac177..d157488 100644 --- a/streampipes-messaging-mqtt/pom.xml +++ b/streampipes-messaging-mqtt/pom.xml
@@ -20,7 +20,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -31,7 +31,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-messaging/pom.xml b/streampipes-messaging/pom.xml index c688373..bc9af02 100644 --- a/streampipes-messaging/pom.xml +++ b/streampipes-messaging/pom.xml
@@ -21,7 +21,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,7 +32,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> </dependencies> </project> \ No newline at end of file
diff --git a/streampipes-model-client/pom.xml b/streampipes-model-client/pom.xml index 431bad4..391f540 100644 --- a/streampipes-model-client/pom.xml +++ b/streampipes-model-client/pom.xml
@@ -21,7 +21,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <artifactId>streampipes-model-client</artifactId> @@ -32,12 +32,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-commons</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model-shared</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-model-shared/pom.xml b/streampipes-model-shared/pom.xml index 11eb69b..ff90040 100644 --- a/streampipes-model-shared/pom.xml +++ b/streampipes-model-shared/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/streampipes-model/pom.xml b/streampipes-model/pom.xml index 53f9c6c..9230111 100644 --- a/streampipes-model/pom.xml +++ b/streampipes-model/pom.xml
@@ -23,29 +23,29 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <dependencies> <!-- StreamPipes dependencies --> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-commons</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model-shared</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-logging</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-vocabulary</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies --> <dependency>
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/MessageLd.java b/streampipes-model/src/main/java/org/apache/streampipes/model/MessageLd.java deleted file mode 100644 index 61b3cd8..0000000 --- a/streampipes-model/src/main/java/org/apache/streampipes/model/MessageLd.java +++ /dev/null
@@ -1,117 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.model; - -import org.apache.commons.lang3.RandomStringUtils; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class MessageLd { - - private static final String prefix = "urn:streampipes.org:spi:"; - - private String elementId; - - private boolean success; - - private String elementName; - - private List<NotificationLd> notifications; - - public MessageLd() { - this.elementId = prefix - + this.getClass().getSimpleName().toLowerCase() - + ":" - + RandomStringUtils.randomAlphabetic(6); - this.elementName = ""; - } - - public MessageLd(MessageLd other) { - this(); - this.success = other.isSuccess(); - this.elementName = other.getElementName(); - this.notifications = other.getNotifications(); - } - - public MessageLd(boolean success){ - this(); - this.success = success; - this.notifications = null; - } - - public MessageLd(boolean success, List<NotificationLd> notifications) { - this(); - this.success = success; - this.notifications = notifications; - } - - public MessageLd(boolean success, List<NotificationLd> notifications, String elementName) { - this(success, notifications); - this.elementName = elementName; - } - - - public MessageLd(boolean success, NotificationLd...notifications) { - this(); - this.success = success; - this.notifications = new ArrayList<>(); - this.notifications.addAll(Arrays.asList(notifications)); - } - - public boolean isSuccess() { - return success; - } - - public void setSuccess(boolean success) { - this.success = success; - } - - public List<NotificationLd> getNotifications() { - return notifications; - } - - public void setNotifications(List<NotificationLd> notifications) { - this.notifications = notifications; - } - - public boolean addNotification(NotificationLd notification) - { - return notifications.add(notification); - } - - public String getElementName() { - return elementName; - } - - public void setElementName(String elementName) { - this.elementName = elementName; - } - - public String getElementId() { - return elementId; - } - - public void setElementId(String elementId) { - this.elementId = elementId; - } - - -}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/NotificationLd.java b/streampipes-model/src/main/java/org/apache/streampipes/model/NotificationLd.java deleted file mode 100644 index 7b6b7b8..0000000 --- a/streampipes-model/src/main/java/org/apache/streampipes/model/NotificationLd.java +++ /dev/null
@@ -1,95 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.streampipes.model; - -import org.apache.commons.lang3.RandomStringUtils; - -public class NotificationLd { - - private static final String prefix = "urn:streampipes.org:spi:"; - - private String elementId; - - private String title; - - private String description; - - private String additionalInformation; - - public NotificationLd() { - this.elementId = prefix - + this.getClass().getSimpleName().toLowerCase() - + ":" - + RandomStringUtils.randomAlphabetic(6); - this.additionalInformation = ""; - } - - public NotificationLd(NotificationLd other) { - this(); - this.title = other.getTitle(); - this.description = other.getDescription(); - this.additionalInformation = other.getAdditionalInformation(); - } - - public NotificationLd(String title, String description) { - this(); - this.title = title; - this.description = description; - } - - public NotificationLd(String title, String description, - String additionalInformation) { - this(); - this.title = title; - this.description = description; - this.additionalInformation = additionalInformation; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getAdditionalInformation() { - return additionalInformation; - } - - public void setAdditionalInformation(String additionalInformation) { - this.additionalInformation = additionalInformation; - } - - public String getElementId() { - return elementId; - } - - public void setElementId(String elementId) { - this.elementId = elementId; - } -}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/StreamPipesErrorMessage.java b/streampipes-model/src/main/java/org/apache/streampipes/model/StreamPipesErrorMessage.java new file mode 100644 index 0000000..c6bf711 --- /dev/null +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/StreamPipesErrorMessage.java
@@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.model; + +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.apache.streampipes.model.shared.annotation.TsModel; + +@TsModel +public class StreamPipesErrorMessage { + + private String level; + private String title; + private String detail; + + private String cause; + private String fullStackTrace; + + public static StreamPipesErrorMessage from(Exception exception) { + String cause = exception.getCause() != null ? exception.getCause().getMessage() : exception.getMessage(); + return new StreamPipesErrorMessage( + "error", + exception.getMessage(), + "", + ExceptionUtils.getStackTrace(exception), + cause); + } + + public StreamPipesErrorMessage(String level, + String title, + String detail) { + this.level = level; + this.title = title; + this.detail = detail; + } + + public StreamPipesErrorMessage(String level, + String title, + String detail, + String fullStackTrace, + String cause) { + this.level = level; + this.title = title; + this.detail = detail; + this.fullStackTrace = fullStackTrace; + this.cause = cause; + } + + public String getLevel() { + return level; + } + + public void setLevel(String level) { + this.level = level; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + + public String getFullStackTrace() { + return fullStackTrace; + } + + public void setFullStackTrace(String fullStackTrace) { + this.fullStackTrace = fullStackTrace; + } + + public String getCause() { + return cause; + } + + public void setCause(String cause) { + this.cause = cause; + } +}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/assets/AssetLink.java b/streampipes-model/src/main/java/org/apache/streampipes/model/assets/AssetLink.java new file mode 100644 index 0000000..74d15f0 --- /dev/null +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/assets/AssetLink.java
@@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.model.assets; + +import java.util.Objects; + +public class AssetLink { + + private String resourceId; + private String linkType; + private String linkLabel; + private String queryHint; + private boolean editingDisabled; + + public AssetLink() { + } + + public String getResourceId() { + return resourceId; + } + + public void setResourceId(String resourceId) { + this.resourceId = resourceId; + } + + public String getLinkType() { + return linkType; + } + + public void setLinkType(String linkType) { + this.linkType = linkType; + } + + public String getLinkLabel() { + return linkLabel; + } + + public void setLinkLabel(String linkLabel) { + this.linkLabel = linkLabel; + } + + public boolean isEditingDisabled() { + return editingDisabled; + } + + public void setEditingDisabled(boolean editingDisabled) { + this.editingDisabled = editingDisabled; + } + + public String getQueryHint() { + return queryHint; + } + + public void setQueryHint(String queryHint) { + this.queryHint = queryHint; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AssetLink assetLink = (AssetLink) o; + return resourceId.equals(assetLink.resourceId) && queryHint.equals(assetLink.queryHint); + } + + @Override + public int hashCode() { + return Objects.hash(resourceId, queryHint); + } +}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/assets/AssetLinkType.java b/streampipes-model/src/main/java/org/apache/streampipes/model/assets/AssetLinkType.java new file mode 100644 index 0000000..79d6c26 --- /dev/null +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/assets/AssetLinkType.java
@@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.model.assets; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import org.apache.streampipes.commons.constants.GenericDocTypes; + +import java.util.ArrayList; +import java.util.List; + +public class AssetLinkType { + + public final String appDocType = GenericDocTypes.DOC_ASSET_LINK_TYPE; + + @JsonProperty("_id") + private @SerializedName("_id") String id; + + private String linkType; + private String linkLabel; + private String linkColor; + private String linkIcon; + private String linkQueryHint; + private List<String> navPaths; + private boolean navigationActive; + + public AssetLinkType(String linkType, + String linkLabel, + String linkColor, + String linkIcon, + String linkQueryHint, + List<String> navPaths, + boolean navigationActive) { + this.linkType = linkType; + this.linkLabel = linkLabel; + this.linkColor = linkColor; + this.linkIcon = linkIcon; + this.linkQueryHint = linkQueryHint; + this.navPaths = navPaths; + this.navigationActive = navigationActive; + } + + public AssetLinkType() { + this.navPaths = new ArrayList<>(); + } + + public String getLinkType() { + return linkType; + } + + public void setLinkType(String linkType) { + this.linkType = linkType; + } + + public String getLinkLabel() { + return linkLabel; + } + + public void setLinkLabel(String linkLabel) { + this.linkLabel = linkLabel; + } + + public String getLinkColor() { + return linkColor; + } + + public void setLinkColor(String linkColor) { + this.linkColor = linkColor; + } + + public String getLinkIcon() { + return linkIcon; + } + + public void setLinkIcon(String linkIcon) { + this.linkIcon = linkIcon; + } + + public String getLinkQueryHint() { + return linkQueryHint; + } + + public void setLinkQueryHint(String linkQueryHint) { + this.linkQueryHint = linkQueryHint; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getAppDocType() { + return appDocType; + } + + public List<String> getNavPaths() { + return navPaths; + } + + public void setNavPaths(List<String> navPaths) { + this.navPaths = navPaths; + } + + public boolean isNavigationActive() { + return navigationActive; + } + + public void setNavigationActive(boolean navigationActive) { + this.navigationActive = navigationActive; + } +}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/assets/AssetType.java b/streampipes-model/src/main/java/org/apache/streampipes/model/assets/AssetType.java new file mode 100644 index 0000000..45b7151 --- /dev/null +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/assets/AssetType.java
@@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.model.assets; + +public class AssetType { + + private String assetIcon; + private String assetIconColor; + private String assetTypeCategory; + private String assetTypeLabel; + + public AssetType() { + } + + public String getAssetIcon() { + return assetIcon; + } + + public void setAssetIcon(String assetIcon) { + this.assetIcon = assetIcon; + } + + public String getAssetIconColor() { + return assetIconColor; + } + + public void setAssetIconColor(String assetIconColor) { + this.assetIconColor = assetIconColor; + } + + public String getAssetTypeCategory() { + return assetTypeCategory; + } + + public void setAssetTypeCategory(String assetTypeCategory) { + this.assetTypeCategory = assetTypeCategory; + } + + public String getAssetTypeLabel() { + return assetTypeLabel; + } + + public void setAssetTypeLabel(String assetTypeLabel) { + this.assetTypeLabel = assetTypeLabel; + } +}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/assets/SpAsset.java b/streampipes-model/src/main/java/org/apache/streampipes/model/assets/SpAsset.java new file mode 100644 index 0000000..eeee4c6 --- /dev/null +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/assets/SpAsset.java
@@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.model.assets; + +import java.util.ArrayList; +import java.util.List; + +public class SpAsset { + + private String assetId; + private String assetName; + private String assetDescription; + + private AssetType assetType; + private List<AssetLink> assetLinks; + + private List<SpAsset> assets; + + public SpAsset() { + this.assets = new ArrayList<>(); + this.assetLinks = new ArrayList<>(); + } + + public String getAssetId() { + return assetId; + } + + public void setAssetId(String assetId) { + this.assetId = assetId; + } + + public String getAssetName() { + return assetName; + } + + public void setAssetName(String assetName) { + this.assetName = assetName; + } + + public String getAssetDescription() { + return assetDescription; + } + + public void setAssetDescription(String assetDescription) { + this.assetDescription = assetDescription; + } + + public AssetType getAssetType() { + return assetType; + } + + public void setAssetType(AssetType assetType) { + this.assetType = assetType; + } + + public List<AssetLink> getAssetLinks() { + return assetLinks; + } + + public void setAssetLinks(List<AssetLink> assetLinks) { + this.assetLinks = assetLinks; + } + + public List<SpAsset> getAssets() { + return assets; + } + + public void setAssets(List<SpAsset> assets) { + this.assets = assets; + } +}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/assets/SpAssetModel.java b/streampipes-model/src/main/java/org/apache/streampipes/model/assets/SpAssetModel.java new file mode 100644 index 0000000..99787aa --- /dev/null +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/assets/SpAssetModel.java
@@ -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. + * + */ + +package org.apache.streampipes.model.assets; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import org.apache.streampipes.commons.constants.GenericDocTypes; + +public class SpAssetModel extends SpAsset { + + public static final String appDocType = GenericDocTypes.DOC_ASSET_MANGEMENT; + + @JsonProperty("_id") + private @SerializedName("_id") String id; + + private boolean removable; + + public SpAssetModel() { + super(); + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public boolean isRemovable() { + return removable; + } + + public void setRemovable(boolean removable) { + this.removable = removable; + } +}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/AdapterDescription.java b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/AdapterDescription.java index 5647f3f..173f2e1 100644 --- a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/AdapterDescription.java +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/adapter/AdapterDescription.java
@@ -23,6 +23,7 @@ import org.apache.streampipes.model.connect.rules.TransformationRuleDescription; import org.apache.streampipes.model.connect.rules.schema.SchemaTransformationRuleDescription; import org.apache.streampipes.model.connect.rules.stream.StreamTransformationRuleDescription; +import org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescription; import org.apache.streampipes.model.connect.rules.value.ValueTransformationRuleDescription; import org.apache.streampipes.model.grounding.*; import org.apache.streampipes.model.shared.annotation.TsModel; @@ -162,17 +163,18 @@ this.adapterType = adapterType; } - public List getValueRules() { - List tmp = new ArrayList<>(); + public List<TransformationRuleDescription> getValueRules() { + var tmp = new ArrayList<TransformationRuleDescription>(); rules.forEach(rule -> { - if(rule instanceof ValueTransformationRuleDescription) + if(rule instanceof ValueTransformationRuleDescription && !(rule instanceof AddTimestampRuleDescription)) { tmp.add(rule); + } }); return tmp; } - public List getStreamRules() { - List tmp = new ArrayList<>(); + public List<TransformationRuleDescription> getStreamRules() { + var tmp = new ArrayList<TransformationRuleDescription>(); rules.forEach(rule -> { if(rule instanceof StreamTransformationRuleDescription) tmp.add(rule); @@ -180,8 +182,8 @@ return tmp; } - public List getSchemaRules() { - List tmp = new ArrayList<>(); + public List<TransformationRuleDescription> getSchemaRules() { + var tmp = new ArrayList<TransformationRuleDescription>(); rules.forEach(rule -> { if(rule instanceof SchemaTransformationRuleDescription) tmp.add(rule); @@ -231,10 +233,19 @@ this.selectedEndpointUrl = selectedEndpointUrl; } + /** + * @deprecated check if the service group can be removed as a single pipeline element + * can correspond to different service groups + */ + @Deprecated public String getCorrespondingServiceGroup() { return correspondingServiceGroup; } + /** + * @deprecated check if the service group can be removed as a single pipeline element + * can correspond to different service groups + */ public void setCorrespondingServiceGroup(String correspondingServiceGroup) { this.correspondingServiceGroup = correspondingServiceGroup; }
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/AdapterEventPreview.java b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/AdapterEventPreview.java new file mode 100644 index 0000000..d70af4f --- /dev/null +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/AdapterEventPreview.java
@@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.model.connect.guess; + +import org.apache.streampipes.model.connect.rules.TransformationRuleDescription; +import org.apache.streampipes.model.shared.annotation.TsModel; + +import java.util.List; +import java.util.Map; + +@TsModel +public class AdapterEventPreview { + + private List<TransformationRuleDescription> rules; + + private Map<String, GuessTypeInfo> inputData; + + public List<TransformationRuleDescription> getRules() { + return rules; + } + + public void setRules(List<TransformationRuleDescription> rules) { + this.rules = rules; + } + + public Map<String, GuessTypeInfo> getInputData() { + return inputData; + } + + public void setInputData(Map<String, GuessTypeInfo> inputData) { + this.inputData = inputData; + } +}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/AdapterGuessInfo.java b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/AdapterGuessInfo.java new file mode 100644 index 0000000..6aa137f --- /dev/null +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/AdapterGuessInfo.java
@@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.model.connect.guess; + +import org.apache.streampipes.model.schema.EventSchema; + +import java.util.List; +import java.util.Map; + +public class AdapterGuessInfo { + + private EventSchema eventSchema; + private List<Map<String, GuessTypeInfo>> eventPreview; + + public AdapterGuessInfo() { + } + + public AdapterGuessInfo(EventSchema eventSchema, + Map<String, GuessTypeInfo> singleEventSample) { + this.eventSchema = eventSchema; + this.eventPreview = List.of(singleEventSample); + } + + public EventSchema getEventSchema() { + return eventSchema; + } + + public void setEventSchema(EventSchema eventSchema) { + this.eventSchema = eventSchema; + } + + public List<Map<String, GuessTypeInfo>> getEventPreview() { + return eventPreview; + } + + public void setEventPreview(List<Map<String, GuessTypeInfo>> eventPreview) { + this.eventPreview = eventPreview; + } +}
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/FieldStatus.java similarity index 87% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/FieldStatus.java index 58ba04b..eec688b 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/FieldStatus.java
@@ -16,3 +16,10 @@ * */ +package org.apache.streampipes.model.connect.guess; + +public enum FieldStatus { + GOOD, + BAD, + ATTENTION +}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/FieldStatusInfo.java b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/FieldStatusInfo.java new file mode 100644 index 0000000..a66b83d --- /dev/null +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/FieldStatusInfo.java
@@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.model.connect.guess; + +public class FieldStatusInfo { + + private FieldStatus fieldStatus; + private String additionalInfo; + private boolean changesRequired; + + public static FieldStatusInfo good() { + var info = new FieldStatusInfo(); + info.setFieldStatus(FieldStatus.GOOD); + return info; + } + + public static FieldStatusInfo bad(String additionalInfo, + boolean changesRequired) { + var info = new FieldStatusInfo(); + info.setFieldStatus(FieldStatus.BAD); + info.setAdditionalInfo(additionalInfo); + info.setChangesRequired(changesRequired); + + return info; + } + + public FieldStatusInfo() { + } + + public FieldStatus getFieldStatus() { + return fieldStatus; + } + + public void setFieldStatus(FieldStatus fieldStatus) { + this.fieldStatus = fieldStatus; + } + + public String getAdditionalInfo() { + return additionalInfo; + } + + public void setAdditionalInfo(String additionalInfo) { + this.additionalInfo = additionalInfo; + } + + public boolean isChangesRequired() { + return changesRequired; + } + + public void setChangesRequired(boolean changesRequired) { + this.changesRequired = changesRequired; + } +}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/GuessSchema.java b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/GuessSchema.java index 4bda9da..ba39f89 100644 --- a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/GuessSchema.java +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/GuessSchema.java
@@ -22,18 +22,31 @@ import org.apache.streampipes.model.schema.EventSchema; import org.apache.streampipes.model.shared.annotation.TsModel; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + @TsModel public class GuessSchema extends UnnamedStreamPipesEntity { public EventSchema eventSchema; + public List<Map<String, GuessTypeInfo>> eventPreview; + + public Map<String, FieldStatusInfo> fieldStatusInfo; + public GuessSchema() { super(); + this.eventPreview = new ArrayList<>(); + this.fieldStatusInfo = new HashMap<>(); } public GuessSchema(GuessSchema other) { super(other); this.eventSchema = other.getEventSchema() != null ? new EventSchema(other.getEventSchema()) : null; + this.eventPreview = other.getEventPreview(); + this.fieldStatusInfo = other.getFieldStatusInfo(); } public EventSchema getEventSchema() { return eventSchema; @@ -43,4 +56,21 @@ this.eventSchema = eventSchema; } + public List<Map<String, GuessTypeInfo>> getEventPreview() { + return eventPreview; + } + + public void setEventPreview(List<Map<String, GuessTypeInfo>> eventPreview) { + this.eventPreview = eventPreview; + } + + public Map<String, FieldStatusInfo> getFieldStatusInfo() { + return fieldStatusInfo; + } + + public void setFieldStatusInfo(Map<String, FieldStatusInfo> fieldStatusInfo) { + this.fieldStatusInfo = fieldStatusInfo; + } + + }
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/GuessTypeInfo.java b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/GuessTypeInfo.java new file mode 100644 index 0000000..7404451 --- /dev/null +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/GuessTypeInfo.java
@@ -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. + * + */ + +package org.apache.streampipes.model.connect.guess; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +public class GuessTypeInfo { + + private String type; + + @JsonTypeInfo(use = JsonTypeInfo.Id.NONE, property = "type") + private Object value; + + public GuessTypeInfo() { + } + + public GuessTypeInfo(String type, Object value) { + this.type = type; + this.value = value; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } +}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/TransformationRuleDescription.java b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/TransformationRuleDescription.java index bd1b85b..590b416 100644 --- a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/TransformationRuleDescription.java +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/TransformationRuleDescription.java
@@ -41,6 +41,7 @@ @JsonSubTypes.Type(DeleteRuleDescription.class), @JsonSubTypes.Type(RenameRuleDescription.class), @JsonSubTypes.Type(MoveRuleDescription.class), + @JsonSubTypes.Type(ChangeDatatypeTransformationRuleDescription.class), @JsonSubTypes.Type(CorrectionValueTransformationRuleDescription.class), }) public abstract class TransformationRuleDescription extends UnnamedStreamPipesEntity {
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/value/ChangeDatatypeTransformationRuleDescription.java b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/value/ChangeDatatypeTransformationRuleDescription.java new file mode 100644 index 0000000..aa64e64 --- /dev/null +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/value/ChangeDatatypeTransformationRuleDescription.java
@@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.model.connect.rules.value; + +public class ChangeDatatypeTransformationRuleDescription extends ValueTransformationRuleDescription { + + private String runtimeKey; + private String originalDatatypeXsd; + private String targetDatatypeXsd; + + public ChangeDatatypeTransformationRuleDescription() { + } + + public ChangeDatatypeTransformationRuleDescription(ChangeDatatypeTransformationRuleDescription other) { + super(other); + this.runtimeKey = other.getRuntimeKey(); + this.originalDatatypeXsd = other.getOriginalDatatypeXsd(); + this.targetDatatypeXsd = other.getTargetDatatypeXsd(); + } + + public String getRuntimeKey() { + return runtimeKey; + } + + public void setRuntimeKey(String runtimeKey) { + this.runtimeKey = runtimeKey; + } + + public String getOriginalDatatypeXsd() { + return originalDatatypeXsd; + } + + public void setOriginalDatatypeXsd(String originalDatatypeXsd) { + this.originalDatatypeXsd = originalDatatypeXsd; + } + + public String getTargetDatatypeXsd() { + return targetDatatypeXsd; + } + + public void setTargetDatatypeXsd(String targetDatatypeXsd) { + this.targetDatatypeXsd = targetDatatypeXsd; + } +}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/DataLakeMeasure.java b/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/DataLakeMeasure.java index 532e537..5b90fd9 100644 --- a/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/DataLakeMeasure.java +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/DataLakeMeasure.java
@@ -18,6 +18,8 @@ package org.apache.streampipes.model.datalake; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; import org.apache.streampipes.model.base.UnnamedStreamPipesEntity; import org.apache.streampipes.model.schema.EventSchema; import org.apache.streampipes.model.shared.annotation.TsModel; @@ -25,12 +27,21 @@ @TsModel public class DataLakeMeasure extends UnnamedStreamPipesEntity { + public final static String CURRENT_SCHEMA_VERSION = "1.1"; + + @JsonProperty("_rev") + private @SerializedName("_rev") String rev; + private String measureName; + + private String timestampField; private EventSchema eventSchema; private String pipelineId; private String pipelineName; private boolean pipelineIsRunning; + private String schemaVersion; + public DataLakeMeasure() { super(); } @@ -47,6 +58,12 @@ this.eventSchema = eventSchema; } + public DataLakeMeasure(String measureName, String timestampField, EventSchema eventSchema) { + this.measureName = measureName; + this.eventSchema = eventSchema; + this.timestampField = timestampField; + } + public String getMeasureName() { return measureName; } @@ -86,4 +103,28 @@ public void setPipelineIsRunning(boolean pipelineIsRunning) { this.pipelineIsRunning = pipelineIsRunning; } + + public String getSchemaVersion() { + return schemaVersion; + } + + public void setSchemaVersion(String schemaVersion) { + this.schemaVersion = schemaVersion; + } + + public String getTimestampField() { + return timestampField; + } + + public void setTimestampField(String timestampField) { + this.timestampField = timestampField; + } + + public String getRev() { + return rev; + } + + public void setRev(String rev) { + this.rev = rev; + } }
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/SpQueryResult.java b/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/SpQueryResult.java index 8a2a54c..c3c9ef7 100644 --- a/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/SpQueryResult.java +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/SpQueryResult.java
@@ -31,6 +31,7 @@ private List<DataSeries> allDataSeries; private int sourceIndex; private SpQueryStatus spQueryStatus; + private String forId; public SpQueryResult() { this.total = 0; @@ -92,4 +93,12 @@ public void setSpQueryStatus(SpQueryStatus spQueryStatus) { this.spQueryStatus = spQueryStatus; } + + public String getForId() { + return forId; + } + + public void setForId(String forId) { + this.forId = forId; + } }
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/export/AssetExportConfiguration.java b/streampipes-model/src/main/java/org/apache/streampipes/model/export/AssetExportConfiguration.java new file mode 100644 index 0000000..bd1e946 --- /dev/null +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/export/AssetExportConfiguration.java
@@ -0,0 +1,170 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.model.export; + +import java.util.HashSet; +import java.util.Set; + +public class AssetExportConfiguration { + + private String assetId; + private String assetName; + + private Set<ExportItem> assets; + private Set<ExportItem> adapters; + private Set<ExportItem> dashboards; + private Set<ExportItem> dataViews; + private Set<ExportItem> dataLakeMeasures; + private Set<ExportItem> dataSources; + private Set<ExportItem> pipelines; + private Set<ExportItem> files; + + private boolean overrideBrokerSettings; + + public AssetExportConfiguration() { + this.adapters = new HashSet<>(); + this.dashboards = new HashSet<>(); + this.dataViews = new HashSet<>(); + this.dataLakeMeasures = new HashSet<>(); + this.dataSources = new HashSet<>(); + this.pipelines = new HashSet<>(); + this.files = new HashSet<>(); + this.assets = new HashSet<>(); + } + + public Set<ExportItem> getAdapters() { + return adapters; + } + + public void setAdapters(Set<ExportItem> adapters) { + this.adapters = adapters; + } + + public void addAdapter(ExportItem item) { + this.adapters.add(item); + } + + public Set<ExportItem> getDashboards() { + return dashboards; + } + + public void setDashboards(Set<ExportItem> dashboards) { + this.dashboards = dashboards; + } + + public void addDashboard(ExportItem item) { + this.dashboards.add(item); + } + + public Set<ExportItem> getDataViews() { + return dataViews; + } + + public void setDataViews(Set<ExportItem> dataViews) { + this.dataViews = dataViews; + } + + public void addDataView(ExportItem item) { + this.dataViews.add(item); + } + + public Set<ExportItem> getDataLakeMeasures() { + return dataLakeMeasures; + } + + public void setDataLakeMeasures(Set<ExportItem> dataLakeMeasures) { + this.dataLakeMeasures = dataLakeMeasures; + } + + public void addDataLakeMeasure(ExportItem item) { + this.dataLakeMeasures.add(item); + } + + public Set<ExportItem> getDataSources() { + return dataSources; + } + + public void setDataSources(Set<ExportItem> dataSources) { + this.dataSources = dataSources; + } + + public void addDataSource(ExportItem item) { + this.dataSources.add(item); + } + + public String getAssetId() { + return assetId; + } + + public void setAssetId(String assetId) { + this.assetId = assetId; + } + + public Set<ExportItem> getPipelines() { + return pipelines; + } + + public void setPipelines(Set<ExportItem> pipelines) { + this.pipelines = pipelines; + } + + public void addPipeline(ExportItem item) { + this.pipelines.add(item); + } + + public Set<ExportItem> getFiles() { + return files; + } + + public void setFiles(Set<ExportItem> files) { + this.files = files; + } + + public void addFile(ExportItem item) { + this.files.add(item); + } + + public String getAssetName() { + return assetName; + } + + public void setAssetName(String assetName) { + this.assetName = assetName; + } + + public Set<ExportItem> getAssets() { + return assets; + } + + public void setAssets(Set<ExportItem> assets) { + this.assets = assets; + } + + public void addAsset(ExportItem asset) { + this.assets.add(asset); + } + + public boolean isOverrideBrokerSettings() { + return overrideBrokerSettings; + } + + public void setOverrideBrokerSettings(boolean overrideBrokerSettings) { + this.overrideBrokerSettings = overrideBrokerSettings; + } +}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/export/ExportConfiguration.java b/streampipes-model/src/main/java/org/apache/streampipes/model/export/ExportConfiguration.java new file mode 100644 index 0000000..2a0052b --- /dev/null +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/export/ExportConfiguration.java
@@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +package org.apache.streampipes.model.export; + +import org.apache.streampipes.model.shared.annotation.TsModel; + +import java.util.ArrayList; +import java.util.List; + +@TsModel +public class ExportConfiguration { + + private List<AssetExportConfiguration> assetExportConfiguration; + + public ExportConfiguration() { + this.assetExportConfiguration = new ArrayList<>(); + } + + public List<AssetExportConfiguration> getAssetExportConfiguration() { + return assetExportConfiguration; + } + + public void setAssetExportConfiguration(List<AssetExportConfiguration> assetExportConfiguration) { + this.assetExportConfiguration = assetExportConfiguration; + } +}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/export/ExportItem.java b/streampipes-model/src/main/java/org/apache/streampipes/model/export/ExportItem.java new file mode 100644 index 0000000..cb62711 --- /dev/null +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/export/ExportItem.java
@@ -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. + * + */ + +package org.apache.streampipes.model.export; + +public class ExportItem { + + private String resourceId; + private String label; + private boolean selected; + + public ExportItem() { + } + + public ExportItem(String resourceId, String label, boolean selected) { + this.resourceId = resourceId; + this.label = label; + this.selected = selected; + } + + public String getResourceId() { + return resourceId; + } + + public void setResourceId(String resourceId) { + this.resourceId = resourceId; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public boolean isSelected() { + return selected; + } + + public void setSelected(boolean selected) { + this.selected = selected; + } +}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/export/StreamPipesApplicationPackage.java b/streampipes-model/src/main/java/org/apache/streampipes/model/export/StreamPipesApplicationPackage.java new file mode 100644 index 0000000..a95dc63 --- /dev/null +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/export/StreamPipesApplicationPackage.java
@@ -0,0 +1,204 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.model.export; + +import org.apache.streampipes.model.shared.annotation.TsModel; + +import java.util.HashSet; +import java.util.Set; + +@TsModel +public class StreamPipesApplicationPackage { + + private Set<String> requiredProcessorAppIds; + private Set<String> requiredDataSinkAppIds; + private Set<String> requiredAdapterAppIds; + + private Set<String> assets; + private Set<String> adapters; + private Set<String> dashboards; + private Set<String> dashboardWidgets; + private Set<String> dataViews; + private Set<String> dataViewWidgets; + private Set<String> dataLakeMeasures; + private Set<String> dataSources; + private Set<String> pipelines; + private Set<String> files; + + public StreamPipesApplicationPackage() { + this.requiredProcessorAppIds = new HashSet<>(); + this.requiredDataSinkAppIds = new HashSet<>(); + this.requiredAdapterAppIds = new HashSet<>(); + + this.adapters = new HashSet<>(); + this.assets = new HashSet<>(); + this.dashboards = new HashSet<>(); + this.dashboardWidgets = new HashSet<>(); + this.dataViews = new HashSet<>(); + this.dataViewWidgets = new HashSet<>(); + this.dataLakeMeasures = new HashSet<>(); + this.dataSources = new HashSet<>(); + this.pipelines = new HashSet<>(); + this.files = new HashSet<>(); + } + + public Set<String> getRequiredProcessorAppIds() { + return requiredProcessorAppIds; + } + + public void setRequiredProcessorAppIds(Set<String> requiredProcessorAppIds) { + this.requiredProcessorAppIds = requiredProcessorAppIds; + } + + public Set<String> getRequiredDataSinkAppIds() { + return requiredDataSinkAppIds; + } + + public void setRequiredDataSinkAppIds(Set<String> requiredDataSinkAppIds) { + this.requiredDataSinkAppIds = requiredDataSinkAppIds; + } + + public Set<String> getRequiredAdapterAppIds() { + return requiredAdapterAppIds; + } + + public void setRequiredAdapterAppIds(Set<String> requiredAdapterAppIds) { + this.requiredAdapterAppIds = requiredAdapterAppIds; + } + + public Set<String> getAdapters() { + return adapters; + } + + public void setAdapters(Set<String> adapters) { + this.adapters = adapters; + } + + public void addAdapter(String adapter) { + this.adapters.add(adapter); + } + + public Set<String> getDashboards() { + return dashboards; + } + + public void setDashboards(Set<String> dashboards) { + this.dashboards = dashboards; + } + + public void addDashboard(String dashboard) { + this.dashboards.add(dashboard); + } + + public Set<String> getDashboardWidgets() { + return dashboardWidgets; + } + + public void setDashboardWidgets(Set<String> dashboardWidgets) { + this.dashboardWidgets = dashboardWidgets; + } + + public void addDashboardWidget(String dashboardWidget) { + this.dashboardWidgets.add(dashboardWidget); + } + + public Set<String> getDataViews() { + return dataViews; + } + + public void setDataViews(Set<String> dataViews) { + this.dataViews = dataViews; + } + + public void addDataView(String dataView) { + this.dataViews.add(dataView); + } + + public Set<String> getDataViewWidgets() { + return dataViewWidgets; + } + + public void setDataViewWidgets(Set<String> dataViewWidgets) { + this.dataViewWidgets = dataViewWidgets; + } + + public void addDataViewWidget(String dataViewWidget) { + this.dataViewWidgets.add(dataViewWidget); + } + + public Set<String> getDataLakeMeasures() { + return dataLakeMeasures; + } + + public void setDataLakeMeasures(Set<String> dataLakeMeasures) { + this.dataLakeMeasures = dataLakeMeasures; + } + + public void addDataLakeMeasure(String dataLakeMeasure) { + this.dataLakeMeasures.add(dataLakeMeasure); + } + + public Set<String> getDataSources() { + return dataSources; + } + + public void setDataSources(Set<String> dataSources) { + this.dataSources = dataSources; + } + + public void addDataSource(String dataSource) { + this.dataSources.add(dataSource); + } + + public Set<String> getPipelines() { + return pipelines; + } + + public void setPipelines(Set<String> pipelines) { + this.pipelines = pipelines; + } + + public void addPipeline(String pipeline) { + this.pipelines.add(pipeline); + } + + public Set<String> getFiles() { + return files; + } + + public void setFiles(Set<String> files) { + this.files = files; + } + + public void addFile(String file) { + this.files.add(file); + } + + public Set<String> getAssets() { + return assets; + } + + public void setAssets(Set<String> assets) { + this.assets = assets; + } + + public void addAsset(String asset) { + this.assets.add(asset); + } +}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/runtime/Event.java b/streampipes-model/src/main/java/org/apache/streampipes/model/runtime/Event.java index 23143fe..84fd010 100644 --- a/streampipes-model/src/main/java/org/apache/streampipes/model/runtime/Event.java +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/runtime/Event.java
@@ -17,6 +17,7 @@ */ package org.apache.streampipes.model.runtime; +import org.apache.streampipes.commons.exceptions.SpRuntimeException; import org.apache.streampipes.model.constants.PropertySelectorConstants; import org.apache.streampipes.model.runtime.field.AbstractField; import org.apache.streampipes.model.runtime.field.PrimitiveField; @@ -71,7 +72,7 @@ .map(Map.Entry::getValue) .filter(entry -> entry.getFieldNameIn().equals(runtimeName)) .findFirst() - .orElseThrow(() -> new IllegalArgumentException("Field " + runtimeName + " not found")); + .orElseThrow(() -> new SpRuntimeException("Field " + runtimeName + " not found")); } public void removeFieldBySelector(String fieldSelector) {
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/template/PipelineTemplateDescription.java b/streampipes-model/src/main/java/org/apache/streampipes/model/template/PipelineTemplateDescription.java index 81f46b4..52fa8f3 100644 --- a/streampipes-model/src/main/java/org/apache/streampipes/model/template/PipelineTemplateDescription.java +++ b/streampipes-model/src/main/java/org/apache/streampipes/model/template/PipelineTemplateDescription.java
@@ -28,15 +28,6 @@ @TsModel public class PipelineTemplateDescription extends NamedStreamPipesEntity { - //@RdfProperty(RDFS.LABEL) - //private String pipelineTemplateName; - - //@RdfProperty(StreamPipes.INTERNAL_NAME) - //private String pipelineTemplateId; - - //@RdfProperty(RDFS.DESCRIPTION) - //private String pipelineTemplateDescription; - private List<BoundPipelineElement> boundTo; public PipelineTemplateDescription() {
diff --git a/streampipes-performance-tests/pom.xml b/streampipes-performance-tests/pom.xml index 36cb506..c31a013 100644 --- a/streampipes-performance-tests/pom.xml +++ b/streampipes-performance-tests/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,22 +32,22 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging-kafka</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-pipeline-management</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat-json</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-pipeline-management/pom.xml b/streampipes-pipeline-management/pom.xml index 19af5ba..e40e532 100644 --- a/streampipes-pipeline-management/pom.xml +++ b/streampipes-pipeline-management/pom.xml
@@ -21,7 +21,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <artifactId>streampipes-pipeline-management</artifactId> @@ -30,87 +30,87 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-commons</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-container</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat-cbor</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat-fst</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat-json</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat-smile</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging-jms</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging-mqtt</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging-kafka</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model-client</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-resource-management</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-serializers-json</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-service-discovery</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-storage-management</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-user-management</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies --> <dependency> @@ -135,13 +135,13 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-measurement-units</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-test-utils</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <scope>test</scope> </dependency> <dependency>
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/execution/endpoint/ExtensionsServiceEndpointGenerator.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/execution/endpoint/ExtensionsServiceEndpointGenerator.java index b3feb3b..8d430e4 100644 --- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/execution/endpoint/ExtensionsServiceEndpointGenerator.java +++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/execution/endpoint/ExtensionsServiceEndpointGenerator.java
@@ -65,7 +65,7 @@ return getServiceEndpoints().get(0); } else { LOG.error("Could not find any service endpoints for appId {}, serviceTag {}", appId, this.spServiceUrlProvider.getServiceTag(appId).asString()); - throw new NoServiceEndpointsAvailableException("Could not find any matching service endpoints"); + throw new NoServiceEndpointsAvailableException("Could not find any matching service endpoints - are all software components running?"); } } }
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/CouchDbInstallationStep.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/CouchDbInstallationStep.java index 7a89ddc..f204ab2 100644 --- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/CouchDbInstallationStep.java +++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/CouchDbInstallationStep.java
@@ -18,6 +18,8 @@ package org.apache.streampipes.manager.setup; +import org.apache.streampipes.manager.setup.tasks.CreateAssetLinkTypeTask; +import org.apache.streampipes.manager.setup.tasks.CreateDefaultAssetTask; import org.apache.streampipes.model.client.endpoint.ExtensionsServiceEndpoint; import org.apache.streampipes.storage.couchdb.impl.ExtensionsServiceEndpointStorageImpl; import org.apache.streampipes.storage.couchdb.utils.Utils; @@ -44,6 +46,8 @@ createDatabases(); createViews(); addRdfEndpoints(); + new CreateAssetLinkTypeTask().execute(); + new CreateDefaultAssetTask().execute(); } @Override
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/tasks/CreateAssetLinkTypeTask.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/tasks/CreateAssetLinkTypeTask.java new file mode 100644 index 0000000..90ddc2d --- /dev/null +++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/tasks/CreateAssetLinkTypeTask.java
@@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.manager.setup.tasks; + +import org.apache.streampipes.commons.exceptions.SpRuntimeException; +import org.apache.streampipes.commons.random.UUIDGenerator; +import org.apache.streampipes.model.assets.AssetLinkType; +import org.apache.streampipes.storage.api.IGenericStorage; +import org.apache.streampipes.storage.management.StorageDispatcher; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +public class CreateAssetLinkTypeTask implements InstallationTask { + + private List<AssetLinkType> defaultLinkTypes = Arrays.asList( + new AssetLinkType("data-view", "Data View", "var(--color-data-view)", "search", "data-view", List.of("dataexplorer"), true), + new AssetLinkType("dashboard", "Dashboard", "var(--color-dashboard)", "insert_chart", "dashboard", List.of("dashboard"), true), + new AssetLinkType("adapter", "Adapter", "var(--color-adapter)", "power", "adapter", List.of("connect"), true), + new AssetLinkType("data-source", "Data Source", "var(--color-data-source)", "dataset", "data-source", List.of(), false), + new AssetLinkType("pipeline", "Pipeline", "var(--color-pipeline)", "play_arrow", "pipeline", List.of("pipeline", "details"), true), + new AssetLinkType("measurement", "Data Lake Storage", "var(--color-measurement)", "folder", "measurement", List.of(), false), + new AssetLinkType("file", "File", "var(--color-file)", "draft", "file", List.of(), false) + ); + + @Override + public void execute() { + var genericStorage = getGenericStorage(); + + this.defaultLinkTypes.forEach(link -> { + try { + link.setId(UUIDGenerator.generateUuid()); + genericStorage.create(link, AssetLinkType.class); + } catch (IOException e) { + e.printStackTrace(); + throw new SpRuntimeException("Could not create asset link document"); + } + }); + } + + private IGenericStorage getGenericStorage() { + return StorageDispatcher.INSTANCE.getNoSqlStore().getGenericStorage(); + } +}
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/tasks/CreateDefaultAssetTask.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/tasks/CreateDefaultAssetTask.java new file mode 100644 index 0000000..9293592 --- /dev/null +++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/tasks/CreateDefaultAssetTask.java
@@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.manager.setup.tasks; + +import org.apache.streampipes.commons.constants.GenericDocTypes; +import org.apache.streampipes.model.assets.SpAssetModel; +import org.apache.streampipes.storage.management.StorageDispatcher; + +import java.io.IOException; + +public class CreateDefaultAssetTask implements InstallationTask { + + @Override + public void execute() { + var asset = new SpAssetModel(); + asset.setId(GenericDocTypes.DEFAULT_ASSET_DOC_ID); + asset.setAssetId("default-asset"); + asset.setAssetName("Default Asset"); + asset.setRemovable(true); + + try { + StorageDispatcher.INSTANCE.getNoSqlStore().getGenericStorage().create(asset, SpAssetModel.class); + } catch (IOException e) { + e.printStackTrace(); + } + } +}
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/tasks/InstallationTask.java similarity index 87% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/tasks/InstallationTask.java index 58ba04b..39ec0f1 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/tasks/InstallationTask.java
@@ -16,3 +16,9 @@ * */ +package org.apache.streampipes.manager.setup.tasks; + +public interface InstallationTask { + + void execute(); +}
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/AbstractTemplateHandler.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/AbstractTemplateHandler.java new file mode 100644 index 0000000..b53ba70 --- /dev/null +++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/AbstractTemplateHandler.java
@@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.manager.template; + +import org.apache.streampipes.model.template.PipelineElementTemplate; + +import java.util.HashMap; +import java.util.Map; + +public abstract class AbstractTemplateHandler<T> { + + protected T element; + protected PipelineElementTemplate template; + + protected boolean overwriteNameAndDescription; + + public AbstractTemplateHandler(PipelineElementTemplate template, + T element, + boolean overwriteNameAndDescription) { + this.template = template; + this.element = element; + this.overwriteNameAndDescription = overwriteNameAndDescription; + } + + public T applyTemplateOnPipelineElement() { + Map<String, Object> configs = new HashMap<>(); + template.getTemplateConfigs().forEach((key, value) -> configs.put(key, value.getValue())); + PipelineElementTemplateVisitor visitor = new PipelineElementTemplateVisitor(configs); + visitStaticProperties(visitor); + + if (overwriteNameAndDescription) { + applyNameAndDescription(template.getTemplateName(), template.getTemplateDescription()); + } + + return element; + } + + protected abstract void visitStaticProperties(PipelineElementTemplateVisitor visitor); + + protected abstract void applyNameAndDescription(String name, String description); +}
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/AdapterTemplateHandler.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/AdapterTemplateHandler.java new file mode 100644 index 0000000..c3aa7d3 --- /dev/null +++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/AdapterTemplateHandler.java
@@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.manager.template; + +import org.apache.streampipes.model.connect.adapter.*; +import org.apache.streampipes.model.template.PipelineElementTemplate; + +public class AdapterTemplateHandler extends AbstractTemplateHandler<AdapterDescription> { + + public AdapterTemplateHandler(PipelineElementTemplate template, + AdapterDescription adapterDescription, + boolean overwriteNameAndDescription) { + super(template, adapterDescription, overwriteNameAndDescription); + } + + @Override + protected void visitStaticProperties(PipelineElementTemplateVisitor visitor) { + if (element instanceof SpecificAdapterStreamDescription || element instanceof SpecificAdapterSetDescription) { + element.getConfig().forEach(config -> config.accept(visitor)); + } else if (element instanceof GenericAdapterSetDescription || element instanceof GenericAdapterStreamDescription) { + ((GenericAdapterDescription) element).getProtocolDescription().getConfig().forEach(config -> config.accept(visitor)); + } + } + + @Override + protected void applyNameAndDescription(String name, String description) { + element.setName(name); + element.setDescription(description); + } +}
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateHandler.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateHandler.java index 97881fa..1269f35 100644 --- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateHandler.java +++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateHandler.java
@@ -20,35 +20,22 @@ import org.apache.streampipes.model.base.InvocableStreamPipesEntity; import org.apache.streampipes.model.template.PipelineElementTemplate; -import java.util.HashMap; -import java.util.Map; - -public abstract class PipelineElementTemplateHandler<T extends InvocableStreamPipesEntity> { - - protected T pipelineElement; - protected PipelineElementTemplate template; - - private boolean overwriteNameAndDescription; +public abstract class PipelineElementTemplateHandler<T extends InvocableStreamPipesEntity> extends AbstractTemplateHandler<T> { public PipelineElementTemplateHandler(PipelineElementTemplate template, T pipelineElement, boolean overwriteNameAndDescription) { - this.template = template; - this.pipelineElement = pipelineElement; - this.overwriteNameAndDescription = overwriteNameAndDescription; + super(template, pipelineElement, overwriteNameAndDescription); } - public T applyTemplateOnPipelineElement() { - Map<String, Object> configs = new HashMap<>(); - template.getTemplateConfigs().forEach((key, value) -> configs.put(key, value.getValue())); - PipelineElementTemplateVisitor visitor = new PipelineElementTemplateVisitor(configs); - pipelineElement.getStaticProperties().forEach(config -> config.accept(visitor)); - - if (overwriteNameAndDescription) { - pipelineElement.setName(template.getTemplateName()); - pipelineElement.setDescription(template.getTemplateDescription()); - } - - return pipelineElement; + protected void visitStaticProperties(PipelineElementTemplateVisitor visitor) { + element.getStaticProperties().forEach(config -> config.accept(visitor)); } + + protected void applyNameAndDescription(String name, String description) { + element.setName(name); + element.setDescription(description); + } + + }
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateVisitor.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateVisitor.java index 5da9a2b..4c533aa 100644 --- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateVisitor.java +++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineElementTemplateVisitor.java
@@ -127,8 +127,10 @@ Map<String, Object> values = getAsMap(staticPropertyAlternative); StaticProperty property = staticPropertyAlternative.getStaticProperty(); staticPropertyAlternative.setSelected(Boolean.parseBoolean(String.valueOf(values.get("selected")))); - PipelineElementTemplateVisitor visitor = new PipelineElementTemplateVisitor(getAsMap(values, "staticProperty")); - property.accept(visitor); + if (property != null) { + PipelineElementTemplateVisitor visitor = new PipelineElementTemplateVisitor(getAsMap(values, "staticProperty")); + property.accept(visitor); + } } }
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineGenerator.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineGenerator.java index 63957d8..33e61cc 100644 --- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineGenerator.java +++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/template/PipelineGenerator.java
@@ -63,7 +63,7 @@ pipeline.setStreams(Collections.singletonList(prepareStream(datasetId))); pipeline.setSepas(new ArrayList<>()); pipeline.setActions(new ArrayList<>()); - collectInvocations("domId" + count, pipelineTemplateDescription.getBoundTo()); + collectInvocations("jsplumb_domId" + count, pipelineTemplateDescription.getBoundTo()); return pipeline; } @@ -145,6 +145,6 @@ private String getDom() { count++; - return "domId" + count; + return "jsplumb_domId" + count; } }
diff --git a/streampipes-platform-services/pom.xml b/streampipes-platform-services/pom.xml index 5558c74..2f7d6aa 100644 --- a/streampipes-platform-services/pom.xml +++ b/streampipes-platform-services/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -31,27 +31,27 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-data-explorer</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-rest-shared</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-storage-api</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-rest</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency>
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeMeasureResourceV3.java b/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeMeasureResourceV3.java similarity index 96% rename from streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeMeasureResourceV3.java rename to streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeMeasureResourceV3.java index 57e3b93..877b884 100644 --- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeMeasureResourceV3.java +++ b/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeMeasureResourceV3.java
@@ -16,7 +16,7 @@ * */ -package org.apache.streampipes.rest.impl.datalake; +package org.apache.streampipes.ps; import org.apache.streampipes.dataexplorer.DataLakeNoUserManagementV3; import org.apache.streampipes.model.schema.EventSchema; @@ -28,6 +28,7 @@ import javax.ws.rs.core.Response; @Path("/v3/datalake/measure") +@Deprecated public class DataLakeMeasureResourceV3 extends AbstractAuthGuardedRestResource { private DataLakeNoUserManagementV3 dataLakeManagement;
diff --git a/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeMeasureResourceV4.java b/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeMeasureResourceV4.java new file mode 100644 index 0000000..9f71f16 --- /dev/null +++ b/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeMeasureResourceV4.java
@@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.ps; + +import org.apache.streampipes.dataexplorer.DataLakeManagementV4; +import org.apache.streampipes.model.datalake.DataLakeMeasure; +import org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource; +import org.apache.streampipes.rest.shared.annotation.JacksonSerialized; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +@Path("/v4/datalake/measure") +public class DataLakeMeasureResourceV4 extends AbstractAuthGuardedRestResource { + + private DataLakeManagementV4 dataLakeManagement; + + public DataLakeMeasureResourceV4() { + this.dataLakeManagement = new DataLakeManagementV4(); + } + + @POST + @JacksonSerialized + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + @Path("/") + public Response addDataLake(DataLakeMeasure dataLakeMeasure) { + DataLakeMeasure result = this.dataLakeManagement.addDataLake(dataLakeMeasure); + return ok(result); + } + + @GET + @JacksonSerialized + @Produces(MediaType.APPLICATION_JSON) + @Path("{id}") + public Response getDataLakeMeasure(@PathParam("id") String measureId) { + return ok(this.dataLakeManagement.getById(measureId)); + } +}
diff --git a/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeResourceV3.java b/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeResourceV3.java index 900a812..00fd8c9 100644 --- a/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeResourceV3.java +++ b/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeResourceV3.java
@@ -31,41 +31,11 @@ import java.util.List; @Path("/v3/datalake") +@Deprecated public class DataLakeResourceV3 extends AbstractRestResource { -// private DataLakeManagementV3 dataLakeManagement; -// public DataLakeResourceV3() { } -// -// public DataLakeResourceV3(DataLakeManagementV3 dataLakeManagement) { -// this.dataLakeManagement = dataLakeManagement; -// } -// -//// @GET -//// @Produces(MediaType.APPLICATION_JSON) -//// @GsonWithIds -//// @Path("/data/{index}/paging") -//// public Response getPage(@PathParam("index") String index, -//// @Context UriInfo info, -//// @QueryParam("itemsPerPage") int itemsPerPage) { -//// -//// PageResult result; -//// String page = info.getQueryParameters().getFirst("page"); -//// -//// try { -//// if (page != null) { -//// result = this.dataLakeManagement.getEvents(index, itemsPerPage, Integer.parseInt(page)); -//// } else { -//// result = this.dataLakeManagement.getEvents(index, itemsPerPage); -//// } -//// return Response.ok(result).build(); -//// } catch (IOException e) { -//// e.printStackTrace(); -//// -//// return Response.serverError().build(); -//// } -//// } -// + @GET @JacksonSerialized @Produces(MediaType.APPLICATION_JSON) @@ -74,168 +44,5 @@ List<DataLakeMeasure> result = DataExplorerUtils.getInfos(); return ok(result); } -// -// @Deprecated -// @GET -// @Produces(MediaType.APPLICATION_OCTET_STREAM) -// @Path("/data/{index}") -// public Response getAllData(@PathParam("index") String index, -// @QueryParam("format") String format) { -// StreamingOutput streamingOutput = output -> dataLakeManagement.getAllEvents(index, format, output); -// -// return Response.ok(streamingOutput, MediaType.APPLICATION_OCTET_STREAM). -// header("Content-Disposition", "attachment; filename=\"datalake." + format + "\"") -// .build(); -// } -// -// @GET -// @Produces(MediaType.APPLICATION_OCTET_STREAM) -// @Path("/data/{index}/download") -// public Response downloadData(@PathParam("index") String index, -// @QueryParam("format") String format) { -// StreamingOutput streamingOutput = output -> dataLakeManagement.getAllEvents(index, format, output); -// -// return Response.ok(streamingOutput, MediaType.APPLICATION_OCTET_STREAM). -// header("Content-Disposition", "attachment; filename=\"datalake." + format + "\"") -// .build(); -// } -// -// @GET -// @Produces(MediaType.APPLICATION_JSON) -// @Path("/data/{index}/last/{value}/{unit}") -// public Response getAllData(@PathParam("index") String index, -// @PathParam("value") int value, -// @PathParam("unit") String unit, -// @Context UriInfo info) { -// -// -// String aggregationUnit = info.getQueryParameters().getFirst("aggregationUnit"); -// String aggregationValue = info.getQueryParameters().getFirst("aggregationValue"); -// -// DataSeries result; -// try { -// if (aggregationUnit != null && aggregationValue != null) { -// result = dataLakeManagement.getEventsFromNow(index, unit, value, aggregationUnit, -// Integer.parseInt(aggregationValue)); -// } else { -// result = dataLakeManagement.getEventsFromNowAutoAggregation(index, unit, value); -// } -// return Response.ok(result).build(); -// } catch (RuntimeException e) { -// return constructErrorMessage(new Notification(e.getMessage(), "")); -// } -// } -// -// @GET -// @Produces(MediaType.APPLICATION_JSON) -// @Path("/data/{index}/{startdate}/{enddate}") -// public Response getAllData(@Context UriInfo info, -// @PathParam("index") String index, -// @PathParam("startdate") long startdate, -// @PathParam("enddate") long enddate) { -// -// String aggregationUnit = info.getQueryParameters().getFirst("aggregationUnit"); -// String aggregationValue = info.getQueryParameters().getFirst("aggregationValue"); -// -// DataSeries result; -// -// try { -// if (aggregationUnit != null && aggregationValue != null) { -// result = dataLakeManagement.getEvents(index, startdate, enddate, aggregationUnit, -// Integer.parseInt(aggregationValue)); -// -// } else { -// result = dataLakeManagement.getEventsAutoAggregation(index, startdate, enddate); -// } -// return Response.ok(result).build(); -// } catch (RuntimeException e) { -// return constructErrorMessage(new Notification(e.getMessage(), "")); -// } -// } -// -// @GET -// @Produces(MediaType.APPLICATION_JSON) -// @Path("/data/{index}/{startdate}/{enddate}/grouping/{groupingTag}") -// public Response getAllDataGrouping(@Context UriInfo info, -// @PathParam("index") String index, -// @PathParam("startdate") long startdate, -// @PathParam("enddate") long enddate, -// @PathParam("groupingTag") String groupingTag) { -// -// String aggregationUnit = info.getQueryParameters().getFirst("aggregationUnit"); -// String aggregationValue = info.getQueryParameters().getFirst("aggregationValue"); -// -// SPQueryResult result; -// try { -// if (aggregationUnit != null && aggregationValue != null) { -// result = dataLakeManagement.getEvents(index, startdate, enddate, aggregationUnit, -// Integer.parseInt(aggregationValue), groupingTag); -// } else { -// result = dataLakeManagement.getEventsAutoAggregation(index, startdate, enddate, groupingTag); -// } -// return Response.ok(result).build(); -// } catch (RuntimeException e) { -// return constructErrorMessage(new Notification(e.getMessage(), "")); -// } -// } -// -// @DELETE -// @Produces(MediaType.APPLICATION_JSON) -// @Path("/data/delete/all") -// public Response removeAllData() { -// -// boolean result = dataLakeManagement.removeAllDataFromDataLake(); -// -// return Response.ok(result).build(); -// } -// -// @GET -// @Produces(MediaType.APPLICATION_OCTET_STREAM) -// @Path("/data/{index}/{startdate}/{enddate}/download") -// public Response downloadData(@PathParam("index") String index, @QueryParam("format") String format, -// @PathParam("startdate") long start, @PathParam("enddate") long end) { -// StreamingOutput streamingOutput = output -> dataLakeManagement.getAllEvents(index, format, start, end, output); -// -// return Response.ok(streamingOutput, MediaType.APPLICATION_OCTET_STREAM). -// header("Content-Disposition", "attachment; filename=\"datalake." + format + "\"") -// .build(); -// } -// -// @GET -// @Path("/data/image/{route}/file") -// @Produces("image/png") -// public Response getImage(@PathParam("route") String fileRoute) throws IOException { -// return ok(dataLakeManagement.getImage(fileRoute)); -// } -// -// @POST -// @Path("/data/image/{route}/coco") -// public void saveImageCoco(@PathParam("route") String fileRoute, String data) throws IOException { -// dataLakeManagement.saveImageCoco(fileRoute, data); -// } -// -// @GET -// @Path("/data/image/{route}/coco") -// @Produces("application/json") -// public Response getImageCoco(@PathParam("route") String fileRoute) throws IOException { -// return ok(dataLakeManagement.getImageCoco(fileRoute)); -// } -// -// @POST -// @Produces(MediaType.TEXT_PLAIN) -// @Path("/data/{index}/{startdate}/{enddate}/labeling/{column}/{timestampColumn}") -// public Response labelData(@Context UriInfo info, -// @PathParam("index") String index, -// @PathParam("startdate") long startdate, -// @PathParam("enddate") long enddate, -// @PathParam("column") String column, -// @PathParam("timestampColumn") String timestampColumn) { -// -// String label = info.getQueryParameters().getFirst("label"); -// this.dataLakeManagement.updateLabels(index, column, startdate, enddate, label, timestampColumn); -// -// return Response.ok("Successfully updated database.", MediaType.TEXT_PLAIN).build(); -// } -// -// + }
diff --git a/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeResourceV4.java b/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeResourceV4.java index 4791b4c..840e939 100644 --- a/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeResourceV4.java +++ b/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeResourceV4.java
@@ -27,6 +27,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import org.apache.streampipes.dataexplorer.DataLakeManagementV4; import org.apache.streampipes.dataexplorer.v4.ProvidedQueryParams; +import org.apache.streampipes.model.StreamPipesErrorMessage; import org.apache.streampipes.model.datalake.DataLakeConfiguration; import org.apache.streampipes.model.datalake.DataLakeMeasure; import org.apache.streampipes.rest.core.base.impl.AbstractRestResource; @@ -40,13 +41,10 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import static org.apache.streampipes.dataexplorer.v4.SupportedDataLakeQueryParameters.*; -class Placeholder { -} - - @Path("v4/datalake") public class DataLakeResourceV4 extends AbstractRestResource { @@ -156,19 +154,33 @@ MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters(); - if (! (checkProvidedQueryParams(queryParams))) { + if (!(checkProvidedQueryParams(queryParams))) { return badRequest(); } else { ProvidedQueryParams sanitizedParams = populate(measurementID, queryParams); try { SpQueryResult result = this.dataLakeManagement.getData(sanitizedParams); return ok(result); - } catch (IllegalArgumentException e) { - return badRequest(e.getMessage()); + } catch (RuntimeException e) { + return badRequest(StreamPipesErrorMessage.from(e)); } } } + @POST + @Path("/query") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public Response getData(List<Map<String, String>> queryParams) { + var results = queryParams + .stream() + .map(qp -> new ProvidedQueryParams(qp.get("measureName"), qp)) + .map(params -> this.dataLakeManagement.getData(params)) + .collect(Collectors.toList()); + + return ok(results); + } + @GET @Path("/measurements/{measurementID}/download") @Produces(MediaType.APPLICATION_OCTET_STREAM) @@ -188,6 +200,7 @@ , @Parameter(in = ParameterIn.QUERY, description = "name of aggregation function used for grouping operation") @QueryParam(QP_AGGREGATION_FUNCTION) String aggregationFunction , @Parameter(in = ParameterIn.QUERY, description = "time interval for aggregation (e.g. 1m - one minute) for grouping operation") @QueryParam(QP_TIME_INTERVAL) String timeInterval , @Parameter(in = ParameterIn.QUERY, description = "format specification (csv, json - default is csv) for data download") @QueryParam(QP_FORMAT) String format + , @Parameter(in = ParameterIn.QUERY, description = "csv delimiter (comma or semicolon)") @QueryParam(QP_CSV_DELIMITER) String csvDelimiter , @Parameter(in = ParameterIn.QUERY, description = "filter conditions (a comma-separated list of filter conditions such as [field,operator,condition])") @QueryParam(QP_FILTER) String filter , @Context UriInfo uriInfo) { @@ -219,23 +232,6 @@ return ok(this.dataLakeManagement.getDataLakeConfiguration()); } - @POST - @Path("/measurements/{measurementID}/labeling") - @Consumes(MediaType.APPLICATION_JSON) - @Operation(summary = "Label data points of the measurement series with given id", tags = {"Data Lake"}, - responses = { - @ApiResponse(responseCode = "200", description = "Labeling was successful")}) - public Response labelData(@Parameter(in = ParameterIn.PATH, description = "the id of the measurement series", required = true) @PathParam("measurementID") String measurementID - , @Parameter(in = ParameterIn.DEFAULT, description = "the label details that should be written into database") Placeholder body - - , @Parameter(in = ParameterIn.QUERY, description = "start date for slicing operation") @QueryParam("startDate") String startDate - , @Parameter(in = ParameterIn.QUERY, description = "end date for slicing operation") @QueryParam("endDate") String endDate) { - /** - * TODO: implementation of method stump - */ - return null; - } - @DELETE @Path("/measurements") @Operation(summary = "Remove all stored measurement series from Data Lake", tags = {"Data Lake"},
diff --git a/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/PipelineElementTemplateResource.java b/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/PipelineElementTemplateResource.java index dfa5bbc..d159e2e 100644 --- a/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/PipelineElementTemplateResource.java +++ b/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/PipelineElementTemplateResource.java
@@ -24,8 +24,10 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.parameters.RequestBody; import io.swagger.v3.oas.annotations.responses.ApiResponse; +import org.apache.streampipes.manager.template.AdapterTemplateHandler; import org.apache.streampipes.manager.template.DataProcessorTemplateHandler; import org.apache.streampipes.manager.template.DataSinkTemplateHandler; +import org.apache.streampipes.model.connect.adapter.AdapterDescription; import org.apache.streampipes.model.graph.DataProcessorInvocation; import org.apache.streampipes.model.graph.DataSinkInvocation; import org.apache.streampipes.model.template.PipelineElementTemplate; @@ -194,4 +196,32 @@ return ok(new DataProcessorTemplateHandler(template, invocation, Boolean.parseBoolean(overwriteNameAndDescription)) .applyTemplateOnPipelineElement()); } + + @POST + @Path("{id}/adapter") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + @JacksonSerialized + @Operation(summary = "Configure an adapter with a pipeline element template.", + tags = {"Pipeline Element Templates"}, + responses = { + @ApiResponse(content = { + @Content( + mediaType = "application/json", + schema = @Schema(implementation = AdapterDescription.class)) + }, responseCode = "200", description = "The configured adapter model"), + }) + public Response getPipelineElementForTemplate(@Parameter(description = "The id of the pipeline element template", required = true) + @PathParam("id") String id, + + @Parameter(description = "Overwrite the name and description of the pipeline element with the labels given in the pipeline element template") + @QueryParam("overwriteNames") String overwriteNameAndDescription, + + @RequestBody(description = "The adapter that should be configured with the template contents", + content = @Content(schema = @Schema(implementation = AdapterDescription.class))) AdapterDescription adapterDescription) { + PipelineElementTemplate template = getPipelineElementTemplateStorage().getElementById(id); + var desc = new AdapterTemplateHandler(template, adapterDescription, Boolean.parseBoolean(overwriteNameAndDescription)) + .applyTemplateOnPipelineElement(); + return ok(desc); + } }
diff --git a/streampipes-resource-management/pom.xml b/streampipes-resource-management/pom.xml index 9a63661..68f3dbf 100644 --- a/streampipes-resource-management/pom.xml +++ b/streampipes-resource-management/pom.xml
@@ -16,13 +16,11 @@ ~ limitations under the License. ~ --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,17 +30,17 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-mail</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-storage-management</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-user-management</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> </dependencies>
diff --git a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractPipelineElementResourceManager.java b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractPipelineElementResourceManager.java index 90b31c3..ad77da9 100644 --- a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractPipelineElementResourceManager.java +++ b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractPipelineElementResourceManager.java
@@ -56,8 +56,10 @@ public void delete(String elementId) { D description = find(elementId); - deleteAssetsAndPermissions(description); - db.deleteElement(description); + if (description != null) { + deleteAssetsAndPermissions(description); + db.deleteElement(description); + } } private void deleteAssetsAndPermissions(D description) {
diff --git a/streampipes-rest-core-base/pom.xml b/streampipes-rest-core-base/pom.xml index d835f7c..7768c0f 100644 --- a/streampipes-rest-core-base/pom.xml +++ b/streampipes-rest-core-base/pom.xml
@@ -17,13 +17,11 @@ ~ --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -33,22 +31,22 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-rest-shared</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-user-management</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-storage-management</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-pipeline-management</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> </dependencies>
diff --git a/streampipes-rest-shared/pom.xml b/streampipes-rest-shared/pom.xml index 606d5ad..836a9de 100644 --- a/streampipes-rest-shared/pom.xml +++ b/streampipes-rest-shared/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,7 +32,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-commons</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>org.apache.httpcomponents</groupId> @@ -43,7 +43,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-serializers-json</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-rest/pom.xml b/streampipes-rest/pom.xml index 8cedd5b..4daa862 100644 --- a/streampipes-rest/pom.xml +++ b/streampipes-rest/pom.xml
@@ -21,7 +21,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <name>StreamPipes REST API</name> <artifactId>streampipes-rest</artifactId> @@ -32,7 +32,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-commons</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>org.apache.httpcomponents</groupId> @@ -43,67 +43,72 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-config</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-data-explorer</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.streampipes</groupId> + <artifactId>streampipes-data-export</artifactId> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-measurement-units</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging-jms</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-mail</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model-client</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-pipeline-management</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-rest-shared</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-serializers-json</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-service-discovery</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-user-management</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-rest-core-base</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-connect-container-master</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/GenericStorageResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/GenericStorageResource.java new file mode 100644 index 0000000..663e96a --- /dev/null +++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/GenericStorageResource.java
@@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.rest.impl; + +import org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource; +import org.apache.streampipes.rest.security.AuthConstants; +import org.apache.streampipes.storage.api.IGenericStorage; +import org.apache.streampipes.storage.management.StorageDispatcher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Component; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +@Path("/v2/storage-generic") +@Component +@PreAuthorize(AuthConstants.IS_ADMIN_ROLE) +public class GenericStorageResource extends AbstractAuthGuardedRestResource { + + public static final String APP_DOC_NAME = "appDocName"; + + private static final Logger LOG = LoggerFactory.getLogger(GenericStorageResource.class); + + @GET + @Path("{appDocName}") + @Produces(MediaType.APPLICATION_JSON) + public Response getAll(@PathParam(APP_DOC_NAME) String appDocName) { + try { + List<Map<String, Object>> assets = getGenericStorage().findAll(appDocName); + return ok(assets); + } catch (IOException e) { + LOG.error("Could not connect to storage", e); + return fail(); + } + } + + @POST + @Path("{appDocName}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response create(@PathParam(APP_DOC_NAME) String appDocName, + String document) { + try { + Map<String, Object> obj = getGenericStorage().create(document); + return ok(obj); + } catch (IOException e) { + LOG.error("Could not connect to storage", e); + return fail(); + } + } + + @GET + @Path("{appDocName}/{id}") + @Produces(MediaType.APPLICATION_JSON) + public Response getCategory(@PathParam(APP_DOC_NAME) String appDocName, + @PathParam("id") String documentId) { + try { + Map<String, Object> obj = getGenericStorage().findOne(documentId); + return ok(obj); + } catch (IOException e) { + LOG.error("Could not connect to storage", e); + return fail(); + } + } + + @PUT + @Path("{appDocName}/{id}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response update(@PathParam(APP_DOC_NAME) String appDocName, + @PathParam("id") String documentId, + String document) { + try { + Map<String, Object> obj = getGenericStorage().update(documentId, document); + return ok(obj); + } catch (IOException e) { + LOG.error("Could not connect to storage", e); + return fail(); + } + } + + @DELETE + @Path("{appDocName}/{id}/{rev}") + @Produces(MediaType.APPLICATION_JSON) + public Response delete(@PathParam(APP_DOC_NAME) String appDocName, + @PathParam("id") String documentId, + @PathParam("rev") String rev) { + try { + getGenericStorage().delete(documentId, rev); + return ok(); + } catch (IOException e) { + LOG.error("Could not connect to storage", e); + return fail(); + } + } + + private IGenericStorage getGenericStorage() { + return StorageDispatcher.INSTANCE.getNoSqlStore().getGenericStorage(); + } + + }
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/AssetManagementResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/AssetManagementResource.java new file mode 100644 index 0000000..d0317ae --- /dev/null +++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/AssetManagementResource.java
@@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.rest.impl.admin; + +import org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource; +import org.apache.streampipes.rest.security.AuthConstants; +import org.apache.streampipes.storage.api.IGenericStorage; +import org.apache.streampipes.storage.management.StorageDispatcher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Component; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.util.List; +import java.util.Map; + + +@Path("/v2/assets") +@Component +@PreAuthorize(AuthConstants.IS_ADMIN_ROLE) +public class AssetManagementResource extends AbstractAuthGuardedRestResource { + + private static final Logger LOG = LoggerFactory.getLogger(AssetManagementResource.class); + + private static final String APP_DOC_TYPE = "asset-management"; + + @GET + @Produces(MediaType.APPLICATION_JSON) + public Response getAll() { + try { + List<Map<String, Object>> assets = getGenericStorage().findAll(APP_DOC_TYPE); + return ok(assets); + } catch (IOException e) { + LOG.error("Could not connect to storage", e); + return fail(); + } + } + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response create(String asset) { + try { + Map<String, Object> obj = getGenericStorage().create(asset); + return ok(obj); + } catch (IOException e) { + LOG.error("Could not connect to storage", e); + return fail(); + } + } + + @GET + @Path("/{id}") + @Produces(MediaType.APPLICATION_JSON) + public Response getCategory(@PathParam("id") String assetId) { + try { + Map<String, Object> obj = getGenericStorage().findOne(assetId); + return ok(obj); + } catch (IOException e) { + LOG.error("Could not connect to storage", e); + return fail(); + } + } + + @PUT + @Path("/{id}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response update(@PathParam("id") String assetId, String asset) { + try { + Map<String, Object> obj = getGenericStorage().update(assetId, asset); + return ok(obj); + } catch (IOException e) { + LOG.error("Could not connect to storage", e); + return fail(); + } + } + + @DELETE + @Path("/{id}/{rev}") + @Produces(MediaType.APPLICATION_JSON) + public Response delete(@PathParam("id") String assetId, @PathParam("rev") String rev) { + try { + getGenericStorage().delete(assetId, rev); + return ok(); + } catch (IOException e) { + LOG.error("Could not connect to storage", e); + return fail(); + } + } + + private IGenericStorage getGenericStorage() { + return StorageDispatcher.INSTANCE.getNoSqlStore().getGenericStorage(); + } + + +}
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/DataExportResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/DataExportResource.java new file mode 100644 index 0000000..fff7945 --- /dev/null +++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/DataExportResource.java
@@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.rest.impl.admin; + +import org.apache.streampipes.export.ExportManager; +import org.apache.streampipes.model.export.ExportConfiguration; +import org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource; +import org.apache.streampipes.rest.security.AuthConstants; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Component; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.util.List; + +@Path("/v2/export") +@Component +@PreAuthorize(AuthConstants.IS_ADMIN_ROLE) +public class DataExportResource extends AbstractAuthGuardedRestResource { + + @Path("/preview") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response getExportPreview(List<String> selectedAssetIds) { + var exportConfig = ExportManager.getExportPreview(selectedAssetIds); + return ok(exportConfig); + } + + @Path("/download") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_OCTET_STREAM) + public Response getExportPreview(ExportConfiguration exportConfiguration) throws IOException { + var applicationPackage = ExportManager.getExportPackage(exportConfiguration); + return ok(applicationPackage); + } + +}
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/DataImportResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/DataImportResource.java new file mode 100644 index 0000000..61b8b4f --- /dev/null +++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/DataImportResource.java
@@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.rest.impl.admin; + +import org.apache.streampipes.export.ImportManager; +import org.apache.streampipes.model.export.AssetExportConfiguration; +import org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource; +import org.apache.streampipes.rest.security.AuthConstants; +import org.glassfish.jersey.media.multipart.FormDataContentDisposition; +import org.glassfish.jersey.media.multipart.FormDataParam; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Component; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.io.InputStream; + +@Path("/v2/import") +@Component +@PreAuthorize(AuthConstants.IS_ADMIN_ROLE) +public class DataImportResource extends AbstractAuthGuardedRestResource { + + private static final Logger LOG = LoggerFactory.getLogger(DataImportResource.class); + + @Path("/preview") + @POST + @Consumes(MediaType.MULTIPART_FORM_DATA) + @Produces(MediaType.APPLICATION_JSON) + public Response getImportPreview(@FormDataParam("file_upload") InputStream uploadedInputStream, + @FormDataParam("file_upload") FormDataContentDisposition fileDetail) throws IOException { + var importConfig = ImportManager.getImportPreview(uploadedInputStream); + return ok(importConfig); + } + + @POST + @Consumes(MediaType.MULTIPART_FORM_DATA) + @Produces(MediaType.APPLICATION_JSON) + public Response importData(@FormDataParam("file_upload") InputStream uploadedInputStream, + @FormDataParam("file_upload") FormDataContentDisposition fileDetail, + @FormDataParam("configuration") AssetExportConfiguration exportConfiguration) { + try { + ImportManager.performImport(uploadedInputStream, exportConfiguration, getAuthenticatedUserSid()); + return ok(); + } catch (IOException e) { + LOG.error("An error occurred while importing resources", e); + return fail(); + } + + } +}
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AdapterResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AdapterResource.java index 9935ee1..477fe9f 100644 --- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AdapterResource.java +++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/AdapterResource.java
@@ -20,6 +20,7 @@ import org.apache.streampipes.connect.api.exception.AdapterException; import org.apache.streampipes.connect.container.master.management.AdapterMasterManagement; +import org.apache.streampipes.model.StreamPipesErrorMessage; import org.apache.streampipes.model.connect.adapter.AdapterDescription; import org.apache.streampipes.model.message.Notifications; import org.apache.streampipes.rest.security.AuthConstants; @@ -92,7 +93,7 @@ return ok(Notifications.success("Adapter started")); } catch (AdapterException e) { LOG.error("Could not stop adapter with id " +adapterId, e); - return ok(Notifications.error(e.getMessage())); + return serverError(StreamPipesErrorMessage.from(e)); } } @@ -107,7 +108,7 @@ return ok(Notifications.success("Adapter stopped")); } catch (AdapterException e) { LOG.error("Could not start adapter with id " +adapterId, e); - return ok(Notifications.error(e.getMessage())); + return serverError(StreamPipesErrorMessage.from(e)); } }
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/DescriptionResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/DescriptionResource.java index 90e6508..5681952 100644 --- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/DescriptionResource.java +++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/DescriptionResource.java
@@ -18,6 +18,7 @@ package org.apache.streampipes.rest.impl.connect; import org.apache.streampipes.commons.exceptions.NoServiceEndpointsAvailableException; +import org.apache.streampipes.commons.exceptions.SpRuntimeException; import org.apache.streampipes.connect.api.exception.AdapterException; import org.apache.streampipes.connect.container.master.management.DescriptionManagement; import org.apache.streampipes.connect.container.master.management.WorkerUrlProvider; @@ -27,10 +28,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.GET; -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.util.List; @@ -154,4 +152,15 @@ return fail(); } } + + @DELETE + @Path("{adapterId}") + public Response deleteAdapter(@PathParam("adapterId") String adapterId) { + try { + this.managementService.deleteAdapterDescription(adapterId); + return ok(); + } catch (SpRuntimeException e) { + return badRequest(e); + } + } }
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/GuessResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/GuessResource.java index 474c119..b678b9e 100644 --- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/GuessResource.java +++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/GuessResource.java
@@ -18,21 +18,25 @@ package org.apache.streampipes.rest.impl.connect; +import org.apache.streampipes.commons.exceptions.NoServiceEndpointsAvailableException; import org.apache.streampipes.connect.api.exception.ParseException; import org.apache.streampipes.connect.api.exception.WorkerAdapterException; import org.apache.streampipes.connect.container.master.management.GuessManagement; +import org.apache.streampipes.model.StreamPipesErrorMessage; import org.apache.streampipes.model.connect.adapter.AdapterDescription; +import org.apache.streampipes.model.connect.guess.AdapterEventPreview; import org.apache.streampipes.model.connect.guess.GuessSchema; -import org.apache.streampipes.model.message.Notifications; import org.apache.streampipes.rest.shared.annotation.JacksonSerialized; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.ws.rs.Consumes; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import java.io.IOException; @Path("/v2/connect/master/guess") @@ -56,13 +60,22 @@ return ok(result); } catch (ParseException e) { LOG.error("Error while parsing events: ", e); - return serverError(Notifications.error(e.getMessage())); + return badRequest(StreamPipesErrorMessage.from(e)); } catch (WorkerAdapterException e) { - return serverError(e.getContent()); - } catch (Exception e) { - LOG.error("Error while guess schema for AdapterDescription: ", e); - return serverError(Notifications.error(e.getMessage())); + return serverError(StreamPipesErrorMessage.from(e)); + } catch (NoServiceEndpointsAvailableException | IOException e) { + LOG.error(e.getMessage()); + return serverError(StreamPipesErrorMessage.from(e)); } } + + @POST + @JacksonSerialized + @Path("/schema/preview") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public Response getAdapterEventPreview(AdapterEventPreview previewRequest) { + return ok(managementService.performAdapterEventPreview(previewRequest)); + } }
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/RuntimeResolvableResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/RuntimeResolvableResource.java index 1db6196..5f3fe1f 100644 --- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/RuntimeResolvableResource.java +++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/RuntimeResolvableResource.java
@@ -19,13 +19,17 @@ package org.apache.streampipes.rest.impl.connect; import org.apache.streampipes.commons.exceptions.NoServiceEndpointsAvailableException; +import org.apache.streampipes.commons.exceptions.SpConfigurationException; import org.apache.streampipes.connect.api.exception.AdapterException; import org.apache.streampipes.connect.container.master.management.WorkerAdministrationManagement; import org.apache.streampipes.connect.container.master.management.WorkerRestClient; import org.apache.streampipes.connect.container.master.management.WorkerUrlProvider; +import org.apache.streampipes.model.StreamPipesErrorMessage; import org.apache.streampipes.model.runtime.RuntimeOptionsRequest; import org.apache.streampipes.model.runtime.RuntimeOptionsResponse; import org.apache.streampipes.rest.shared.annotation.JacksonSerialized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; @@ -34,6 +38,8 @@ @Path("/v2/connect/master/resolvable") public class RuntimeResolvableResource extends AbstractAdapterResource<WorkerAdministrationManagement> { + private static final Logger LOG = LoggerFactory.getLogger(RuntimeResolvableResource.class); + private final WorkerUrlProvider workerUrlProvider; public RuntimeResolvableResource() { @@ -56,11 +62,16 @@ RuntimeOptionsResponse result = WorkerRestClient.getConfiguration(workerEndpoint, appId, runtimeOptionsRequest); return ok(result); - } catch (AdapterException | NoServiceEndpointsAvailableException e) { - e.printStackTrace(); - return fail(); + } catch (AdapterException e) { + LOG.error("Adapter exception occurred", e); + return serverError(StreamPipesErrorMessage.from(e)); + } catch (NoServiceEndpointsAvailableException e) { + LOG.error("Could not find service endpoint for {} while fetching configuration", appId); + return serverError(StreamPipesErrorMessage.from(e)); + } catch (SpConfigurationException e) { + LOG.error("Tried to fetch a runtime configuration with insufficient settings"); + return badRequest(StreamPipesErrorMessage.from(e)); } - } }
diff --git a/streampipes-sdk-bundle/pom.xml b/streampipes-sdk-bundle/pom.xml index 929ad16..8b3629c 100644 --- a/streampipes-sdk-bundle/pom.xml +++ b/streampipes-sdk-bundle/pom.xml
@@ -16,13 +16,11 @@ ~ limitations under the License. ~ --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,47 +30,47 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-container-extensions</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat-json</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat-cbor</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat-smile</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat-fst</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging-jms</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging-kafka</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging-mqtt</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> </dependencies>
diff --git a/streampipes-sdk/pom.xml b/streampipes-sdk/pom.xml index e99e80e..d801c0e 100644 --- a/streampipes-sdk/pom.xml +++ b/streampipes-sdk/pom.xml
@@ -21,7 +21,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,17 +32,17 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-config</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-vocabulary</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/StaticProperties.java b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/StaticProperties.java index efacba4..2d3cabd 100644 --- a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/StaticProperties.java +++ b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/StaticProperties.java
@@ -48,6 +48,12 @@ return freeTextProperty(label, Datatypes.String); } + public static FreeTextStaticProperty stringFreeTextProperty(Label label, String defaultValue) { + var property = freeTextProperty(label, Datatypes.String); + property.setValue(defaultValue); + return property; + } + public static FreeTextStaticProperty integerFreeTextProperty(Label label) { return freeTextProperty(label, Datatypes.Integer); }
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 b3b4cfb..5665fce 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
@@ -260,7 +260,7 @@ } /** - * @deprecated Use {@link #requiredTextParameter(Label, String)} + * @deprecated Use {@link #requiredTextParameterWithLink(Label, String)} * @param internalId * @param label * @param description @@ -284,10 +284,27 @@ * value range of the parameter is restricted to the value specification of a selected input event property. * @param label The {@link org.apache.streampipes.sdk.helpers.Label} that describes why this parameter is needed in a * user-friendly manner. + * @param defaultValue The default value is displayed to the user in the input field + * @return this + */ + public BU requiredTextParameter(Label label, + String defaultValue) { + FreeTextStaticProperty fsp = StaticProperties.stringFreeTextProperty(label, defaultValue); + + this.staticProperties.add(fsp); + return me(); + } + + + /** + * Defines a text-based configuration parameter provided by pipeline developers at pipeline authoring time. The + * value range of the parameter is restricted to the value specification of a selected input event property. + * @param label The {@link org.apache.streampipes.sdk.helpers.Label} that describes why this parameter is needed in a + * user-friendly manner. * @param linkedMappingPropertyInternalName The inernalId of the {@link org.apache.streampipes.model.staticproperty.MappingProperty} * @return this */ - public BU requiredTextParameter(Label label, String + public BU requiredTextParameterWithLink(Label label, String linkedMappingPropertyInternalName) { FreeTextStaticProperty fsp = prepareFreeTextStaticProperty(label, XSD._string.toString());
diff --git a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/GuessSchemaBuilder.java b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/GuessSchemaBuilder.java index 91e0da1..8f88a54 100644 --- a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/GuessSchemaBuilder.java +++ b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/GuessSchemaBuilder.java
@@ -18,18 +18,20 @@ package org.apache.streampipes.sdk.builder.adapter; import org.apache.streampipes.model.connect.guess.GuessSchema; +import org.apache.streampipes.model.connect.guess.GuessTypeInfo; import org.apache.streampipes.model.schema.EventProperty; import org.apache.streampipes.model.schema.EventSchema; -import java.util.ArrayList; -import java.util.List; +import java.util.*; public class GuessSchemaBuilder { private List<EventProperty> eventProperties; + private Map<String, GuessTypeInfo> samples; private GuessSchemaBuilder() { this.eventProperties = new ArrayList<>(); + this.samples = new HashMap<>(); } /** @@ -39,6 +41,13 @@ return new GuessSchemaBuilder(); } + public GuessSchemaBuilder sample(String runtimeName, + Object sampleValue) { + this.samples.put(runtimeName, new GuessTypeInfo(sampleValue.getClass().getCanonicalName(), sampleValue)); + + return this; + } + public GuessSchemaBuilder property(EventProperty property) { this.eventProperties.add(property); @@ -56,6 +65,7 @@ eventSchema.setEventProperties(eventProperties); guessSchema.setEventSchema(eventSchema); + guessSchema.setEventPreview(List.of(this.samples)); return guessSchema; }
diff --git a/streampipes-security-jwt/pom.xml b/streampipes-security-jwt/pom.xml index 13b7a8e..2128339 100644 --- a/streampipes-security-jwt/pom.xml +++ b/streampipes-security-jwt/pom.xml
@@ -16,13 +16,11 @@ ~ limitations under the License. ~ --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,7 +30,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-commons</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId>
diff --git a/streampipes-serializers-json/pom.xml b/streampipes-serializers-json/pom.xml index 1fd8b26..fb88b77 100644 --- a/streampipes-serializers-json/pom.xml +++ b/streampipes-serializers-json/pom.xml
@@ -20,7 +20,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -31,12 +31,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model-client</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies --> @@ -49,7 +49,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-test-utils</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <scope>test</scope> </dependency> <dependency>
diff --git a/streampipes-service-base/pom.xml b/streampipes-service-base/pom.xml index 41e0ddf..4c5811a 100644 --- a/streampipes-service-base/pom.xml +++ b/streampipes-service-base/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,12 +32,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-commons</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-service-discovery</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-service-discovery-api/pom.xml b/streampipes-service-discovery-api/pom.xml index 245242b..fd73b1d 100644 --- a/streampipes-service-discovery-api/pom.xml +++ b/streampipes-service-discovery-api/pom.xml
@@ -17,13 +17,11 @@ ~ --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/streampipes-service-discovery-consul/pom.xml b/streampipes-service-discovery-consul/pom.xml index 0561614..2d79d0e 100644 --- a/streampipes-service-discovery-consul/pom.xml +++ b/streampipes-service-discovery-consul/pom.xml
@@ -17,13 +17,11 @@ ~ --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -33,17 +31,17 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-logging</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-serializers-json</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-service-discovery-api</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- third-party dependencies -->
diff --git a/streampipes-service-discovery/pom.xml b/streampipes-service-discovery/pom.xml index f3f3ff9..b4a26be 100644 --- a/streampipes-service-discovery/pom.xml +++ b/streampipes-service-discovery/pom.xml
@@ -17,13 +17,11 @@ ~ --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -33,12 +31,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-service-discovery-api</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-service-discovery-consul</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> </dependencies>
diff --git a/streampipes-service-extensions-base/pom.xml b/streampipes-service-extensions-base/pom.xml index 98c4ce6..5570442 100644 --- a/streampipes-service-extensions-base/pom.xml +++ b/streampipes-service-extensions-base/pom.xml
@@ -17,13 +17,11 @@ ~ --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -33,17 +31,17 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-client</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-container</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-service-base</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> </dependencies>
diff --git a/streampipes-service-extensions-base/src/main/java/org/apache/streampipes/service/extensions/base/client/StreamPipesClientRuntimeConnectionResolver.java b/streampipes-service-extensions-base/src/main/java/org/apache/streampipes/service/extensions/base/client/StreamPipesClientRuntimeConnectionResolver.java index e9bf03b..52cf1b5 100644 --- a/streampipes-service-extensions-base/src/main/java/org/apache/streampipes/service/extensions/base/client/StreamPipesClientRuntimeConnectionResolver.java +++ b/streampipes-service-extensions-base/src/main/java/org/apache/streampipes/service/extensions/base/client/StreamPipesClientRuntimeConnectionResolver.java
@@ -20,15 +20,16 @@ import org.apache.streampipes.client.credentials.CredentialsProvider; import org.apache.streampipes.client.credentials.StreamPipesTokenCredentials; import org.apache.streampipes.client.model.ClientConnectionUrlResolver; -import org.apache.streampipes.commons.constants.Envs; import org.apache.streampipes.commons.constants.DefaultEnvValues; +import org.apache.streampipes.commons.constants.Envs; +import org.apache.streampipes.commons.exceptions.SpRuntimeException; import org.apache.streampipes.commons.networking.Networking; -import org.apache.streampipes.service.base.BaseNetworkingConfig; import org.apache.streampipes.svcdiscovery.SpServiceDiscovery; import org.apache.streampipes.svcdiscovery.api.model.DefaultSpServiceGroups; import org.apache.streampipes.svcdiscovery.api.model.DefaultSpServiceTags; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import java.net.UnknownHostException; import java.util.Collections; import java.util.List; @@ -47,7 +48,7 @@ } @Override - public String getBaseUrl() { + public String getBaseUrl() throws SpRuntimeException { List<String> baseUrls = findClientServices(); if (baseUrls.size() > 0) { if (Envs.SP_DEBUG.exists()) {
diff --git a/streampipes-sources/pom.xml b/streampipes-sources/pom.xml index a90de6d..6624b6c 100644 --- a/streampipes-sources/pom.xml +++ b/streampipes-sources/pom.xml
@@ -21,7 +21,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <artifactId>streampipes-sources</artifactId> @@ -31,7 +31,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-container</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> </dependencies> </project> \ No newline at end of file
diff --git a/streampipes-storage-api/pom.xml b/streampipes-storage-api/pom.xml index 64d5248..2b0aa0c 100644 --- a/streampipes-storage-api/pom.xml +++ b/streampipes-storage-api/pom.xml
@@ -21,7 +21,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <artifactId>streampipes-storage-api</artifactId> @@ -32,12 +32,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model-client</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> </dependencies> </project>
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataLakeStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataLakeStorage.java index d16cfc2..25159f0 100644 --- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataLakeStorage.java +++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataLakeStorage.java
@@ -18,6 +18,7 @@ package org.apache.streampipes.storage.api; +import org.apache.streampipes.model.datalake.DataExplorerWidgetModel; import org.apache.streampipes.model.datalake.DataLakeMeasure; import java.util.List; @@ -27,4 +28,8 @@ boolean storeDataLakeMeasure(DataLakeMeasure measure); List<DataLakeMeasure> getAllDataLakeMeasures(); + + DataLakeMeasure findOne(String id); + + void updateDataLakeMeasure(DataLakeMeasure measure); }
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/ErrorMessageLd.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IGenericStorage.java similarity index 60% rename from streampipes-model/src/main/java/org/apache/streampipes/model/ErrorMessageLd.java rename to streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IGenericStorage.java index 091f35b..b74bbc5 100644 --- a/streampipes-model/src/main/java/org/apache/streampipes/model/ErrorMessageLd.java +++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IGenericStorage.java
@@ -16,25 +16,23 @@ * */ -package org.apache.streampipes.model; +package org.apache.streampipes.storage.api; +import java.io.IOException; import java.util.List; +import java.util.Map; -public class ErrorMessageLd extends MessageLd { +public interface IGenericStorage { - public ErrorMessageLd() { - super(false); - } + List<Map<String, Object>> findAll(String type) throws IOException; - public ErrorMessageLd(NotificationLd...notifications) { - super(false, notifications); - } + Map<String, Object> findOne(String id) throws IOException; - public ErrorMessageLd(List<NotificationLd> notifications) { - super(false, notifications.toArray(new NotificationLd[0])); - } + Map<String, Object> create(String payload) throws IOException; - public ErrorMessageLd(String elementName, List<NotificationLd> notifications) { - super(false, notifications, elementName); - } + <T> T create(T payload, Class<T> targetClass) throws IOException; + + Map<String, Object> update(String id, String payload) throws IOException; + + void delete(String id, String rev) throws IOException; }
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java index 5c52dbc..6b4af15 100644 --- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java +++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java
@@ -19,6 +19,8 @@ public interface INoSqlStorage { + IGenericStorage getGenericStorage(); + IAdapterStorage getAdapterInstanceStorage(); IAdapterStorage getAdapterDescriptionStorage();
diff --git a/streampipes-storage-couchdb/pom.xml b/streampipes-storage-couchdb/pom.xml index dd4bf66..fcc41eb 100644 --- a/streampipes-storage-couchdb/pom.xml +++ b/streampipes-storage-couchdb/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,22 +32,22 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-service-discovery</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model-client</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-storage-api</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies --> @@ -72,7 +72,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-test-utils</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> <scope>test</scope> </dependency> <dependency>
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java index 4a8b835..581ff22 100644 --- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java +++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java
@@ -30,6 +30,11 @@ } @Override + public IGenericStorage getGenericStorage() { + return new GenericStorageImpl(); + } + + @Override public IAdapterStorage getAdapterInstanceStorage() { return new AdapterInstanceStorageImpl(); }
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.scss b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/constants/GenericCouchDbConstants.java similarity index 74% copy from ui/src/app/pipeline-details/pipeline-details.component.scss copy to streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/constants/GenericCouchDbConstants.java index a375af7..97a597e 100644 --- a/ui/src/app/pipeline-details/pipeline-details.component.scss +++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/constants/GenericCouchDbConstants.java
@@ -16,7 +16,12 @@ * */ -.md-padding { - padding: 10px; -} +package org.apache.streampipes.storage.couchdb.constants; +public class GenericCouchDbConstants { + + public static final String DESIGN_DOC_NAME = "appDocType"; + public static final String VIEW_NAME = "appDocType"; + public static final String DB_NAME = "genericstorage"; + +}
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/AdapterInstanceStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/AdapterInstanceStorageImpl.java index da84fb8..ff6540b 100644 --- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/AdapterInstanceStorageImpl.java +++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/AdapterInstanceStorageImpl.java
@@ -58,7 +58,7 @@ @Override public AdapterDescription getAdapter(String adapterId) { DbCommand<Optional<AdapterDescription>, AdapterDescription> cmd = new FindCommand<>(couchDbClientSupplier, adapterId, AdapterDescription.class); - return cmd.execute().get(); + return cmd.execute().orElse(null); } @Override
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataLakeStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataLakeStorageImpl.java index 60a7559..943638a 100644 --- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataLakeStorageImpl.java +++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataLakeStorageImpl.java
@@ -41,4 +41,14 @@ List<DataLakeMeasure> dataLakeMeasures = findAll(); return dataLakeMeasures; } + + @Override + public DataLakeMeasure findOne(String id) { + return find(id).orElse(null); + } + + @Override + public void updateDataLakeMeasure(DataLakeMeasure measure) { + update(measure); + } }
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/GenericStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/GenericStorageImpl.java new file mode 100644 index 0000000..27606dd --- /dev/null +++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/GenericStorageImpl.java
@@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.streampipes.storage.couchdb.impl; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.net.UrlEscapers; +import org.apache.http.client.fluent.Content; +import org.apache.http.client.fluent.Request; +import org.apache.streampipes.storage.api.IGenericStorage; +import org.apache.streampipes.storage.couchdb.constants.GenericCouchDbConstants; +import org.apache.streampipes.storage.couchdb.utils.Utils; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class GenericStorageImpl implements IGenericStorage { + + private static final String ID = "id"; + private static final String SLASH = "/"; + + private final TypeReference<Map<String,Object>> typeRef = new TypeReference<>() {}; + private final ObjectMapper mapper; + + public GenericStorageImpl() { + this.mapper = new ObjectMapper(); + this.mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + + @Override + public List<Map<String, Object>> findAll(String type) throws IOException { + String query = getDatabaseRoute() + "/_design/appDocType/_view/appDocType?" + UrlEscapers.urlPathSegmentEscaper().escape("startkey=[\"" + type + "\"]&endkey=[\"" + type + "\",{}]&include_docs=true"); + Map<String, Object> queryResult = this.queryDocuments(query); + + List<Map<String, Object>> rows = (List<Map<String, Object>>) queryResult.get("rows"); + List<Map<String, Object>> result = new ArrayList<>(); + + for (Map<String, Object> row : rows) { + if (!((String) row.get(ID)).startsWith("_design")) { + result.add((Map<String, Object>) row.get("doc")); + } + } + + return result; + } + + @Override + public Map<String, Object> findOne(String id) throws IOException { + return this.queryDocuments(getDatabaseRoute() + SLASH + id); + } + + @Override + public Map<String, Object> create(String payload) throws IOException { + Request req = Utils.postRequest(getDatabaseRoute(), payload); + Content content = executeAndReturnContent(req); + + Map<String, Object> requestResult = deserialize(content.asString()); + return this.findOne((String) requestResult.get(ID)); + } + + @Override + public <T> T create(T payload, Class<T> targetClass) throws IOException { + Map<String, Object> result = this.create(this.mapper.writeValueAsString(payload)); + return this.mapper.convertValue(result, targetClass); + } + + @Override + public Map<String, Object> update(String id, String payload) throws IOException { + Request req = Utils.putRequest(getDatabaseRoute() + SLASH + id, payload); + Content content = executeAndReturnContent(req); + + Map<String, Object> requestResult = deserialize(content.asString()); + return this.findOne((String) requestResult.get(ID)); + } + + @Override + public void delete(String id, String rev) throws IOException { + Request req = Utils.deleteRequest(getDatabaseRoute() + SLASH + id + "?rev=" + rev); + Content content = executeAndReturnContent(req); + } + + private Map<String, Object> queryDocuments(String route) throws IOException { + Request req = Utils.getRequest(route); + Content content = executeAndReturnContent(req); + + return deserialize(content.asString(StandardCharsets.UTF_8)); + } + + private Map<String, Object> deserialize(String payload) throws JsonProcessingException { + + return mapper.readValue(payload, typeRef); + } + + private Content executeAndReturnContent(Request req) throws IOException { + return req.execute().returnContent(); + } + + private String getDatabaseRoute() { + return Utils.getDatabaseRoute(GenericCouchDbConstants.DB_NAME); + } +}
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/serializer/GsonSerializer.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/serializer/GsonSerializer.java index af208ac..311c55f 100644 --- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/serializer/GsonSerializer.java +++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/serializer/GsonSerializer.java
@@ -108,6 +108,7 @@ .registerSubtype(UnitTransformRuleDescription.class, "org.apache.streampipes.model.UnitTransformRuleDescription") .registerSubtype(TimestampTranfsformationRuleDescription.class, "org.apache.streampipes.model.TimestampTranfsformationRuleDescription") .registerSubtype(EventRateTransformationRuleDescription.class, "org.apache.streampipes.model.EventRateTransformationRuleDescription") + .registerSubtype(ChangeDatatypeTransformationRuleDescription.class, "org.apache.streampipes.model.ChangeDatatypeTransformationRuleDescription") .registerSubtype(CorrectionValueTransformationRuleDescription.class, "org.apache.streampipes.model.CorrectionValueTransformationRuleDescription")); builder.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(AdapterDescription.class, "type")
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/CouchDbViewGenerator.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/CouchDbViewGenerator.java new file mode 100644 index 0000000..b9c4409 --- /dev/null +++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/CouchDbViewGenerator.java
@@ -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. + * + */ + +package org.apache.streampipes.storage.couchdb.utils; + +import org.apache.http.client.fluent.Request; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +import static org.apache.streampipes.storage.couchdb.constants.GenericCouchDbConstants.*; + +public class CouchDbViewGenerator { + + private static final Logger LOG = LoggerFactory.getLogger(CouchDbViewGenerator.class); + + public void createGenericDatabaseIfNotExists() { + LOG.info("Checking if generic database {} exists...", DB_NAME); + + try { + int status = Request.Put(Utils.getDatabaseRoute(DB_NAME)).execute().returnResponse().getStatusLine().getStatusCode(); + + if (status == 201) { + LOG.info("Database {} successfully created", DB_NAME); + createViews(); + } else if (status == 412) { + LOG.info("Database {} already present", DB_NAME); + } else { + LOG.warn("Status code {} from CouchDB - something went wrong during install!", status); + } + } catch (IOException e) { + LOG.error("Could not connect to CouchDB storage", e); + } + } + + private void createViews() throws IOException { + LOG.info("Initializing database views..."); + + String viewContent = "{\n" + + "\"views\": {\n" + + "\"appDocType\": {\n" + + "\"map\": \"function (doc) {\\nif (doc._id) {\\nemit([doc.appDocType, doc._id], 1)\\n}\\n}\"\n" + + "}\n" + + "},\n" + + "\"language\": \"javascript\"\n" + + "}"; + + int status = Utils.putRequest(Utils.getDatabaseRoute(DB_NAME) + "/_design/" + DESIGN_DOC_NAME, viewContent) + .execute() + .returnResponse() + .getStatusLine() + .getStatusCode(); + + if (status == 201) { + LOG.info("View {} successfully created", VIEW_NAME); + } else { + LOG.warn("Status code {} from CouchDB - something went wrong during view generation!", status); + } + } +}
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java index 34a989a..d12e6e4 100644 --- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java +++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java
@@ -18,6 +18,8 @@ package org.apache.streampipes.storage.couchdb.utils; +import org.apache.http.client.fluent.Request; +import org.apache.http.entity.ContentType; import org.apache.streampipes.storage.couchdb.serializer.GsonSerializer; import org.lightcouch.CouchDbClient; import org.lightcouch.CouchDbProperties; @@ -180,12 +182,53 @@ return new CouchDbClient(props(dbname)); } - public static CouchDbClient getCoucbDbClient(String table) { - return new CouchDbClient(props(table)); + public static CouchDbClient getCouchDbClient(String database) { + return new CouchDbClient(props(database)); } private static CouchDbProperties props(String dbname) { - return new CouchDbProperties(dbname, true, CouchDbConfig.INSTANCE.getProtocol(), - CouchDbConfig.INSTANCE.getHost(), CouchDbConfig.INSTANCE.getPort(), null, null); + return new CouchDbProperties( + dbname, + true, + CouchDbConfig.INSTANCE.getProtocol(), + CouchDbConfig.INSTANCE.getHost(), + CouchDbConfig.INSTANCE.getPort(), + null, + null); + } + + public static String getDatabaseRoute(String databaseName) { + return toUrl() + "/" + databaseName; + } + + private static String toUrl() { + return CouchDbConfig.INSTANCE.getProtocol() + + "://" + CouchDbConfig.INSTANCE.getHost() + + ":" + CouchDbConfig.INSTANCE.getPort(); + } + + public static Request getRequest(String route) { + return append(Request.Get(route)); + } + + public static Request postRequest(String route, + String payload) { + return append(Request.Post(route).bodyString(payload, ContentType.APPLICATION_JSON)); + } + + public static Request deleteRequest(String route) { + return append(Request.Delete(route)); + } + + public static Request putRequest(String route, + String payload) { + return append(Request.Put(route).bodyString(payload, ContentType.APPLICATION_JSON)); + } + + private static Request append(Request req) { + req.connectTimeout(1000) + .socketTimeout(100000); + + return req; } }
diff --git a/streampipes-storage-management/pom.xml b/streampipes-storage-management/pom.xml index c9df714..c102948 100644 --- a/streampipes-storage-management/pom.xml +++ b/streampipes-storage-management/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,12 +32,12 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-storage-api</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-storage-couchdb</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> </dependencies> </project>
diff --git a/streampipes-test-utils/pom.xml b/streampipes-test-utils/pom.xml index f1a48f1..0961a45 100644 --- a/streampipes-test-utils/pom.xml +++ b/streampipes-test-utils/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,7 +32,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- Test dependencies -->
diff --git a/streampipes-user-management/pom.xml b/streampipes-user-management/pom.xml index e3056e5..a9f6c65 100644 --- a/streampipes-user-management/pom.xml +++ b/streampipes-user-management/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,22 +32,22 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-config</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-model-client</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-security-jwt</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-storage-management</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-vocabulary/pom.xml b/streampipes-vocabulary/pom.xml index b6a9a2a..4850636 100644 --- a/streampipes-vocabulary/pom.xml +++ b/streampipes-vocabulary/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/streampipes-wrapper-distributed/pom.xml b/streampipes-wrapper-distributed/pom.xml index 66473cc..0aec356 100644 --- a/streampipes-wrapper-distributed/pom.xml +++ b/streampipes-wrapper-distributed/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,22 +32,22 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging-jms</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging-kafka</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging-mqtt</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> </dependencies> </project> \ No newline at end of file
diff --git a/streampipes-wrapper-flink/pom.xml b/streampipes-wrapper-flink/pom.xml index e976ee6..d30a26e 100644 --- a/streampipes-wrapper-flink/pom.xml +++ b/streampipes-wrapper-flink/pom.xml
@@ -21,7 +21,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <artifactId>streampipes-wrapper-flink</artifactId> @@ -32,7 +32,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-distributed</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-wrapper-kafka-streams/pom.xml b/streampipes-wrapper-kafka-streams/pom.xml index fa67897..f200b96 100644 --- a/streampipes-wrapper-kafka-streams/pom.xml +++ b/streampipes-wrapper-kafka-streams/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,7 +32,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-distributed</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-wrapper-python/pom.xml b/streampipes-wrapper-python/pom.xml index fee32e1..c41e6d2 100644 --- a/streampipes-wrapper-python/pom.xml +++ b/streampipes-wrapper-python/pom.xml
@@ -20,7 +20,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion>
diff --git a/streampipes-wrapper-python/requirements.txt b/streampipes-wrapper-python/requirements.txt index f5cd4b6..d029896 100644 --- a/streampipes-wrapper-python/requirements.txt +++ b/streampipes-wrapper-python/requirements.txt
@@ -1,4 +1,4 @@ -waitress==2.1.1 +waitress==2.1.2 click==7.1.2 confluent-kafka==1.4.2 Flask==1.1.2
diff --git a/streampipes-wrapper-python/setup.py b/streampipes-wrapper-python/setup.py index 11f267f..ba40ffd 100644 --- a/streampipes-wrapper-python/setup.py +++ b/streampipes-wrapper-python/setup.py
@@ -43,7 +43,7 @@ 'Flask==1.1.2', 'flask-classful==0.14.2', 'Flask-Negotiate==0.1.0', - 'waitress==2.1.1', + 'waitress==2.1.2', 'python-consul==1.1.0' ], tests_require=[],
diff --git a/streampipes-wrapper-siddhi/pom.xml b/streampipes-wrapper-siddhi/pom.xml index fa4e337..99f56c9 100644 --- a/streampipes-wrapper-siddhi/pom.xml +++ b/streampipes-wrapper-siddhi/pom.xml
@@ -21,7 +21,7 @@ <parent> <artifactId>streampipes-parent</artifactId> <groupId>org.apache.streampipes</groupId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -33,7 +33,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper-standalone</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <!-- External dependencies -->
diff --git a/streampipes-wrapper-standalone/pom.xml b/streampipes-wrapper-standalone/pom.xml index b4b9286..8c005ca 100644 --- a/streampipes-wrapper-standalone/pom.xml +++ b/streampipes-wrapper-standalone/pom.xml
@@ -21,7 +21,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <artifactId>streampipes-wrapper-standalone</artifactId> @@ -32,7 +32,7 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-wrapper</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> </dependencies> </project> \ No newline at end of file
diff --git a/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/routing/StandaloneSpInputCollector.java b/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/routing/StandaloneSpInputCollector.java index 47f0956..77277c6 100644 --- a/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/routing/StandaloneSpInputCollector.java +++ b/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/routing/StandaloneSpInputCollector.java
@@ -49,11 +49,7 @@ } private void send(RawDataProcessor rawDataProcessor, byte[] event) { - try { rawDataProcessor.process(dataFormatDefinition.toMap(event), topic); - } catch (SpRuntimeException e) { - e.printStackTrace(); - } } @Override
diff --git a/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneEventProcessorRuntime.java b/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneEventProcessorRuntime.java index 196b396..e297d47 100644 --- a/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneEventProcessorRuntime.java +++ b/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneEventProcessorRuntime.java
@@ -27,13 +27,17 @@ import org.apache.streampipes.wrapper.routing.SpOutputCollector; import org.apache.streampipes.wrapper.runtime.EventProcessor; import org.apache.streampipes.wrapper.standalone.manager.ProtocolManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Map; import java.util.function.Supplier; public class StandaloneEventProcessorRuntime<B extends EventProcessorBindingParams> extends - StandalonePipelineElementRuntime<B, DataProcessorInvocation, - EventProcessorRuntimeParams<B>, EventProcessorRuntimeContext, EventProcessor<B>> { + StandalonePipelineElementRuntime<B, DataProcessorInvocation, + EventProcessorRuntimeParams<B>, EventProcessorRuntimeContext, EventProcessor<B>> { + + private static final Logger LOG = LoggerFactory.getLogger(StandaloneEventProcessorRuntime.class); public StandaloneEventProcessorRuntime(Supplier<EventProcessor<B>> supplier, EventProcessorRuntimeParams<B> params) { @@ -43,18 +47,18 @@ public SpOutputCollector getOutputCollector() throws SpRuntimeException { return ProtocolManager.findOutputCollector( - params - .getBindingParams() - .getGraph() - .getOutputStream() - .getEventGrounding() - .getTransportProtocol(), - params.getBindingParams() - .getGraph() - .getOutputStream() - .getEventGrounding() - .getTransportFormats() - .get(0)); + params + .getBindingParams() + .getGraph() + .getOutputStream() + .getEventGrounding() + .getTransportProtocol(), + params.getBindingParams() + .getGraph() + .getOutputStream() + .getEventGrounding() + .getTransportFormats() + .get(0)); } @Override @@ -65,8 +69,12 @@ } @Override - public void process(Map<String, Object> rawEvent, String sourceInfo) throws SpRuntimeException { - getEngine().onEvent(params.makeEvent(rawEvent, sourceInfo), getOutputCollector()); + public void process(Map<String, Object> rawEvent, String sourceInfo) { + try { + engine.onEvent(params.makeEvent(rawEvent, sourceInfo), getOutputCollector()); + } catch (RuntimeException e) { + LOG.error("RuntimeException while processing event in {}", engine.getClass().getCanonicalName(), e); + } } @Override
diff --git a/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneEventSinkRuntime.java b/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneEventSinkRuntime.java index 75b0b8e..c1fd982 100644 --- a/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneEventSinkRuntime.java +++ b/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneEventSinkRuntime.java
@@ -25,16 +25,20 @@ import org.apache.streampipes.wrapper.params.runtime.EventSinkRuntimeParams; import org.apache.streampipes.wrapper.routing.SpInputCollector; import org.apache.streampipes.wrapper.runtime.EventSink; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Map; import java.util.function.Supplier; public class StandaloneEventSinkRuntime<B extends EventSinkBindingParams> extends - StandalonePipelineElementRuntime<B, DataSinkInvocation, - EventSinkRuntimeParams<B>, EventSinkRuntimeContext, EventSink<B>> { + StandalonePipelineElementRuntime<B, DataSinkInvocation, + EventSinkRuntimeParams<B>, EventSinkRuntimeContext, EventSink<B>> { + + private static final Logger LOG = LoggerFactory.getLogger(StandaloneEventSinkRuntime.class); public StandaloneEventSinkRuntime(Supplier<EventSink<B>> supplier, EventSinkRuntimeParams<B> - params) { + params) { super(supplier, params); } @@ -46,8 +50,12 @@ } @Override - public void process(Map<String, Object> rawEvent, String sourceInfo) throws SpRuntimeException { - engine.onEvent(params.makeEvent(rawEvent, sourceInfo)); + public void process(Map<String, Object> rawEvent, String sourceInfo) { + try { + engine.onEvent(params.makeEvent(rawEvent, sourceInfo)); + } catch (RuntimeException e) { + LOG.error("RuntimeException while processing event in {}", engine.getClass().getCanonicalName() , e); + } } @Override @@ -66,7 +74,7 @@ @Override public void postDiscard() throws SpRuntimeException { - for(SpInputCollector spInputCollector : getInputCollectors()) { + for (SpInputCollector spInputCollector : getInputCollectors()) { spInputCollector.disconnect(); } }
diff --git a/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneExternalEventProcessorRuntime.java b/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneExternalEventProcessorRuntime.java index a2177f2..01c0187 100644 --- a/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneExternalEventProcessorRuntime.java +++ b/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneExternalEventProcessorRuntime.java
@@ -42,7 +42,7 @@ } @Override - public void process(Map<String, Object> rawEvent, String sourceInfo) throws SpRuntimeException { + public void process(Map<String, Object> rawEvent, String sourceInfo) { }
diff --git a/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneExternalEventSinkRuntime.java b/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneExternalEventSinkRuntime.java index 3fb06e2..418702d 100644 --- a/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneExternalEventSinkRuntime.java +++ b/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneExternalEventSinkRuntime.java
@@ -41,7 +41,7 @@ } @Override - public void process(Map<String, Object> rawEvent, String sourceInfo) throws SpRuntimeException { + public void process(Map<String, Object> rawEvent, String sourceInfo) { }
diff --git a/streampipes-wrapper/pom.xml b/streampipes-wrapper/pom.xml index a02e8a9..45ecc38 100644 --- a/streampipes-wrapper/pom.xml +++ b/streampipes-wrapper/pom.xml
@@ -21,7 +21,7 @@ <parent> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-parent</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </parent> <artifactId>streampipes-wrapper</artifactId> @@ -30,32 +30,32 @@ <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-container</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-service-extensions-base</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-client</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-dataformat</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-messaging</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.streampipes</groupId> <artifactId>streampipes-sdk</artifactId> - <version>0.70.0-SNAPSHOT</version> + <version>0.71.0-SNAPSHOT</version> </dependency> </dependencies> </project>
diff --git a/streampipes-wrapper/src/main/java/org/apache/streampipes/wrapper/routing/RawDataProcessor.java b/streampipes-wrapper/src/main/java/org/apache/streampipes/wrapper/routing/RawDataProcessor.java index 648b9b5..bb4117c 100644 --- a/streampipes-wrapper/src/main/java/org/apache/streampipes/wrapper/routing/RawDataProcessor.java +++ b/streampipes-wrapper/src/main/java/org/apache/streampipes/wrapper/routing/RawDataProcessor.java
@@ -17,11 +17,9 @@ */ package org.apache.streampipes.wrapper.routing; -import org.apache.streampipes.commons.exceptions.SpRuntimeException; - import java.util.Map; public interface RawDataProcessor { - void process(Map<String, Object> rawEvent, String sourceInfo) throws SpRuntimeException; + void process(Map<String, Object> rawEvent, String sourceInfo); }
diff --git a/ui/.gitignore b/ui/.gitignore index fa76110..77e77f6 100644 --- a/ui/.gitignore +++ b/ui/.gitignore
@@ -21,6 +21,7 @@ # prebuild src/app/app-routing.module.ts +src/app/app-overview/apps.ts src/app/appng5.module.ts src/app/home/home.service.ts src/app/services/version/version.service.ts
diff --git a/ui/cypress/fixtures/connect/schemaRules/expected.csv b/ui/cypress/fixtures/connect/schemaRules/expected.csv index 38a8aeb..411fac9 100644 --- a/ui/cypress/fixtures/connect/schemaRules/expected.csv +++ b/ui/cypress/fixtures/connect/schemaRules/expected.csv
@@ -1,2 +1,2 @@ -count;staticpropertyname;temperature +count;staticPropertyName;temperature 122.0;id1;11.0
diff --git a/ui/cypress/fixtures/datalake/sample.csv b/ui/cypress/fixtures/datalake/sample.csv index 355a4a0..09d1490 100644 --- a/ui/cypress/fixtures/datalake/sample.csv +++ b/ui/cypress/fixtures/datalake/sample.csv
@@ -1,11 +1,11 @@ timestamp;randombool;randomnumber;randomtext -1623871499055;true;62.0;c -1623871500059;false;46.0;a -1623871501064;true;41.0;b -1623871502070;true;41.0;b -1623871503078;false;22.0;b -1623871504082;true;56.0;a -1623871505084;false;77.0;b -1623871506086;true;77.0;a -1623871507091;true;85.0;b -1623871508093;false;22.0;a +1653871499055;true;62.0;c +1653871500059;false;46.0;a +1653871501064;true;41.0;b +1653871502070;true;41.0;b +1653871503078;false;22.0;b +1653871504082;true;56.0;a +1653871505084;false;77.0;b +1653871506086;true;77.0;a +1653871507091;true;85.0;b +1653871508093;false;22.0;a
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/math1/description.json b/ui/cypress/fixtures/pipelineElement/enrich-jvm/math1/description.json new file mode 100644 index 0000000..704e892 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/math1/description.json
@@ -0,0 +1,20 @@ +{ + "name": "math", + "config": [ + { + "type": "drop-down", + "selector": "leftOperand", + "value": "temperature1" + }, + { + "type": "drop-down", + "selector": "rightOperand", + "value": "temperature2" + }, + { + "type": "radio", + "selector": "operation", + "value": "\\+" + } + ] +}
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/math1/expected.csv b/ui/cypress/fixtures/pipelineElement/enrich-jvm/math1/expected.csv new file mode 100644 index 0000000..5b481a5 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/math1/expected.csv
@@ -0,0 +1,3 @@ +time;calculationResult;temperature1;temperature2 +1623871499055;5.0;2.0;3.0 +1623871500059;7.0;3.0;4.0
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/math1/input.csv b/ui/cypress/fixtures/pipelineElement/enrich-jvm/math1/input.csv new file mode 100644 index 0000000..1b75ffa --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/math1/input.csv
@@ -0,0 +1,3 @@ +timestamp;temperature1;temperature2 +1623871499055;2;3 +1623871500059;3;4
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/math2/description.json b/ui/cypress/fixtures/pipelineElement/enrich-jvm/math2/description.json new file mode 100644 index 0000000..7104559 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/math2/description.json
@@ -0,0 +1,20 @@ +{ + "name": "math", + "config": [ + { + "type": "drop-down", + "selector": "leftOperand", + "value": "temperature1" + }, + { + "type": "drop-down", + "selector": "rightOperand", + "value": "temperature2" + }, + { + "type": "radio", + "selector": "operation", + "value": "\\/" + } + ] +}
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/math2/expected.csv b/ui/cypress/fixtures/pipelineElement/enrich-jvm/math2/expected.csv new file mode 100644 index 0000000..43a0779 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/math2/expected.csv
@@ -0,0 +1,3 @@ +time;calculationResult;temperature1;temperature2 +1623871499055;1.0;4.0;4.0 +1623871500059;20.0;100.0;5.0
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/math2/input.csv b/ui/cypress/fixtures/pipelineElement/enrich-jvm/math2/input.csv new file mode 100644 index 0000000..aaad252 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/math2/input.csv
@@ -0,0 +1,3 @@ +timestamp;temperature1;temperature2 +1623871499055;4;4 +1623871500059;100.0;5.0
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/math3/description.json b/ui/cypress/fixtures/pipelineElement/enrich-jvm/math3/description.json new file mode 100644 index 0000000..968a447 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/math3/description.json
@@ -0,0 +1,20 @@ +{ + "name": "math", + "config": [ + { + "type": "drop-down", + "selector": "leftOperand", + "value": "temperature1" + }, + { + "type": "drop-down", + "selector": "rightOperand", + "value": "temperature2" + }, + { + "type": "radio", + "selector": "operation", + "value": "\\*" + } + ] +}
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/math3/expected.csv b/ui/cypress/fixtures/pipelineElement/enrich-jvm/math3/expected.csv new file mode 100644 index 0000000..3f681d9 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/math3/expected.csv
@@ -0,0 +1,3 @@ +time;calculationResult;temperature1;temperature2 +1623871499055;8.0;4.0;2.0 +1623871500059;17.5;3.5;5.0
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/math3/input.csv b/ui/cypress/fixtures/pipelineElement/enrich-jvm/math3/input.csv new file mode 100644 index 0000000..9e97f57 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/math3/input.csv
@@ -0,0 +1,3 @@ +timestamp;temperature1;temperature2 +1623871499055;4;2 +1623871500059;3.5;5.0
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/staticmath1/description.json b/ui/cypress/fixtures/pipelineElement/enrich-jvm/staticmath1/description.json new file mode 100644 index 0000000..7416eea --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/staticmath1/description.json
@@ -0,0 +1,20 @@ +{ + "name": "static_math", + "config": [ + { + "type": "drop-down", + "selector": "leftOperand", + "value": "temperature1" + }, + { + "type": "input", + "selector": "rightOperandValue", + "value": "5" + }, + { + "type": "radio", + "selector": "operation", + "value": "\\*" + } + ] +}
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/staticmath1/expected.csv b/ui/cypress/fixtures/pipelineElement/enrich-jvm/staticmath1/expected.csv new file mode 100644 index 0000000..6727b72 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/staticmath1/expected.csv
@@ -0,0 +1,3 @@ +time;temperature1 +1623871499055;20.0 +1623871500059;17.5
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/staticmath1/input.csv b/ui/cypress/fixtures/pipelineElement/enrich-jvm/staticmath1/input.csv new file mode 100644 index 0000000..437bd65 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/staticmath1/input.csv
@@ -0,0 +1,3 @@ +timestamp;temperature1 +1623871499055;4 +1623871500059;3.5
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/staticmath2/description.json b/ui/cypress/fixtures/pipelineElement/enrich-jvm/staticmath2/description.json new file mode 100644 index 0000000..948f842 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/staticmath2/description.json
@@ -0,0 +1,20 @@ +{ + "name": "static_math", + "config": [ + { + "type": "drop-down", + "selector": "leftOperand", + "value": "temperature1" + }, + { + "type": "input", + "selector": "rightOperandValue", + "value": "1.5" + }, + { + "type": "radio", + "selector": "operation", + "value": "\\/" + } + ] +}
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/staticmath2/expected.csv b/ui/cypress/fixtures/pipelineElement/enrich-jvm/staticmath2/expected.csv new file mode 100644 index 0000000..5a04b8a --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/staticmath2/expected.csv
@@ -0,0 +1,3 @@ +time;temperature1 +1623871499055;4.0 +1623871500059;2.0
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/staticmath2/input.csv b/ui/cypress/fixtures/pipelineElement/enrich-jvm/staticmath2/input.csv new file mode 100644 index 0000000..933646d --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/staticmath2/input.csv
@@ -0,0 +1,3 @@ +timestamp;temperature1 +1623871499055;6 +1623871500059;3
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/trigonometry1/description.json b/ui/cypress/fixtures/pipelineElement/enrich-jvm/trigonometry1/description.json new file mode 100644 index 0000000..7edea59 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/trigonometry1/description.json
@@ -0,0 +1,15 @@ +{ + "name": "trigonometry_functions", + "config": [ + { + "type": "drop-down", + "selector": "operand", + "value": "temperature1" + }, + { + "type": "radio", + "selector": "operation", + "value": "sin" + } + ] +}
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/trigonometry1/expected.csv b/ui/cypress/fixtures/pipelineElement/enrich-jvm/trigonometry1/expected.csv new file mode 100644 index 0000000..bef8e92 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/trigonometry1/expected.csv
@@ -0,0 +1,3 @@ +time;temperature1;trigonometryResult +1623871499055;90.0;0.8939966636005579 +1623871500059;180.0;-0.8011526357338304
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/trigonometry1/input.csv b/ui/cypress/fixtures/pipelineElement/enrich-jvm/trigonometry1/input.csv new file mode 100644 index 0000000..13f6543 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/trigonometry1/input.csv
@@ -0,0 +1,3 @@ +timestamp;temperature1 +1623871499055;90 +1623871500059;180.0
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/trigonometry2/description.json b/ui/cypress/fixtures/pipelineElement/enrich-jvm/trigonometry2/description.json new file mode 100644 index 0000000..d8304c3 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/trigonometry2/description.json
@@ -0,0 +1,15 @@ +{ + "name": "trigonometry_functions", + "config": [ + { + "type": "drop-down", + "selector": "operand", + "value": "temperature1" + }, + { + "type": "radio", + "selector": "operation", + "value": "cos" + } + ] +}
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/trigonometry2/expected.csv b/ui/cypress/fixtures/pipelineElement/enrich-jvm/trigonometry2/expected.csv new file mode 100644 index 0000000..5ca7cff --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/trigonometry2/expected.csv
@@ -0,0 +1,3 @@ +time;temperature1;trigonometryResult +1623871499055;120.0;0.8141809705265618 +1623871500059;150.0;0.6992508064783751
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/trigonometry2/input.csv b/ui/cypress/fixtures/pipelineElement/enrich-jvm/trigonometry2/input.csv new file mode 100644 index 0000000..1de8e27 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/trigonometry2/input.csv
@@ -0,0 +1,3 @@ +timestamp;temperature1 +1623871499055;120 +1623871500059;150.0
diff --git a/ui/cypress/fixtures/pipelineElement/enrich-jvm/valueChange1/expected.csv b/ui/cypress/fixtures/pipelineElement/enrich-jvm/valueChange1/expected.csv index deedcfc..55b0312 100644 --- a/ui/cypress/fixtures/pipelineElement/enrich-jvm/valueChange1/expected.csv +++ b/ui/cypress/fixtures/pipelineElement/enrich-jvm/valueChange1/expected.csv
@@ -1,4 +1,4 @@ -time;ischanged;numberlist +time;isChanged;numberlist 1623871499055;false;2.0 1623871500059;false;3.0 1623871501064;true;4.0
diff --git a/ui/cypress/fixtures/pipelineElement/filters-jvm/thresholdDetection1/expected.csv b/ui/cypress/fixtures/pipelineElement/filters-jvm/thresholdDetection1/expected.csv index a4d4d84..52727c6 100644 --- a/ui/cypress/fixtures/pipelineElement/filters-jvm/thresholdDetection1/expected.csv +++ b/ui/cypress/fixtures/pipelineElement/filters-jvm/thresholdDetection1/expected.csv
@@ -1,4 +1,4 @@ -time;randomnumber;thresholddetected +time;randomnumber;thresholdDetected 1623871499055;62.0;true 1623871500059;46.0;false 1623871501064;41.0;false
diff --git a/ui/cypress/fixtures/pipelineElement/filters-siddhi/count1/description.json b/ui/cypress/fixtures/pipelineElement/filters-siddhi/count1/description.json index 8c17a38..d7ff167 100644 --- a/ui/cypress/fixtures/pipelineElement/filters-siddhi/count1/description.json +++ b/ui/cypress/fixtures/pipelineElement/filters-siddhi/count1/description.json
@@ -8,6 +8,11 @@ "value": "text" }, { + "type": "drop-down", + "selector": "timestamp-mapping", + "value": "timestamp" + }, + { "type": "radio", "selector": "scale", "value": "Seconds"
diff --git a/ui/cypress/fixtures/pipelineElement/filters-siddhi/count1/input.csv b/ui/cypress/fixtures/pipelineElement/filters-siddhi/count1/input.csv index a9b2ad7..c9d251c 100644 --- a/ui/cypress/fixtures/pipelineElement/filters-siddhi/count1/input.csv +++ b/ui/cypress/fixtures/pipelineElement/filters-siddhi/count1/input.csv
@@ -1,4 +1,4 @@ timestamp;text 1623871499055;hello 1623871503078;world -1623871503079;hello +1623871504079;hello
diff --git a/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase1/description.json b/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase1/description.json index 6635a5f..dc722f6 100644 --- a/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase1/description.json +++ b/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase1/description.json
@@ -12,7 +12,7 @@ "value": "Increase" }, { - "type": "input", + "type": "slider", "selector": "increase", "value": "100" },
diff --git a/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase1/expected.csv b/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase1/expected.csv index b35c308..cf3cbf9 100644 --- a/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase1/expected.csv +++ b/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase1/expected.csv
@@ -1,2 +1,2 @@ -time;sensorvalue +time;sensorValue 1623871503078;10.0
diff --git a/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase2/description.json b/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase2/description.json index 6635a5f..dc722f6 100644 --- a/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase2/description.json +++ b/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase2/description.json
@@ -12,7 +12,7 @@ "value": "Increase" }, { - "type": "input", + "type": "slider", "selector": "increase", "value": "100" },
diff --git a/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase3/description.json b/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase3/description.json index 6635a5f..dc722f6 100644 --- a/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase3/description.json +++ b/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase3/description.json
@@ -12,7 +12,7 @@ "value": "Increase" }, { - "type": "input", + "type": "slider", "selector": "increase", "value": "100" },
diff --git a/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase3/expected.csv b/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase3/expected.csv index b35c308..cf3cbf9 100644 --- a/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase3/expected.csv +++ b/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase3/expected.csv
@@ -1,2 +1,2 @@ -time;sensorvalue +time;sensorValue 1623871503078;10.0
diff --git a/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase3/input.csv b/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase3/input.csv index 73ccb34..b881d67 100644 --- a/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase3/input.csv +++ b/ui/cypress/fixtures/pipelineElement/filters-siddhi/increase3/input.csv
@@ -2,3 +2,4 @@ 1623871499055;1.0 1623871503078;10 1623871503085;11 +1623871503086;15
diff --git a/ui/cypress/fixtures/pipelineElement/transformation-jvm/booleanCounter1/expected.csv b/ui/cypress/fixtures/pipelineElement/transformation-jvm/booleanCounter1/expected.csv index 715670f..550e14d 100644 --- a/ui/cypress/fixtures/pipelineElement/transformation-jvm/booleanCounter1/expected.csv +++ b/ui/cypress/fixtures/pipelineElement/transformation-jvm/booleanCounter1/expected.csv
@@ -1,4 +1,4 @@ -time;booleantocount;counter +time;booleanToCount;counter 1623871499055;true;1 1623871502070;false;2 1623871505084;true;3
diff --git a/ui/cypress/fixtures/pipelineElement/transformation-jvm/booleanCounter2/description.json b/ui/cypress/fixtures/pipelineElement/transformation-jvm/booleanCounter2/description.json new file mode 100644 index 0000000..81ca935 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/transformation-jvm/booleanCounter2/description.json
@@ -0,0 +1,15 @@ +{ + "name": "boolean_counter", + "config": [ + { + "type": "drop-down", + "selector": "field", + "value": "randomboolean" + }, + { + "type": "radio", + "selector": "flank", + "value": "BOTH" + } + ] +}
diff --git a/ui/cypress/fixtures/pipelineElement/transformation-jvm/booleanCounter2/expected.csv b/ui/cypress/fixtures/pipelineElement/transformation-jvm/booleanCounter2/expected.csv new file mode 100644 index 0000000..1eaabc8 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/transformation-jvm/booleanCounter2/expected.csv
@@ -0,0 +1,8 @@ +time;counter;randomboolean +1623871501064;1;true +1623871502070;2;false +1623871503078;3;true +1623871504082;4;false +1623871505084;5;true +1623871506086;6;false +1623871507091;7;true
diff --git a/ui/cypress/fixtures/pipelineElement/transformation-jvm/booleanCounter2/input.csv b/ui/cypress/fixtures/pipelineElement/transformation-jvm/booleanCounter2/input.csv new file mode 100644 index 0000000..691d574 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/transformation-jvm/booleanCounter2/input.csv
@@ -0,0 +1,11 @@ +timestamp;randomboolean +1623871499055;false +1623871500059;false +1623871501064;true +1623871502070;false +1623871503078;true +1623871504082;false +1623871505084;true +1623871506086;false +1623871507091;true +1623871508093;true
diff --git a/ui/cypress/fixtures/pipelineElement/transformation-jvm/booleanInverter1/expected.csv b/ui/cypress/fixtures/pipelineElement/transformation-jvm/booleanInverter1/expected.csv index 35eeb28..dae89b0 100644 --- a/ui/cypress/fixtures/pipelineElement/transformation-jvm/booleanInverter1/expected.csv +++ b/ui/cypress/fixtures/pipelineElement/transformation-jvm/booleanInverter1/expected.csv
@@ -1,4 +1,4 @@ -time;booleantoinvert +time;booleanToInvert 1623871499055;false 1623871500059;false 1623871501064;false
diff --git a/ui/cypress/fixtures/pipelineElement/transformation-jvm/countArray1/expected.csv b/ui/cypress/fixtures/pipelineElement/transformation-jvm/countArray1/expected.csv index 6d5dcbf..2f327e4 100644 --- a/ui/cypress/fixtures/pipelineElement/transformation-jvm/countArray1/expected.csv +++ b/ui/cypress/fixtures/pipelineElement/transformation-jvm/countArray1/expected.csv
@@ -1,4 +1,4 @@ -time;countvalue +time;countValue 1623871499055;4.0 1623871500059;2.0 1623871507091;5.0
diff --git a/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldHasher1/description.json b/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldHasher1/description.json new file mode 100644 index 0000000..147ee23 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldHasher1/description.json
@@ -0,0 +1,7 @@ +{ + "name": "field_hasher", + "config": [ + {"type": "drop-down", "selector": "property-mapping", "value": "sensorId"}, + {"type": "radio", "selector": "hash-algorithm", "value": "SHA1"} + ] +}
diff --git a/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldHasher1/expected.csv b/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldHasher1/expected.csv new file mode 100644 index 0000000..27830ff --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldHasher1/expected.csv
@@ -0,0 +1,3 @@ +time;sensorId +1623871499055;a9993e364706816aba3e25717850c26c9cd0d89d +1623871500059;40bd001563085fc35165329ea1ff5c5ecbdbbeef
diff --git a/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldHasher1/input.csv b/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldHasher1/input.csv new file mode 100644 index 0000000..bcbd541 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldHasher1/input.csv
@@ -0,0 +1,3 @@ +timestamp;sensorId +1623871499055;abc +1623871500059;123
diff --git a/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldHasher2/description.json b/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldHasher2/description.json new file mode 100644 index 0000000..75aff69 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldHasher2/description.json
@@ -0,0 +1,7 @@ +{ + "name": "field_hasher", + "config": [ + {"type": "drop-down", "selector": "property-mapping", "value": "sensorId"}, + {"type": "radio", "selector": "hash-algorithm", "value": "MD5"} + ] +}
diff --git a/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldHasher2/expected.csv b/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldHasher2/expected.csv new file mode 100644 index 0000000..8f61632 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldHasher2/expected.csv
@@ -0,0 +1,3 @@ +time;sensorId +1623871499055;900150983cd24fb0d6963f7d28e17f72 +1623871500059;202cb962ac59075b964b07152d234b70
diff --git a/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldHasher2/input.csv b/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldHasher2/input.csv new file mode 100644 index 0000000..3f2fd76 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldHasher2/input.csv
@@ -0,0 +1,5 @@ +timestamp;sensorId +1623871499055;abc +1623871500059;123 + +
diff --git a/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldMapper1/description.json b/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldMapper1/description.json new file mode 100644 index 0000000..40a5298 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldMapper1/description.json
@@ -0,0 +1,8 @@ +{ + "name": "field_mapper", + "config": [ + {"type": "checkbox", "selector": "value1", "value": "check"}, + {"type": "checkbox", "selector": "value2", "value": "check"}, + {"type": "input", "selector": "fieldName", "value": "hashedField"} + ] +}
diff --git a/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldMapper1/expected.csv b/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldMapper1/expected.csv new file mode 100644 index 0000000..cc037c0 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldMapper1/expected.csv
@@ -0,0 +1,3 @@ +time;hashedField +1623871499055;e80b5017098950fc58aad83c8c14978e +1623871500059;e10adc3949ba59abbe56e057f20f883e
diff --git a/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldMapper1/input.csv b/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldMapper1/input.csv new file mode 100644 index 0000000..3808251 --- /dev/null +++ b/ui/cypress/fixtures/pipelineElement/transformation-jvm/fieldMapper1/input.csv
@@ -0,0 +1,5 @@ +timestamp;value1;value2 +1623871499055;abc;def +1623871500059;123;456 + +
diff --git a/ui/cypress/fixtures/pipelineElement/transformation-jvm/signalEdgeFilter1/expected.csv b/ui/cypress/fixtures/pipelineElement/transformation-jvm/signalEdgeFilter1/expected.csv index 48599eb..71be1ef 100644 --- a/ui/cypress/fixtures/pipelineElement/transformation-jvm/signalEdgeFilter1/expected.csv +++ b/ui/cypress/fixtures/pipelineElement/transformation-jvm/signalEdgeFilter1/expected.csv
@@ -1,4 +1,4 @@ -time;booleanedge +time;booleanEdge 1623871499055;true 1623871502070;false 1623871505084;true
diff --git a/ui/cypress/support/model/UserInputType.ts b/ui/cypress/support/model/UserInputType.ts index 694b84c..0938fd5 100644 --- a/ui/cypress/support/model/UserInputType.ts +++ b/ui/cypress/support/model/UserInputType.ts
@@ -25,5 +25,6 @@ 'code-input' | 'click' | 'button' | + 'slider' | 'select';
diff --git a/ui/cypress/support/utils/ConnectEventSchemaUtils.ts b/ui/cypress/support/utils/ConnectEventSchemaUtils.ts index c39da21..a9044a6 100644 --- a/ui/cypress/support/utils/ConnectEventSchemaUtils.ts +++ b/ui/cypress/support/utils/ConnectEventSchemaUtils.ts
@@ -19,7 +19,7 @@ export class ConnectEventSchemaUtils { public static markPropertyAsDimension(propertyName: string) { - cy.dataCy('property-scope-' + propertyName) + cy.dataCy('property-scope-' + propertyName, { timeout: 10000 }) .click() .get('.mat-option-text') .contains('Dimension') @@ -119,6 +119,7 @@ // validate that static value is persisted cy.dataCy('edit-' + propertyName, { timeout: 10000 }).click({ force: true }); cy.dataCy('connect-change-runtime-type', { timeout: 10000 }).contains(dataType); + cy.wait(1000); cy.dataCy('sp-save-edit-property').click(); } public static eventSchemaNextBtnDisabled() {
diff --git a/ui/cypress/support/utils/ConnectUtils.ts b/ui/cypress/support/utils/ConnectUtils.ts index becfa72..dc8c390 100644 --- a/ui/cypress/support/utils/ConnectUtils.ts +++ b/ui/cypress/support/utils/ConnectUtils.ts
@@ -32,6 +32,8 @@ ConnectUtils.goToConnect(); + ConnectUtils.goToNewAdapterPage(); + ConnectUtils.selectAdapter(adapterConfiguration.adapterType); ConnectUtils.configureAdapter(adapterConfiguration.adapterConfiguration); @@ -72,6 +74,8 @@ private static addGenericAdapter(adapterConfiguration: GenericAdapterInput) { ConnectUtils.goToConnect(); + ConnectUtils.goToNewAdapterPage(); + ConnectUtils.selectAdapter(adapterConfiguration.adapterType); ConnectUtils.configureAdapter(adapterConfiguration.protocolConfiguration); @@ -90,16 +94,24 @@ ConnectEventSchemaUtils.finishEventSchemaConfiguration(); } - public static addMachineDataSimulator(name: string) { + public static addMachineDataSimulator(name: string, persist: boolean = false) { - const configuration = SpecificAdapterBuilder + const builder = SpecificAdapterBuilder .create('Machine_Data_Simulator') .setName(name) - .addInput('input', 'wait-time-ms', '1000') - .build(); + .addInput('input', 'wait-time-ms', '1000'); + + if (persist) { + builder.setTimestampProperty('timestamp'). + setStoreInDataLake(); + } + + const configuration = builder.build(); ConnectUtils.goToConnect(); + ConnectUtils.goToNewAdapterPage(); + ConnectUtils.selectAdapter(configuration.adapterType); ConnectUtils.configureAdapter(configuration.adapterConfiguration); @@ -114,13 +126,17 @@ cy.visit('#/connect'); } + public static goToNewAdapterPage() { + cy.dataCy('connect-create-new-adapter-button').click(); + } + public static selectAdapter(name) { // Select adapter cy.get('#' + name).click(); } public static configureAdapter(configs: UserInput[]) { - + cy.wait(2000); StaticPropertyUtils.input(configs); // Next Button should not be disabled @@ -185,13 +201,11 @@ // Delete adapter cy.visit('#/connect'); - cy.get('div').contains('My Adapters').parent().click(); - cy.dataCy('delete').should('have.length', 1); - cy.dataCy('delete').click(); + cy.dataCy('delete-adapter').should('have.length', 1); cy.dataCy('delete-adapter').click(); + cy.dataCy('delete-adapter-confirmation').click(); cy.dataCy('adapter-deletion-in-progress', { timeout: 10000 }).should('be.visible'); - cy.dataCy('delete', { timeout: 20000 }).should('have.length', 0); - // }); + cy.dataCy('delete-adapter', { timeout: 20000 }).should('have.length', 0); } public static setUpPreprocessingRuleTest(): AdapterInput { @@ -207,6 +221,7 @@ ConnectUtils.goToConnect(); + ConnectUtils.goToNewAdapterPage(); ConnectUtils.selectAdapter(adapterConfiguration.adapterType); ConnectUtils.configureAdapter(adapterConfiguration.protocolConfiguration); ConnectUtils.configureFormat(adapterConfiguration); @@ -227,7 +242,7 @@ cy.wait(10000); DataLakeUtils.checkResults( - 'adaptertotestrules', + 'Adapter to test rules', expectedFile, ignoreTime); }
diff --git a/ui/cypress/support/utils/DataLakeUtils.ts b/ui/cypress/support/utils/DataLakeUtils.ts index 39b29cd..9596f38 100644 --- a/ui/cypress/support/utils/DataLakeUtils.ts +++ b/ui/cypress/support/utils/DataLakeUtils.ts
@@ -65,7 +65,7 @@ DataLakeUtils.selectTimeRange( new Date(2020, 10, 20, 22, 44), new Date(2021, 10, 20, 22, 44)); - DataLakeUtils.addNewWidget(); + // DataLakeUtils.addNewWidget(); DataLakeUtils.selectDataSet(dataSet); DataLakeUtils.dataConfigSelectAllFields(); DataLakeUtils.selectVisualizationConfig(); @@ -100,7 +100,6 @@ .click(); this.editDataView(name); - // cy.get('div').contains(name).parent().click(); } @@ -131,10 +130,8 @@ public static saveAndReEditWidget(dataViewName: string) { // Save configuration DataLakeUtils.saveDataExplorerWidgetConfiguration(); - DataLakeUtils.clickStartTab(); + DataLakeUtils.goBackToOverview(); DataLakeUtils.editDataView(dataViewName); - // Edit widget again - DataLakeUtils.editWidget('datalake_configuration'); } public static clickTab(tabName: string) { @@ -142,10 +139,13 @@ cy.get('div').contains(tabName).parent().click(); } - public static clickStartTab() { - this.clickTab('Start'); + + public static goBackToOverview() { + cy.dataCy('save-data-explorer-go-back-to-overview') + .click(); } + public static addNewWidget() { cy.dataCy('add-new-widget') .click(); @@ -168,7 +168,7 @@ if (amountOfFilter === 0) { cy.dataCy('design-panel-data-settings-filter-field').should('not.exist'); } else { - cy.dataCy('design-panel-data-settings-filter-field').should('be.visible'); + cy.dataCy('design-panel-data-settings-filter-field', { timeout: 20000 }).should('be.visible'); } } @@ -245,8 +245,7 @@ } public static goToDatalakeConfiguration() { - cy.visit('#/configuration'); - cy.get('div').contains('DataLake').parent().click(); + cy.visit('#/configuration/datalake'); } public static checkResults(dataLakeIndex: string, fileRoute: string, ignoreTime?: boolean) { @@ -254,7 +253,7 @@ // Validate result in datalake cy.request({ method: 'GET', - url: `/streampipes-backend/api/v4/datalake/measurements/${dataLakeIndex}/download?format=csv`, + url: `/streampipes-backend/api/v4/datalake/measurements/${dataLakeIndex}/download?format=csv&delimiter=semicolon`, headers: { 'content-type': 'application/octet-stream' },
diff --git a/ui/cypress/support/utils/PipelineUtils.ts b/ui/cypress/support/utils/PipelineUtils.ts index d74522c..6e2d18e 100644 --- a/ui/cypress/support/utils/PipelineUtils.ts +++ b/ui/cypress/support/utils/PipelineUtils.ts
@@ -49,7 +49,8 @@ private static goToPipelineEditor() { // Go to StreamPipes editor - cy.visit('#/editor'); + cy.visit('#/pipelines'); + cy.dataCy('pipelines-navigate-to-editor').click(); } private static selectDataStream(pipelineInput: PipelineInput) { @@ -91,22 +92,24 @@ cy.dataCy('sp-editor-pipeline-name').type(pipelineInput.pipelineName); cy.dataCy('sp-editor-checkbox-start-immediately').children().click(); cy.dataCy('sp-editor-save').click(); - cy.dataCy('sp-pipeline-started-dialog', { timeout: 10000 }).should('be.visible'); - cy.dataCy('sp-pipeline-dialog-close', { timeout: 10000 }).click(); + cy.dataCy('sp-pipeline-started-dialog', { timeout: 15000 }).should('be.visible'); + cy.dataCy('sp-pipeline-dialog-close', { timeout: 15000 }).click(); } public static checkAmountOfPipelinesPipeline(amount: number) { cy.visit('#/pipelines'); - cy.dataCy('delete').should('have.length', amount); + cy.dataCy('delete-pipeline').should('have.length', amount); } public static deletePipeline() { // Delete pipeline cy.visit('#/pipelines'); - cy.dataCy('delete').should('have.length', 1); - cy.dataCy('delete').click({ force: true }); + cy.dataCy('delete-pipeline').should('have.length', 1); + cy.dataCy('delete-pipeline').click({ force: true }); + cy.dataCy('sp-pipeline-stop-and-delete').click(); - cy.dataCy('delete', { timeout: 10000 }).should('have.length', 0); + + cy.dataCy('delete-pipeline', { timeout: 10000 }).should('have.length', 0); } }
diff --git a/ui/cypress/support/utils/StaticPropertyUtils.ts b/ui/cypress/support/utils/StaticPropertyUtils.ts index a8d9f35..e3e730d 100644 --- a/ui/cypress/support/utils/StaticPropertyUtils.ts +++ b/ui/cypress/support/utils/StaticPropertyUtils.ts
@@ -33,14 +33,16 @@ } else if (config.type === 'radio') { cy.dataCy(config.selector.replace(' ', '_').toLowerCase() + '-' + config.value.replace(' ', '_').toLowerCase()).click(); } else if (config.type === 'click') { - cy.dataCy(config.selector).click({ force: true }); + cy.dataCy(config.selector).click({force: true}); } else if (config.type === 'code-input') { cy.dataCy('reset-code-' + config.selector).click(); cy.dataCy('code-editor-' + config.selector).type(config.value); } else if (config.type === 'input') { - cy.dataCy(config.selector).type(config.value).blur(); - } else { - cy.dataCy(config.selector).type(config.value); + cy.dataCy(config.selector).clear().type(config.value).blur(); + } else if (config.type === 'slider') { + cy.dataCy(config.selector).type(config.value); + } else { + cy.dataCy(config.selector).type(config.value); } }); }
diff --git a/ui/cypress/support/utils/UserUtils.ts b/ui/cypress/support/utils/UserUtils.ts index 8dd2754..c816ca6 100644 --- a/ui/cypress/support/utils/UserUtils.ts +++ b/ui/cypress/support/utils/UserUtils.ts
@@ -28,13 +28,8 @@ .addRole(UserRole.ROLE_ADMIN) .build(); - - // public static testUserName = 'admin@streampipes.apache.org'; - // public static testUserPassword = 'admin'; - public static goToUserConfiguration() { - cy.visit('#/configuration'); - cy.get('div').contains('Security').parent().click(); + cy.visit('#/configuration/security'); } public static addUser(user: User) {
diff --git a/ui/cypress/tests/adapter/opcAdapter.ts b/ui/cypress/tests/adapter/opcAdapter.ts index 74ad8ba..8ec8e54 100644 --- a/ui/cypress/tests/adapter/opcAdapter.ts +++ b/ui/cypress/tests/adapter/opcAdapter.ts
@@ -47,7 +47,7 @@ const getAdapterBuilder = (pullMode: boolean) => { - const host: string = ParameterUtils.get('ipe-girlitz.fzi.de', 'opcua'); + const host: string = ParameterUtils.get('localhost', 'opcua'); const builder = SpecificAdapterBuilder .create('OPC_UA')
diff --git a/ui/cypress/tests/dashboard/dashboardTest.smoke.spec.ts b/ui/cypress/tests/dashboard/dashboardTest.smoke.spec.ts index dd8eabf..be6ad80 100644 --- a/ui/cypress/tests/dashboard/dashboardTest.smoke.spec.ts +++ b/ui/cypress/tests/dashboard/dashboardTest.smoke.spec.ts
@@ -17,31 +17,15 @@ */ import { ConnectUtils } from '../../support/utils/ConnectUtils'; -import { PipelineUtils } from '../../support/utils/PipelineUtils'; -import { PipelineElementBuilder } from '../../support/builder/PipelineElementBuilder'; -import { PipelineBuilder } from '../../support/builder/PipelineBuilder'; import { DashboardUtils } from '../../support/utils/DashboardUtils'; -const adapterName = 'simulator'; - - describe('Test live dashboard', () => { beforeEach('Setup Test', () => { cy.initStreamPipesTest(); - ConnectUtils.addMachineDataSimulator(adapterName); + ConnectUtils.addMachineDataSimulator('simulator', true); }); it('Perform Test', () => { - const pipelineName = 'DashboardPipeline'; - const pipelineInput = PipelineBuilder.create(pipelineName) - .addSource(adapterName) - .addSink( - PipelineElementBuilder.create('data_lake') - .addInput('input', 'db_measurement', 'demo') - .build()) - .build(); - - PipelineUtils.testPipeline(pipelineInput); DashboardUtils.goToDashboard(); @@ -49,7 +33,7 @@ const dashboardName = 'testDashboard'; DashboardUtils.addAndEditDashboard(dashboardName); - DashboardUtils.addWidget(pipelineName, 'raw'); + DashboardUtils.addWidget('Persist_simulator', 'raw'); // Validate that data is coming (at least 3 events) DashboardUtils.validateRawWidgetEvents(3);
diff --git a/ui/cypress/tests/datalake/widgetDataConfiguration.smoke.spec.ts b/ui/cypress/tests/datalake/widgetDataConfiguration.smoke.spec.ts index 4dab10a..a97e5d3 100644 --- a/ui/cypress/tests/datalake/widgetDataConfiguration.smoke.spec.ts +++ b/ui/cypress/tests/datalake/widgetDataConfiguration.smoke.spec.ts
@@ -25,6 +25,9 @@ beforeEach('Setup Test', () => { cy.initStreamPipesTest(); DataLakeUtils.loadDataIntoDataLake('datalake/sample.csv'); + // cy.login(); + // DataLakeUtils.goToDatalake(); + }); it('Perform Test', () => { @@ -82,6 +85,7 @@ /** * Test groupBy configuration and if it is persisted correctly */ + cy.wait(1000); DataLakeUtils.clickGroupBy('randomtext'); cy.wait(1000); cy.dataCy('data-explorer-table-row-randomtext', { timeout: 10000 }).first({ timeout: 10000 }).contains('a', { timeout: 10000 });
diff --git a/ui/cypress/tests/experimental/testJvmArchetype/.env b/ui/cypress/tests/experimental/testJvmArchetype/.env index 1b8ff24..0330973 100644 --- a/ui/cypress/tests/experimental/testJvmArchetype/.env +++ b/ui/cypress/tests/experimental/testJvmArchetype/.env
@@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -SP_VERSION=0.70.0-SNAPSHOT +SP_VERSION=0.70.0 SP_DOCKER_REGISTRY=apachestreampipes SP_SUBNET=172.31.0.0/16 SP_CONSUL_CONTAINER_IP=172.31.0.9
diff --git a/ui/cypress/tests/experimental/testJvmArchetype/backend/.env b/ui/cypress/tests/experimental/testJvmArchetype/backend/.env index 1b8ff24..0330973 100644 --- a/ui/cypress/tests/experimental/testJvmArchetype/backend/.env +++ b/ui/cypress/tests/experimental/testJvmArchetype/backend/.env
@@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -SP_VERSION=0.70.0-SNAPSHOT +SP_VERSION=0.70.0 SP_DOCKER_REGISTRY=apachestreampipes SP_SUBNET=172.31.0.0/16 SP_CONSUL_CONTAINER_IP=172.31.0.9
diff --git a/ui/cypress/tests/experimental/testJvmArchetype/testArchetype.sh b/ui/cypress/tests/experimental/testJvmArchetype/testArchetype.sh index e365b18..7e77f97 100755 --- a/ui/cypress/tests/experimental/testJvmArchetype/testArchetype.sh +++ b/ui/cypress/tests/experimental/testJvmArchetype/testArchetype.sh
@@ -15,7 +15,7 @@ # limitations under the License. mvn archetype:generate -DarchetypeGroupId=org.apache.streampipes \ - -DarchetypeArtifactId=streampipes-archetype-extensions-jvm -DarchetypeVersion=0.70.0-SNAPSHOT \ + -DarchetypeArtifactId=streampipes-archetype-extensions-jvm -DarchetypeVersion=0.70.0 \ -DgroupId=org.streampipes.test -DartifactId=automated-test -DclassNamePrefix=AutomatedTest -DpackageName=test -DinteractiveMode=false cd automated-test
diff --git a/ui/cypress/tests/pipelineElement/SinglePipelineElement.ts b/ui/cypress/tests/pipelineElement/SinglePipelineElement.ts index 635d222..4fbb135 100644 --- a/ui/cypress/tests/pipelineElement/SinglePipelineElement.ts +++ b/ui/cypress/tests/pipelineElement/SinglePipelineElement.ts
@@ -22,7 +22,7 @@ const allTests = Cypress.env('processingElements'); allTests.forEach(test => { - const testNames = ['countArray1']; + const testNames = ['staticmath1']; const processorTest = test as ProcessorTest;
diff --git a/ui/cypress/tests/thirdparty/MySQLDb.ts b/ui/cypress/tests/thirdparty/MySQLDb.ts deleted file mode 100644 index ac661ba..0000000 --- a/ui/cypress/tests/thirdparty/MySQLDb.ts +++ /dev/null
@@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { SpecificAdapterBuilder } from '../../support/builder/SpecificAdapterBuilder'; -import { PipelineElementBuilder } from '../../support/builder/PipelineElementBuilder'; -import { ThirdPartyIntegrationUtils } from '../../support/utils/ThirdPartyIntegrationUtils'; -import { PipelineElementInput } from '../../support/model/PipelineElementInput'; -import { ParameterUtils } from '../../support/utils/ParameterUtils'; - -describe('Test MySQL Integration', () => { - beforeEach('Setup Test', () => { - cy.initStreamPipesTest(); - }); - - it('Perform Test', () => { - const dbName = 'cypressDatabase'; - const host: string = ParameterUtils.get('localhost', 'mysql'); - - const sink: PipelineElementInput = PipelineElementBuilder.create('mysql_database') - .addInput('input', 'host', host) - .addInput('input', 'user', 'root') - .addInput('input', 'password', '7uc4rAymrPhxv6a5') - .addInput('input', 'db', 'sp') - .addInput('input', 'table', dbName) - .build(); - - const adapter = SpecificAdapterBuilder - .create('MySql_Stream_Adapter') - .setName('MySQL Adapter') - .setTimestampProperty('timestamp') - .addInput('input', 'mysqlHost', host) - .addInput('input', 'mysqlUser', 'root') - .addInput('input', 'mysqlPassword', '7uc4rAymrPhxv6a5') - .addInput('input', 'mysqlDatabase', 'sp') - .addInput('input', 'mysqlTable', dbName) - .build(); - - ThirdPartyIntegrationUtils.runTest(sink, adapter); - }); - -});
diff --git a/ui/deployment/app-routing.module.mst b/ui/deployment/app-routing.module.mst index 8994a2f..093d7a5 100644 --- a/ui/deployment/app-routing.module.mst +++ b/ui/deployment/app-routing.module.mst
@@ -22,7 +22,6 @@ import {LoginComponent} from "./login/components/login/login.component"; import {SetupComponent} from "./login/components/setup/setup.component"; import {StreampipesComponent} from "./core/components/streampipes/streampipes.component"; -import {PipelineDetailsComponent} from "./pipeline-details/pipeline-details.component"; import {StandaloneDashboardComponent} from "./dashboard/components/standalone/standalone-dashboard.component"; import {AuthCanActivateChildrenGuard} from "./_guards/auth.can-activate-children.guard"; import {ConfiguredCanActivateGuard} from "./_guards/configured.can-activate.guard"; @@ -42,9 +41,9 @@ import { ActivateAccountComponent } from './login/components/activate-account/activate-account.component'; {{#modulesActive}} -{{#ng5}} +{{#componentImport}} import { {{{ng5_component}}} } from '{{{ng5_componentPath}}}'; -{{/ng5}} +{{/componentImport}} {{/modulesActive}} const routes: Routes = [ @@ -60,13 +59,16 @@ { path: '', component: StreampipesComponent, children: [ { path: '', component: HomeComponent, canActivate: [ConfiguredCanActivateGuard] }, {{#modulesActive}} - {{#ng5}} + {{#componentImport}} { path: '{{{link}}}', component: {{{ng5_component}}}, data: { authPageNames: [{{{pageNames}}}]}}, - {{/ng5}} + {{/componentImport}} + {{^componentImport}} + { path: '', data: { authPageNames: [{{{pageNames}}}]}, loadChildren: () => import('{{{path}}}').then(m => m.{{{ng5_moduleName}}})}, + {{/componentImport}} {{/modulesActive}} + { path: 'notifications', component: NotificationsComponent }, { path: 'info', component: InfoComponent }, - { path: 'pipeline-details', component: PipelineDetailsComponent }, { path: 'profile', component: ProfileComponent}, ], canActivateChild: [AuthCanActivateChildrenGuard, PageAuthGuard] } ];
diff --git a/ui/deployment/appng5.module.mst b/ui/deployment/appng5.module.mst index f0d2471..d2352e3 100644 --- a/ui/deployment/appng5.module.mst +++ b/ui/deployment/appng5.module.mst
@@ -39,9 +39,7 @@ import { LOADING_BAR_CONFIG } from '@ngx-loading-bar/core'; {{#modulesActive}} -{{#ng5}} import { {{{ng5_moduleName}}} } from '{{{path}}}'; -{{/ng5}} {{/modulesActive}} import { NotificationModule } from './notifications/notifications.module'; @@ -80,9 +78,7 @@ ServicesModule, ProfileModule, {{#modulesActive}} - {{#ng5}} {{{ng5_moduleName}}}, - {{/ng5}} {{/modulesActive}} ], providers: [
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/deployment/apps.ts similarity index 62% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/deployment/apps.ts index 58ba04b..c049ded 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/deployment/apps.ts
@@ -16,3 +16,18 @@ * */ +import { App } from './apps.model'; + +export class AvailableAppsService { + + public static apps: App[] = [ + { + appName: 'Asset Dashboards', + appDescription: 'Monitor measurements of your assets by placing visualizations on an image of your asset.', + appId: 'asset-monitoring', + appLink: 'asset-monitoring', + appModuleLink: () => + import('../app-asset-monitoring/app-asset-monitoring.module').then(m => m.AppAssetMonitoringModule) + } + ]; +}
diff --git a/ui/deployment/base-navigation.component.mst b/ui/deployment/base-navigation.component.mst index 7922163..cb0005a 100644 --- a/ui/deployment/base-navigation.component.mst +++ b/ui/deployment/base-navigation.component.mst
@@ -17,9 +17,10 @@ */ -import {NavigationEnd, Router} from "@angular/router"; +import { NavigationEnd, Router } from '@angular/router'; import { PageName } from '../../_enums/page-name.enum'; import { AuthService } from '../../services/auth.service'; +import { AppConstants } from '../../services/app.constants'; export abstract class BaseNavigationComponent { @@ -67,7 +68,8 @@ constructor(protected authService: AuthService, - protected router: Router) { + protected router: Router, + private appConstants: AppConstants) { } @@ -81,7 +83,7 @@ this.activePageName = this.getPageTitle(this.activePage); this.router.events.subscribe(event => { if (event instanceof NavigationEnd) { - this.activePage = event.url.replace('/', ''); + this.activePage = event.url.split('/')[1]; this.activePageName = this.getPageTitle(this.activePage); } }); @@ -93,7 +95,7 @@ getPageTitle(path) { const allMenuItems = this.menu.concat(this.admin); - let currentTitle = 'StreamPipes'; + let currentTitle = this.appConstants.APP_NAME; allMenuItems.forEach(m => { if (m.link === path) { currentTitle = m.title;
diff --git a/ui/deployment/dev/config.yml b/ui/deployment/dev/config.yml index d134f44..dc1acdf 100644 --- a/ui/deployment/dev/config.yml +++ b/ui/deployment/dev/config.yml
@@ -19,12 +19,12 @@ logo-navigation: 'deployment/dev/img/logo-navigation.png' favicon: 'deployment/dev/img/favicon.png' modules: - - spEditor - spPipelines - spConnect - spDashboard - spDataExplorer - spAppOverview - spAdd + - spAssets - spFiles - spConfiguration
diff --git a/ui/deployment/modules.yml b/ui/deployment/modules.yml index a63513e..8655b53 100644 --- a/ui/deployment/modules.yml +++ b/ui/deployment/modules.yml
@@ -13,8 +13,23 @@ # See the License for the specific language governing permissions and # limitations under the License. + +spAssets: + componentImport: False + ng5_moduleName: 'AssetsModule' + ng5_component: 'EditorComponent' + ng5_componentPath: './editor/editor.component' + path: './assets/assets.module' + link: 'assets' + url: '/editor/:pipeline' + title: 'Asset Management' + description: 'Manage assets which help assigning pipelines, dashboards and adapters to real-world objects such as machines and plants.' + icon: 'precision_manufacturing' + homeImage: '' + admin: true + pageNames: 'PageName.ASSETS' spEditor: - ng5: True + componentImport: True ng5_moduleName: 'EditorModule' ng5_component: 'EditorComponent' ng5_componentPath: './editor/editor.component' @@ -28,7 +43,7 @@ admin: false pageNames: 'PageName.PIPELINE_EDITOR' spConnect: - ng5: True + componentImport: False ng5_moduleName: 'ConnectModule' ng5_component: 'ConnectComponent' ng5_componentPath: './connect/connect.component' @@ -42,7 +57,7 @@ admin: False pageNames: 'PageName.CONNECT' spPipelines: - ng5: True + componentImport: False ng5_moduleName: 'PipelinesModule' ng5_component: 'PipelinesComponent' ng5_componentPath: './pipelines/pipelines.component' @@ -56,7 +71,7 @@ admin: False pageNames: 'PageName.PIPELINE_OVERVIEW' spAdd: - ng5: True + componentImport: False ng5_moduleName: 'AddModule' ng5_component: 'AddComponent' ng5_componentPath: './add/add.component' @@ -70,10 +85,10 @@ admin: True pageNames: 'PageName.INSTALL_PIPELINE_ELEMENTS' spConfiguration: - ng5: True + componentImport: False ng5_moduleName: 'ConfigurationModule' - ng5_component: 'ConfigurationComponent' - ng5_componentPath: './configuration/configuration.component' + ng5_component: 'GeneralConfigurationComponent' + ng5_componentPath: './configuration/general-configuration/general-configuration.component' path: './configuration/configuration.module' link: 'configuration' url: '/configuration' @@ -84,12 +99,12 @@ pageNames: 'PageName.SETTINGS' admin: True spAppOverview: - ng5: True + componentImport: False ng5_moduleName: 'AppOverviewModule' ng5_component: 'AppOverviewComponent' ng5_componentPath: './app-overview/app-overview.component' path: './app-overview/app-overview.module' - link: 'app-overview' + link: 'apps' url: '/apps' title: 'Apps' description: 'The app overview allows you to view and open additional StreamPipes plugins.' @@ -98,7 +113,7 @@ admin: false pageNames: 'PageName.APPS' spDashboard: - ng5: True + componentImport: False ng5_moduleName: 'DashboardModule' ng5_component: 'DashboardComponent' ng5_componentPath: './dashboard/dashboard.component' @@ -112,7 +127,7 @@ admin: false pageNames: 'PageName.DASHBOARD' spDataExplorer: - ng5: True + componentImport: False ng5_moduleName: 'DataExplorerModule' ng5_component: 'DataExplorerComponent' ng5_componentPath: './data-explorer/data-explorer.component' @@ -126,7 +141,7 @@ admin: false pageNames: 'PageName.DATA_EXPLORER' spFiles: - ng5: True + componentImport: False ng5_moduleName: 'FilesModule' ng5_component: 'FilesComponent' ng5_componentPath: './files/files.component'
diff --git a/ui/deployment/prebuild.js b/ui/deployment/prebuild.js index f104a2e..0c1a81d 100644 --- a/ui/deployment/prebuild.js +++ b/ui/deployment/prebuild.js
@@ -62,7 +62,7 @@ for (let module of config.modules) { modulesActive['modulesActive'].push({ module: module, - ng5: modules[module]['ng5'], + componentImport: modules[module]['componentImport'], ng1_templateUrl: modules[module]['ng1_templateUrl'], ng5_moduleName: modules[module]['ng5_moduleName'], ng5_component: modules[module]['ng5_component'], @@ -77,7 +77,7 @@ description: modules[module]['description'], homeImage: modules[module]['homeImage'] }); - console.log('Active Angular ' + (modules[module]['ng5']===true?5:1) + ' Module: ' + module); + console.log('Active Angular Module: ' + module); } // Create necessary JavaScript-Files from Template and move to respective Directory @@ -85,6 +85,7 @@ fs.writeFileSync('src/app/home/home.service.ts', mustache.render(fs.readFileSync('deployment/home.service.mst', 'utf8').toString(), modulesActive)); fs.writeFileSync('src/app/app-routing.module.ts', mustache.render(fs.readFileSync('deployment/app-routing.module.mst', 'utf8').toString(), modulesActive)); fs.writeFileSync('src/app/core/components/base-navigation.component.ts', mustache.render(fs.readFileSync('deployment/base-navigation.component.mst', 'utf8').toString(), modulesActive)); +fs.writeFileSync('src/app/app-overview/apps.ts', fs.readFileSync('deployment/apps.ts')); fs.writeFileSync('src/scss/sp/sp-theme.scss', fs.readFileSync('deployment/sp-theme.scss')); fs.writeFileSync('src/app/services/app.constants.ts', fs.readFileSync('deployment/app-constants.ts', 'utf8'));
diff --git a/ui/deployment/sp-theme.scss b/ui/deployment/sp-theme.scss index db812e6..286bd61 100644 --- a/ui/deployment/sp-theme.scss +++ b/ui/deployment/sp-theme.scss
@@ -163,7 +163,10 @@ .small .mat-tab-label-content { text-transform: none; font-size: 11pt; +} +:root { + --color-loading-bar: #{mat-color($accent)}; } .dark-mode { @@ -174,6 +177,19 @@ background: #121212; } + .mat-button-toggle-checked { + background: var(--color-accent); + color: var(--color-bg-0); + } + + .mat-button-toggle-checked.mat-button-toggle-appearance-standard { + color: var(--color-bg-0); + } + + .mat-button-toggle-appearance-standard .mat-button-toggle-label-content { + line-height: 30px; + } + .mat-toolbar.mat-primary { color: #121212; } @@ -219,6 +235,19 @@ background: #FFFFFF; } + .mat-button-toggle-checked { + background: var(--color-accent); + color: var(--color-bg-0); + } + + .mat-button-toggle-checked.mat-button-toggle-appearance-standard { + color: var(--color-bg-0); + } + + .mat-button-toggle-appearance-standard .mat-button-toggle-label-content { + line-height: 30px; + } + --color-primary: #{mat-color($primary)}; --color-accent: #{mat-color($accent)};
diff --git a/ui/package.json b/ui/package.json index e4eb153..60b734d 100644 --- a/ui/package.json +++ b/ui/package.json
@@ -8,17 +8,17 @@ "url": "https://github.com/apache/incubator-streampipes" }, "scripts": { - "build-libs": "ng build @streampipes/shared-ui && ng build @streampipes/platform-services", - "install-libs": "npm install @streampipes/shared-ui@file:./dist/streampipes/shared-ui @streampipes/platform-services@file:./dist/streampipes/platform-services --no-save", + "build-libs": "ng build @streampipes/platform-services && ng build @streampipes/shared-ui", + "install-libs": "npm install @streampipes/platform-services@file:./dist/streampipes/platform-services @streampipes/shared-ui@file:./dist/streampipes/shared-ui --no-save", "build-libraries": "npm run build-libs && npm run install-libs", "start": "node ./deployment/prebuild.js && npm run build-libraries && ng serve", "test": "node ./deployment/prebuild.js && npm run build-libraries && ng test", "start-plain": "npm run build-libraries && ng serve", - "build-plain": "set NODE_OPTIONS=--max-old-space-size=10192 && npm run build-libraries && ng build --configuration production", + "build-plain": "set NODE_OPTIONS=--max-old-space-size=8192 && npm run build-libraries && ng build --configuration production", "run-prebuild-script": "node ./deployment/prebuild.js", - "build": "node ./deployment/prebuild.js && set NODE_OPTIONS=--max-old-space-size=10192 && npm run build-libraries && ng build --configuration production", - "build-dev": "node ./deployment/prebuild.js && set NODE_OPTIONS=--max-old-space-size=10192 && npm run build-libraries && ng build", - "build-rc": "node ./deployment/prebuild.js rel && set NODE_OPTIONS=--max-old-space-size=10192 && npm run build-libraries && ng build --configuration production", + "build": "node ./deployment/prebuild.js && set NODE_OPTIONS=--max-old-space-size=8192 && npm run build-libraries && ng build --configuration production", + "build-dev": "node ./deployment/prebuild.js && set NODE_OPTIONS=--max-old-space-size=8192 && npm run build-libraries && ng build", + "build-rc": "node ./deployment/prebuild.js rel && set NODE_OPTIONS=--max-old-space-size=8192 && npm run build-libraries && ng build --configuration production", "lint": "tslint -c tslint.json 'src/**/*.ts*", "analyze": "webpack-bundle-analyzer dist/stats.json", "test-cypress-open": "cypress open", @@ -43,7 +43,7 @@ "@angular/platform-browser-dynamic": "^13.3.0", "@angular/router": "^13.3.0", "@asymmetrik/ngx-leaflet": "6.0.1", - "@auth0/angular-jwt": "^5.0.2", + "@auth0/angular-jwt": "5.0.2", "@circlon/angular-tree-component": "^11.0.4", "@ctrl/ngx-codemirror": "5.1.1", "@danielmoncada/angular-datetime-picker": "^13.1.1", @@ -58,7 +58,7 @@ "@panzoom/panzoom": "^4.4.3", "@swimlane/ngx-charts": "16.0.0", "angular-datatables": "^13.0.1", - "angular-gridster2": "^13.1.1", + "angular-gridster2": "13.1.1", "angular-plotly.js": "^4.0.0", "angular2-uuid": "1.1.1", "codemirror": "^5.55.0", @@ -75,7 +75,7 @@ "konva": "3.2.4", "leaflet": "1.6.0", "lodash": "4.17.21", - "material-icons": "^0.5.3", + "material-icons": "^1.11.4", "ngx-color-picker": "^11.0.0", "ngx-echarts": "^8.0.1", "ngx-quill": "15.0.0", @@ -87,7 +87,7 @@ "shepherd.js": "^9.0.0", "showdown": "1.9.1", "stream-browserify": "3.0.0", - "swagger-ui": "^4.2.1", + "swagger-ui": "4.12.0", "tslib": "^2.0.0", "zone.js": "~0.11.4" }, @@ -96,8 +96,8 @@ "@angular-devkit/build-angular": "^13.3.0", "@angular/cli": "^13.3.0", "@angular/compiler-cli": "^13.3.0", - "@cypress/webpack-batteries-included-preprocessor": "^2.0.0", - "@cypress/webpack-preprocessor": "^5.11.1", + "@cypress/webpack-batteries-included-preprocessor": "2.2.3", + "@cypress/webpack-preprocessor": "5.12.0", "@ngtools/webpack": "^13.3.0", "@types/angular": "^1.7.4", "@types/jasmine": "~3.6.0", @@ -107,6 +107,7 @@ "@types/node": "^12.19.3", "@types/rx": "^4.1.2", "@types/showdown": "1.9.3", + "ajv-keywords": "^5.1.0", "assert": "^2.0.0", "codelyzer": "^6.0.0", "compression-webpack-plugin": "^9.2.0", @@ -114,7 +115,6 @@ "csv-string": "^4.1.0", "cypress": "^9.5.2", "cypress-file-upload": "^5.0.8", - "file-loader": "^5.1.0", "html-webpack-plugin": "^5.5.0", "jasmine-core": "^3.6.0", "js-yaml": "^3.14.0", @@ -131,14 +131,17 @@ "prettier": "1.14.2", "raw-loader": "^4.0.2", "resize-observer-polyfill": "^1.5.1", - "sass-loader": "^12.4.0", - "style-loader": "^0.23.1", "to-string-loader": "^1.1.5", "tslint": "~6.1.0", "tslint-config-prettier": "^1.15.0", "typescript": "4.6.2", - "webpack": "^5.72.0", - "webpack-cli": "^4.9.0", + "webpack": "^5.73.0", + "webpack-cli": "^4.9.2", "webpack-merge": "^5.8.0" + }, + "overrides": { + "@angular-architects/module-federation": { + "@angular-architects/module-federation-runtime": "14.0.1" + } } }
diff --git a/ui/src/app/connect/services/data-marketplace.service.ts b/ui/projects/streampipes/platform-services/src/lib/apis/adapter.service.ts similarity index 67% rename from ui/src/app/connect/services/data-marketplace.service.ts rename to ui/projects/streampipes/platform-services/src/lib/apis/adapter.service.ts index a8dc5f9..f337ab4 100644 --- a/ui/src/app/connect/services/data-marketplace.service.ts +++ b/ui/projects/streampipes/platform-services/src/lib/apis/adapter.service.ts
@@ -19,25 +19,16 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { map } from 'rxjs/operators'; -import { ConnectService } from './connect.service'; -import { - AdapterDescription, - AdapterDescriptionUnion, - GenericAdapterSetDescription, - GenericAdapterStreamDescription, - Message, - SpecificAdapterSetDescription, - SpecificAdapterStreamDescription, - PlatformServicesCommons -} from '@streampipes/platform-services'; -import { Observable } from 'rxjs'; -@Injectable() -export class DataMarketplaceService { +import { Observable } from 'rxjs'; +import { PlatformServicesCommons } from './commons.service'; +import { AdapterDescription, AdapterDescriptionUnion, Message } from '../model/gen/streampipes-model'; + +@Injectable({providedIn: 'root'}) +export class AdapterService { constructor( private http: HttpClient, - private connectService: ConnectService, private platformServicesCommons: PlatformServicesCommons) { } @@ -47,13 +38,16 @@ getAdapterDescriptions(): Observable<AdapterDescriptionUnion[]> { return this.requestAdapterDescriptions('/master/description/adapters'); - } getAdapters(): Observable<AdapterDescriptionUnion[]> { return this.requestAdapterDescriptions('/master/adapters'); } + deleteAdapterDescription(adapterId: string): Observable<any> { + return this.http.delete(`${this.connectPath}/master/description/${adapterId}`); + } + requestAdapterDescriptions(path: string): Observable<AdapterDescriptionUnion[]> { return this.http .get( @@ -100,26 +94,6 @@ ); } - cloneAdapterDescription(toClone: AdapterDescriptionUnion): AdapterDescriptionUnion { - let result: AdapterDescriptionUnion; - - if (this.connectService.isGenericDescription(toClone)) { - if (toClone instanceof GenericAdapterStreamDescription) { - result = GenericAdapterStreamDescription.fromData(toClone, new GenericAdapterStreamDescription()); - } else if (toClone instanceof GenericAdapterSetDescription) { - result = GenericAdapterSetDescription.fromData(toClone, new GenericAdapterSetDescription()); - } - } else { - if (toClone instanceof SpecificAdapterStreamDescription) { - result = SpecificAdapterStreamDescription.fromData(toClone, new SpecificAdapterStreamDescription()); - } else if (toClone instanceof SpecificAdapterSetDescription) { - result = SpecificAdapterSetDescription.fromData(toClone, new SpecificAdapterSetDescription()); - } - } - - return result; - } - getAssetUrl(appId) { return `${this.connectPath}/master/description/${appId}/assets`; }
diff --git a/ui/projects/streampipes/platform-services/src/lib/apis/asset-management.service.ts b/ui/projects/streampipes/platform-services/src/lib/apis/asset-management.service.ts new file mode 100644 index 0000000..5cf4ce2 --- /dev/null +++ b/ui/projects/streampipes/platform-services/src/lib/apis/asset-management.service.ts
@@ -0,0 +1,57 @@ +/* + * 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 } from '@angular/common/http'; +import { PlatformServicesCommons } from './commons.service'; +import { Observable } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class AssetManagementService { + + constructor(private http: HttpClient, + private platformServicesCommons: PlatformServicesCommons) { + } + + createAsset(asset: any): Observable<any> { + return this.http.post(this.assetBasePath, asset); + } + + getAllAssets(): Observable<any> { + return this.http.get(this.assetBasePath); + } + + getAsset(assetId: string): Observable<any> { + return this.http.get(`${this.assetBasePath}/${assetId}`); + } + + updateAsset(asset: any): Observable<any> { + return this.http.put(`${this.assetBasePath}/${asset._id}`, asset); + } + + deleteAsset(assetId: string, rev: string): Observable<any> { + return this.http.delete(`${this.assetBasePath}/${assetId}/${rev}`); + } + + private get assetBasePath() { + return this.platformServicesCommons.apiBasePath + '/assets'; + } + +}
diff --git a/ui/src/app/dashboard/services/dashboard.service.ts b/ui/projects/streampipes/platform-services/src/lib/apis/dashboard.service.ts similarity index 92% rename from ui/src/app/dashboard/services/dashboard.service.ts rename to ui/projects/streampipes/platform-services/src/lib/apis/dashboard.service.ts index bcb6940..e06d548 100644 --- a/ui/src/app/dashboard/services/dashboard.service.ts +++ b/ui/projects/streampipes/platform-services/src/lib/apis/dashboard.service.ts
@@ -20,16 +20,15 @@ import { Injectable } from '@angular/core'; import { map } from 'rxjs/operators'; import { Observable } from 'rxjs'; -import { MeasurementUnit } from '../../core-model/measurement-unit/MeasurementUnit'; -import { - Dashboard, - DashboardWidgetModel, - Pipeline, - VisualizablePipeline, - PlatformServicesCommons -} from '@streampipes/platform-services'; +import { MeasurementUnit } from '../model/measurement-unit/MeasurementUnit'; +import { PlatformServicesCommons } from './commons.service'; +import { DashboardWidgetModel, Pipeline, VisualizablePipeline } from '../model/gen/streampipes-model'; +import { Dashboard } from '../model/dashboard/dashboard.model'; -@Injectable() + +@Injectable({ + providedIn: 'root' +}) export class DashboardService {
diff --git a/ui/projects/streampipes/platform-services/src/lib/apis/data-view-data-explorer.service.ts b/ui/projects/streampipes/platform-services/src/lib/apis/data-view-data-explorer.service.ts index ea89b7d..3c721f0 100644 --- a/ui/projects/streampipes/platform-services/src/lib/apis/data-view-data-explorer.service.ts +++ b/ui/projects/streampipes/platform-services/src/lib/apis/data-view-data-explorer.service.ts
@@ -46,6 +46,12 @@ return this.sharedDatalakeRestService.getDashboards(this.dashboardUrl); } + getDataView(dataViewId: string): Observable<Dashboard> { + return this.http.get(this.dashboardUrl + '/' + dataViewId).pipe(map(data => { + return data as Dashboard; + })); + } + updateDashboard(dashboard: Dashboard): Observable<Dashboard> { return this.sharedDatalakeRestService.updateDashboard(this.dashboardUrl, dashboard); }
diff --git a/ui/projects/streampipes/platform-services/src/lib/apis/datalake-rest.service.ts b/ui/projects/streampipes/platform-services/src/lib/apis/datalake-rest.service.ts index 249c9f5..6f78699 100644 --- a/ui/projects/streampipes/platform-services/src/lib/apis/datalake-rest.service.ts +++ b/ui/projects/streampipes/platform-services/src/lib/apis/datalake-rest.service.ts
@@ -17,8 +17,8 @@ */ import { Injectable } from '@angular/core'; -import { HttpClient, HttpRequest } from '@angular/common/http'; -import { Observable } from 'rxjs'; +import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http'; +import { Observable, of } from 'rxjs'; import { DataLakeMeasure, PageResult, SpQueryResult } from '../model/gen/streampipes-model'; import { map } from 'rxjs/operators'; import { DatalakeQueryParameters } from '../model/datalake/DatalakeQueryParameters'; @@ -38,6 +38,10 @@ return this.baseUrl + '/api/v4' + '/datalake'; } + public get dataLakeMeasureUrl() { + return this.baseUrl + '/api/v4/datalake/measure'; + } + getAllMeasurementSeries(): Observable<DataLakeMeasure[]> { const url = this.dataLakeUrl + '/measurements/'; return this.http.get(url).pipe(map(response => { @@ -45,13 +49,30 @@ })); } + getMeasurement(id: string): Observable<DataLakeMeasure> { + return this.http.get(`${this.dataLakeMeasureUrl}/${id}`).pipe(map(res => res as DataLakeMeasure)); + } + + performMultiQuery(queryParams: DatalakeQueryParameters[]): Observable<SpQueryResult[]> { + return this.http.post(`${this.dataLakeUrl}/query`, queryParams, {headers: {ignoreLoadingBar: ''}}) + .pipe(map(response => response as SpQueryResult[])); + } + getData(index: string, queryParams: DatalakeQueryParameters, ignoreLoadingBar?: boolean): Observable<SpQueryResult> { - const url = this.dataLakeUrl + '/measurements/' + index; - const headers = ignoreLoadingBar ? { ignoreLoadingBar: '' } : {}; - // @ts-ignore - return this.http.get<SpQueryResult>(url, { params: queryParams }, headers); + + const columns = queryParams.columns; + if (columns === '') { + const emptyQueryResult = new SpQueryResult(); + emptyQueryResult.total = 0; + return of(emptyQueryResult); + } else { + const url = this.dataLakeUrl + '/measurements/' + index; + const headers = ignoreLoadingBar ? {ignoreLoadingBar: ''} : {}; + // @ts-ignore + return this.http.get<SpQueryResult>(url, {params: queryParams, headers}); + } } @@ -62,77 +83,61 @@ itemsPerPage, undefined, undefined, order, undefined, undefined); // @ts-ignore - return this.http.get<PageResult>(url, { params: queryParams }); + return this.http.get<PageResult>(url, {params: queryParams}); } getTagValues(index: string, fieldNames: string[]): Observable<Map<string, string[]>> { - return this.http.get(this.dataLakeUrl + '/measurements/' + index + '/tags?fields=' + fieldNames.toString()) - .pipe(map(r => r as Map<string, string[]>)); + + if (fieldNames.length === 0) { + return of(new Map<string, string[]>()); + } else { + return this.http.get(this.dataLakeUrl + '/measurements/' + index + '/tags?fields=' + fieldNames.toString()) + .pipe(map(r => r as Map<string, string[]>)); + + } } - // getGroupedData(index: string, groupingTags: string, aggregationFunction?: string, columns?: string, startDate?: number, endDate?: - // number, aggregationTimeUnit?: string, aggregationTimeValue?: number, order?: string, limit?: number): - // Observable<SpQueryResult> { - // - // const url = this.dataLakeUrl + '/measurements/' + index; - // let _aggregationFunction = 'mean'; - // let timeInterval = '2000ms'; - // - // if (aggregationFunction) { - // _aggregationFunction = aggregationFunction; - // } - // - // if (aggregationTimeUnit && aggregationTimeValue) { - // timeInterval = aggregationTimeValue + aggregationTimeUnit; - // } - // - // const queryParams: DatalakeQueryParameters = this.getQueryParameters(columns, startDate, endDate, undefined, limit, - // undefined, groupingTags, order, _aggregationFunction, timeInterval); - // - // // @ts-ignore - // return this.http.get<GroupedDataResult>(url, { params: queryParams }); - // } - - downloadRawData(index, format) { - const url = this.dataLakeUrl + '/measurements/' + index + '/download?format=' + format; - - const request = new HttpRequest('GET', url, { - reportProgress: true, - responseType: 'text' - }); - - return this.http.request(request); + downloadRawData(index: string, + format: string, + delimiter: string, + startTime?: number, + endTime?: number) { + const queryParams = (startTime && endTime) ? {format, delimiter, startDate: startTime, endDate: endTime} : { + format, + delimiter + }; + return this.buildDownloadRequest(index, queryParams); } downloadQueriedData( - index, - format, - startDate?, - endDate?, - columns?, - aggregationFunction?, - aggregationTimeUnit?, - aggregationTimeValue?, - groupingsTags?, - order?, - limit?, - offset?) { - const url = this.dataLakeUrl + '/measurements/' + index + '/download?format=' + format; - const timeInterval = aggregationTimeValue + aggregationTimeUnit; + index: string, + format: string, + delimiter: string, + queryParams: DatalakeQueryParameters) { - const queryParams: DatalakeQueryParameters = this.getQueryParameters(columns, startDate, endDate, undefined, - limit, offset, groupingsTags, order, aggregationFunction, timeInterval); + (queryParams as any).format = format; + (queryParams as any).delimiter = delimiter; + return this.buildDownloadRequest(index, queryParams); + } + + buildDownloadRequest(index: string, + queryParams: any) { + const url = this.dataLakeUrl + '/measurements/' + index + '/download'; const request = new HttpRequest('GET', url, { reportProgress: true, responseType: 'text', - params: queryParams + params: this.toHttpParams(queryParams) }); return this.http.request(request); } + toHttpParams(queryParamObject: any): HttpParams { + return new HttpParams({fromObject: queryParamObject}); + } + removeData(index: string) { const url = this.dataLakeUrl + '/measurements/' + index;
diff --git a/ui/projects/streampipes/platform-services/src/lib/apis/generic-storage.service.ts b/ui/projects/streampipes/platform-services/src/lib/apis/generic-storage.service.ts new file mode 100644 index 0000000..4cdc45d --- /dev/null +++ b/ui/projects/streampipes/platform-services/src/lib/apis/generic-storage.service.ts
@@ -0,0 +1,66 @@ +/* + * 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 } from '@angular/common/http'; +import { PlatformServicesCommons } from './commons.service'; +import { Observable } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class GenericStorageService { + + constructor(private http: HttpClient, + private platformServicesCommons: PlatformServicesCommons) { + } + + createDocument(appDocName: string, + document: any): Observable<any> { + return this.http.post(this.getAppDocPath(appDocName), document); + } + + getAllDocuments(appDocName: string): Observable<any> { + return this.http.get(this.getAppDocPath(appDocName)); + } + + getDocument(appDocName: string, + documentId: string): Observable<any> { + return this.http.get(`${this.getAppDocPath(appDocName)}/${documentId}`); + } + + updateDocument(appDocName: string, + document: any): Observable<any> { + return this.http.put(`${this.getAppDocPath(appDocName)}/${document._id}`, document); + } + + deleteDocument(appDocName: string, + documentId: string, + rev: string): Observable<any> { + return this.http.delete(`${this.getAppDocPath(appDocName)}/${documentId}/${rev}`); + } + + private getAppDocPath(appDocName: string): string { + return this.genericStorageBasePath + '/' + appDocName; + } + + private get genericStorageBasePath() { + return this.platformServicesCommons.apiBasePath + '/storage-generic'; + } + +}
diff --git a/ui/projects/streampipes/platform-services/src/lib/apis/pipeline-element-template.service.ts b/ui/projects/streampipes/platform-services/src/lib/apis/pipeline-element-template.service.ts index 4bfef5c..6cca1d5 100644 --- a/ui/projects/streampipes/platform-services/src/lib/apis/pipeline-element-template.service.ts +++ b/ui/projects/streampipes/platform-services/src/lib/apis/pipeline-element-template.service.ts
@@ -20,6 +20,8 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { + AdapterDescription, + AdapterDescriptionUnion, DataProcessorInvocation, DataSinkInvocation, PipelineElementTemplate @@ -46,6 +48,10 @@ })); } + deletePipelineElementTemplate(templateId: string): Observable<any> { + return this.http.delete(`${this.platformServicesCommons.apiBasePath}/pipeline-element-templates/${templateId}`); + } + getConfiguredDataProcessorForTemplate(templateId: string, invocation: DataProcessorInvocation): Observable<DataProcessorInvocation> { return this.http.post(this.platformServicesCommons.apiBasePath + '/pipeline-element-templates/' + templateId + '/processor', invocation) @@ -62,6 +68,12 @@ })); } + getConfiguredAdapterForTemplate(templateId: string, + adapter: AdapterDescriptionUnion): Observable<any> { + return this.http.post(this.platformServicesCommons.apiBasePath + + '/pipeline-element-templates/' + templateId + '/adapter', adapter); + } + storePipelineElementTemplate(template: PipelineElementTemplate) { return this.http.post(this.platformServicesCommons.apiBasePath + '/pipeline-element-templates', template); }
diff --git a/ui/projects/streampipes/platform-services/src/lib/model/assets/asset.model.ts b/ui/projects/streampipes/platform-services/src/lib/model/assets/asset.model.ts new file mode 100644 index 0000000..626e627 --- /dev/null +++ b/ui/projects/streampipes/platform-services/src/lib/model/assets/asset.model.ts
@@ -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. + * + */ + +export interface AssetLinkType { + linkType: string; + linkLabel: string; + linkColor: string; + linkIcon?: string; + linkQueryHint?: string; + navPaths: string[]; + navigationActive: boolean; +} + +export interface AssetType { + assetIcon: string; + assetIconColor: string; + assetTypeCategory: string; + assetTypeLabel: string; +} + +export interface AssetLink { + resourceId: string; + linkType: 'data-view' | 'dashboard' | 'adapter' | 'source' | string; + linkLabel: string; + queryHint: string; + editingDisabled: boolean; + navigationActive: boolean; +} + +export interface SpAsset { + assetId: string; + assetName: string; + assetDescription: string; + + assetType: AssetType; + assetLinks: AssetLink[]; + + assets: SpAsset[]; +} + +export interface SpAssetModel extends SpAsset { + _id: string; + _rev: string; + + appDocType: string; + + removable: boolean; +} +
diff --git a/ui/projects/streampipes/platform-services/src/lib/model/datalake/DatalakeQueryParameters.ts b/ui/projects/streampipes/platform-services/src/lib/model/datalake/DatalakeQueryParameters.ts index 3cfd937..d694935 100644 --- a/ui/projects/streampipes/platform-services/src/lib/model/datalake/DatalakeQueryParameters.ts +++ b/ui/projects/streampipes/platform-services/src/lib/model/datalake/DatalakeQueryParameters.ts
@@ -32,5 +32,8 @@ public filter: string; public maximumAmountOfEvents: number; + // should be only used for multi-query requests + public measureName: string; + public forId: string; }
diff --git a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts index 393aa4c..b6e2425 100644 --- a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts +++ b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
@@ -15,13 +15,14 @@ * limitations under the License. */ + /* tslint:disable */ /* eslint-disable */ // @ts-nocheck -// Generated using typescript-generator version 2.27.744 on 2022-04-25 13:56:39. +// Generated using typescript-generator version 2.27.744 on 2022-08-23 09:28:28. export class AbstractStreamPipesEntity { - "@class": "org.apache.streampipes.model.base.AbstractStreamPipesEntity" | "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.GenericAdapterStreamDescription" | "org.apache.streampipes.model.connect.adapter.SpecificAdapterStreamDescription" | "org.apache.streampipes.model.connect.grounding.ProtocolDescription" | "org.apache.streampipes.model.graph.DataSourceDescription" | "org.apache.streampipes.model.template.PipelineTemplateDescription" | "org.apache.streampipes.model.connect.grounding.FormatDescription" | "org.apache.streampipes.model.SpDataStream" | "org.apache.streampipes.model.SpDataSet" | "org.apache.streampipes.model.base.InvocableStreamPipesEntity" | "org.apache.streampipes.model.graph.DataProcessorInvocation" | "org.apache.streampipes.model.graph.DataSinkInvocation" | "org.apache.streampipes.model.base.UnnamedStreamPipesEntity" | "org.apache.streampipes.model.connect.guess.GuessSchema" | "org.apache.streampipes.model.connect.rules.TransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.ValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescription" | "org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription" | "org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.stream.StreamTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.stream.EventRateTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.stream.RemoveDuplicatesTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.SchemaTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.CreateNestedRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.DeleteRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.RenameRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.MoveRuleDescription" | "org.apache.streampipes.model.dashboard.DashboardWidgetSettings" | "org.apache.streampipes.model.datalake.DataLakeMeasure" | "org.apache.streampipes.model.runtime.RuntimeOptionsRequest" | "org.apache.streampipes.model.runtime.RuntimeOptionsResponse" | "org.apache.streampipes.model.staticproperty.StaticProperty" | "org.apache.streampipes.model.staticproperty.CodeInputStaticProperty" | "org.apache.streampipes.model.staticproperty.CollectionStaticProperty" | "org.apache.streampipes.model.staticproperty.ColorPickerStaticProperty" | "org.apache.streampipes.model.staticproperty.DomainStaticProperty" | "org.apache.streampipes.model.staticproperty.FileStaticProperty" | "org.apache.streampipes.model.staticproperty.FreeTextStaticProperty" | "org.apache.streampipes.model.staticproperty.MatchingStaticProperty" | "org.apache.streampipes.model.staticproperty.RuntimeResolvableTreeInputStaticProperty" | "org.apache.streampipes.model.staticproperty.SecretStaticProperty" | "org.apache.streampipes.model.staticproperty.StaticPropertyAlternative" | "org.apache.streampipes.model.staticproperty.StaticPropertyAlternatives" | "org.apache.streampipes.model.staticproperty.StaticPropertyGroup" | "org.apache.streampipes.model.staticproperty.SlideToggleStaticProperty" | "org.apache.streampipes.model.staticproperty.SelectionStaticProperty" | "org.apache.streampipes.model.staticproperty.AnyStaticProperty" | "org.apache.streampipes.model.staticproperty.RuntimeResolvableAnyStaticProperty" | "org.apache.streampipes.model.staticproperty.OneOfStaticProperty" | "org.apache.streampipes.model.staticproperty.RuntimeResolvableOneOfStaticProperty" | "org.apache.streampipes.model.staticproperty.MappingProperty" | "org.apache.streampipes.model.staticproperty.MappingPropertyUnary" | "org.apache.streampipes.model.staticproperty.MappingPropertyNary" | "org.apache.streampipes.model.template.PipelineTemplateInvocation" | "org.apache.streampipes.model.ApplicationLink" | "org.apache.streampipes.model.grounding.EventGrounding" | "org.apache.streampipes.model.schema.EventSchema" | "org.apache.streampipes.model.template.BoundPipelineElement" | "org.apache.streampipes.model.grounding.TransportProtocol" | "org.apache.streampipes.model.grounding.JmsTransportProtocol" | "org.apache.streampipes.model.grounding.KafkaTransportProtocol" | "org.apache.streampipes.model.grounding.MqttTransportProtocol" | "org.apache.streampipes.model.grounding.TransportFormat" | "org.apache.streampipes.model.quality.EventStreamQualityRequirement" | "org.apache.streampipes.model.quality.MeasurementCapability" | "org.apache.streampipes.model.quality.MeasurementObject" | "org.apache.streampipes.model.schema.EventProperty" | "org.apache.streampipes.model.schema.EventPropertyList" | "org.apache.streampipes.model.schema.EventPropertyNested" | "org.apache.streampipes.model.schema.EventPropertyPrimitive" | "org.apache.streampipes.model.output.OutputStrategy" | "org.apache.streampipes.model.output.AppendOutputStrategy" | "org.apache.streampipes.model.output.CustomOutputStrategy" | "org.apache.streampipes.model.output.CustomTransformOutputStrategy" | "org.apache.streampipes.model.output.FixedOutputStrategy" | "org.apache.streampipes.model.output.KeepOutputStrategy" | "org.apache.streampipes.model.output.ListOutputStrategy" | "org.apache.streampipes.model.output.TransformOutputStrategy" | "org.apache.streampipes.model.output.UserDefinedOutputStrategy" | "org.apache.streampipes.model.monitoring.ElementStatusInfoSettings" | "org.apache.streampipes.model.staticproperty.Option" | "org.apache.streampipes.model.staticproperty.SupportedProperty" | "org.apache.streampipes.model.staticproperty.PropertyValueSpecification" | "org.apache.streampipes.model.grounding.TopicDefinition" | "org.apache.streampipes.model.grounding.SimpleTopicDefinition" | "org.apache.streampipes.model.grounding.WildcardTopicDefinition" | "org.apache.streampipes.model.quality.MeasurementProperty" | "org.apache.streampipes.model.quality.EventStreamQualityDefinition" | "org.apache.streampipes.model.quality.Frequency" | "org.apache.streampipes.model.quality.Latency" | "org.apache.streampipes.model.quality.EventPropertyQualityDefinition" | "org.apache.streampipes.model.quality.Accuracy" | "org.apache.streampipes.model.quality.MeasurementRange" | "org.apache.streampipes.model.quality.Precision" | "org.apache.streampipes.model.quality.Resolution" | "org.apache.streampipes.model.quality.EventPropertyQualityRequirement" | "org.apache.streampipes.model.output.PropertyRenameRule" | "org.apache.streampipes.model.schema.ValueSpecification" | "org.apache.streampipes.model.schema.QuantitativeValue" | "org.apache.streampipes.model.schema.Enumeration" | "org.apache.streampipes.model.output.TransformOperation" | "org.apache.streampipes.model.grounding.WildcardTopicMapping"; + "@class": "org.apache.streampipes.model.base.AbstractStreamPipesEntity" | "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.GenericAdapterStreamDescription" | "org.apache.streampipes.model.connect.adapter.SpecificAdapterStreamDescription" | "org.apache.streampipes.model.connect.grounding.ProtocolDescription" | "org.apache.streampipes.model.graph.DataSourceDescription" | "org.apache.streampipes.model.template.PipelineTemplateDescription" | "org.apache.streampipes.model.connect.grounding.FormatDescription" | "org.apache.streampipes.model.SpDataStream" | "org.apache.streampipes.model.SpDataSet" | "org.apache.streampipes.model.base.InvocableStreamPipesEntity" | "org.apache.streampipes.model.graph.DataProcessorInvocation" | "org.apache.streampipes.model.graph.DataSinkInvocation" | "org.apache.streampipes.model.base.UnnamedStreamPipesEntity" | "org.apache.streampipes.model.connect.guess.GuessSchema" | "org.apache.streampipes.model.connect.rules.TransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.ValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescription" | "org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription" | "org.apache.streampipes.model.connect.rules.value.ChangeDatatypeTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.stream.StreamTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.stream.EventRateTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.stream.RemoveDuplicatesTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.SchemaTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.CreateNestedRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.DeleteRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.RenameRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.MoveRuleDescription" | "org.apache.streampipes.model.dashboard.DashboardWidgetSettings" | "org.apache.streampipes.model.datalake.DataLakeMeasure" | "org.apache.streampipes.model.runtime.RuntimeOptionsRequest" | "org.apache.streampipes.model.runtime.RuntimeOptionsResponse" | "org.apache.streampipes.model.staticproperty.StaticProperty" | "org.apache.streampipes.model.staticproperty.CodeInputStaticProperty" | "org.apache.streampipes.model.staticproperty.CollectionStaticProperty" | "org.apache.streampipes.model.staticproperty.ColorPickerStaticProperty" | "org.apache.streampipes.model.staticproperty.DomainStaticProperty" | "org.apache.streampipes.model.staticproperty.FileStaticProperty" | "org.apache.streampipes.model.staticproperty.FreeTextStaticProperty" | "org.apache.streampipes.model.staticproperty.MatchingStaticProperty" | "org.apache.streampipes.model.staticproperty.RuntimeResolvableTreeInputStaticProperty" | "org.apache.streampipes.model.staticproperty.SecretStaticProperty" | "org.apache.streampipes.model.staticproperty.StaticPropertyAlternative" | "org.apache.streampipes.model.staticproperty.StaticPropertyAlternatives" | "org.apache.streampipes.model.staticproperty.StaticPropertyGroup" | "org.apache.streampipes.model.staticproperty.SlideToggleStaticProperty" | "org.apache.streampipes.model.staticproperty.SelectionStaticProperty" | "org.apache.streampipes.model.staticproperty.AnyStaticProperty" | "org.apache.streampipes.model.staticproperty.RuntimeResolvableAnyStaticProperty" | "org.apache.streampipes.model.staticproperty.OneOfStaticProperty" | "org.apache.streampipes.model.staticproperty.RuntimeResolvableOneOfStaticProperty" | "org.apache.streampipes.model.staticproperty.MappingProperty" | "org.apache.streampipes.model.staticproperty.MappingPropertyUnary" | "org.apache.streampipes.model.staticproperty.MappingPropertyNary" | "org.apache.streampipes.model.template.PipelineTemplateInvocation" | "org.apache.streampipes.model.ApplicationLink" | "org.apache.streampipes.model.grounding.EventGrounding" | "org.apache.streampipes.model.schema.EventSchema" | "org.apache.streampipes.model.template.BoundPipelineElement" | "org.apache.streampipes.model.grounding.TransportProtocol" | "org.apache.streampipes.model.grounding.JmsTransportProtocol" | "org.apache.streampipes.model.grounding.KafkaTransportProtocol" | "org.apache.streampipes.model.grounding.MqttTransportProtocol" | "org.apache.streampipes.model.grounding.TransportFormat" | "org.apache.streampipes.model.quality.EventStreamQualityRequirement" | "org.apache.streampipes.model.quality.MeasurementCapability" | "org.apache.streampipes.model.quality.MeasurementObject" | "org.apache.streampipes.model.schema.EventProperty" | "org.apache.streampipes.model.schema.EventPropertyList" | "org.apache.streampipes.model.schema.EventPropertyNested" | "org.apache.streampipes.model.schema.EventPropertyPrimitive" | "org.apache.streampipes.model.output.OutputStrategy" | "org.apache.streampipes.model.output.AppendOutputStrategy" | "org.apache.streampipes.model.output.CustomOutputStrategy" | "org.apache.streampipes.model.output.CustomTransformOutputStrategy" | "org.apache.streampipes.model.output.FixedOutputStrategy" | "org.apache.streampipes.model.output.KeepOutputStrategy" | "org.apache.streampipes.model.output.ListOutputStrategy" | "org.apache.streampipes.model.output.TransformOutputStrategy" | "org.apache.streampipes.model.output.UserDefinedOutputStrategy" | "org.apache.streampipes.model.monitoring.ElementStatusInfoSettings" | "org.apache.streampipes.model.staticproperty.Option" | "org.apache.streampipes.model.staticproperty.SupportedProperty" | "org.apache.streampipes.model.staticproperty.PropertyValueSpecification" | "org.apache.streampipes.model.grounding.TopicDefinition" | "org.apache.streampipes.model.grounding.SimpleTopicDefinition" | "org.apache.streampipes.model.grounding.WildcardTopicDefinition" | "org.apache.streampipes.model.quality.MeasurementProperty" | "org.apache.streampipes.model.quality.EventStreamQualityDefinition" | "org.apache.streampipes.model.quality.Frequency" | "org.apache.streampipes.model.quality.Latency" | "org.apache.streampipes.model.quality.EventPropertyQualityDefinition" | "org.apache.streampipes.model.quality.Accuracy" | "org.apache.streampipes.model.quality.MeasurementRange" | "org.apache.streampipes.model.quality.Precision" | "org.apache.streampipes.model.quality.Resolution" | "org.apache.streampipes.model.quality.EventPropertyQualityRequirement" | "org.apache.streampipes.model.output.PropertyRenameRule" | "org.apache.streampipes.model.schema.ValueSpecification" | "org.apache.streampipes.model.schema.QuantitativeValue" | "org.apache.streampipes.model.schema.Enumeration" | "org.apache.streampipes.model.output.TransformOperation" | "org.apache.streampipes.model.grounding.WildcardTopicMapping"; elementId: string; static fromData(data: AbstractStreamPipesEntity, target?: AbstractStreamPipesEntity): AbstractStreamPipesEntity { @@ -36,7 +37,7 @@ } export class UnnamedStreamPipesEntity extends AbstractStreamPipesEntity { - "@class": "org.apache.streampipes.model.base.UnnamedStreamPipesEntity" | "org.apache.streampipes.model.connect.guess.GuessSchema" | "org.apache.streampipes.model.connect.rules.TransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.ValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescription" | "org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription" | "org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.stream.StreamTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.stream.EventRateTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.stream.RemoveDuplicatesTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.SchemaTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.CreateNestedRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.DeleteRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.RenameRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.MoveRuleDescription" | "org.apache.streampipes.model.dashboard.DashboardWidgetSettings" | "org.apache.streampipes.model.datalake.DataLakeMeasure" | "org.apache.streampipes.model.runtime.RuntimeOptionsRequest" | "org.apache.streampipes.model.runtime.RuntimeOptionsResponse" | "org.apache.streampipes.model.staticproperty.StaticProperty" | "org.apache.streampipes.model.staticproperty.CodeInputStaticProperty" | "org.apache.streampipes.model.staticproperty.CollectionStaticProperty" | "org.apache.streampipes.model.staticproperty.ColorPickerStaticProperty" | "org.apache.streampipes.model.staticproperty.DomainStaticProperty" | "org.apache.streampipes.model.staticproperty.FileStaticProperty" | "org.apache.streampipes.model.staticproperty.FreeTextStaticProperty" | "org.apache.streampipes.model.staticproperty.MatchingStaticProperty" | "org.apache.streampipes.model.staticproperty.RuntimeResolvableTreeInputStaticProperty" | "org.apache.streampipes.model.staticproperty.SecretStaticProperty" | "org.apache.streampipes.model.staticproperty.StaticPropertyAlternative" | "org.apache.streampipes.model.staticproperty.StaticPropertyAlternatives" | "org.apache.streampipes.model.staticproperty.StaticPropertyGroup" | "org.apache.streampipes.model.staticproperty.SlideToggleStaticProperty" | "org.apache.streampipes.model.staticproperty.SelectionStaticProperty" | "org.apache.streampipes.model.staticproperty.AnyStaticProperty" | "org.apache.streampipes.model.staticproperty.RuntimeResolvableAnyStaticProperty" | "org.apache.streampipes.model.staticproperty.OneOfStaticProperty" | "org.apache.streampipes.model.staticproperty.RuntimeResolvableOneOfStaticProperty" | "org.apache.streampipes.model.staticproperty.MappingProperty" | "org.apache.streampipes.model.staticproperty.MappingPropertyUnary" | "org.apache.streampipes.model.staticproperty.MappingPropertyNary" | "org.apache.streampipes.model.template.PipelineTemplateInvocation" | "org.apache.streampipes.model.ApplicationLink" | "org.apache.streampipes.model.grounding.EventGrounding" | "org.apache.streampipes.model.schema.EventSchema" | "org.apache.streampipes.model.template.BoundPipelineElement" | "org.apache.streampipes.model.grounding.TransportProtocol" | "org.apache.streampipes.model.grounding.JmsTransportProtocol" | "org.apache.streampipes.model.grounding.KafkaTransportProtocol" | "org.apache.streampipes.model.grounding.MqttTransportProtocol" | "org.apache.streampipes.model.grounding.TransportFormat" | "org.apache.streampipes.model.quality.EventStreamQualityRequirement" | "org.apache.streampipes.model.quality.MeasurementCapability" | "org.apache.streampipes.model.quality.MeasurementObject" | "org.apache.streampipes.model.schema.EventProperty" | "org.apache.streampipes.model.schema.EventPropertyList" | "org.apache.streampipes.model.schema.EventPropertyNested" | "org.apache.streampipes.model.schema.EventPropertyPrimitive" | "org.apache.streampipes.model.output.OutputStrategy" | "org.apache.streampipes.model.output.AppendOutputStrategy" | "org.apache.streampipes.model.output.CustomOutputStrategy" | "org.apache.streampipes.model.output.CustomTransformOutputStrategy" | "org.apache.streampipes.model.output.FixedOutputStrategy" | "org.apache.streampipes.model.output.KeepOutputStrategy" | "org.apache.streampipes.model.output.ListOutputStrategy" | "org.apache.streampipes.model.output.TransformOutputStrategy" | "org.apache.streampipes.model.output.UserDefinedOutputStrategy" | "org.apache.streampipes.model.monitoring.ElementStatusInfoSettings" | "org.apache.streampipes.model.staticproperty.Option" | "org.apache.streampipes.model.staticproperty.SupportedProperty" | "org.apache.streampipes.model.staticproperty.PropertyValueSpecification" | "org.apache.streampipes.model.grounding.TopicDefinition" | "org.apache.streampipes.model.grounding.SimpleTopicDefinition" | "org.apache.streampipes.model.grounding.WildcardTopicDefinition" | "org.apache.streampipes.model.quality.MeasurementProperty" | "org.apache.streampipes.model.quality.EventStreamQualityDefinition" | "org.apache.streampipes.model.quality.Frequency" | "org.apache.streampipes.model.quality.Latency" | "org.apache.streampipes.model.quality.EventPropertyQualityDefinition" | "org.apache.streampipes.model.quality.Accuracy" | "org.apache.streampipes.model.quality.MeasurementRange" | "org.apache.streampipes.model.quality.Precision" | "org.apache.streampipes.model.quality.Resolution" | "org.apache.streampipes.model.quality.EventPropertyQualityRequirement" | "org.apache.streampipes.model.output.PropertyRenameRule" | "org.apache.streampipes.model.schema.ValueSpecification" | "org.apache.streampipes.model.schema.QuantitativeValue" | "org.apache.streampipes.model.schema.Enumeration" | "org.apache.streampipes.model.output.TransformOperation" | "org.apache.streampipes.model.grounding.WildcardTopicMapping"; + "@class": "org.apache.streampipes.model.base.UnnamedStreamPipesEntity" | "org.apache.streampipes.model.connect.guess.GuessSchema" | "org.apache.streampipes.model.connect.rules.TransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.ValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescription" | "org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription" | "org.apache.streampipes.model.connect.rules.value.ChangeDatatypeTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.stream.StreamTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.stream.EventRateTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.stream.RemoveDuplicatesTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.SchemaTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.CreateNestedRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.DeleteRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.RenameRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.MoveRuleDescription" | "org.apache.streampipes.model.dashboard.DashboardWidgetSettings" | "org.apache.streampipes.model.datalake.DataLakeMeasure" | "org.apache.streampipes.model.runtime.RuntimeOptionsRequest" | "org.apache.streampipes.model.runtime.RuntimeOptionsResponse" | "org.apache.streampipes.model.staticproperty.StaticProperty" | "org.apache.streampipes.model.staticproperty.CodeInputStaticProperty" | "org.apache.streampipes.model.staticproperty.CollectionStaticProperty" | "org.apache.streampipes.model.staticproperty.ColorPickerStaticProperty" | "org.apache.streampipes.model.staticproperty.DomainStaticProperty" | "org.apache.streampipes.model.staticproperty.FileStaticProperty" | "org.apache.streampipes.model.staticproperty.FreeTextStaticProperty" | "org.apache.streampipes.model.staticproperty.MatchingStaticProperty" | "org.apache.streampipes.model.staticproperty.RuntimeResolvableTreeInputStaticProperty" | "org.apache.streampipes.model.staticproperty.SecretStaticProperty" | "org.apache.streampipes.model.staticproperty.StaticPropertyAlternative" | "org.apache.streampipes.model.staticproperty.StaticPropertyAlternatives" | "org.apache.streampipes.model.staticproperty.StaticPropertyGroup" | "org.apache.streampipes.model.staticproperty.SlideToggleStaticProperty" | "org.apache.streampipes.model.staticproperty.SelectionStaticProperty" | "org.apache.streampipes.model.staticproperty.AnyStaticProperty" | "org.apache.streampipes.model.staticproperty.RuntimeResolvableAnyStaticProperty" | "org.apache.streampipes.model.staticproperty.OneOfStaticProperty" | "org.apache.streampipes.model.staticproperty.RuntimeResolvableOneOfStaticProperty" | "org.apache.streampipes.model.staticproperty.MappingProperty" | "org.apache.streampipes.model.staticproperty.MappingPropertyUnary" | "org.apache.streampipes.model.staticproperty.MappingPropertyNary" | "org.apache.streampipes.model.template.PipelineTemplateInvocation" | "org.apache.streampipes.model.ApplicationLink" | "org.apache.streampipes.model.grounding.EventGrounding" | "org.apache.streampipes.model.schema.EventSchema" | "org.apache.streampipes.model.template.BoundPipelineElement" | "org.apache.streampipes.model.grounding.TransportProtocol" | "org.apache.streampipes.model.grounding.JmsTransportProtocol" | "org.apache.streampipes.model.grounding.KafkaTransportProtocol" | "org.apache.streampipes.model.grounding.MqttTransportProtocol" | "org.apache.streampipes.model.grounding.TransportFormat" | "org.apache.streampipes.model.quality.EventStreamQualityRequirement" | "org.apache.streampipes.model.quality.MeasurementCapability" | "org.apache.streampipes.model.quality.MeasurementObject" | "org.apache.streampipes.model.schema.EventProperty" | "org.apache.streampipes.model.schema.EventPropertyList" | "org.apache.streampipes.model.schema.EventPropertyNested" | "org.apache.streampipes.model.schema.EventPropertyPrimitive" | "org.apache.streampipes.model.output.OutputStrategy" | "org.apache.streampipes.model.output.AppendOutputStrategy" | "org.apache.streampipes.model.output.CustomOutputStrategy" | "org.apache.streampipes.model.output.CustomTransformOutputStrategy" | "org.apache.streampipes.model.output.FixedOutputStrategy" | "org.apache.streampipes.model.output.KeepOutputStrategy" | "org.apache.streampipes.model.output.ListOutputStrategy" | "org.apache.streampipes.model.output.TransformOutputStrategy" | "org.apache.streampipes.model.output.UserDefinedOutputStrategy" | "org.apache.streampipes.model.monitoring.ElementStatusInfoSettings" | "org.apache.streampipes.model.staticproperty.Option" | "org.apache.streampipes.model.staticproperty.SupportedProperty" | "org.apache.streampipes.model.staticproperty.PropertyValueSpecification" | "org.apache.streampipes.model.grounding.TopicDefinition" | "org.apache.streampipes.model.grounding.SimpleTopicDefinition" | "org.apache.streampipes.model.grounding.WildcardTopicDefinition" | "org.apache.streampipes.model.quality.MeasurementProperty" | "org.apache.streampipes.model.quality.EventStreamQualityDefinition" | "org.apache.streampipes.model.quality.Frequency" | "org.apache.streampipes.model.quality.Latency" | "org.apache.streampipes.model.quality.EventPropertyQualityDefinition" | "org.apache.streampipes.model.quality.Accuracy" | "org.apache.streampipes.model.quality.MeasurementRange" | "org.apache.streampipes.model.quality.Precision" | "org.apache.streampipes.model.quality.Resolution" | "org.apache.streampipes.model.quality.EventPropertyQualityRequirement" | "org.apache.streampipes.model.output.PropertyRenameRule" | "org.apache.streampipes.model.schema.ValueSpecification" | "org.apache.streampipes.model.schema.QuantitativeValue" | "org.apache.streampipes.model.schema.Enumeration" | "org.apache.streampipes.model.output.TransformOperation" | "org.apache.streampipes.model.grounding.WildcardTopicMapping"; static fromData(data: UnnamedStreamPipesEntity, target?: UnnamedStreamPipesEntity): UnnamedStreamPipesEntity { if (!data) { @@ -169,11 +170,11 @@ eventGrounding: EventGrounding; icon: string; rules: TransformationRuleDescriptionUnion[]; - schemaRules: any[]; + schemaRules: TransformationRuleDescriptionUnion[]; selectedEndpointUrl: string; - streamRules: any[]; + streamRules: TransformationRuleDescriptionUnion[]; userName: string; - valueRules: any[]; + valueRules: TransformationRuleDescriptionUnion[]; static fromData(data: AdapterDescription, target?: AdapterDescription): AdapterDescription { if (!data) { @@ -192,9 +193,9 @@ instance.selectedEndpointUrl = data.selectedEndpointUrl; instance.correspondingServiceGroup = data.correspondingServiceGroup; instance.correspondingDataStreamElementId = data.correspondingDataStreamElementId; - instance.valueRules = __getCopyArrayFn(__identity<any>())(data.valueRules); - instance.streamRules = __getCopyArrayFn(__identity<any>())(data.streamRules); - instance.schemaRules = __getCopyArrayFn(__identity<any>())(data.schemaRules); + instance.valueRules = __getCopyArrayFn(TransformationRuleDescription.fromDataUnion)(data.valueRules); + instance.streamRules = __getCopyArrayFn(TransformationRuleDescription.fromDataUnion)(data.streamRules); + instance.schemaRules = __getCopyArrayFn(TransformationRuleDescription.fromDataUnion)(data.schemaRules); return instance; } @@ -215,6 +216,21 @@ } } +export class AdapterEventPreview { + inputData: { [index: string]: GuessTypeInfo }; + rules: TransformationRuleDescriptionUnion[]; + + static fromData(data: AdapterEventPreview, target?: AdapterEventPreview): AdapterEventPreview { + if (!data) { + return data; + } + const instance = target || new AdapterEventPreview(); + instance.rules = __getCopyArrayFn(TransformationRuleDescription.fromDataUnion)(data.rules); + instance.inputData = __getCopyObjectFn(GuessTypeInfo.fromData)(data.inputData); + return instance; + } +} + export class AdapterSetDescription extends AdapterDescription { "@class": "org.apache.streampipes.model.connect.adapter.AdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.GenericAdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.SpecificAdapterSetDescription"; dataSet: SpDataSet; @@ -289,7 +305,7 @@ } export class TransformationRuleDescription extends UnnamedStreamPipesEntity { - "@class": "org.apache.streampipes.model.connect.rules.TransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.ValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescription" | "org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription" | "org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.stream.StreamTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.stream.EventRateTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.stream.RemoveDuplicatesTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.SchemaTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.CreateNestedRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.DeleteRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.RenameRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.MoveRuleDescription"; + "@class": "org.apache.streampipes.model.connect.rules.TransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.ValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescription" | "org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription" | "org.apache.streampipes.model.connect.rules.value.ChangeDatatypeTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.stream.StreamTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.stream.EventRateTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.stream.RemoveDuplicatesTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.SchemaTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.CreateNestedRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.DeleteRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.RenameRuleDescription" | "org.apache.streampipes.model.connect.rules.schema.MoveRuleDescription"; static fromData(data: TransformationRuleDescription, target?: TransformationRuleDescription): TransformationRuleDescription { if (!data) { @@ -325,6 +341,8 @@ return RenameRuleDescription.fromData(data); case "org.apache.streampipes.model.connect.rules.schema.MoveRuleDescription": return MoveRuleDescription.fromData(data); + case "org.apache.streampipes.model.connect.rules.value.ChangeDatatypeTransformationRuleDescription": + return ChangeDatatypeTransformationRuleDescription.fromData(data); case "org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription": return CorrectionValueTransformationRuleDescription.fromData(data); } @@ -332,7 +350,7 @@ } export class ValueTransformationRuleDescription extends TransformationRuleDescription { - "@class": "org.apache.streampipes.model.connect.rules.value.ValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescription" | "org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription" | "org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription"; + "@class": "org.apache.streampipes.model.connect.rules.value.ValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescription" | "org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription" | "org.apache.streampipes.model.connect.rules.value.ChangeDatatypeTransformationRuleDescription" | "org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription"; static fromData(data: ValueTransformationRuleDescription, target?: ValueTransformationRuleDescription): ValueTransformationRuleDescription { if (!data) { @@ -588,6 +606,39 @@ } } +export class AssetExportConfiguration { + adapters: ExportItem[]; + assetId: string; + assetName: string; + assets: ExportItem[]; + dashboards: ExportItem[]; + dataLakeMeasures: ExportItem[]; + dataSources: ExportItem[]; + dataViews: ExportItem[]; + files: ExportItem[]; + overrideBrokerSettings: boolean; + pipelines: ExportItem[]; + + static fromData(data: AssetExportConfiguration, target?: AssetExportConfiguration): AssetExportConfiguration { + if (!data) { + return data; + } + const instance = target || new AssetExportConfiguration(); + instance.assetId = data.assetId; + instance.assetName = data.assetName; + instance.assets = __getCopyArrayFn(ExportItem.fromData)(data.assets); + instance.adapters = __getCopyArrayFn(ExportItem.fromData)(data.adapters); + instance.dashboards = __getCopyArrayFn(ExportItem.fromData)(data.dashboards); + instance.dataViews = __getCopyArrayFn(ExportItem.fromData)(data.dataViews); + instance.dataLakeMeasures = __getCopyArrayFn(ExportItem.fromData)(data.dataLakeMeasures); + instance.dataSources = __getCopyArrayFn(ExportItem.fromData)(data.dataSources); + instance.pipelines = __getCopyArrayFn(ExportItem.fromData)(data.pipelines); + instance.files = __getCopyArrayFn(ExportItem.fromData)(data.files); + instance.overrideBrokerSettings = data.overrideBrokerSettings; + return instance; + } +} + export class BoundPipelineElement extends UnnamedStreamPipesEntity { "@class": "org.apache.streampipes.model.template.BoundPipelineElement"; connectedTo: BoundPipelineElement[]; @@ -643,6 +694,25 @@ } } +export class ChangeDatatypeTransformationRuleDescription extends ValueTransformationRuleDescription { + "@class": "org.apache.streampipes.model.connect.rules.value.ChangeDatatypeTransformationRuleDescription"; + originalDatatypeXsd: string; + runtimeKey: string; + targetDatatypeXsd: string; + + static fromData(data: ChangeDatatypeTransformationRuleDescription, target?: ChangeDatatypeTransformationRuleDescription): ChangeDatatypeTransformationRuleDescription { + if (!data) { + return data; + } + const instance = target || new ChangeDatatypeTransformationRuleDescription(); + super.fromData(data, instance); + instance.runtimeKey = data.runtimeKey; + instance.originalDatatypeXsd = data.originalDatatypeXsd; + instance.targetDatatypeXsd = data.targetDatatypeXsd; + return instance; + } +} + export class CodeInputStaticProperty extends StaticProperty { "@class": "org.apache.streampipes.model.staticproperty.CodeInputStaticProperty"; codeTemplate: string; @@ -956,11 +1026,14 @@ export class DataLakeMeasure extends UnnamedStreamPipesEntity { "@class": "org.apache.streampipes.model.datalake.DataLakeMeasure"; + _rev: string; eventSchema: EventSchema; measureName: string; pipelineId: string; pipelineIsRunning: boolean; pipelineName: string; + schemaVersion: string; + timestampField: string; static fromData(data: DataLakeMeasure, target?: DataLakeMeasure): DataLakeMeasure { if (!data) { @@ -969,10 +1042,13 @@ const instance = target || new DataLakeMeasure(); super.fromData(data, instance); instance.measureName = data.measureName; + instance.timestampField = data.timestampField; instance.eventSchema = EventSchema.fromData(data.eventSchema); instance.pipelineId = data.pipelineId; instance.pipelineName = data.pipelineName; instance.pipelineIsRunning = data.pipelineIsRunning; + instance.schemaVersion = data.schemaVersion; + instance._rev = data._rev; return instance; } } @@ -1525,6 +1601,53 @@ } } +export class ExportConfiguration { + assetExportConfiguration: AssetExportConfiguration[]; + + static fromData(data: ExportConfiguration, target?: ExportConfiguration): ExportConfiguration { + if (!data) { + return data; + } + const instance = target || new ExportConfiguration(); + instance.assetExportConfiguration = __getCopyArrayFn(AssetExportConfiguration.fromData)(data.assetExportConfiguration); + return instance; + } +} + +export class ExportItem { + label: string; + resourceId: string; + selected: boolean; + + static fromData(data: ExportItem, target?: ExportItem): ExportItem { + if (!data) { + return data; + } + const instance = target || new ExportItem(); + instance.resourceId = data.resourceId; + instance.label = data.label; + instance.selected = data.selected; + return instance; + } +} + +export class FieldStatusInfo { + additionalInfo: string; + changesRequired: boolean; + fieldStatus: FieldStatus; + + static fromData(data: FieldStatusInfo, target?: FieldStatusInfo): FieldStatusInfo { + if (!data) { + return data; + } + const instance = target || new FieldStatusInfo(); + instance.fieldStatus = data.fieldStatus; + instance.additionalInfo = data.additionalInfo; + instance.changesRequired = data.changesRequired; + return instance; + } +} + export class FileMetadata { createdAt: number; createdByUser: string; @@ -1696,7 +1819,9 @@ export class GuessSchema extends UnnamedStreamPipesEntity { "@class": "org.apache.streampipes.model.connect.guess.GuessSchema"; + eventPreview: { [index: string]: GuessTypeInfo }[]; eventSchema: EventSchema; + fieldStatusInfo: { [index: string]: FieldStatusInfo }; static fromData(data: GuessSchema, target?: GuessSchema): GuessSchema { if (!data) { @@ -1705,6 +1830,23 @@ const instance = target || new GuessSchema(); super.fromData(data, instance); instance.eventSchema = EventSchema.fromData(data.eventSchema); + instance.eventPreview = __getCopyArrayFn(__getCopyObjectFn(GuessTypeInfo.fromData))(data.eventPreview); + instance.fieldStatusInfo = __getCopyObjectFn(FieldStatusInfo.fromData)(data.fieldStatusInfo); + return instance; + } +} + +export class GuessTypeInfo { + type: string; + value: any; + + static fromData(data: GuessTypeInfo, target?: GuessTypeInfo): GuessTypeInfo { + if (!data) { + return data; + } + const instance = target || new GuessTypeInfo(); + instance.type = data.type; + instance.value = data.value; return instance; } } @@ -2500,9 +2642,9 @@ const instance = target || new PipelineTemplateDescription(); super.fromData(data, instance); instance.boundTo = __getCopyArrayFn(BoundPipelineElement.fromData)(data.boundTo); - instance.pipelineTemplateName = data.pipelineTemplateName; - instance.pipelineTemplateDescription = data.pipelineTemplateDescription; instance.pipelineTemplateId = data.pipelineTemplateId; + instance.pipelineTemplateDescription = data.pipelineTemplateDescription; + instance.pipelineTemplateName = data.pipelineTemplateName; return instance; } } @@ -2911,6 +3053,7 @@ export class SpQueryResult { allDataSeries: DataSeries[]; + forId: string; headers: string[]; sourceIndex: number; spQueryStatus: SpQueryStatus; @@ -2926,6 +3069,7 @@ instance.allDataSeries = __getCopyArrayFn(DataSeries.fromData)(data.allDataSeries); instance.sourceIndex = data.sourceIndex; instance.spQueryStatus = data.spQueryStatus; + instance.forId = data.forId; return instance; } } @@ -3007,6 +3151,64 @@ } } +export class StreamPipesApplicationPackage { + adapters: string[]; + assets: string[]; + dashboardWidgets: string[]; + dashboards: string[]; + dataLakeMeasures: string[]; + dataSources: string[]; + dataViewWidgets: string[]; + dataViews: string[]; + files: string[]; + pipelines: string[]; + requiredAdapterAppIds: string[]; + requiredDataSinkAppIds: string[]; + requiredProcessorAppIds: string[]; + + static fromData(data: StreamPipesApplicationPackage, target?: StreamPipesApplicationPackage): StreamPipesApplicationPackage { + if (!data) { + return data; + } + const instance = target || new StreamPipesApplicationPackage(); + instance.requiredProcessorAppIds = __getCopyArrayFn(__identity<string>())(data.requiredProcessorAppIds); + instance.requiredDataSinkAppIds = __getCopyArrayFn(__identity<string>())(data.requiredDataSinkAppIds); + instance.requiredAdapterAppIds = __getCopyArrayFn(__identity<string>())(data.requiredAdapterAppIds); + instance.assets = __getCopyArrayFn(__identity<string>())(data.assets); + instance.adapters = __getCopyArrayFn(__identity<string>())(data.adapters); + instance.dashboards = __getCopyArrayFn(__identity<string>())(data.dashboards); + instance.dashboardWidgets = __getCopyArrayFn(__identity<string>())(data.dashboardWidgets); + instance.dataViews = __getCopyArrayFn(__identity<string>())(data.dataViews); + instance.dataViewWidgets = __getCopyArrayFn(__identity<string>())(data.dataViewWidgets); + instance.dataLakeMeasures = __getCopyArrayFn(__identity<string>())(data.dataLakeMeasures); + instance.dataSources = __getCopyArrayFn(__identity<string>())(data.dataSources); + instance.pipelines = __getCopyArrayFn(__identity<string>())(data.pipelines); + instance.files = __getCopyArrayFn(__identity<string>())(data.files); + return instance; + } +} + +export class StreamPipesErrorMessage { + cause: string; + detail: string; + fullStackTrace: string; + level: string; + title: string; + + static fromData(data: StreamPipesErrorMessage, target?: StreamPipesErrorMessage): StreamPipesErrorMessage { + if (!data) { + return data; + } + const instance = target || new StreamPipesErrorMessage(); + instance.level = data.level; + instance.title = data.title; + instance.detail = data.detail; + instance.cause = data.cause; + instance.fullStackTrace = data.fullStackTrace; + return instance; + } +} + export class SuccessMessage extends Message { static fromData(data: SuccessMessage, target?: SuccessMessage): SuccessMessage { @@ -3259,6 +3461,8 @@ export type EventStreamQualityDefinitionUnion = Frequency | Latency; +export type FieldStatus = "GOOD" | "BAD" | "ATTENTION"; + export type MappingPropertyUnion = MappingPropertyNary | MappingPropertyUnary; export type MeasurementPropertyUnion = EventPropertyQualityDefinition | EventStreamQualityDefinition; @@ -3283,7 +3487,7 @@ export type TopicDefinitionUnion = SimpleTopicDefinition | WildcardTopicDefinition; -export type TransformationRuleDescriptionUnion = AddTimestampRuleDescription | AddValueTransformationRuleDescription | TimestampTranfsformationRuleDescription | UnitTransformRuleDescription | EventRateTransformationRuleDescription | RemoveDuplicatesTransformationRuleDescription | CreateNestedRuleDescription | DeleteRuleDescription | RenameRuleDescription | MoveRuleDescription | CorrectionValueTransformationRuleDescription; +export type TransformationRuleDescriptionUnion = AddTimestampRuleDescription | AddValueTransformationRuleDescription | TimestampTranfsformationRuleDescription | UnitTransformRuleDescription | EventRateTransformationRuleDescription | RemoveDuplicatesTransformationRuleDescription | CreateNestedRuleDescription | DeleteRuleDescription | RenameRuleDescription | MoveRuleDescription | ChangeDatatypeTransformationRuleDescription | CorrectionValueTransformationRuleDescription; export type TransportProtocolUnion = JmsTransportProtocol | KafkaTransportProtocol | MqttTransportProtocol;
diff --git a/ui/src/app/core-model/measurement-unit/MeasurementUnit.ts b/ui/projects/streampipes/platform-services/src/lib/model/measurement-unit/MeasurementUnit.ts similarity index 100% rename from ui/src/app/core-model/measurement-unit/MeasurementUnit.ts rename to ui/projects/streampipes/platform-services/src/lib/model/measurement-unit/MeasurementUnit.ts
diff --git a/ui/projects/streampipes/platform-services/src/lib/query/data-view-query-generator.service.ts b/ui/projects/streampipes/platform-services/src/lib/query/data-view-query-generator.service.ts index a4d1c73..97b64fc 100644 --- a/ui/projects/streampipes/platform-services/src/lib/query/data-view-query-generator.service.ts +++ b/ui/projects/streampipes/platform-services/src/lib/query/data-view-query-generator.service.ts
@@ -54,8 +54,7 @@ generateQuery(startTime: number, endTime: number, sourceConfig: SourceConfig, - maximumResultingEvents: number = -1 - ): DatalakeQueryParameters { + maximumResultingEvents: number = -1): DatalakeQueryParameters { const queryBuilder = DatalakeQueryParameterBuilder.create(startTime, endTime); const queryConfig = sourceConfig.queryConfig; @@ -65,9 +64,9 @@ ); if (sourceConfig.queryConfig.groupBy !== undefined) { - const selectedGroupByFields = sourceConfig.queryConfig.groupBy.filter(field => field.selected); + const selectedGroupByFields = sourceConfig.queryConfig.groupBy.filter(field => field.selected === true); if (selectedGroupByFields.length > 0) { - queryBuilder.withGrouping(sourceConfig.queryConfig.groupBy); + queryBuilder.withGrouping(selectedGroupByFields); } } @@ -75,6 +74,10 @@ queryBuilder.withFilters(queryConfig.selectedFilters); } + if (queryConfig.order) { + queryBuilder.withOrdering(queryConfig.order); + } + if (sourceConfig.queryType === 'single') { queryBuilder.withLimit(1); } else if (sourceConfig.queryType === 'raw') {
diff --git a/ui/projects/streampipes/platform-services/src/public-api.ts b/ui/projects/streampipes/platform-services/src/public-api.ts index 7e959d8..e686a6e 100644 --- a/ui/projects/streampipes/platform-services/src/public-api.ts +++ b/ui/projects/streampipes/platform-services/src/public-api.ts
@@ -24,10 +24,14 @@ export * from './lib/platform-services.module'; export * from './lib/apis/commons.service'; +export * from './lib/apis/adapter.service'; +export * from './lib/apis/asset-management.service'; export * from './lib/apis/data-view-data-explorer.service'; export * from './lib/apis/datalake-rest.service'; +export * from './lib/apis/dashboard.service'; export * from './lib/apis/files.service'; export * from './lib/apis/general-config.service'; +export * from './lib/apis/generic-storage.service'; export * from './lib/apis/mail-config.service'; export * from './lib/apis/measurement-units.service'; export * from './lib/apis/permissions.service'; @@ -48,6 +52,7 @@ export * from './lib/model/dashboard/dashboard.model'; export * from './lib/model/email-config.model'; export * from './lib/model/general-config.model'; +export * from './lib/model/measurement-unit/MeasurementUnit'; export * from './lib/model/gen/streampipes-model-client'; export * from './lib/model/gen/streampipes-model'; @@ -55,3 +60,5 @@ export * from './lib/query/DatalakeQueryParameterBuilder'; export * from './lib/query/data-view-query-generator.service'; export * from './lib/model/user/user.model'; + +export * from './lib/model/assets/asset.model';
diff --git a/ui/projects/streampipes/shared-ui/package.json b/ui/projects/streampipes/shared-ui/package.json index 95c7477..8a55c7f 100644 --- a/ui/projects/streampipes/shared-ui/package.json +++ b/ui/projects/streampipes/shared-ui/package.json
@@ -3,10 +3,13 @@ "version": "0.0.1", "peerDependencies": { "@angular/animations": "^13.3.0", + "@angular/cdk": "^13.3.0", "@angular/common": "^13.3.0", "@angular/core": "^13.3.0", + "@angular/flex-layout": "^13.0.0-beta.38", "@angular/material": "^13.3.0", - "@angular/cdk": "^13.3.0", + "@angular/router": "^13.3.0", + "@streampipes/platform-services": "0.0.1", "rxjs": "^6.6.2" }, "dependencies": {
diff --git a/ui/src/app/connect/components/schema-editor/event-schema-preview/event-schema-preview.component.html b/ui/projects/streampipes/shared-ui/src/lib/components/basic-header-title/header-title.component.html similarity index 89% rename from ui/src/app/connect/components/schema-editor/event-schema-preview/event-schema-preview.component.html rename to ui/projects/streampipes/shared-ui/src/lib/components/basic-header-title/header-title.component.html index 79bf5a4..972c2a0 100644 --- a/ui/src/app/connect/components/schema-editor/event-schema-preview/event-schema-preview.component.html +++ b/ui/projects/streampipes/shared-ui/src/lib/components/basic-header-title/header-title.component.html
@@ -16,4 +16,4 @@ ~ --> -<pre>{{ eventSchema | json }}</pre> \ No newline at end of file +<div class="header-title title-left-border" [ngStyle]="{margin: margin}">{{title}}</div>
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.scss b/ui/projects/streampipes/shared-ui/src/lib/components/basic-header-title/header-title.component.scss similarity index 84% copy from ui/src/app/pipeline-details/pipeline-details.component.scss copy to ui/projects/streampipes/shared-ui/src/lib/components/basic-header-title/header-title.component.scss index a375af7..f4e4f2d 100644 --- a/ui/src/app/pipeline-details/pipeline-details.component.scss +++ b/ui/projects/streampipes/shared-ui/src/lib/components/basic-header-title/header-title.component.scss
@@ -16,7 +16,13 @@ * */ -.md-padding { - padding: 10px; +.title-left-border { + border-left: 4px solid var(--color-accent); + padding-left: 8px; +} + +.header-title { + font-size: 20pt; + font-weight: bold; }
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.ts b/ui/projects/streampipes/shared-ui/src/lib/components/basic-header-title/header-title.component.ts similarity index 72% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.ts copy to ui/projects/streampipes/shared-ui/src/lib/components/basic-header-title/header-title.component.ts index 4e64c25..6b27876 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.ts +++ b/ui/projects/streampipes/shared-ui/src/lib/components/basic-header-title/header-title.component.ts
@@ -17,20 +17,19 @@ */ import { Component, Input, OnInit } from '@angular/core'; -import { Notification } from '@streampipes/platform-services'; @Component({ - selector: 'sp-error-message', - templateUrl: './error-message.component.html', - styleUrls: ['./error-message.component.scss'] + selector: 'sp-basic-header-title-component', + templateUrl: './header-title.component.html', + styleUrls: ['./header-title.component.scss'] }) -export class ErrorMessageComponent implements OnInit { +export class SpBasicHeaderTitleComponent implements OnInit { - @Input() errorMessages: Notification[]; + @Input() + title: string; - showErrorMessage = false; - - constructor() { } + @Input() + margin = '20px 0px'; ngOnInit(): void { }
diff --git a/ui/projects/streampipes/shared-ui/src/lib/components/basic-inner-panel/basic-inner-panel.component.html b/ui/projects/streampipes/shared-ui/src/lib/components/basic-inner-panel/basic-inner-panel.component.html new file mode 100644 index 0000000..9d58bff --- /dev/null +++ b/ui/projects/streampipes/shared-ui/src/lib/components/basic-inner-panel/basic-inner-panel.component.html
@@ -0,0 +1,32 @@ +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~ + --> + +<div fxLayout="column" fxFlex="100" class="panel-outer" [ngStyle]="{margin: outerMargin}"> + <div class="general-panel-header" fxLayout="row" fxFlex="100" fxLayoutAlign="start center" *ngIf="!hideToolbar"> + <div fxLayout="fill" fxFlex="100"> + <div fxLayoutAlign="start center" fxLayout="row"> + <div class="content-box-title" *ngIf="showTitle">{{panelTitle}}</div> + </div> + <ng-content select="[header]" fxFlex class="pr-5"></ng-content> + </div> + </div> + + <div class="general-panel" [ngStyle]="{padding: innerPadding}"> + <ng-content fxFlex="100"></ng-content> + </div> +</div>
diff --git a/ui/src/app/connect/components/format-item-json/format-item-json.component.scss b/ui/projects/streampipes/shared-ui/src/lib/components/basic-inner-panel/basic-inner-panel.component.scss similarity index 60% copy from ui/src/app/connect/components/format-item-json/format-item-json.component.scss copy to ui/projects/streampipes/shared-ui/src/lib/components/basic-inner-panel/basic-inner-panel.component.scss index 30123c0..c4d52df 100644 --- a/ui/src/app/connect/components/format-item-json/format-item-json.component.scss +++ b/ui/projects/streampipes/shared-ui/src/lib/components/basic-inner-panel/basic-inner-panel.component.scss
@@ -16,32 +16,32 @@ * */ - -.format-label { - line-height:50px; - margin: auto; - text-align: center; - font-weight: bold; - font-size: 1.3em; +.panel-outer { + margin-top: 15px; + margin-bottom: 15px; + border: 2px solid var(--color-bg-3); } -.format-box { +.general-panel { + border: 0px solid var(--color-bg-3); +} + +.general-panel-header { + margin-top: -1px; + background: var(--color-bg-2); + border: 0px solid var(--color-bg-3); + border-bottom: 2px solid var(--color-bg-3); + padding-left: 5px; + height: 50px; min-height: 50px; - box-shadow: 1px 1px 2px #555; - border: 1px solid gray; - cursor: pointer; - padding: 10px; - opacity: 0.7; - margin: 10px; - background: #ffffff; + max-height: 50px; } -.format-box:hover { - opacity: 1; +.content-box-title { + margin-left: 5px; + padding-left: 5px; + border-left: 4px solid var(--color-accent); + font-weight: 600; + font-size: 13pt; + white-space: nowrap; } - -.selectedItem { - opacity: 1; - background-color: grey; -} -
diff --git a/ui/src/app/connect/components/schema-editor/event-schema-preview/event-schema-preview.component.ts b/ui/projects/streampipes/shared-ui/src/lib/components/basic-inner-panel/basic-inner-panel.component.ts similarity index 70% rename from ui/src/app/connect/components/schema-editor/event-schema-preview/event-schema-preview.component.ts rename to ui/projects/streampipes/shared-ui/src/lib/components/basic-inner-panel/basic-inner-panel.component.ts index f80de67..3e56b98 100644 --- a/ui/src/app/connect/components/schema-editor/event-schema-preview/event-schema-preview.component.ts +++ b/ui/projects/streampipes/shared-ui/src/lib/components/basic-inner-panel/basic-inner-panel.component.ts
@@ -17,13 +17,27 @@ */ import { Component, Input } from '@angular/core'; -import { EventSchema } from '@streampipes/platform-services'; @Component({ - selector: 'sp-event-schema-preview', - templateUrl: './event-schema-preview.component.html', - styleUrls: ['./event-schema-preview.component.scss'] + selector: 'sp-basic-inner-panel', + templateUrl: './basic-inner-panel.component.html', + styleUrls: ['./basic-inner-panel.component.scss'] }) -export class EventSchemaPreviewComponent { - @Input() eventSchema: EventSchema; +export class SpBasicInnerPanelComponent { + + @Input() + panelTitle: string; + + @Input() + showTitle = true; + + @Input() + innerPadding = '15px'; + + @Input() + outerMargin = '0px'; + + @Input() + hideToolbar = false; + }
diff --git a/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.html b/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.html new file mode 100644 index 0000000..12a4534 --- /dev/null +++ b/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.html
@@ -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. + ~ + --> + +<div fxLayout="column" class="page-container"> + <div fxLayout="row" class="p-0 sp-bg-lightgray page-container-nav"> + <div fxFlex="100" class="page-container-nav pr-5" fxLayout="row"> + <div fxLayout="row" + fxLayoutAlign="start center" + style="border-right: 2px solid var(--color-bg-2)" *ngIf="showBackLink"> + <button mat-button + mat-icon-button + color="accent" + matTooltip="Back" + (click)="navigateBack()" + class="edit-menu-btn" + data-cy="save-data-explorer-go-back-to-overview"> + <mat-icon>arrow_back</mat-icon> + </button> + </div> + <nav mat-tab-nav-bar color="accent"> + <a mat-tab-link *ngFor="let item of spNavigationItems" + (click)="navigateTo(item)" + [active]="activeLink === item.itemId"> + <span class="upper-case">{{item.itemTitle}}</span> + </a> + </nav> + <span fxFlex></span> + <ng-content select="[nav]" fxFlex="100" fxLayout="row" fxLayoutAlign="end center"></ng-content> + </div> + </div> + + <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100"> + <ng-content fxFlex="100"></ng-content> + </div> +</div>
diff --git a/ui/src/app/connect/components/format-item-json/format-item-json.component.scss b/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.scss similarity index 69% copy from ui/src/app/connect/components/format-item-json/format-item-json.component.scss copy to ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.scss index 30123c0..4bbebfc 100644 --- a/ui/src/app/connect/components/format-item-json/format-item-json.component.scss +++ b/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.scss
@@ -16,32 +16,32 @@ * */ - -.format-label { - line-height:50px; - margin: auto; - text-align: center; - font-weight: bold; - font-size: 1.3em; -} - -.format-box { - min-height: 50px; - box-shadow: 1px 1px 2px #555; - border: 1px solid gray; - cursor: pointer; +.page-container-padding-inner { padding: 10px; - opacity: 0.7; +} + +.sp-bg-lightgray { + background-color: var(--color-bg-1); +} + +.sp-tab-bg { + background-color: var(--color-bg-1); +} + +.page-container { margin: 10px; - background: #ffffff; + border: 1px solid var(--color-bg-3); + min-height: calc(100% - 50px); } -.format-box:hover { - opacity: 1; +.page-container-padding-inner { + margin: 10px; } -.selectedItem { - opacity: 1; - background-color: grey; +.upper-case { + text-transform: uppercase; } +.pr-5 { + padding-right: 5px; +}
diff --git a/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.ts b/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.ts new file mode 100644 index 0000000..5ab53a5 --- /dev/null +++ b/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.ts
@@ -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. + * + */ + +import { Component, Input } from '@angular/core'; +import { Router } from '@angular/router'; +import { SpNavigationItem } from '../../models/sp-navigation.model'; + +@Component({ + selector: 'sp-basic-nav-tabs', + templateUrl: './basic-nav-tabs.component.html', + styleUrls: ['./basic-nav-tabs.component.scss'] +}) +export class SpBasicNavTabsComponent { + + @Input() + spNavigationItems: SpNavigationItem[]; + + @Input() + activeLink: string; + + @Input() + showBackLink = false; + + @Input() + backLinkTarget: string[] = []; + + constructor(private router: Router) { + + } + + navigateTo(spNavigationItem: SpNavigationItem) { + this.router.navigate(spNavigationItem.itemLink); + } + + navigateBack() { + this.router.navigate(this.backLinkTarget); + } +}
diff --git a/ui/projects/streampipes/shared-ui/src/lib/components/basic-view/basic-view.component.html b/ui/projects/streampipes/shared-ui/src/lib/components/basic-view/basic-view.component.html new file mode 100644 index 0000000..a8bf704 --- /dev/null +++ b/ui/projects/streampipes/shared-ui/src/lib/components/basic-view/basic-view.component.html
@@ -0,0 +1,43 @@ +<!-- + ~ 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" class="p-0 sp-bg-lightgray page-container-nav" *ngIf="!hideNavbar"> + <div fxLayout="fill" fxFlex="100" class="pl-5 pr-5"> + <div fxLayout="row" + fxLayoutAlign="start center" + style="border-right: 2px solid var(--color-bg-2)" *ngIf="showBackLink"> + <button mat-button + mat-icon-button + color="accent" + matTooltip="Back" + (click)="navigateBack()" + class="edit-menu-btn" + data-cy="save-data-explorer-go-back-to-overview"> + <mat-icon>arrow_back</mat-icon> + </button> + </div> + <ng-content select="[nav]" fxFlex="100"></ng-content> + </div> + </div> + + <div [ngClass]="padding ? 'page-container-padding-inner' : ''" fxLayout="column" fxFlex="100"> + <ng-content fxFlex="100"></ng-content> + </div> +</div> +
diff --git a/ui/projects/streampipes/shared-ui/src/lib/components/basic-view/basic-view.component.scss b/ui/projects/streampipes/shared-ui/src/lib/components/basic-view/basic-view.component.scss new file mode 100644 index 0000000..95d1ed5 --- /dev/null +++ b/ui/projects/streampipes/shared-ui/src/lib/components/basic-view/basic-view.component.scss
@@ -0,0 +1,58 @@ +/* + * 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. + * + */ + +.fixed-height { + flex-direction: row; + box-sizing: border-box; + display: flex; + flex: 1 1 100%; + max-height: 100%; + overflow-y: auto; +} + +.page-container-nav { + line-height:24px; + height: 50px; + border-bottom:1px solid var(--color-bg-3); +} + +.sp-bg-lightgray { + background-color: var(--color-bg-1); +} + +.sp-tab-bg { + background-color: var(--color-bg-1); +} + +.page-container { + margin: 10px; + border: 1px solid var(--color-bg-3); + min-height: calc(100% - 50px); +} + +.page-container-padding-inner { + margin: 20px; +} + +.pl-5 { + padding-left: 5px; +} + +.pr-5 { + padding-right: 5px; +}
diff --git a/ui/src/app/connect/components/schema-editor/event-schema-preview/event-schema-preview.component.ts b/ui/projects/streampipes/shared-ui/src/lib/components/basic-view/basic-view.component.ts similarity index 65% copy from ui/src/app/connect/components/schema-editor/event-schema-preview/event-schema-preview.component.ts copy to ui/projects/streampipes/shared-ui/src/lib/components/basic-view/basic-view.component.ts index f80de67..12af9e3 100644 --- a/ui/src/app/connect/components/schema-editor/event-schema-preview/event-schema-preview.component.ts +++ b/ui/projects/streampipes/shared-ui/src/lib/components/basic-view/basic-view.component.ts
@@ -17,13 +17,32 @@ */ import { Component, Input } from '@angular/core'; -import { EventSchema } from '@streampipes/platform-services'; +import { Router } from '@angular/router'; @Component({ - selector: 'sp-event-schema-preview', - templateUrl: './event-schema-preview.component.html', - styleUrls: ['./event-schema-preview.component.scss'] + selector: 'sp-basic-view', + templateUrl: './basic-view.component.html', + styleUrls: ['./basic-view.component.scss'] }) -export class EventSchemaPreviewComponent { - @Input() eventSchema: EventSchema; +export class SpBasicViewComponent { + + @Input() + padding = false; + + @Input() + showBackLink = false; + + @Input() + backLinkTarget: string[]; + + @Input() + hideNavbar = false; + + constructor(private router: Router) { + + } + + navigateBack() { + this.router.navigate(this.backLinkTarget); + } }
diff --git a/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.component.html b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.component.html new file mode 100644 index 0000000..06dbd0c --- /dev/null +++ b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.component.html
@@ -0,0 +1,47 @@ +<!-- + ~ 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-20"> + <div fxFlex="100" fxLayout="column" class="mt-10"> + <div *ngIf="title" fxLayoutAlign="start center" fxFlex="100" class="title-message color-warn"> + <i class="material-icons color-warn" style="margin-right: 15px;">warning</i> + <span class="color-warn">{{title}}</span> + </div> + <div class="error-details-title">Probable cause</div> + <div class="log-message" [innerText]="message.cause"> + </div> + <div class="mt-10"> + <button mat-button color="accent" (click)="showDetails = !showDetails">Full details</button> + </div> + <div fxFlex="100" fxLayout="column" *ngIf="showDetails" class="mt-10"> + <div class="error-details-title">Full stack trace</div> + <div class="log-message"> + <div [innerText]="message.fullStackTrace"></div> + </div> + </div> + </div> + + </div> + <mat-divider></mat-divider> + <div class="sp-dialog-actions actions-align-right"> + <button mat-button mat-raised-button class="mat-basic" (click)="close()"> + Close + </button> + </div> +</div>
diff --git a/ui/src/app/connect/components/format-item-json/format-item-json.component.scss b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.component.scss similarity index 60% copy from ui/src/app/connect/components/format-item-json/format-item-json.component.scss copy to ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.component.scss index 30123c0..05d9cfd 100644 --- a/ui/src/app/connect/components/format-item-json/format-item-json.component.scss +++ b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.component.scss
@@ -16,32 +16,40 @@ * */ - -.format-label { - line-height:50px; - margin: auto; - text-align: center; - font-weight: bold; - font-size: 1.3em; -} - -.format-box { - min-height: 50px; - box-shadow: 1px 1px 2px #555; - border: 1px solid gray; - cursor: pointer; +.log-message { + background-color: black; + font: 9pt Inconsolata, monospace; + text-shadow: 0 0 5px #C8C8C8; + color: white; padding: 10px; - opacity: 0.7; - margin: 10px; - background: #ffffff; + max-width: 100%; + min-height: 50px; + max-height: 300px; + overflow-y: scroll; + white-space: pre-wrap; } -.format-box:hover { - opacity: 1; +.error-details-title { + font-size: 13pt; + font-weight: var(--color-default-text); + border-left: 3px solid var(--color-accent); + padding-left: 10px; + margin-bottom: 15px; } -.selectedItem { - opacity: 1; - background-color: grey; +.mt-10 { + margin-top: 10px; } +.p-20 { + padding: 20px; +} + +.color-warn { + color: var(--color-warn); +} + +.title-message { + font-size: 16pt; + margin-bottom: 15px; +}
diff --git a/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.component.ts b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.component.ts new file mode 100644 index 0000000..b735d74 --- /dev/null +++ b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.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, Input, OnInit } from '@angular/core'; +import { StreamPipesErrorMessage } from '@streampipes/platform-services'; +import { DialogRef } from '../../../dialog/base-dialog/dialog-ref'; + +@Component({ + selector: 'sp-exception-details-dialog', + templateUrl: './exception-details-dialog.component.html', + styleUrls: ['./exception-details-dialog.component.scss', '../../../../../../../../src/scss/sp/sp-dialog.scss'] +}) +export class SpExceptionDetailsDialogComponent implements OnInit { + + @Input() + message: StreamPipesErrorMessage; + + @Input() + title: string; + + showDetails = false; + + constructor(private dialogRef: DialogRef<SpExceptionDetailsDialogComponent>) { + + } + + close() { + this.dialogRef.close(); + } + + ngOnInit(): void { + console.log(this.title); + } + +}
diff --git a/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/sp-exception-message.component.html b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/sp-exception-message.component.html new file mode 100644 index 0000000..46238bf --- /dev/null +++ b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/sp-exception-message.component.html
@@ -0,0 +1,38 @@ +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~ + --> + +<div fxLayout="column" fxFlex="100" class="error-panel error"> + <div fxLayout="row"> + <div fxFlex="100" fxLayoutAlign="start center"> + <div fxLayout="row" fxLayoutAlign="start center" class="p-5" fxFlex="100"> + <div fxLayoutAlign="start center"> + <i class="material-icons color-warn" style="margin-right: 15px;">warning</i> + <h5 fxFlex class="color-warn">{{message.title}}</h5> + </div> + <span fxFlex></span> + <div fxLayoutAlign="end center" *ngIf="showDetails"> + <button mat-button (click)="openDetailsDialog()"> + <i class="material-icons">visibility</i> Details + </button> + </div> + </div> + + </div> + </div> + +</div>
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/sp-exception-message.component.scss similarity index 82% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/sp-exception-message.component.scss index 58ba04b..15a00db 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/sp-exception-message.component.scss
@@ -16,3 +16,15 @@ * */ +.error-panel { + background: var(--color-bg-1); + border-radius: 5px; +} + +.error { + border: 1px solid var(--color-warn); +} + +.color-warn { + color: var(--color-warn); +}
diff --git a/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/sp-exception-message.component.ts b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/sp-exception-message.component.ts new file mode 100644 index 0000000..2d78e1b --- /dev/null +++ b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/sp-exception-message.component.ts
@@ -0,0 +1,56 @@ +/* + * 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, Input } from '@angular/core'; +import { StreamPipesErrorMessage } from '@streampipes/platform-services'; +import { DialogService } from '../../dialog/base-dialog/base-dialog.service'; +import { PanelType } from '../../dialog/base-dialog/base-dialog.model'; +import { SpExceptionDetailsDialogComponent } from './exception-details-dialog/exception-details-dialog.component'; + +@Component({ + selector: 'sp-exception-message', + templateUrl: './sp-exception-message.component.html', + styleUrls: ['./sp-exception-message.component.scss'] +}) +export class SpExceptionMessageComponent { + + @Input() + level = 'error'; + + @Input() + showDetails = true; + + @Input() + message: StreamPipesErrorMessage; + + constructor(private dialogService: DialogService) { + + } + + openDetailsDialog() { + this.dialogService.open(SpExceptionDetailsDialogComponent, { + panelType: PanelType.STANDARD_PANEL, + width: '80vw', + title: 'Error Details', + data: { + 'message': this.message + } + }); + } + +}
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/projects/streampipes/shared-ui/src/lib/models/sp-navigation.model.ts similarity index 81% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/projects/streampipes/shared-ui/src/lib/models/sp-navigation.model.ts index 58ba04b..1a90c9e 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/projects/streampipes/shared-ui/src/lib/models/sp-navigation.model.ts
@@ -16,3 +16,13 @@ * */ +export interface SpNavigationItem { + itemId: string; + itemTitle: string; + itemLink: string[]; +} + +export interface SpBreadcrumbItem { + label: string; + link?: string[]; +}
diff --git a/ui/projects/streampipes/shared-ui/src/lib/services/breadcrumb.service.ts b/ui/projects/streampipes/shared-ui/src/lib/services/breadcrumb.service.ts new file mode 100644 index 0000000..1d915c6 --- /dev/null +++ b/ui/projects/streampipes/shared-ui/src/lib/services/breadcrumb.service.ts
@@ -0,0 +1,46 @@ +/* + * 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 { BehaviorSubject } from 'rxjs'; +import { SpBreadcrumbItem } from '../models/sp-navigation.model'; +import { Injectable } from '@angular/core'; + +@Injectable({providedIn: 'root'}) +export class SpBreadcrumbService { + + currentNavHierarchy$: BehaviorSubject<SpBreadcrumbItem[]> = new BehaviorSubject<SpBreadcrumbItem[]>([]); + + updateBreadcrumb(breadcrumbItems: SpBreadcrumbItem[]) { + this.currentNavHierarchy$.next(breadcrumbItems); + } + + public getRootLink(baseRoute: SpBreadcrumbItem): SpBreadcrumbItem[] { + return [this.removeLink({...baseRoute})]; + } + + public makeRoute(baseItems: SpBreadcrumbItem[], label: string, link?: string[]) { + baseItems.push({label, link}); + return baseItems; + } + + public removeLink(item: SpBreadcrumbItem): SpBreadcrumbItem { + const newItem = {...item}; + newItem.link = undefined; + return newItem; + } +}
diff --git a/ui/projects/streampipes/shared-ui/src/lib/shared-ui.module.ts b/ui/projects/streampipes/shared-ui/src/lib/shared-ui.module.ts index f7102fc..8e40ee5 100644 --- a/ui/projects/streampipes/shared-ui/src/lib/shared-ui.module.ts +++ b/ui/projects/streampipes/shared-ui/src/lib/shared-ui.module.ts
@@ -24,21 +24,52 @@ import { PortalModule } from '@angular/cdk/portal'; import { MatButtonModule } from '@angular/material/button'; import { OverlayModule } from '@angular/cdk/overlay'; +import { SpBasicViewComponent } from './components/basic-view/basic-view.component'; +import { FlexLayoutModule } from '@angular/flex-layout'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { SpBasicNavTabsComponent } from './components/basic-nav-tabs/basic-nav-tabs.component'; +import { MatTabsModule } from '@angular/material/tabs'; +import { SpBasicInnerPanelComponent } from './components/basic-inner-panel/basic-inner-panel.component'; +import { SpBasicHeaderTitleComponent } from './components/basic-header-title/header-title.component'; +import { SpExceptionMessageComponent } from './components/sp-exception-message/sp-exception-message.component'; +import { SpExceptionDetailsDialogComponent } from './components/sp-exception-message/exception-details-dialog/exception-details-dialog.component'; +import { MatDividerModule } from '@angular/material/divider'; @NgModule({ declarations: [ ConfirmDialogComponent, PanelDialogComponent, - StandardDialogComponent + StandardDialogComponent, + SpBasicInnerPanelComponent, + SpBasicHeaderTitleComponent, + SpBasicViewComponent, + SpBasicNavTabsComponent, + SpExceptionMessageComponent, + SpExceptionDetailsDialogComponent ], imports: [ CommonModule, - PortalModule, + FlexLayoutModule, MatButtonModule, - OverlayModule + MatDividerModule, + MatIconModule, + MatTabsModule, + MatTooltipModule, + PortalModule, + OverlayModule, ], exports: [ - ConfirmDialogComponent, PanelDialogComponent, StandardDialogComponent + ConfirmDialogComponent, + PanelDialogComponent, + StandardDialogComponent, + SpBasicInnerPanelComponent, + SpBasicHeaderTitleComponent, + SpBasicViewComponent, + SpBasicNavTabsComponent, + SpExceptionMessageComponent, + SpExceptionDetailsDialogComponent ] }) -export class SharedUiModule { } +export class SharedUiModule { +}
diff --git a/ui/projects/streampipes/shared-ui/src/public-api.ts b/ui/projects/streampipes/shared-ui/src/public-api.ts index b7b26ed..a19dfd5 100644 --- a/ui/projects/streampipes/shared-ui/src/public-api.ts +++ b/ui/projects/streampipes/shared-ui/src/public-api.ts
@@ -19,7 +19,6 @@ export * from './lib/shared-ui.module'; export * from './lib/dialog/base-dialog/base-dialog.model'; -// export * from './lib/dialog/base-dialog/base-dialog.component'; export * from './lib/dialog/base-dialog/base-dialog.service'; export * from './lib/dialog/base-dialog/dialog-ref'; @@ -27,4 +26,15 @@ export * from './lib/dialog/panel-dialog/panel-dialog.component'; export * from './lib/dialog/standard-dialog/standard-dialog.component'; +export * from './lib/components/basic-header-title/header-title.component'; +export * from './lib/components/basic-inner-panel/basic-inner-panel.component'; +export * from './lib/components/basic-view/basic-view.component'; +export * from './lib/components/basic-nav-tabs/basic-nav-tabs.component'; +export * from './lib/components/sp-exception-message/sp-exception-message.component'; +export * from './lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.component'; + +export * from './lib/models/sp-navigation.model'; + +export * from './lib/services/breadcrumb.service'; +
diff --git a/ui/src/app/_enums/page-name.enum.ts b/ui/src/app/_enums/page-name.enum.ts index 472780a..a681bcc 100644 --- a/ui/src/app/_enums/page-name.enum.ts +++ b/ui/src/app/_enums/page-name.enum.ts
@@ -30,4 +30,5 @@ FILE_UPLOAD, PROFILE, SETTINGS, + ASSETS }
diff --git a/ui/src/app/add/add.component.html b/ui/src/app/add/add.component.html index 63c025a..0c75094 100644 --- a/ui/src/app/add/add.component.html +++ b/ui/src/app/add/add.component.html
@@ -16,61 +16,59 @@ ~ --> -<div fxLayout="column" class="page-container"> - <div fxLayout="row" class="border sp-bg-lightgray p-0"> - <div fxFlex="100" class="page-container-nav"> - <div fxFlex="100" fxLayout="row"> - <button mat-button mat-flat-button color="accent" (click)="showManageRdfEndpointsDialog()">Manage - Endpoints - </button> - <div fxFlex fxLayoutAlign="start center" [attr.id]="'peType'"> - <mat-tab-group [selectedIndex]="selectedCategoryIndex" - (selectedIndexChange)="setSelectedTab($event)" color="accent"> - <mat-tab label="All"></mat-tab> - <mat-tab label="Data Sets"></mat-tab> - <mat-tab label="Data Streams"></mat-tab> - <mat-tab label="Data Processors"></mat-tab> - <mat-tab label="Data Sinks"></mat-tab> - </mat-tab-group> - </div> - </div> - </div> - </div> - <div fxLayout="row" class="fixed-height add-options sp-tab-bg"> - <div class="add-options-item pl-5" fxLayoutAlign="start center" fxLayout="row"> - <div fxFlex="100" fxLayout="row"> - <button mat-button mat-raised-button color="accent" - [disabled]="selectedEndpointItems.length === 0" - (click)="installSelected()" class="mr-10"> - <i class="material-icons">cloud_download</i> - Install selected - </button> - <button mat-button mat-raised-button color="accent" - [disabled]="selectedEndpointItems.length === 0" - (click)="uninstallSelected()" class="mr-10"> - <i class="material-icons">delete</i> - Uninstall selected - </button> - <button mat-button mat-icon-button color="accent" class="mr-10" (click)="selectAll(true)" - matTooltip="Select all" matTooltipPosition="above"> - <i class="material-icons">queue</i> - </button> - <button mat-button mat-icon-button color="accent" class="mr-10" (click)="selectAll(false)" - matTooltip="Select none" matTooltipPosition="above"> - <i class="material-icons">filter_none</i> - </button> - </div> +<sp-basic-view [showBackLink]="false" [padding]="true"> + <div nav fxFlex="100" fxLayoutAlign="start center" fxLayout="row" class="pl-10"> + <div fxFlex="100" fxLayout="row"> + <button mat-button mat-raised-button color="accent" [disabled]="selectedEndpointItems.length === 0" + (click)="installSelected()" class="mr-10"> + <i class="material-icons">cloud_download</i> + Install selected + </button> + <button mat-button mat-raised-button color="accent" [disabled]="selectedEndpointItems.length === 0" + (click)="uninstallSelected()" class="mr-10"> + <i class="material-icons">delete</i> + Uninstall selected + </button> + <button mat-button mat-icon-button color="accent" class="mr-10" (click)="selectAll(true)" + matTooltip="Select all" matTooltipPosition="above"> + <i class="material-icons">queue</i> + </button> + <button mat-button mat-icon-button color="accent" class="mr-10" (click)="selectAll(false)" + matTooltip="Select none" matTooltipPosition="above"> + <i class="material-icons">filter_none</i> + </button> </div> <span fxFlex></span> - <div class="add-options-item pl-5" fxLayoutAlign="start center" fxLayout="row"> - <mat-icon>search</mat-icon> - - <mat-form-field class="form-style" color="accent"> - <input matInput placeholder="Find Element" value="" [(ngModel)]="filterTerm" - name="something"> + <div fxLayoutAlign="start center" fxLayout="row"> + <mat-form-field color="accent"> + <mat-select [(value)]="selectedCategory" + (selectionChange)="filterByCatergory($event)"> + <mat-option [value]="'all'"> + All + </mat-option> + <mat-option [value]="'set'"> + Sets + </mat-option> + <mat-option [value]="'stream'"> + Streams + </mat-option> + <mat-option [value]="'sepa'"> + Processors + </mat-option> + <mat-option [value]="'action'"> + Sinks + </mat-option> + </mat-select> </mat-form-field> </div> - <div class="add-options-item" fxLayoutAlign="start center" fxLayout="row"> + <div class="ml-10" fxLayoutAlign="start center" fxLayout="row"> + <mat-icon>search</mat-icon> + + <mat-form-field class="form-style" color="accent" floatLabel="never"> + <input matInput placeholder="Find Element" value="" [(ngModel)]="filterTerm" name="something"> + </mat-form-field> + </div> + <div fxLayoutAlign="start center" fxLayout="row" class="ml-10"> <mat-form-field color="accent"> <mat-select [(value)]="selectedInstallationStatus"> <mat-option [value]="'all'"> @@ -85,31 +83,35 @@ </mat-select> </mat-form-field> </div> - <div class="add-options-item" fxLayoutAlign="start center" fxLayout="row"> - <button mat-button mat-icon-button color="accent" (click)="getEndpointItems()" - matTooltip="Reload items" matTooltipPosition="above"> + <div fxLayoutAlign="start center" fxLayout="row" class="ml-10"> + <button mat-button mat-icon-button color="accent" (click)="getEndpointItems()" matTooltip="Reload items" + matTooltipPosition="above"> <mat-icon>refresh</mat-icon> </button> </div> + <button mat-button mat-icon-button color="accent" (click)="showManageRdfEndpointsDialog()" + matTooltip="Manage Endpoints"> + <i class="material-icons">settings</i> + </button> </div> + <div fxLayout="column" fxFlex="100"> - <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" class="page-container-padding-inner" - *ngIf="endpointItemsLoadingComplete"> - <div fxLayoutAlign="start start" fxLayout="column"> + <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" + *ngIf="endpointItemsLoadingComplete"> + <div fxLayoutAlign="start start" fxLayout="column"> + <sp-basic-header-title-component title="Available Pipeline Elements"></sp-basic-header-title-component> + </div> + <div fxLayout="row wrap" class="w-100"> + <sp-endpoint-item fxFlex="33" [itemSelected]="endpointItem.selected" [item]="endpointItem" + (triggerInstallation)="triggerInstallation($event)" + *ngFor="let endpointItem of endpointItems | pipelineElementTypeFilter: selectedTab | pipelineElementNameFilter: filterTerm | pipelineElementInstallationStatusFilter: selectedInstallationStatus | orderBy: 'asc':'name'" + class="p-15" (click)="toggleSelected(endpointItem)"></sp-endpoint-item> + </div> </div> - <div fxLayout="row wrap" class="w-100"> - <sp-endpoint-item fxFlex="33" - [itemSelected]="endpointItem.selected" - [item]="endpointItem" - (triggerInstallation)="triggerInstallation($event)" - *ngFor="let endpointItem of endpointItems | pipelineElementTypeFilter: selectedTab | pipelineElementNameFilter: filterTerm | pipelineElementInstallationStatusFilter: selectedInstallationStatus | orderBy: 'asc':'name'" - class="p-15" - (click)="toggleSelected(endpointItem)"></sp-endpoint-item> + <div fxFlex="100" fxLayout="row" fxLayoutAlign="center center" *ngIf="!endpointItemsLoadingComplete"> + <mat-spinner [mode]="'indeterminate'" [diameter]="20" color="accent"></mat-spinner> + <h4> Searching for available pipeline elements, please wait...</h4> </div> </div> - <div fxFlex="100" fxLayout="row" fxLayoutAlign="center center" *ngIf="!endpointItemsLoadingComplete"> - <mat-spinner [mode]="'indeterminate'" [diameter]="20" color="accent"></mat-spinner> - <h4> Searching for available pipeline elements, please wait...</h4> - </div> -</div> +</sp-basic-view>
diff --git a/ui/src/app/add/add.component.scss b/ui/src/app/add/add.component.scss index b641e78..ffe023f 100644 --- a/ui/src/app/add/add.component.scss +++ b/ui/src/app/add/add.component.scss
@@ -30,6 +30,10 @@ margin-right: 10px; } +.ml-10 { + margin-left: 10px; +} + .add-options { padding:0px; border-bottom: 1px solid var(--color-bg-2);
diff --git a/ui/src/app/add/add.component.ts b/ui/src/app/add/add.component.ts index 7df4a35..62e5e3f 100644 --- a/ui/src/app/add/add.component.ts +++ b/ui/src/app/add/add.component.ts
@@ -16,13 +16,14 @@ * */ -import { RestApi } from '../services/rest-api.service'; import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { AddService } from './services/add.service'; -import { DialogRef, DialogService, PanelType } from '@streampipes/shared-ui'; +import { DialogRef, DialogService, PanelType, SpBreadcrumbService } from '@streampipes/shared-ui'; import { AddEndpointComponent } from './dialogs/add-endpoint/add-endpoint.component'; import { EndpointInstallationComponent } from './dialogs/endpoint-installation/endpoint-installation.component'; import { ExtensionsServiceEndpointItem } from '@streampipes/platform-services'; +import { Router } from '@angular/router'; +import { SpAddRoutes } from './add.routes'; @Component({ selector: 'sp-add', @@ -31,6 +32,8 @@ }) export class AddComponent implements OnInit { + activeLink: string; + results: any[]; loading: boolean; endpointItems: ExtensionsServiceEndpointItem[]; @@ -39,16 +42,18 @@ availableTypes: string[] = ['all', 'set', 'stream', 'sepa', 'action']; selectedCategoryIndex = 0; + selectedCategory = 'all'; selectedEndpointItems: any[] = []; _filterTerm = ''; _selectedInstallationStatus = 'all'; - constructor(private restApi: RestApi, - private addService: AddService, + constructor(private addService: AddService, private dialogService: DialogService, - private changeDetectorRef: ChangeDetectorRef) { + private changeDetectorRef: ChangeDetectorRef, + private router: Router, + private breadcrumbService: SpBreadcrumbService) { this.results = []; this.loading = false; this.endpointItems = []; @@ -56,6 +61,7 @@ } ngOnInit() { + this.breadcrumbService.updateBreadcrumb(this.breadcrumbService.getRootLink(SpAddRoutes.BASE)); this.getEndpointItems(); this.selectedTab = 'all'; } @@ -81,6 +87,10 @@ return endpointItem.selected; } + filterByCatergory(category) { + this.selectedTab = category.value; + } + selectAll(selected) { this.selectedEndpointItems = []; this.endpointItems.forEach(item => { @@ -95,20 +105,7 @@ }); this.changeDetectorRef.detectChanges(); } - - getTitle(selectedTab) { - if (selectedTab === 'source') { - return 'Data Sources'; - } else if (selectedTab === 'sepa') { - return 'Processing Elements'; - } else if (selectedTab === 'action') { - return 'Data Sinks'; - } else if (selectedTab === 'all') { - return 'All Pipeline Elements'; - } else { - return 'Marketplace'; - } - } + showManageRdfEndpointsDialog() { const dialogRef: DialogRef<AddEndpointComponent> = this.dialogService.open(AddEndpointComponent, { @@ -195,4 +192,9 @@ get selectedInstallationStatus(): string { return this._selectedInstallationStatus; } + + navigateTo(routeId: string): void { + this.router.navigate(['add', routeId]); + this.activeLink = routeId; + } }
diff --git a/ui/src/app/add/add.module.ts b/ui/src/app/add/add.module.ts index 176ee2d..9c91e7d 100644 --- a/ui/src/app/add/add.module.ts +++ b/ui/src/app/add/add.module.ts
@@ -33,6 +33,8 @@ import { EndpointInstallationComponent } from './dialogs/endpoint-installation/endpoint-installation.component'; import { PipelineElementNameFilter } from './filter/pipeline-element-name.pipe'; import { PipelineElementInstallationStatusFilter } from './filter/pipeline-element-installation-status.pipe'; +import { RouterModule } from "@angular/router"; +import { SharedUiModule } from '../../../projects/streampipes/shared-ui/src/lib/shared-ui.module'; @NgModule({ @@ -44,6 +46,18 @@ CoreUiModule, CustomMaterialModule, MatProgressSpinnerModule, + RouterModule.forChild([ + { + path: 'add', + children: [ + { + path: '', + component: AddComponent + } + ] + } + ]), + SharedUiModule ], declarations: [ AddComponent,
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/add/add.routes.ts similarity index 77% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/add/add.routes.ts index 58ba04b..a035fea 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/add/add.routes.ts
@@ -16,3 +16,10 @@ * */ +import { SpBreadcrumbItem, } from '@streampipes/shared-ui'; + +export class SpAddRoutes { + + static ADD_BASE_LINK = 'add'; + static BASE: SpBreadcrumbItem = {label: 'Install Pipeline Elements', link: [SpAddRoutes.ADD_BASE_LINK]}; +}
diff --git a/ui/src/app/add/dialogs/add-endpoint/add-endpoint.component.html b/ui/src/app/add/dialogs/add-endpoint/add-endpoint.component.html index 6dd1064..2b9c7cf 100644 --- a/ui/src/app/add/dialogs/add-endpoint/add-endpoint.component.html +++ b/ui/src/app/add/dialogs/add-endpoint/add-endpoint.component.html
@@ -50,7 +50,7 @@ </div> </div> <div style="margin-top:10px;"> - <button mat-button mat-raised-button color="accent" (click)="showAddInput()">Add Category</button> + <button mat-button mat-raised-button color="accent" (click)="showAddInput()">Add Endpoint</button> </div> </div> <mat-divider></mat-divider>
diff --git a/ui/src/app/app-asset-monitoring/app-asset-monitoring.component.html b/ui/src/app/app-asset-monitoring/app-asset-monitoring.component.html index 13dae74..8026958 100644 --- a/ui/src/app/app-asset-monitoring/app-asset-monitoring.component.html +++ b/ui/src/app/app-asset-monitoring/app-asset-monitoring.component.html
@@ -16,21 +16,19 @@ ~ --> -<div fxLayout="column" fxFlex="100" class="page-container-connect"> - <div fxLayout="row" class="sp-tab-bg"> - <div fxLayout="fill" class="page-container-nav"> - <mat-tab-group [selectedIndex]="selectedIndex" (selectedIndexChange)="selectedIndexChange($event)" color="accent"> - <mat-tab label="Asset Dashboards"> - </mat-tab> - <mat-tab id="all-adapters" label="New Asset Dashboard"> - </mat-tab> - </mat-tab-group> - </div> - </div> +<sp-basic-view showBackLink="true" [backLinkTarget]="['apps']"> + <ng-container nav> + <mat-tab-group [selectedIndex]="selectedIndex" (selectedIndexChange)="selectedIndexChange($event)" color="accent"> + <mat-tab label="Asset Dashboards"> + </mat-tab> + <mat-tab id="all-adapters" label="New Asset Dashboard"> + </mat-tab> + </mat-tab-group> + </ng-container> <div fxLayout="column" fxFlex="100"> - <sp-asset-dashboard-overview *ngIf="selectedIndex == 0 && !dashboardSelected" fxFlex="100" (selectedDashboard)="openDashboard($event)"></sp-asset-dashboard-overview> + <sp-asset-dashboard-overview *ngIf="selectedIndex == 0 && !dashboardSelected" fxFlex="100" (selectedDashboard)="openDashboard($event)" (createDashboard)="selectedIndex = 1"></sp-asset-dashboard-overview> <sp-view-asset fxFlex="100" *ngIf="selectedIndex == 0 && dashboardSelected" [dashboardConfig]="selectedDashboard" (dashboardClosed)="closeDashboard($event)" (editDashboardEmitter)="editDashboard($event)"></sp-view-asset> <sp-create-asset *ngIf="selectedIndex == 1" fxFlex="100" (dashboardClosed)="closeDashboard($event)" [dashboardConfig]="selectedDashboard"></sp-create-asset> </div> -</div> +</sp-basic-view>
diff --git a/ui/src/app/app-asset-monitoring/app-asset-monitoring.component.ts b/ui/src/app/app-asset-monitoring/app-asset-monitoring.component.ts index b0e7a31..3d9542a 100644 --- a/ui/src/app/app-asset-monitoring/app-asset-monitoring.component.ts +++ b/ui/src/app/app-asset-monitoring/app-asset-monitoring.component.ts
@@ -18,6 +18,9 @@ import { Component, EventEmitter, OnInit, Output } from '@angular/core'; import { DashboardConfiguration } from './model/dashboard-configuration.model'; +import { SpBreadcrumbService } from '@streampipes/shared-ui'; +import { SpAppRoutes } from '../app-overview/apps.routes'; +import { SpAppAssetMonitoringRoutes } from './app-asset-monitoring.routes'; @Component({ selector: 'sp-app-asset-monitoring', @@ -32,11 +35,12 @@ selectedDashboard: DashboardConfiguration; @Output() appOpened = new EventEmitter<boolean>(); - constructor() { + constructor(private breadcrumbService: SpBreadcrumbService) { } ngOnInit() { + this.breadcrumbService.updateBreadcrumb([SpAppRoutes.BASE, this.breadcrumbService.removeLink(SpAppAssetMonitoringRoutes.BASE)]); this.appOpened.emit(true); }
diff --git a/ui/src/app/app-asset-monitoring/app-asset-monitoring.module.ts b/ui/src/app/app-asset-monitoring/app-asset-monitoring.module.ts index a2882c5..215705e 100644 --- a/ui/src/app/app-asset-monitoring/app-asset-monitoring.module.ts +++ b/ui/src/app/app-asset-monitoring/app-asset-monitoring.module.ts
@@ -39,36 +39,45 @@ import { AssetDashboardOverviewComponent } from './components/dashboard-overview/dashboard-overview.component'; import { AddLinkDialogComponent } from './dialog/add-link/add-link-dialog.component'; import { DashboardModule } from '../dashboard/dashboard.module'; +import { RouterModule } from '@angular/router'; +import { SharedUiModule } from '@streampipes/shared-ui'; @NgModule({ - imports: [ - CommonModule, - FlexLayoutModule, - CustomMaterialModule, - MatGridListModule, - MatInputModule, - MatFormFieldModule, - FormsModule, - ColorPickerModule, - DashboardModule - ], - declarations: [ - AppAssetMonitoringComponent, - CreateAssetComponent, - ViewAssetComponent, - AddLinkDialogComponent, - AddPipelineDialogComponent, - SaveDashboardDialogComponent, - AssetDashboardOverviewComponent - ], - providers: [ - RestService, - ShapeService, - ElementIconText - ], - exports: [ - AppAssetMonitoringComponent - ] + imports: [ + CommonModule, + FlexLayoutModule, + CustomMaterialModule, + MatGridListModule, + MatInputModule, + MatFormFieldModule, + FormsModule, + ColorPickerModule, + DashboardModule, + RouterModule.forChild([ + { + path: '', + component: AppAssetMonitoringComponent + } + ]), + SharedUiModule + ], + declarations: [ + AppAssetMonitoringComponent, + CreateAssetComponent, + ViewAssetComponent, + AddLinkDialogComponent, + AddPipelineDialogComponent, + SaveDashboardDialogComponent, + AssetDashboardOverviewComponent + ], + providers: [ + RestService, + ShapeService, + ElementIconText + ], + exports: [ + AppAssetMonitoringComponent + ] }) export class AppAssetMonitoringModule { }
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/app-asset-monitoring/app-asset-monitoring.routes.ts similarity index 73% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/app-asset-monitoring/app-asset-monitoring.routes.ts index 58ba04b..13b9f4c 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/app-asset-monitoring/app-asset-monitoring.routes.ts
@@ -16,3 +16,10 @@ * */ +import { SpBreadcrumbItem, } from '@streampipes/shared-ui'; +import { SpAppRoutes } from '../app-overview/apps.routes'; + +export class SpAppAssetMonitoringRoutes { + + static BASE: SpBreadcrumbItem = {label: 'Asset Monitoring', link: [SpAppRoutes.APP_BASE_LINK, 'asset-monitoring']}; +}
diff --git a/ui/src/app/app-asset-monitoring/components/dashboard-overview/dashboard-overview.component.html b/ui/src/app/app-asset-monitoring/components/dashboard-overview/dashboard-overview.component.html index 3c38093..90b7037 100644 --- a/ui/src/app/app-asset-monitoring/components/dashboard-overview/dashboard-overview.component.html +++ b/ui/src/app/app-asset-monitoring/components/dashboard-overview/dashboard-overview.component.html
@@ -20,7 +20,7 @@ <h1>Asset Dashboards</h1> <mat-grid-list [cols]="3" [rowHeight]="500" - [gutterSize]="10" fxFlex="100"> + [gutterSize]="10" fxFlex="100" *ngIf="dashboardConfigs.length > 0"> <mat-grid-tile class="gray" *ngFor="let dashboardConfig of dashboardConfigs"> @@ -41,7 +41,8 @@ </mat-card> </mat-grid-tile> </mat-grid-list> - <div *ngIf="dashboardConfigs.length == 0"> - <h4>(no dashboards available, navigate to <i>New Dashboard</i> to create a new asset dashboard)</h4> + <div *ngIf="dashboardConfigs.length == 0" fxLayoutAlign="center center" fxFlex="100" fxLayout="column"> + <h4>No asset dashboards available</h4> + <button mat-button mat-raised-button color="accent" style="margin-top: 10px;" (click)="createDashboard.emit()">Create new</button> </div> </div>
diff --git a/ui/src/app/app-asset-monitoring/components/dashboard-overview/dashboard-overview.component.ts b/ui/src/app/app-asset-monitoring/components/dashboard-overview/dashboard-overview.component.ts index 57b0a6f..65e7a9c 100644 --- a/ui/src/app/app-asset-monitoring/components/dashboard-overview/dashboard-overview.component.ts +++ b/ui/src/app/app-asset-monitoring/components/dashboard-overview/dashboard-overview.component.ts
@@ -28,6 +28,7 @@ export class AssetDashboardOverviewComponent implements OnInit { @Output() selectedDashboard = new EventEmitter<DashboardConfiguration>(); + @Output() createDashboard = new EventEmitter<void>(); dashboardConfigs: DashboardConfiguration[] = [];
diff --git a/ui/src/app/app-asset-monitoring/components/view-asset/view-asset.component.ts b/ui/src/app/app-asset-monitoring/components/view-asset/view-asset.component.ts index 8a88fbf..ca435e3 100644 --- a/ui/src/app/app-asset-monitoring/components/view-asset/view-asset.component.ts +++ b/ui/src/app/app-asset-monitoring/components/view-asset/view-asset.component.ts
@@ -21,8 +21,7 @@ import Konva from 'konva'; import { DashboardConfiguration } from '../../model/dashboard-configuration.model'; import { RestService } from '../../services/rest.service'; -import { DashboardService } from '../../../dashboard/services/dashboard.service'; -import { DatalakeQueryParameterBuilder, DatalakeRestService, SpQueryResult } from '@streampipes/platform-services'; +import { DatalakeQueryParameterBuilder, DatalakeRestService, SpQueryResult, DashboardService } from '@streampipes/platform-services'; import { Subscription, timer } from 'rxjs'; import { switchMap } from 'rxjs/operators';
diff --git a/ui/src/app/app-overview/app-overview.component.html b/ui/src/app/app-overview/app-overview.component.html index 9085fd3..40ad6e2 100644 --- a/ui/src/app/app-overview/app-overview.component.html +++ b/ui/src/app/app-overview/app-overview.component.html
@@ -16,39 +16,27 @@ ~ --> -<div fxLayout="column" class="page-container page-container-connect"> - <div fxLayout="row" class="sp-tab-bg"> - <div fxLayoutAlign="end center" fxLayout="fill" class="page-container-nav" - style="padding-right:10px; width:100%;min-height:50px;line-height:24px;margin-bottom:1px;"> - <div *ngIf="appOpen"> - <button mat-button mat-raised-button color="accent" (click)="appClosed()"> - Close App - </button> - </div> - </div> - </div> +<sp-basic-view padding="true"> + <ng-container nav> - <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100" *ngIf="!appOpen"> - <div fxFlex="100" fxLayout="column"> - <h1>My apps</h1> - <mat-card class="example-card" *ngFor="let app of apps"> - <div fxFlex="100" fxLayout="row"> - <div fxFlex="75" fxLayout="column" fxLayoutAlign="center start"> - <mat-card-header> - <mat-card-title> {{app.appName}}</mat-card-title> - <mat-card-subtitle>{{app.appDescription}}</mat-card-subtitle> - </mat-card-header> - </div> - <div fxFlex="25" fxLayoutAlign="center end" fxLayout="column"> - <button mat-button mat-raised-button color="accent" (click)="selectApp(app.appId)">Open App - </button> - </div> + </ng-container> + + + <div fxFlex="100" fxLayout="column"> + <sp-basic-header-title-component title="My apps"></sp-basic-header-title-component> + <mat-card class="example-card" *ngFor="let app of apps"> + <div fxFlex="100" fxLayout="row"> + <div fxFlex="75" fxLayout="column" fxLayoutAlign="center start"> + <mat-card-header> + <mat-card-title> {{app.appName}}</mat-card-title> + <mat-card-subtitle>{{app.appDescription}}</mat-card-subtitle> + </mat-card-header> </div> - </mat-card> - </div> + <div fxFlex="25" fxLayoutAlign="center end" fxLayout="column"> + <button mat-button mat-raised-button color="accent" (click)="selectApp(app.appLink)">Open App + </button> + </div> + </div> + </mat-card> </div> - <div class="fixed-height" fxLayout="column" fxFlex="100"> - <sp-app-asset-monitoring (appOpened)="appOpened($event)" - *ngIf="currentlySelectedApp === apps[0].appId"></sp-app-asset-monitoring> - </div> -</div> +</sp-basic-view>
diff --git a/ui/src/app/app-overview/app-overview.component.ts b/ui/src/app/app-overview/app-overview.component.ts index d89f93b..8c0aaa6 100644 --- a/ui/src/app/app-overview/app-overview.component.ts +++ b/ui/src/app/app-overview/app-overview.component.ts
@@ -17,6 +17,11 @@ */ import { Component, OnInit } from '@angular/core'; +import { App } from './apps.model'; +import { AvailableAppsService } from './apps'; +import { Router } from '@angular/router'; +import { SpBreadcrumbService } from '@streampipes/shared-ui'; +import { SpAppRoutes } from './apps.routes'; @Component({ templateUrl: './app-overview.component.html', @@ -24,41 +29,20 @@ }) export class AppOverviewComponent implements OnInit { - selectedIndex = 0; - appOpen = false; - currentlySelectedApp = ''; + apps: App[] = []; - apps: any[] = [ - { - appName: 'Asset Dashboards', - appDescription: 'Monitor measurements of your assets by placing visualizations on an image of your asset.', - appId: 'asset-monitoring', - } - ]; - - constructor() { + constructor(private router: Router, + private breadcrumbService: SpBreadcrumbService) { } ngOnInit() { - + this.breadcrumbService.updateBreadcrumb(this.breadcrumbService.getRootLink(SpAppRoutes.BASE)); + this.apps = AvailableAppsService.apps; } - selectedIndexChange(index: number) { - this.selectedIndex = index; - } - - appOpened(appOpen: boolean) { - this.appOpen = appOpen; - } - - appClosed() { - this.appOpen = false; - this.currentlySelectedApp = ''; - } - - selectApp(appId: string) { - this.currentlySelectedApp = appId; + selectApp(appLink: string) { + this.router.navigate(['apps', appLink]); }
diff --git a/ui/src/app/app-overview/app-overview.module.ts b/ui/src/app/app-overview/app-overview.module.ts index 1d95617..d924dfd 100644 --- a/ui/src/app/app-overview/app-overview.module.ts +++ b/ui/src/app/app-overview/app-overview.module.ts
@@ -27,22 +27,39 @@ import { MatInputModule } from '@angular/material/input'; import { AppAssetMonitoringModule } from '../app-asset-monitoring/app-asset-monitoring.module'; import { AppOverviewComponent } from './app-overview.component'; +import { RouterModule } from '@angular/router'; +import { AvailableAppsService } from './apps'; +import { PageName } from '../_enums/page-name.enum'; +import { SharedUiModule } from '@streampipes/shared-ui'; @NgModule({ - imports: [ - CommonModule, - FlexLayoutModule, - CustomMaterialModule, - MatGridListModule, - MatInputModule, - MatFormFieldModule, - FormsModule, - AppAssetMonitoringModule, - ], - declarations: [ - AppOverviewComponent, - ], - providers: [] + imports: [ + AppAssetMonitoringModule, + CommonModule, + CustomMaterialModule, + FlexLayoutModule, + FormsModule, + MatGridListModule, + MatInputModule, + MatFormFieldModule, + SharedUiModule, + RouterModule.forChild([ + { + path: 'apps', + children: [{'path': '', component: AppOverviewComponent}, ...AvailableAppsService.apps.map(app => { + return { + path: app.appLink, + data: {authPageNames: [PageName.APPS]}, + loadChildren: app.appModuleLink + }; + }) as any] + } + ]) + ], + declarations: [ + AppOverviewComponent, + ], + providers: [] }) export class AppOverviewModule { }
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/app-overview/apps.model.ts similarity index 85% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/app-overview/apps.model.ts index 58ba04b..8d1d871 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/app-overview/apps.model.ts
@@ -16,3 +16,10 @@ * */ +export interface App { + appName: string; + appDescription: string; + appId: string; + appLink: string; + appModuleLink?: any; +}
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/app-overview/apps.routes.ts similarity index 78% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/app-overview/apps.routes.ts index 58ba04b..27f672d 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/app-overview/apps.routes.ts
@@ -16,3 +16,10 @@ * */ +import { SpBreadcrumbItem, } from '@streampipes/shared-ui'; + +export class SpAppRoutes { + + static APP_BASE_LINK = 'apps'; + static BASE: SpBreadcrumbItem = {label: 'Apps', link: [SpAppRoutes.APP_BASE_LINK]}; +}
diff --git a/ui/src/app/app.component.html b/ui/src/app/app.component.html index 83e668e..fb59095 100644 --- a/ui/src/app/app.component.html +++ b/ui/src/app/app.component.html
@@ -15,7 +15,7 @@ ~ limitations under the License. ~ --> -<ngx-loading-bar [color]="'rgb(27, 20, 100)'"></ngx-loading-bar> +<ngx-loading-bar [color]="'var(--color-loading-bar)'"></ngx-loading-bar> <div [@routeAnimations]="prepareRoute(outlet)"> <router-outlet #outlet="outlet"></router-outlet> -</div> \ No newline at end of file +</div>
diff --git a/ui/src/app/assets/assets.module.ts b/ui/src/app/assets/assets.module.ts new file mode 100644 index 0000000..89d9314 --- /dev/null +++ b/ui/src/app/assets/assets.module.ts
@@ -0,0 +1,102 @@ +/* + * 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 { MatButtonModule } from '@angular/material/button'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatGridListModule } from '@angular/material/grid-list'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { FlexLayoutModule } from '@angular/flex-layout'; +import { CommonModule } from '@angular/common'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { CustomMaterialModule } from '../CustomMaterial/custom-material.module'; +import { DragDropModule } from '@angular/cdk/drag-drop'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { CoreUiModule } from '../core-ui/core-ui.module'; +import { MatDividerModule } from '@angular/material/divider'; +import { PlatformServicesModule } from '@streampipes/platform-services'; +import { RouterModule } from '@angular/router'; +import { SharedUiModule } from '@streampipes/shared-ui'; +import { SpAssetOverviewComponent } from './components/asset-overview/asset-overview.component'; +import { AssetUploadDialogComponent } from './dialog/asset-upload/asset-upload-dialog.component'; +import { SpAssetDetailsComponent } from './components/asset-details/asset-details.component'; +import { SpAssetSelectionPanelComponent } from './components/asset-details/asset-selection-panel/asset-selection-panel.component'; +import { SpAssetDetailsPanelComponent } from './components/asset-details/asset-details-panel/asset-details-panel.component'; +import { MatTreeModule } from '@angular/material/tree'; +import { SpAssetLinkItemComponent } from './components/asset-details/asset-details-panel/asset-link-item/asset-link-item.component'; +import { EditAssetLinkDialogComponent } from './dialog/edit-asset-link/edit-asset-link-dialog.component'; +import { SpCreateAssetDialogComponent } from './dialog/create-asset/create-asset-dialog.component'; +import { SpManageAssetLinksDialogComponent } from './dialog/manage-asset-links/manage-asset-links-dialog.component'; + +@NgModule({ + imports: [ + CommonModule, + CustomMaterialModule, + FlexLayoutModule, + MatGridListModule, + MatButtonModule, + MatProgressSpinnerModule, + MatIconModule, + MatInputModule, + MatCheckboxModule, + MatDividerModule, + MatTooltipModule, + FormsModule, + DragDropModule, + CoreUiModule, + ReactiveFormsModule, + PlatformServicesModule, + RouterModule.forChild([ + { + path: 'assets', + children: [ + { + path: '', + redirectTo: 'overview', + pathMatch: 'full' + }, + { + path: 'overview', + component: SpAssetOverviewComponent + }, + { + path: 'details/:assetId', + component: SpAssetDetailsComponent + } + ] + } + ]), + SharedUiModule, + MatTreeModule, + ], + declarations: [ + AssetUploadDialogComponent, + EditAssetLinkDialogComponent, + SpAssetDetailsComponent, + SpAssetDetailsPanelComponent, + SpAssetLinkItemComponent, + SpAssetOverviewComponent, + SpAssetSelectionPanelComponent, + SpCreateAssetDialogComponent, + SpManageAssetLinksDialogComponent + ], + providers: [], +}) +export class AssetsModule {}
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.scss b/ui/src/app/assets/assets.routes.ts similarity index 75% copy from ui/src/app/pipeline-details/pipeline-details.component.scss copy to ui/src/app/assets/assets.routes.ts index a375af7..bacff60 100644 --- a/ui/src/app/pipeline-details/pipeline-details.component.scss +++ b/ui/src/app/assets/assets.routes.ts
@@ -16,7 +16,11 @@ * */ -.md-padding { - padding: 10px; -} +import { SpBreadcrumbItem, } from '@streampipes/shared-ui'; +export class SpAssetRoutes { + + static BASE: SpBreadcrumbItem = {label: 'Asset Management', link: ['assets']}; + static CREATE: SpBreadcrumbItem = {label: 'New Asset', link: ['assets', 'create']}; + +}
diff --git a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-panel.component.html b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-panel.component.html new file mode 100644 index 0000000..a3cc3d1 --- /dev/null +++ b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-panel.component.html
@@ -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. + ~ + --> + +<div fxFlex="100" fxLayout="column" class="page-container-padding-inner" *ngIf="asset"> + <sp-basic-header-title-component [title]="asset.assetName"></sp-basic-header-title-component> + + <sp-basic-inner-panel panelTitle="Basics" outerMargin="20px 0px"> + <div fxLayout="column" fxFlex="100"> + <mat-form-field color="accent"> + <mat-label>Name</mat-label> + <input matInput [(ngModel)]="asset.assetName" [disabled]="!editMode"> + </mat-form-field> + <mat-form-field color="accent"> + <mat-label>Description</mat-label> + <input matInput [(ngModel)]="asset.assetDescription" [disabled]="!editMode"> + </mat-form-field> + <mat-form-field color="accent"> + <mat-label>ID</mat-label> + <input matInput [(ngModel)]="asset.assetId" [disabled]="!editMode"> + </mat-form-field> + </div> + </sp-basic-inner-panel> + + + <sp-basic-inner-panel panelTitle="Linked Resources" outerMargin="0px 0px"> + <div header fxLayoutAlign="end center" fxLayout="row" fxFlex="100"> + <button mat-button color="accent" *ngIf="editMode" (click)="openManageAssetLinksDialog()"><i class="material-icons">add</i><span> Manage links</span></button> + <button mat-button color="accent" *ngIf="editMode" (click)="openCreateAssetLinkDialog()"><i class="material-icons">add</i><span> Add link</span></button> + </div> + <div fxLayout="column" fxFlex="100" *ngIf="assetLinkTypes"> + <div fxLayout="column" *ngFor="let link of asset.assetLinks; let i = index"> + <sp-asset-link-item-component [assetLink]="link" + [assetLinkIndex]="i" + [assetLinkTypes]="assetLinkTypes" + [editMode]="editMode" + (openEditAssetLinkEmitter)="openEditAssetLinkDialog($event.assetLink, $event.index, false)" + (deleteAssetLinkEmitter)="deleteAssetLink($event)" + class="asset-link-item"> + </sp-asset-link-item-component> + + </div> + </div> + </sp-basic-inner-panel> +</div>
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.scss b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-panel.component.scss similarity index 79% copy from ui/src/app/pipeline-details/pipeline-details.component.scss copy to ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-panel.component.scss index a375af7..1dba0de 100644 --- a/ui/src/app/pipeline-details/pipeline-details.component.scss +++ b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-panel.component.scss
@@ -16,7 +16,15 @@ * */ -.md-padding { - padding: 10px; +.asset-link-item:nth-child(odd) { + background: var(--color-bg-1); } +.asset-link-item:nth-child(even) { + background: var(--color-bg-1); +} + +.asset-link-item { + border-bottom: 1px solid var(--color-bg-3); + padding: 10px; +}
diff --git a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-panel.component.ts b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-panel.component.ts new file mode 100644 index 0000000..9bb9755 --- /dev/null +++ b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-panel.component.ts
@@ -0,0 +1,116 @@ +/* + * 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, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { AssetLink, AssetLinkType, GenericStorageService, SpAsset } from '@streampipes/platform-services'; +import { AssetConstants } from '../../../constants/asset.constants'; +import { AssetUploadDialogComponent } from '../../../dialog/asset-upload/asset-upload-dialog.component'; +import { DialogService, PanelType } from '../../../../../../dist/streampipes/shared-ui'; +import { EditAssetLinkDialogComponent } from '../../../dialog/edit-asset-link/edit-asset-link-dialog.component'; +import { SpManageAssetLinksDialogComponent } from '../../../dialog/manage-asset-links/manage-asset-links-dialog.component'; + + +@Component({ + selector: 'sp-asset-details-panel-component', + templateUrl: './asset-details-panel.component.html', + styleUrls: ['./asset-details-panel.component.scss'] +}) +export class SpAssetDetailsPanelComponent implements OnInit { + + @Input() + asset: SpAsset; + + @Input() + editMode: boolean; + + @Output() + updateAssetEmitter: EventEmitter<SpAsset> = new EventEmitter<SpAsset>(); + + assetLinkTypes: AssetLinkType[]; + + constructor(private genericStorageService: GenericStorageService, + private dialogService: DialogService) { + + } + + ngOnInit(): void { + this.genericStorageService.getAllDocuments(AssetConstants.ASSET_LINK_TYPES_DOC_NAME).subscribe(assetLinkTypes => { + this.assetLinkTypes = assetLinkTypes.sort((a, b) => a.linkLabel.localeCompare(b.linkLabel)); + }); + } + + openManageAssetLinksDialog(): void { + const dialogRef = this.dialogService.open(SpManageAssetLinksDialogComponent, { + panelType: PanelType.SLIDE_IN_PANEL, + title: 'Manage asset links', + width: '50vw', + data: { + 'assetLinks': this.asset.assetLinks, + 'assetLinkTypes': this.assetLinkTypes + } + }); + + dialogRef.afterClosed().subscribe(assetLinks => { + if (assetLinks) { + this.asset.assetLinks = assetLinks; + } + }); + } + + openEditAssetLinkDialog(assetLink: AssetLink, index: number, createMode: boolean): void { + const dialogRef = this.dialogService.open(EditAssetLinkDialogComponent, { + panelType: PanelType.SLIDE_IN_PANEL, + title: createMode ? 'Create ' : 'Update ' + 'asset model', + width: '50vw', + data: { + 'assetLink': assetLink, + 'assetLinkTypes': this.assetLinkTypes, + 'createMode': createMode + } + }); + + dialogRef.afterClosed().subscribe(storedLink => { + if (storedLink) { + if (index > -1) { + this.asset.assetLinks[index] = storedLink; + } else { + this.asset.assetLinks.push(storedLink); + } + this.updateAssetEmitter.emit(this.asset); + } + }); + } + + openCreateAssetLinkDialog(): void { + const assetLink: AssetLink = { + linkLabel: '', + linkType: 'data-view', + editingDisabled: false, + resourceId: '', + navigationActive: true, + queryHint: 'data-view' + }; + this.openEditAssetLinkDialog(assetLink, -1, true); + } + + deleteAssetLink(index: number): void { + this.asset.assetLinks.splice(index, 1); + this.updateAssetEmitter.emit(this.asset); + } + +}
diff --git a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-link-item/asset-link-item.component.html b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-link-item/asset-link-item.component.html new file mode 100644 index 0000000..c9c645a --- /dev/null +++ b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-link-item/asset-link-item.component.html
@@ -0,0 +1,37 @@ +<!-- + ~ 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"> + <div fxLayout="row" fxLayoutGap="10px"> + <div fxLayoutAlign="center center"> + <div fxLayoutAlign="center center" class="link-icon" [ngStyle]="{'background': currentAssetLinkType.linkColor}"> + <i class="material-icons">{{currentAssetLinkType.linkIcon}}</i> + </div> + </div> + <div fxLayoutAlign="start center"><span class="link-label">{{assetLink.linkLabel}}</span></div> + <div fxFlex></div> + <div fxLayoutAlign="end center"> + <button mat-button mat-icon-button color="accent" (click)="openLink()" *ngIf="assetLink.navigationActive"><i class="material-icons">link</i> + </button> + <button mat-button mat-icon-button color="accent" (click)="editLink()" *ngIf="editMode"><i + class="material-icons">edit</i></button> + <button mat-button mat-icon-button color="accent" (click)="deleteLink()" *ngIf="editMode"><i + class="material-icons">delete</i></button> + </div> + </div> +</div>
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.scss b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-link-item/asset-link-item.component.scss similarity index 73% copy from ui/src/app/pipeline-details/pipeline-details.component.scss copy to ui/src/app/assets/components/asset-details/asset-details-panel/asset-link-item/asset-link-item.component.scss index a375af7..11c71ec 100644 --- a/ui/src/app/pipeline-details/pipeline-details.component.scss +++ b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-link-item/asset-link-item.component.scss
@@ -16,7 +16,22 @@ * */ -.md-padding { - padding: 10px; +.link-type { + background: var(--color-primary); + padding: 5px; + border-radius: 5px; } +.link-label { + margin-right: 15px; + font-weight: 500; +} + +.link-icon { + border-radius: 50%; + width: 40px; + height: 40px; + padding: 5px; + color: var(--color-bg-1); + background: var(--color-bg-3); +}
diff --git a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-link-item/asset-link-item.component.ts b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-link-item/asset-link-item.component.ts new file mode 100644 index 0000000..49dd4fd --- /dev/null +++ b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-link-item/asset-link-item.component.ts
@@ -0,0 +1,70 @@ +/* + * 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, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { AssetLink, AssetLinkType } from '@streampipes/platform-services'; +import { Router } from '@angular/router'; + +@Component({ + selector: 'sp-asset-link-item-component', + templateUrl: './asset-link-item.component.html', + styleUrls: ['./asset-link-item.component.scss'] +}) +export class SpAssetLinkItemComponent implements OnInit { + + @Input() + assetLink: AssetLink; + + @Input() + assetLinkIndex: number; + + @Input() + assetLinkTypes: AssetLinkType[]; + + @Input() + editMode: boolean; + + @Output() + openEditAssetLinkEmitter: EventEmitter<{assetLink: AssetLink, index: number}> = new EventEmitter<{assetLink: AssetLink, index: number}>(); + + @Output() + deleteAssetLinkEmitter: EventEmitter<number> = new EventEmitter<number>(); + + currentAssetLinkType: AssetLinkType; + + constructor(private router: Router) { + + } + + ngOnInit(): void { + this.currentAssetLinkType = this.assetLinkTypes.find(t => t.linkType === this.assetLink.linkType); + } + + openLink(): void { + this.router.navigate([...this.currentAssetLinkType.navPaths, this.assetLink.resourceId]); + } + + editLink(): void { + this.openEditAssetLinkEmitter.emit({assetLink: this.assetLink, index: this.assetLinkIndex}); + } + + deleteLink(): void { + this.deleteAssetLinkEmitter.emit(this.assetLinkIndex); + } +}
diff --git a/ui/src/app/assets/components/asset-details/asset-details.component.html b/ui/src/app/assets/components/asset-details/asset-details.component.html new file mode 100644 index 0000000..ceec6c5 --- /dev/null +++ b/ui/src/app/assets/components/asset-details/asset-details.component.html
@@ -0,0 +1,61 @@ +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~ + --> +<sp-basic-view [showBackLink]="true" + [backLinkTarget]="['assets']" + [padding]="false"> + + <div nav fxFlex="100" fxLayoutAlign="start center" fxLayout="row" class="pl-10"> + <div fxLayout="row" fxLayoutAlign="start center" *ngIf="editMode"> + <button mat-button mat-raised-button color="accent" (click)="saveAsset()"> + <i class="material-icons">save</i><span> Save</span> + </button> + </div> + <div fxFlex fxLayout="row" fxLayoutAlign="end center"> + + </div> + </div> + <div fxFlex="100" fxLayout="column" *ngIf="asset"> + <mat-drawer-container class="designer-panel-container h-100 dashboard-grid"> + <mat-drawer #designerDrawer + [opened]="true" + mode="side" + position="start" + class="designer-panel"> + <div fxLayout="column" fxFlex="100"> + <sp-asset-selection-panel-component + [editMode]="editMode" + [assetModel]="asset" + [selectedAsset]="selectedAsset" + (selectedAssetEmitter)="selectedAsset = $event"> + </sp-asset-selection-panel-component> + </div> + </mat-drawer> + <mat-drawer-content class="h-100 dashboard-grid"> + <sp-asset-details-panel-component + *ngIf="selectedAsset" + [asset]="selectedAsset" + [editMode]="editMode" + (updateAssetEmitter)="updateAsset()" + fxFlex="100" + fxLayout="row"> + + </sp-asset-details-panel-component> + </mat-drawer-content> + </mat-drawer-container> + </div> +</sp-basic-view>
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/assets/components/asset-details/asset-details.component.scss similarity index 81% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/assets/components/asset-details/asset-details.component.scss index 58ba04b..676e7ab 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/assets/components/asset-details/asset-details.component.scss
@@ -16,3 +16,17 @@ * */ +.dashboard-grid { + display:flex; + flex-direction: column; + flex: 1 1 100%; +} + +.designer-panel-container { + width: 100%; + height: 100%; +} + +.designer-panel { + width: 400px; +}
diff --git a/ui/src/app/assets/components/asset-details/asset-details.component.ts b/ui/src/app/assets/components/asset-details/asset-details.component.ts new file mode 100644 index 0000000..8f3750c --- /dev/null +++ b/ui/src/app/assets/components/asset-details/asset-details.component.ts
@@ -0,0 +1,95 @@ +/* + * 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 { SpBreadcrumbService } from '@streampipes/shared-ui'; +import { ActivatedRoute } from '@angular/router'; +import { AssetConstants } from '../../constants/asset.constants'; +import { GenericStorageService, SpAsset, SpAssetModel } from '@streampipes/platform-services'; +import { SpAssetRoutes } from '../../assets.routes'; + +@Component({ + selector: 'sp-asset-details-component', + templateUrl: './asset-details.component.html', + styleUrls: ['./asset-details.component.scss'] +}) +export class SpAssetDetailsComponent implements OnInit { + + asset: SpAssetModel; + + selectedAsset: SpAsset; + + editMode: boolean; + + assetModelId: string; + + constructor(private breadcrumbService: SpBreadcrumbService, + private genericStorageService: GenericStorageService, + private route: ActivatedRoute) { + + } + + ngOnInit(): void { + this.assetModelId = this.route.snapshot.params.assetId; + this.editMode = this.route.snapshot.queryParams.editMode; + this.loadAsset(); + } + + loadAsset(): void { + this.genericStorageService.getDocument(AssetConstants.ASSET_APP_DOC_NAME, this.assetModelId).subscribe(asset => { + this.asset = asset; + if (!this.selectedAsset) { + this.selectedAsset = this.asset; + } + this.breadcrumbService.updateBreadcrumb([SpAssetRoutes.BASE, {label: this.asset.assetName}]); + }); + } + + updateAsset() { + this.updateSelected(); + } + + saveAsset() { + this.genericStorageService.updateDocument(AssetConstants.ASSET_APP_DOC_NAME, this.asset).subscribe(res => { + this.loadAsset(); + this.editMode = false; + }); + } + + updateSelected() { + if (this.asset.assetId === this.selectedAsset.assetId) { + this.asset = this.selectedAsset as SpAssetModel; + } else { + this.asset.assets.forEach(a => { + this.walk(a, this.selectedAsset); + }); + } + } + + walk(asset: SpAsset, selectedAsset: SpAsset) { + if (asset.assetId === selectedAsset.assetId) { + asset = selectedAsset; + } else { + if (asset.assets) { + asset.assets.forEach(a => { + this.walk(a, selectedAsset); + }); + } + } + } +}
diff --git a/ui/src/app/assets/components/asset-details/asset-selection-panel/asset-selection-panel.component.html b/ui/src/app/assets/components/asset-details/asset-selection-panel/asset-selection-panel.component.html new file mode 100644 index 0000000..5622b58 --- /dev/null +++ b/ui/src/app/assets/components/asset-details/asset-selection-panel/asset-selection-panel.component.html
@@ -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. + ~ + --> + +<div fxFlex="100" fxLayout="column" class="designer-panel-content" *ngIf="assetModel"> + <div fxLayout="row" class="sp-tab-bg designer-panel-header"> + <div fxLayoutAlign="start center" class="designer-panel-title"><h4>Asset Browser</h4></div> + <div fxFlex fxLayoutAlign="end end"> + + </div> + </div> + <div fxFlex="100" fxLayout="column"> + <div fxFlex fxLayout="column" class="designer-panel-config"> + <mat-tree [dataSource]="dataSource" [treeControl]="treeControl" class="sp-tree" #tree> + <mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle> + <div [ngClass]="node.assetId === selectedAsset.assetId ? 'asset-node selected-node' : 'asset-node'" + fxLayout="row" fxFlex="100" (click)="selectNode(node)" > + <span fxLayoutAlign="end center">{{node.assetName}}</span> + <div fxLayoutAlign="end center" fxFlex *ngIf="editMode"> + <button mat-button + mat-icon-button + (click)="addAsset(node)" + color="accent"> + <i class="material-icons">add</i></button> + <button mat-button + mat-icon-button + (click)="deleteAsset(node)" + color="accent"> + <i class="material-icons">delete</i></button> + </div> + </div> + </mat-tree-node> + <mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild"> + <div class="mat-tree-node"> + <button mat-icon-button matTreeNodeToggle + [attr.data-cy]="'button-' +node.nodeName" + [attr.aria-label]="'Toggle ' + node.nodeName"> + <mat-icon class="mat-icon-rtl-mirror"> + {{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}} + </mat-icon> + </button> + <div [ngClass]="node.assetId === selectedAsset.assetId ? 'asset-node selected-node' : 'asset-node'" + fxLayout="row" fxFlex="100" (click)="selectNode(node)" > + <span fxLayoutAlign="start center">{{node.assetName}}</span> + <div fxLayoutAlign="end center" fxFlex *ngIf="editMode"> + <button mat-button + mat-icon-button + (click)="addAsset(node)" + color="accent"> + <i class="material-icons">add</i></button> + </div> + </div> + </div> + <div [class.sp-tree-invisible]="!treeControl.isExpanded(node)" + role="group"> + <ng-container matTreeNodeOutlet></ng-container> + </div> + </mat-nested-tree-node> + </mat-tree> + </div> + </div> +</div>
diff --git a/ui/src/app/assets/components/asset-details/asset-selection-panel/asset-selection-panel.component.scss b/ui/src/app/assets/components/asset-details/asset-selection-panel/asset-selection-panel.component.scss new file mode 100644 index 0000000..2f3b831 --- /dev/null +++ b/ui/src/app/assets/components/asset-details/asset-selection-panel/asset-selection-panel.component.scss
@@ -0,0 +1,69 @@ +/* + * 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. + * + */ + +.designer-panel-content { + padding: 0; + overflow-y: auto; +} + +.designer-panel-config { + padding: 0; +} + +.designer-panel-title { + margin-left: 5px; +} + +.designer-panel-header { + border-bottom:1px solid var(--color-tab-border); +} + +.sp-tree-invisible { + display: none; +} + +.sp-tree ul, +.sp-tree li { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +.sp-tree .mat-nested-tree-node div[role=group] { + padding-left: 20px; +} + +.sp-tree div[role=group] > .mat-tree-node { + padding-left: 20px; +} + +.asset-node { + font-weight: normal; + cursor: pointer; + font-size: 13pt; + width: 100%; + margin-right: 10px; + padding-left: 5px; + height: 50px; +} + +.selected-node { + font-weight: bold; + background: var(--color-bg-2); + border-bottom: 2px solid var(--color-primary); +}
diff --git a/ui/src/app/assets/components/asset-details/asset-selection-panel/asset-selection-panel.component.ts b/ui/src/app/assets/components/asset-details/asset-selection-panel/asset-selection-panel.component.ts new file mode 100644 index 0000000..4bf1f1d --- /dev/null +++ b/ui/src/app/assets/components/asset-details/asset-selection-panel/asset-selection-panel.component.ts
@@ -0,0 +1,104 @@ +/* + * 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 { AfterViewInit, Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; +import { SpAsset, SpAssetModel } from '@streampipes/platform-services'; +import { NestedTreeControl } from '@angular/cdk/tree'; +import { MatTreeNestedDataSource } from '@angular/material/tree'; + +@Component({ + selector: 'sp-asset-selection-panel-component', + templateUrl: './asset-selection-panel.component.html', + styleUrls: ['./asset-selection-panel.component.scss'] +}) +export class SpAssetSelectionPanelComponent implements OnInit { + + @Input() + assetModel: SpAssetModel; + + @Input() + selectedAsset: SpAsset; + + @Input() + editMode: boolean; + + @Output() + selectedAssetEmitter: EventEmitter<SpAsset> = new EventEmitter<SpAsset>(); + + treeControl = new NestedTreeControl<SpAsset>(node => node.assets); + dataSource = new MatTreeNestedDataSource<SpAsset>(); + + @ViewChild('tree') tree; + + hasChild = (_: number, node: SpAsset) => !!node.assets && node.assets.length > 0; + + ngOnInit(): void { + this.treeControl = new NestedTreeControl<SpAsset>(node => node.assets); + this.dataSource = new MatTreeNestedDataSource<SpAsset>(); + this.dataSource.data = [this.assetModel]; + this.treeControl.dataNodes = [this.assetModel]; + this.treeControl.expandAll(); + } + + selectNode(asset: SpAsset) { + this.selectedAssetEmitter.emit(asset); + } + + addAsset(node: SpAsset) { + if (!node.assets) { + node.assets = []; + } + node.assets.push(this.makeNewAsset()); + this.dataSource.data = [this.assetModel]; + this.treeControl.dataNodes = [this.assetModel]; + this.rerenderTree(); + } + + deleteAsset(node: SpAsset) { + this.removeAssetWithId(this.assetModel.assets, node.assetId); + this.rerenderTree(); + } + + removeAssetWithId(assets: SpAsset[], id: string) { + for (let i = 0; i < assets.length; i++) { + if (assets[i].assetId === id) { + assets.splice(i, 1); + return; + } + if (assets[i].assets) { + this.removeAssetWithId(assets[i].assets, id); + } + } + } + + rerenderTree(): void { + this.dataSource.data = null; + this.dataSource.data = [this.assetModel]; + this.treeControl.expandAll(); + + + } + + makeNewAsset(): SpAsset { + return {assetId: this.makeAssetId(), assetName: 'New Asset', assetDescription: '', assetLinks: [], assetType: undefined, assets: []}; + } + + makeAssetId(): string { + return 'a' + Math.random().toString(36).substring(2, 9); + } +}
diff --git a/ui/src/app/assets/components/asset-overview/asset-overview.component.html b/ui/src/app/assets/components/asset-overview/asset-overview.component.html new file mode 100644 index 0000000..9fcac02 --- /dev/null +++ b/ui/src/app/assets/components/asset-overview/asset-overview.component.html
@@ -0,0 +1,119 @@ +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~ + --> +<sp-basic-view [showBackLink]="false" [padding]="true"> + + <div nav fxFlex="100" fxLayoutAlign="start center" fxLayout="row" class="pl-10"> + <button mat-button + mat-raised-button + color="accent" + data-cy="connect-create-new-adapter-button" + (click)="createNewAsset()"> + <i class="material-icons">add</i> New asset + </button> + <div fxFlex fxLayout="row" fxLayoutAlign="end center"> + <button mat-button mat-icon-button matTooltip="Refresh assets" matTooltipPosition="below" color="accent" + (click)="loadAssets()"> + <i class="material-icons"> + refresh + </i> + </button> + <button mat-button mat-icon-button matTooltip="Upload assets" matTooltipPosition="below" color="accent" + (click)="uploadAsset()"> + <i class="material-icons"> + cloud_upload + </i> + </button> + </div> + </div> + <div fxFlex="100" fxLayout="column"> + <sp-basic-header-title-component title="My assets"></sp-basic-header-title-component> + <div fxFlex="100" fxLayout="row" fxLayoutAlign="center start"> + <sp-basic-inner-panel [showTitle]="false" innerPadding="0" outerMargin="0" fxFlex="90" [hideToolbar]="true"> + <div fxFlex="100" fxLayout="column" *ngIf="existingAssets.length > 0"> + <div fxFlex="100" fxLayout="column"> + <table fxFlex="100" mat-table [dataSource]="dataSource" style="width: 100%;" matSort> + + <ng-container matColumnDef="name"> + <th mat-header-cell mat-sort-header *matHeaderCellDef> Name</th> + <td mat-cell *matCellDef="let asset"> + <div fxLayout="row" fxLayoutAlign="start center"> + <div fxLayoutAlign="start center"> + <i class="material-icons">precision_manufacturing</i> + </div> + <div fxLayoutAlign="center start" fxLayout="column" class="ml-10"> + <h4 style="margin-bottom:0px;">{{asset.assetName}}</h4> + <h5>{{asset.assetDescription != '' ? asset.assetDescription : '-'}}</h5> + </div> + </div> + + </td> + </ng-container> + <ng-container matColumnDef="action"> + <th mat-header-cell *matHeaderCellDef style="justify-content: center;"> Actions</th> + <td mat-cell *matCellDef="let asset"> + <div fxLayout="row"> + <span fxFlex fxFlexOrder="1" fxLayout="row" fxLayoutAlign="center center"> + <button color="accent" mat-button mat-icon-button matTooltip="Show info" + matTooltipPosition="above" (click)="goToDetailsView(asset)"><i + class="material-icons">search</i> + </button> + </span> + <span fxFlex fxFlexOrder="2" fxLayout="row" fxLayoutAlign="center center"> + <button color="accent" mat-button mat-icon-button matTooltip="Edit asset" + matTooltipPosition="above" (click)="goToDetailsView(asset, true)"><i + class="material-icons">edit</i> + </button> + </span> + <span fxFlex fxFlexOrder="3" fxLayout="row" fxLayoutAlign="center center"> +<!-- <button color="accent" mat-button mat-icon-button matTooltip="Manage permissions"--> + <!-- matTooltipPosition="above" (click)="showPermissionsDialog(adapter)"><i--> + <!-- class="material-icons">share</i>--> + <!-- </button>--> + </span> + <span fxFlex fxFlexOrder="4" fxLayout="row" fxLayoutAlign="center center"> + <button color="accent" mat-button mat-icon-button matTooltip="Delete adapter" + data-cy="delete" matTooltipPosition="above" (click)="deleteAsset(asset)"> + <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> + <div fxFlex="100" fxLayoutAlign="end end"> + <mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" + [pageSize]="20" + color="accent"> + </mat-paginator> + </div> + </div> + <div fxFlex="100" + fxLayout="column" + fxLayoutAlign="center center" + *ngIf="existingAssets.length == 0"> + <h5>(no assets available)</h5> + </div> + </sp-basic-inner-panel> + </div> + </div> +</sp-basic-view>
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/assets/components/asset-overview/asset-overview.component.scss similarity index 95% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/assets/components/asset-overview/asset-overview.component.scss index 58ba04b..d172895 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/assets/components/asset-overview/asset-overview.component.scss
@@ -16,3 +16,6 @@ * */ +.ml-10 { + margin-left: 10px; +}
diff --git a/ui/src/app/assets/components/asset-overview/asset-overview.component.ts b/ui/src/app/assets/components/asset-overview/asset-overview.component.ts new file mode 100644 index 0000000..1800e33 --- /dev/null +++ b/ui/src/app/assets/components/asset-overview/asset-overview.component.ts
@@ -0,0 +1,134 @@ +/* + * 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 { MatTableDataSource } from '@angular/material/table'; +import { GenericStorageService, SpAssetModel } from '@streampipes/platform-services'; +import { AssetConstants } from '../../constants/asset.constants'; +import { DialogService, PanelType, SpBreadcrumbService } from '@streampipes/shared-ui'; +import { SpAssetRoutes } from '../../assets.routes'; +import { AssetUploadDialogComponent } from '../../dialog/asset-upload/asset-upload-dialog.component'; +import { Router } from '@angular/router'; +import { SpCreateAssetDialogComponent } from '../../dialog/create-asset/create-asset-dialog.component'; + +@Component({ + selector: 'sp-asset-overview-component', + templateUrl: './asset-overview.component.html', + styleUrls: ['./asset-overview.component.scss'] +}) +export class SpAssetOverviewComponent implements OnInit { + + existingAssets: SpAssetModel[] = []; + + displayedColumns: string[] = ['name', 'action']; + + dataSource: MatTableDataSource<SpAssetModel>; + + constructor(private genericStorageService: GenericStorageService, + private breadcrumbService: SpBreadcrumbService, + private dialogService: DialogService, + private router: Router) { + + } + + ngOnInit(): void { + this.breadcrumbService.updateBreadcrumb(this.breadcrumbService.getRootLink(SpAssetRoutes.BASE)); + this.loadAssets(); + } + + loadAssets(): void { + this.genericStorageService.getAllDocuments(AssetConstants.ASSET_APP_DOC_NAME).subscribe(result => { + this.existingAssets = result as SpAssetModel[]; + this.dataSource = new MatTableDataSource<SpAssetModel>(this.existingAssets); + }); + } + + createNewAsset(assetModel?: SpAssetModel) { + if (!assetModel) { + assetModel = { + assetName: 'New Asset', + assetDescription: '', + assetLinks: [], + assetId: this.generateId(6), + _id: this.generateId(24), + appDocType: 'asset-management', + removable: true, + _rev: undefined, + assets: [], + assetType: undefined + }; + } + const dialogRef = this.dialogService.open(SpCreateAssetDialogComponent, { + panelType: PanelType.STANDARD_PANEL, + title: 'Create asset', + width: '40vw', + data: { + 'createMode': true, + 'assetModel': assetModel + } + }); + + dialogRef.afterClosed().subscribe(() => { + this.loadAssets(); + }); + } + + private generateId(length): string { + const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + let result = ''; + for (let i = length; i > 0; --i) { + result += chars[Math.round(Math.random() * (chars.length - 1))]; + } + return result; + } + + uploadAsset() { + const dialogRef = this.dialogService.open(AssetUploadDialogComponent, { + panelType: PanelType.SLIDE_IN_PANEL, + title: 'Upload asset model', + width: '40vw', + }); + + dialogRef.afterClosed().subscribe(reload => { + if (reload) { + this.loadAssets(); + } + }); + } + + goToDetailsView(asset: SpAssetModel, + editMode = false) { + if (!editMode) { + this.router.navigate(['assets', 'details', asset._id]); + } else { + this.router.navigate(['assets', 'details', asset._id], {queryParams: {'editMode': editMode}}); + } + } + + deleteAsset(asset: SpAssetModel) { + this.genericStorageService.deleteDocument( + AssetConstants.ASSET_APP_DOC_NAME, + asset._id, + asset._rev) + .subscribe(result => { + this.loadAssets(); + }); + } + + +}
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/assets/constants/asset.constants.ts similarity index 83% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/assets/constants/asset.constants.ts index 58ba04b..ee412ee 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/assets/constants/asset.constants.ts
@@ -16,3 +16,8 @@ * */ +export class AssetConstants { + + public static ASSET_APP_DOC_NAME = 'asset-management'; + public static ASSET_LINK_TYPES_DOC_NAME = 'asset-link-type'; +}
diff --git a/ui/src/app/assets/dialog/asset-upload/asset-upload-dialog.component.html b/ui/src/app/assets/dialog/asset-upload/asset-upload-dialog.component.html new file mode 100644 index 0000000..9cd6bf1 --- /dev/null +++ b/ui/src/app/assets/dialog/asset-upload/asset-upload-dialog.component.html
@@ -0,0 +1,68 @@ +<!-- +~ 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" fxLayout="column"> + <div fxFlex style="margin:5px;width:100%" fxLayout="column"> + <mat-form-field style="width: 95%" (click)="fileInput.click();" color="accent"> + <mat-label>Upload JSON file</mat-label> + <input matInput placeholder="File" disabled (value)="fileName"> + <input #fileInput type="file" style="display:none;" + (change)="handleFileInput($event.target.files)" + data-cy="sp-file-management-file-input"> + <div> + {{fileName}} + <mat-progress-bar mode="determinate" value="{{uploadStatus}}" *ngIf="uploadStatus > 0" color="accent"></mat-progress-bar> + </div> + <button color="accent" 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 fxFlex="100"> + <mat-form-field style="width: 100%;height: 100%;" color="accent"> + <mat-label>Insert model</mat-label> + <textarea matInput [(ngModel)]="jsonModel" style="height: 100%;" + cdkTextareaAutosize + cdkAutosizeMinRows="30" + cdkAutosizeMaxRows="30"></textarea> + </mat-form-field> + </div> + </div> + </div> + <mat-divider></mat-divider> + <div class="sp-dialog-actions"> + <button mat-button + mat-raised-button + color="accent" + [disabled]="jsonModel === undefined" + (click)="store()" data-cy="sp-file-management-store-file" style="margin-right:10px;"> + Create asset + </button> + <button mat-button mat-raised-button class="mat-basic" (click)="cancel()" style="margin-right:10px;"> + Cancel + </button> + </div> +</div>
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/assets/dialog/asset-upload/asset-upload-dialog.component.scss similarity index 95% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/assets/dialog/asset-upload/asset-upload-dialog.component.scss index 58ba04b..d25ee74 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/assets/dialog/asset-upload/asset-upload-dialog.component.scss
@@ -16,3 +16,4 @@ * */ +@import 'src/scss/sp/sp-dialog'; \ No newline at end of file
diff --git a/ui/src/app/assets/dialog/asset-upload/asset-upload-dialog.component.ts b/ui/src/app/assets/dialog/asset-upload/asset-upload-dialog.component.ts new file mode 100644 index 0000000..b1f52f1 --- /dev/null +++ b/ui/src/app/assets/dialog/asset-upload/asset-upload-dialog.component.ts
@@ -0,0 +1,77 @@ +/* + * 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 '@streampipes/shared-ui'; +import { GenericStorageService } from '@streampipes/platform-services'; +import { AssetConstants } from '../../constants/asset.constants'; + +@Component({ + selector: 'sp-file-upload-dialog-component', + templateUrl: './asset-upload-dialog.component.html', + styleUrls: ['./asset-upload-dialog.component.scss'] +}) +export class AssetUploadDialogComponent implements OnInit { + + inputValue: string; + fileName: string; + + jsonModel: string; + + hasInput: boolean; + errorMessage = 'Please enter a value'; + + uploadStatus = 0; + + constructor(private dialogRef: DialogRef<AssetUploadDialogComponent>, + private genericStorageService: GenericStorageService) { + + } + + ngOnInit(): void { + } + + handleFileInput(files: any) { + this.uploadStatus = 0; + + const fr = new FileReader(); + + fr.onload = (ev => { + const jsonObject = JSON.parse(ev.target.result as string); + this.jsonModel = JSON.stringify(jsonObject, null, 2); + }); + + fr.readAsText(files.item(0)); + } + + store() { + this.uploadStatus = 0; + if (this.jsonModel !== undefined) { + const jsonObject = JSON.parse(this.jsonModel); + jsonObject._rev = undefined; + this.genericStorageService.createDocument(AssetConstants.ASSET_APP_DOC_NAME, jsonObject).subscribe(result => { + this.dialogRef.close(true); + }); + } + } + + cancel() { + this.dialogRef.close(); + } + +}
diff --git a/ui/src/app/assets/dialog/base-asset-links.directive.ts b/ui/src/app/assets/dialog/base-asset-links.directive.ts new file mode 100644 index 0000000..28df15b --- /dev/null +++ b/ui/src/app/assets/dialog/base-asset-links.directive.ts
@@ -0,0 +1,98 @@ +/* + * 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 { Directive } from '@angular/core'; +import { + AdapterDescriptionUnion, AdapterService, + Dashboard, DashboardService, + DataLakeMeasure, DatalakeRestService, DataViewDataExplorerService, FileMetadata, FilesService, GenericStorageService, + Pipeline, PipelineElementService, PipelineService, + SpDataStream +} from '@streampipes/platform-services'; +import { zip } from 'rxjs'; + +@Directive() +export abstract class BaseAssetLinksDirective { + + // Resources + pipelines: Pipeline[]; + dataViews: Dashboard[]; + dashboards: Dashboard[]; + dataLakeMeasures: DataLakeMeasure[]; + dataSources: SpDataStream[]; + adapters: AdapterDescriptionUnion[]; + files: FileMetadata[]; + + allResources: any[] = []; + + constructor(protected genericStorageService: GenericStorageService, + protected pipelineService: PipelineService, + protected dataViewService: DataViewDataExplorerService, + protected dashboardService: DashboardService, + protected dataLakeService: DatalakeRestService, + protected pipelineElementService: PipelineElementService, + protected adapterService: AdapterService, + protected filesService: FilesService) { + + } + + onInit() { + this.getAllResources(); + } + + getAllResources() { + zip( + this.pipelineService.getOwnPipelines(), + this.dataViewService.getDataViews(), + this.dashboardService.getDashboards(), + this.pipelineElementService.getDataStreams(), + this.dataLakeService.getAllMeasurementSeries(), + this.filesService.getFileMetadata(), + this.adapterService.getAdapters()).subscribe(( + [pipelines, + dataViews, + dashboards, + streams, + measurements, + files, + adapters + ]) => { + this.pipelines = pipelines.sort((a, b) => a.name.localeCompare(b.name)); + this.dataViews = dataViews.sort((a, b) => a.name.localeCompare(b.name)); + this.dashboards = dashboards.sort((a, b) => a.name.localeCompare(b.name)); + this.dataSources = streams.sort((a, b) => a.name.localeCompare(b.name)); + this.dataLakeMeasures = measurements.sort((a, b) => a.measureName.localeCompare(b.measureName)); + this.files = files.sort((a, b) => a.originalFilename.localeCompare(b.originalFilename)); + this.adapters = adapters.sort((a, b) => a.name.localeCompare(b.name)); + + this.allResources = [ + ...this.pipelines, + ...this.dataViews, + ...this.dashboards, + ...this.dataSources, + ...this.dataLakeMeasures, + ...this.files, + ...this.adapters + ]; + this.afterResourcesLoaded(); + }); + } + + abstract afterResourcesLoaded(): void; +} +
diff --git a/ui/src/app/assets/dialog/create-asset/create-asset-dialog.component.html b/ui/src/app/assets/dialog/create-asset/create-asset-dialog.component.html new file mode 100644 index 0000000..3515fd9 --- /dev/null +++ b/ui/src/app/assets/dialog/create-asset/create-asset-dialog.component.html
@@ -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. +~ +--> + +<div class="sp-dialog-container"> + <div class="sp-dialog-content p-15"> + <div fxFlex="100"> + <div fxFlex="100" fxLayout="column" style="margin:5px;width:100%"> + <mat-form-field class="full-width" color="accent"> + <mat-label>Asset Name</mat-label> + <input matInput + data-cy="asset-name" + [(ngModel)]="assetModel.assetName"> + </mat-form-field> + <mat-form-field class="full-width" color="accent"> + <mat-label>Description</mat-label> + <input matInput [(ngModel)]="assetModel.assetDescription"> + </mat-form-field> + </div> + </div> + </div> + <mat-divider></mat-divider> + <div class="sp-dialog-actions actions-align-right"> + <button mat-button mat-raised-button class="mat-basic mr-10" + (click)="onCancel()" style="margin-right: 10px;"> + Close + </button> + <button mat-button mat-raised-button color="accent" + data-cy="save-data-view" + (click)="onSave()"> + {{createMode ? 'Create' : 'Save'}} + </button> + </div> +</div> + +
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/assets/dialog/create-asset/create-asset-dialog.component.scss similarity index 95% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/assets/dialog/create-asset/create-asset-dialog.component.scss index 58ba04b..704f843 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/assets/dialog/create-asset/create-asset-dialog.component.scss
@@ -16,3 +16,4 @@ * */ +@import 'src/scss/sp/sp-dialog';
diff --git a/ui/src/app/assets/dialog/create-asset/create-asset-dialog.component.ts b/ui/src/app/assets/dialog/create-asset/create-asset-dialog.component.ts new file mode 100644 index 0000000..460a304 --- /dev/null +++ b/ui/src/app/assets/dialog/create-asset/create-asset-dialog.component.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 { Component, Input, OnInit } from '@angular/core'; +import { AssetManagementService, DataViewDataExplorerService, SpAssetModel } from '@streampipes/platform-services'; +import { DialogRef } from '@streampipes/shared-ui'; + +@Component({ + selector: 'sp-create-asset-dialog-component', + templateUrl: './create-asset-dialog.component.html', + styleUrls: ['./create-asset-dialog.component.scss'] +}) +export class SpCreateAssetDialogComponent implements OnInit { + + @Input() createMode: boolean; + @Input() assetModel: SpAssetModel; + + constructor( + private dialogRef: DialogRef<SpCreateAssetDialogComponent>, + private assetManagementService: AssetManagementService) { + } + + ngOnInit() { + + } + + onCancel(): void { + this.dialogRef.close(); + } + + onSave(): void { + if (this.createMode) { + this.assetManagementService.createAsset(this.assetModel).subscribe(() => { + this.dialogRef.close(); + }); + } else { + this.assetManagementService.updateAsset(this.assetModel).subscribe(() => { + this.dialogRef.close(); + }); + } + } + +}
diff --git a/ui/src/app/assets/dialog/edit-asset-link/edit-asset-link-dialog.component.html b/ui/src/app/assets/dialog/edit-asset-link/edit-asset-link-dialog.component.html new file mode 100644 index 0000000..143d093 --- /dev/null +++ b/ui/src/app/assets/dialog/edit-asset-link/edit-asset-link-dialog.component.html
@@ -0,0 +1,145 @@ +<!-- +~ 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" fxLayout="column" *ngIf="clonedAssetLink"> + <div fxLayout="column" class="link-configuration link-type-selection"> + <mat-form-field color="accent"> + <mat-label>Link Type</mat-label> + <mat-select fxFlex [(value)]="selectedLinkType" + required (selectionChange)="onLinkTypeChanged($event)"> + <mat-option *ngFor="let assetLinkType of assetLinkTypes" + [value]="assetLinkType">{{assetLinkType.linkLabel}}</mat-option> + </mat-select> + </mat-form-field> + </div> + <div *ngIf="selectedLinkType.linkQueryHint === 'pipeline'" fxLayout="column" class="link-configuration"> + <mat-form-field color="accent" fxFlex="100"> + <mat-label>Pipelines</mat-label> + <mat-select [(ngModel)]="currentResource" + fxFlex (selectionChange)="changeLabel($event.value._id, $event.value.name, $event.value)" + required> + <mat-option *ngFor="let pipeline of pipelines" + [value]="pipeline">{{pipeline.name}}</mat-option> + </mat-select> + </mat-form-field> + </div> + <div *ngIf="selectedLinkType.linkQueryHint === 'data-source'" fxLayout="column" class="link-configuration"> + <mat-form-field color="accent" fxFlex="100"> + <mat-label>Data Source</mat-label> + <mat-select (selectionChange)="changeLabel($event.value.elementId, $event.value.name, $event.value)" + [(value)]="currentResource" + fxFlex + required> + <mat-option *ngFor="let source of dataSources" + [value]="source">{{source.name}}</mat-option> + </mat-select> + </mat-form-field> + </div> + <div *ngIf="selectedLinkType.linkQueryHint === 'dashboard'" fxLayout="column" class="link-configuration"> + <mat-form-field color="accent" fxFlex="100"> + <mat-label>Dashboards</mat-label> + <mat-select (selectionChange)="changeLabel($event.value._id, $event.value.name, $event.value)" + [(value)]="currentResource" + fxFlex + required> + <mat-option *ngFor="let dashboard of dashboards" + [value]="dashboard">{{dashboard.name}}</mat-option> + </mat-select> + </mat-form-field> + </div> + <div *ngIf="selectedLinkType.linkQueryHint === 'data-view'" fxLayout="column" class="link-configuration"> + <mat-form-field color="accent" fxFlex="100"> + <mat-label>Data Views</mat-label> + <mat-select (selectionChange)="changeLabel($event.value._id, $event.value.name, $event.value)" + [(value)]="currentResource" + fxFlex + required> + <mat-option *ngFor="let dataView of dataViews" + [value]="dataView">{{dataView.name}}</mat-option> + </mat-select> + </mat-form-field> + </div> + <div *ngIf="selectedLinkType.linkQueryHint === 'adapter'" fxLayout="column" class="link-configuration"> + <mat-form-field color="accent" fxFlex="100"> + <mat-label>Adapter</mat-label> + <mat-select (selectionChange)="changeLabel($event.value.elementId, $event.value.name, $event.value)" + [(value)]="currentResource" + fxFlex + required> + <mat-option *ngFor="let adapter of adapters" + [value]="adapter">{{adapter.name}}</mat-option> + </mat-select> + </mat-form-field> + </div> + <div *ngIf="selectedLinkType.linkQueryHint === 'measurement'" fxLayout="column" class="link-configuration"> + <mat-form-field color="accent" fxFlex="100"> + <mat-label>Data Lake Storage</mat-label> + <mat-select (selectionChange)="changeLabel($event.value.elementId, $event.value.measureName, $event.value)" + [(value)]="currentResource" + fxFlex + required> + <mat-option *ngFor="let measure of dataLakeMeasures" + [value]="measure">{{measure.measureName}}</mat-option> + </mat-select> + </mat-form-field> + </div> + <div *ngIf="selectedLinkType.linkQueryHint === 'file'" fxLayout="column" class="link-configuration"> + <mat-form-field color="accent" fxFlex="100"> + <mat-label>Files</mat-label> + <mat-select (selectionChange)="changeLabel($event.value.fileId, $event.value.originalFilename, $event.value)" + [(value)]="currentResource" + fxFlex + required> + <mat-option *ngFor="let file of files" + [value]="file">{{file.originalFilename}}</mat-option> + </mat-select> + </mat-form-field> + </div> + <div fxLayout="column" class="link-configuration"> + <mat-form-field color="accent"> + <mat-label>Label</mat-label> + <input matInput [(ngModel)]="clonedAssetLink.linkLabel" required> + </mat-form-field> + </div> + <div fxLayout="column" class="link-configuration"> + <mat-form-field color="accent"> + <mat-label>Resource ID</mat-label> + <input matInput [(ngModel)]="clonedAssetLink.resourceId" required [disabled]="true"> + </mat-form-field> + </div> + <div fxFlex="100"> + + </div> + </div> + </div> + <mat-divider></mat-divider> + <div class="sp-dialog-actions"> + <button mat-button + mat-raised-button + color="accent" + (click)="store()" style="margin-right:10px;" [disabled]="!clonedAssetLink.resourceId"> + {{createMode ? 'Create ' : 'Update' }} link + </button> + <button mat-button mat-raised-button class="mat-basic" (click)="cancel()" style="margin-right:10px;"> + Cancel + </button> + </div> +</div>
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.scss b/ui/src/app/assets/dialog/edit-asset-link/edit-asset-link-dialog.component.scss similarity index 81% copy from ui/src/app/pipeline-details/pipeline-details.component.scss copy to ui/src/app/assets/dialog/edit-asset-link/edit-asset-link-dialog.component.scss index a375af7..e1f0e27 100644 --- a/ui/src/app/pipeline-details/pipeline-details.component.scss +++ b/ui/src/app/assets/dialog/edit-asset-link/edit-asset-link-dialog.component.scss
@@ -16,7 +16,15 @@ * */ -.md-padding { - padding: 10px; +@import 'src/scss/sp/sp-dialog'; + +.link-type-selection { } +.link-configuration { + padding: 10px; + width:100%; + margin:5px; + background: var(--color-bg-1); + border: 1px solid var(--color-bg-3); +}
diff --git a/ui/src/app/assets/dialog/edit-asset-link/edit-asset-link-dialog.component.ts b/ui/src/app/assets/dialog/edit-asset-link/edit-asset-link-dialog.component.ts new file mode 100644 index 0000000..417a086 --- /dev/null +++ b/ui/src/app/assets/dialog/edit-asset-link/edit-asset-link-dialog.component.ts
@@ -0,0 +1,127 @@ +/* + * 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, Input, OnInit } from '@angular/core'; +import { DialogRef } from '@streampipes/shared-ui'; +import { + AdapterDescriptionUnion, + SpDataStream, + AdapterService, + AssetLink, + AssetLinkType, + Dashboard, + DashboardService, + DataLakeMeasure, DatalakeRestService, + DataViewDataExplorerService, + GenericStorageService, + Pipeline, + PipelineService, + PipelineElementService, FileMetadata, FilesService +} from '@streampipes/platform-services'; +import { FormGroup } from '@angular/forms'; +import { zip } from 'rxjs'; +import { MatSelectChange } from '@angular/material/select'; +import { BaseAssetLinksDirective } from '../base-asset-links.directive'; + +@Component({ + selector: 'sp-edit-asset-link-dialog-component', + templateUrl: './edit-asset-link-dialog.component.html', + styleUrls: ['./edit-asset-link-dialog.component.scss'] +}) +export class EditAssetLinkDialogComponent extends BaseAssetLinksDirective implements OnInit { + + @Input() + assetLink: AssetLink; + + @Input() + assetLinkTypes: AssetLinkType[]; + + @Input() + createMode: boolean; + + parentForm: FormGroup; + + clonedAssetLink: AssetLink; + + + currentResource: any; + + selectedLinkType: AssetLinkType; + + constructor(private dialogRef: DialogRef<EditAssetLinkDialogComponent>, + protected genericStorageService: GenericStorageService, + protected pipelineService: PipelineService, + protected dataViewService: DataViewDataExplorerService, + protected dashboardService: DashboardService, + protected dataLakeService: DatalakeRestService, + protected pipelineElementService: PipelineElementService, + protected adapterService: AdapterService, + protected filesService: FilesService) { + super( + genericStorageService, + pipelineService, + dataViewService, + dashboardService, + dataLakeService, + pipelineElementService, + adapterService, + filesService); + } + + ngOnInit(): void { + super.onInit(); + this.clonedAssetLink = {...this.assetLink}; + this.selectedLinkType = this.getCurrAssetLinkType(); + } + + getCurrAssetLinkType(): AssetLinkType { + return this.assetLinkTypes.find(a => a.linkType === this.clonedAssetLink.linkType); + } + + store() { + this.assetLink = this.clonedAssetLink; + this.dialogRef.close(this.assetLink); + } + + cancel() { + this.dialogRef.close(); + } + + onLinkTypeChanged(event: MatSelectChange): void { + this.selectedLinkType = event.value; + const linkType = this.assetLinkTypes.find(a => a.linkType === this.selectedLinkType.linkType); + this.clonedAssetLink.editingDisabled = false; + this.clonedAssetLink.linkType = linkType.linkType; + this.clonedAssetLink.queryHint = linkType.linkQueryHint; + this.clonedAssetLink.navigationActive = linkType.navigationActive; + } + + changeLabel(id: string, label: string, currentResource: any) { + this.clonedAssetLink.resourceId = id; + this.clonedAssetLink.linkLabel = label; + this.currentResource = currentResource; + } + + afterResourcesLoaded(): void { + if (!this.createMode) { + this.currentResource = this.allResources.find(r => r._id === this.clonedAssetLink.resourceId || + r.elementId === this.clonedAssetLink.resourceId); + } + } + +}
diff --git a/ui/src/app/assets/dialog/manage-asset-links/manage-asset-links-dialog.component.html b/ui/src/app/assets/dialog/manage-asset-links/manage-asset-links-dialog.component.html new file mode 100644 index 0000000..eba2f81 --- /dev/null +++ b/ui/src/app/assets/dialog/manage-asset-links/manage-asset-links-dialog.component.html
@@ -0,0 +1,216 @@ +<!-- +~ 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" fxLayout="column" *ngIf="clonedAssetLinks"> + <div fxLayout="column" class="link-configuration"> + <div fxLayout="row" fxLayoutAlign="start center" class="mb-10" fxFlex="100"> + <div fxLayout="row" fxLayoutAlign="start center"> + <span class="general-options-header mb-0">Adapters</span> + </div> + <div fxLayout="row" fxLayoutAlign="end center" fxFlex> + <button mat-button mat-raised-button color="accent" class="small-button" + (click)="selectAll(adapters, elementIdFunction, nameFunction, 'adapter')" + style="margin-right:5px;margin-left:15px;"> + <span>Select All</span> + </button> + <button mat-button mat-raised-button class="mat-basic small-button" + (click)="deselectAll(adapters, elementIdFunction)" + style="margin-right:10px;margin-left:5px;"> + <span>Deselect All</span> + </button> + </div> + </div> + <div *ngFor="let element of adapters" fxLayout="row"> + <mat-checkbox color="accent" + [checked]="linkSelected(element.elementId)" + (change)="selectLink($event.checked, element.elementId, element.name, 'adapter')"> + {{element.name}} + </mat-checkbox> + </div> + </div> + <div fxLayout="column" class="link-configuration"> + <div fxLayout="row" fxLayoutAlign="start center" class="mb-10"> + <div fxLayout="row" fxLayoutAlign="start center"> + <span class="general-options-header mb-0">Dasboards</span> + </div> + <div fxLayout="row" fxLayoutAlign="end center" fxFlex> + <button mat-button mat-raised-button color="accent" class="small-button" + (click)="selectAll(dashboards, idFunction, nameFunction, 'dashboard')" + style="margin-right:5px;margin-left:15px;"> + <span>Select All</span> + </button> + <button mat-button mat-raised-button class="mat-basic small-button" + (click)="deselectAll(dashboards, idFunction)" + style="margin-right:10px;margin-left:5px;"> + <span>Deselect All</span> + </button> + </div> + </div> + <div *ngFor="let element of dashboards" fxLayout="row"> + <mat-checkbox color="accent" + [checked]="linkSelected(element._id)" + (change)="selectLink($event.checked, element._id, element.name, 'dashboard')"> + {{element.name}} + </mat-checkbox> + </div> + </div> + <div fxLayout="column" class="link-configuration"> + <div fxLayout="row" fxLayoutAlign="start center" class="mb-10"> + <div fxLayout="row" fxLayoutAlign="start center"> + <span class="general-options-header mb-0">Data Lake Storage</span> + </div> + <div fxLayout="row" fxLayoutAlign="end center" fxFlex> + <button mat-button mat-raised-button color="accent" class="small-button" + (click)="selectAll(dataLakeMeasures, elementIdFunction, measureNameFunction, 'measurement')" + style="margin-right:5px;margin-left:15px;"> + <span>Select All</span> + </button> + <button mat-button mat-raised-button class="mat-basic small-button" + (click)="deselectAll(dataLakeMeasures, elementIdFunction)" + style="margin-right:10px;margin-left:5px;"> + <span>Deselect All</span> + </button> + </div> + </div> + <div *ngFor="let element of dataLakeMeasures" fxLayout="row"> + <mat-checkbox color="accent" + [checked]="linkSelected(element.elementId)" + (change)="selectLink($event.checked, element.elementId, element.measureName, 'measurement')"> + {{element.measureName}} + </mat-checkbox> + </div> + </div> + <div fxLayout="column" class="link-configuration"> + <div fxLayout="row" fxLayoutAlign="start center" class="mb-10"> + <div fxLayout="row" fxLayoutAlign="start center"> + <span class="general-options-header mb-0">Data Sources</span> + </div> + <div fxLayout="row" fxLayoutAlign="end center" fxFlex> + <button mat-button mat-raised-button color="accent" class="small-button" + (click)="selectAll(dataSources, elementIdFunction, nameFunction, 'data-source')" + style="margin-right:5px;margin-left:15px;"> + <span>Select All</span> + </button> + <button mat-button mat-raised-button class="mat-basic small-button" + (click)="deselectAll(dataSources, elementIdFunction)" + style="margin-right:10px;margin-left:5px;"> + <span>Deselect All</span> + </button> + </div> + </div> + <div *ngFor="let source of dataSources" fxLayout="row"> + <mat-checkbox color="accent" + [checked]="linkSelected(source.elementId)" + (change)="selectLink($event.checked, source.elementId, source.name, 'data-source')"> + {{source.name}} + </mat-checkbox> + </div> + </div> + <div fxLayout="column" class="link-configuration"> + <div fxLayout="row" fxLayoutAlign="start center" class="mb-10"> + <div fxLayout="row" fxLayoutAlign="start center"> + <span class="general-options-header mb-0">Data Views</span> + </div> + <div fxLayout="row" fxLayoutAlign="end center" fxFlex> + <button mat-button mat-raised-button color="accent" class="small-button" + (click)="selectAll(dataViews, idFunction, nameFunction, 'data-view')" + style="margin-right:5px;margin-left:15px;"> + <span>Select All</span> + </button> + <button mat-button mat-raised-button class="mat-basic small-button" + (click)="deselectAll(dataViews, idFunction)" + style="margin-right:10px;margin-left:5px;"> + <span>Deselect All</span> + </button> + </div> + </div> + <div *ngFor="let element of dataViews" fxLayout="row"> + <mat-checkbox color="accent" + [checked]="linkSelected(element._id)" + (change)="selectLink($event.checked, element._id, element.name, 'data-view')"> + {{element.name}} + </mat-checkbox> + </div> + </div> + <div fxLayout="column" class="link-configuration"> + <div fxLayout="row" fxLayoutAlign="start center" class="mb-10"> + <div fxLayout="row" fxLayoutAlign="start center"> + <span class="general-options-header mb-0">Files</span> + </div> + <div fxLayout="row" fxLayoutAlign="end center" fxFlex> + <button mat-button mat-raised-button color="accent" class="small-button" + (click)="selectAll(files, fileIdFunction, filenameFunction, 'file')" + style="margin-right:5px;margin-left:15px;"> + <span>Select All</span> + </button> + <button mat-button mat-raised-button class="mat-basic small-button" + (click)="deselectAll(files, fileIdFunction)" + style="margin-right:10px;margin-left:5px;"> + <span>Deselect All</span> + </button> + </div> + </div> + <div *ngFor="let element of files" fxLayout="row"> + <mat-checkbox color="accent" + [checked]="linkSelected(element.fileId)" + (change)="selectLink($event.checked, element.fileId, element.originalFilename, 'file')"> + {{element.originalFilename}} + </mat-checkbox> + </div> + </div> + <div fxLayout="column" class="link-configuration"> + <div fxLayout="row" fxLayoutAlign="start center" class="mb-10"> + <div fxLayout="row" fxLayoutAlign="start center"> + <span class="general-options-header mb-0">Pipelines</span> + </div> + <div fxLayout="row" fxLayoutAlign="end center" fxFlex> + <button mat-button mat-raised-button color="accent" class="small-button" + (click)="selectAll(pipelines, idFunction, nameFunction, 'pipeline')" + style="margin-right:5px;margin-left:15px;"> + <span>Select All</span> + </button> + <button mat-button mat-raised-button class="mat-basic small-button" + (click)="deselectAll(pipelines, idFunction)" + style="margin-right:10px;margin-left:5px;"> + <span>Deselect All</span> + </button> + </div> + </div> + <div *ngFor="let pipeline of pipelines" fxLayout="row"> + <mat-checkbox color="accent" [checked]="linkSelected(pipeline._id)" + (change)="selectLink($event.checked, pipeline._id, pipeline.name, 'pipeline')">{{pipeline.name}}</mat-checkbox> + </div> + </div> + </div> + </div> + <mat-divider></mat-divider> + <div class="sp-dialog-actions"> + <button mat-button + mat-raised-button + color="accent" + (click)="store()" style="margin-right:10px;"> + Update links + </button> + <button mat-button mat-raised-button class="mat-basic" (click)="cancel()" style="margin-right:10px;"> + Cancel + </button> + </div> +</div>
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.scss b/ui/src/app/assets/dialog/manage-asset-links/manage-asset-links-dialog.component.scss similarity index 81% copy from ui/src/app/pipeline-details/pipeline-details.component.scss copy to ui/src/app/assets/dialog/manage-asset-links/manage-asset-links-dialog.component.scss index a375af7..c7debbd 100644 --- a/ui/src/app/pipeline-details/pipeline-details.component.scss +++ b/ui/src/app/assets/dialog/manage-asset-links/manage-asset-links-dialog.component.scss
@@ -16,7 +16,16 @@ * */ -.md-padding { +@import 'src/scss/sp/sp-dialog'; + +.link-configuration { padding: 10px; + width:100%; + margin:5px; + background: var(--color-bg-1); + border: 1px solid var(--color-bg-3); } +.mb-0 { + margin-bottom: 0; +}
diff --git a/ui/src/app/assets/dialog/manage-asset-links/manage-asset-links-dialog.component.ts b/ui/src/app/assets/dialog/manage-asset-links/manage-asset-links-dialog.component.ts new file mode 100644 index 0000000..320bf83 --- /dev/null +++ b/ui/src/app/assets/dialog/manage-asset-links/manage-asset-links-dialog.component.ts
@@ -0,0 +1,159 @@ +/* + * 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, Input, OnInit } from '@angular/core'; +import { DialogRef } from '@streampipes/shared-ui'; +import { + AdapterDescriptionUnion, + SpDataStream, + AdapterService, + AssetLink, + AssetLinkType, + Dashboard, + DashboardService, + DataLakeMeasure, DatalakeRestService, + DataViewDataExplorerService, + GenericStorageService, + Pipeline, + PipelineService, + PipelineElementService, FileMetadata, FilesService +} from '@streampipes/platform-services'; +import { FormGroup } from '@angular/forms'; +import { zip } from 'rxjs'; +import { MatSelectChange } from '@angular/material/select'; +import { BaseAssetLinksDirective } from '../base-asset-links.directive'; + +@Component({ + selector: 'sp-manage-asset-links-dialog-component', + templateUrl: './manage-asset-links-dialog.component.html', + styleUrls: ['./manage-asset-links-dialog.component.scss'] +}) +export class SpManageAssetLinksDialogComponent extends BaseAssetLinksDirective implements OnInit { + + @Input() + assetLinks: AssetLink[]; + + @Input() + assetLinkTypes: AssetLinkType[]; + + clonedAssetLinks: AssetLink[] = []; + + idFunction = (el) => el._id; + elementIdFunction = (el) => el.elementId; + fileIdFunction = (el) => el.fileId; + nameFunction = (el) => el.name; + filenameFunction = (el) => el.originalFilename; + measureNameFunction = (el) => el.measureName; + + + constructor(private dialogRef: DialogRef<SpManageAssetLinksDialogComponent>, + protected genericStorageService: GenericStorageService, + protected pipelineService: PipelineService, + protected dataViewService: DataViewDataExplorerService, + protected dashboardService: DashboardService, + protected dataLakeService: DatalakeRestService, + protected pipelineElementService: PipelineElementService, + protected adapterService: AdapterService, + protected filesService: FilesService) { + super( + genericStorageService, + pipelineService, + dataViewService, + dashboardService, + dataLakeService, + pipelineElementService, + adapterService, + filesService); + } + + ngOnInit(): void { + super.onInit(); + this.clonedAssetLinks = [ + ...this.assetLinks.map(al => { + return {...al}; + }) + ]; + } + + cancel(): void { + this.dialogRef.close(); + } + + store(): void { + this.assetLinks = this.clonedAssetLinks; + this.dialogRef.close(this.assetLinks); + } + + afterResourcesLoaded(): void { + } + + linkSelected(resourceId: string): boolean { + return this.clonedAssetLinks.find(al => al.resourceId === resourceId) !== undefined; + } + + selectLink(checked: boolean, + resourceId: string, + label: string, + assetLinkType: string): void { + if (checked) { + this.clonedAssetLinks.push(this.makeLink(resourceId, label, assetLinkType)); + } else { + const index = this.clonedAssetLinks.findIndex(al => al.resourceId === resourceId); + this.clonedAssetLinks.splice(index, 1); + } + } + + makeLink(resourceId: string, + label: string, + assetLinkType: string): AssetLink { + + const linkType = this.assetLinkTypes.find(a => a.linkType === assetLinkType); + return { + linkLabel: label, + linkType: linkType.linkType, + editingDisabled: false, + queryHint: linkType.linkQueryHint, + navigationActive: linkType.navigationActive, + resourceId + }; + } + + selectAll(elements: any[], + idFunction: any, + nameFunction: any, + assetLinkType: string): void { + elements.forEach(el => { + const id = idFunction(el); + const elementName = nameFunction(el); + if (!this.linkSelected(id)) { + this.selectLink(true, id, elementName, assetLinkType); + } + }); + } + + deselectAll(elements: any[], + idFunction: any): void { + elements.forEach(el => { + const id = idFunction(el); + const index = this.clonedAssetLinks.findIndex(al => al.resourceId === id); + if (index > -1) { + this.clonedAssetLinks.splice(index, 1); + } + }); + } +}
diff --git a/ui/src/app/configuration/configuration-tabs.ts b/ui/src/app/configuration/configuration-tabs.ts new file mode 100644 index 0000000..367d7a9 --- /dev/null +++ b/ui/src/app/configuration/configuration-tabs.ts
@@ -0,0 +1,34 @@ +/* + * 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 { SpNavigationItem } from '@streampipes/shared-ui'; + +export class SpConfigurationTabs { + + public static getTabs(): SpNavigationItem[] { + return [ + {itemId: 'general', itemTitle: 'General', itemLink: ['configuration', 'general']}, + {itemId: 'datalake', itemTitle: 'Data Lake', itemLink: ['configuration', 'datalake']}, + {itemId: 'email', itemTitle: 'Mail', itemLink: ['configuration', 'email']}, + {itemId: 'export', itemTitle: 'Export/Import', itemLink: ['configuration', 'export']}, + {itemId: 'messaging', itemTitle: 'Messaging', itemLink: ['configuration', 'messaging']}, + {itemId: 'pipelineelement', itemTitle: 'Pipeline Element Configuration', itemLink: ['configuration', 'pipelineelement']}, + {itemId: 'security', itemTitle: 'Security', itemLink: ['configuration', 'security']} + ]; + } +}
diff --git a/ui/src/app/configuration/configuration.component.html b/ui/src/app/configuration/configuration.component.html deleted file mode 100644 index 026c76f..0000000 --- a/ui/src/app/configuration/configuration.component.html +++ /dev/null
@@ -1,61 +0,0 @@ -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one or more - ~ contributor license agreements. See the NOTICE file distributed with - ~ this work for additional information regarding copyright ownership. - ~ The ASF licenses this file to You under the Apache License, Version 2.0 - ~ (the "License"); you may not use this file except in compliance with - ~ the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - ~ - --> - -<div fxLayout="column" class="page-container"> - <div fxLayout="row" class="p-0 sp-bg-lightgray page-container-nav"> - <div fxLayout="fill"> - <mat-tab-group [selectedIndex]="selectedIndex" (selectedIndexChange)="selectedIndexChange($event)" - color="accent"> - <mat-tab label="General"></mat-tab> - <mat-tab label="DataLake"></mat-tab> - <mat-tab label="Mail"></mat-tab> - <mat-tab label="Messaging"></mat-tab> - <mat-tab label="Pipeline Element Configuration"></mat-tab> - <mat-tab label="Security"></mat-tab> - </mat-tab-group> - </div> - </div> - - <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100"> - <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100" - *ngIf="selectedIndex == 0"> - <sp-general-configuration fxFlex="100"></sp-general-configuration> - </div> - <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100" - *ngIf="selectedIndex == 1"> - <sp-datalake-configuration fxFlex="100"></sp-datalake-configuration> - </div> - <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100" - *ngIf="selectedIndex == 2"> - <sp-email-configuration fxFlex="100"></sp-email-configuration> - </div> - <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100" - *ngIf="selectedIndex == 3"> - <messaging-configuration fxFlex="100"></messaging-configuration> - </div> - <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100" - *ngIf="selectedIndex == 4"> - <pipeline-element-configuration fxFlex="100"></pipeline-element-configuration> - </div> - <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100" - *ngIf="selectedIndex == 5"> - <sp-security-configuration fxFlex="100"></sp-security-configuration> - </div> - </div> - -</div>
diff --git a/ui/src/app/configuration/configuration.component.spec.ts b/ui/src/app/configuration/configuration.component.spec.ts deleted file mode 100644 index 21ca1ca..0000000 --- a/ui/src/app/configuration/configuration.component.spec.ts +++ /dev/null
@@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { ConfigurationComponent } from './configuration.component'; -import { CommonModule } from '@angular/common'; -import { FlexLayoutModule } from '@angular/flex-layout'; -import { ConfigurationService } from './shared/configuration.service'; -import { ConfigurationMockService } from './shared/configuration.test.service'; -import { NO_ERRORS_SCHEMA } from '@angular/core'; - -describe('ConfigurationComponent', () => { - - let fixture: ComponentFixture<ConfigurationComponent>; - let configurationComponent: ConfigurationComponent; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [ - CommonModule, - FlexLayoutModule - ], - declarations: [ - ConfigurationComponent - ], - providers: [ - { provide: ConfigurationService, useClass: ConfigurationMockService } - ], - schemas: [ - NO_ERRORS_SCHEMA - ] - }).compileComponents(); - fixture = TestBed.createComponent(ConfigurationComponent); - fixture.detectChanges(); - configurationComponent = fixture.componentInstance; - })); - - it('should create the component', waitForAsync(() => { - expect(configurationComponent).toBeTruthy(); - })); - -});
diff --git a/ui/src/app/configuration/configuration.component.ts b/ui/src/app/configuration/configuration.component.ts deleted file mode 100644 index fdf7d4d..0000000 --- a/ui/src/app/configuration/configuration.component.ts +++ /dev/null
@@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Component } from '@angular/core'; -import { animate, state, style, transition, trigger } from '@angular/animations'; - -@Component({ - templateUrl: './configuration.component.html', - styleUrls: ['./configuration.component.css'], - animations: [ - trigger('detailExpand', [ - state('collapsed', style({height: '0px', minHeight: '0', display: 'none'})), - state('expanded', style({height: '*'})), - transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')), - ]), - ] -}) -export class ConfigurationComponent { - - selectedIndex = 0; - - constructor() { - } - - selectedIndexChange(index: number) { - this.selectedIndex = index; - } - -}
diff --git a/ui/src/app/configuration/configuration.module.ts b/ui/src/app/configuration/configuration.module.ts index 864d918..1aa5060 100644 --- a/ui/src/app/configuration/configuration.module.ts +++ b/ui/src/app/configuration/configuration.module.ts
@@ -26,8 +26,6 @@ import { FlexLayoutModule } from '@angular/flex-layout'; import { CommonModule } from '@angular/common'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; - -import { ConfigurationComponent } from './configuration.component'; import { ConfigurationService } from './shared/configuration.service'; import { ConsulServiceComponent } from './consul-service/consul-service.component'; import { ConsulConfigsComponent } from './consul-configs/consul-configs.component'; @@ -53,9 +51,13 @@ import { EditGroupDialogComponent } from './security-configuration/edit-group-dialog/edit-group-dialog.component'; import { EmailConfigurationComponent } from './email-configuration/email-configuration.component'; import { GeneralConfigurationComponent } from './general-configuration/general-configuration.component'; -import { - SecurityAuthenticationConfigurationComponent -} from './security-configuration/authentication-configuration/authentication-configuration.component'; +import { SecurityAuthenticationConfigurationComponent } from './security-configuration/authentication-configuration/authentication-configuration.component'; +import { RouterModule } from '@angular/router'; +import { SharedUiModule } from '@streampipes/shared-ui'; +import { SpDataExportImportComponent } from './export/data-export-import.component'; +import { SpDataExportDialogComponent } from './export/export-dialog/data-export-dialog.component'; +import { SpDataImportDialogComponent } from './export/import-dialog/data-import-dialog.component'; +import { SpDataExportItemComponent } from './export/export-dialog/data-export-item/data-export-item.component'; @NgModule({ imports: [ @@ -75,9 +77,49 @@ CoreUiModule, ReactiveFormsModule, PlatformServicesModule, + RouterModule.forChild([ + { + path: 'configuration', + children: [ + { + path: '', + redirectTo: 'general', + pathMatch: 'full' + }, + { + path: 'general', + component: GeneralConfigurationComponent + }, + { + path: 'datalake', + component: DatalakeConfigurationComponent + }, + { + path: 'email', + component: EmailConfigurationComponent + }, + { + path: 'export', + component: SpDataExportImportComponent + }, + { + path: 'messaging', + component: MessagingConfigurationComponent + }, + { + path: 'pipelineelement', + component: PipelineElementConfigurationComponent + }, + { + path: 'security', + component: SecurityConfigurationComponent + } + ] + } + ]), + SharedUiModule, ], declarations: [ - ConfigurationComponent, ConsulServiceComponent, ConsulConfigsComponent, ConsulConfigsTextComponent, @@ -97,10 +139,11 @@ SecurityServiceConfigComponent, MessagingConfigurationComponent, DatalakeConfigurationComponent, + SpDataExportImportComponent, + SpDataExportDialogComponent, + SpDataExportItemComponent, + SpDataImportDialogComponent ], - providers: [ - ConfigurationService, - ] + providers: [ConfigurationService], }) -export class ConfigurationModule { -} +export class ConfigurationModule {}
diff --git a/ui/src/app/configuration/configuration.component.css b/ui/src/app/configuration/configuration.routes.ts similarity index 79% rename from ui/src/app/configuration/configuration.component.css rename to ui/src/app/configuration/configuration.routes.ts index cd8f273..79ce64b 100644 --- a/ui/src/app/configuration/configuration.component.css +++ b/ui/src/app/configuration/configuration.routes.ts
@@ -1,22 +1,25 @@ -/* - * 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. - * - */ - -.page-container-padding-inner { - padding: 10px; -} - +/* + * 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 { SpBreadcrumbItem, } from '@streampipes/shared-ui'; + +export class SpConfigurationRoutes { + + static CONFIGURATION_BASE_LINK = 'configuration'; + static BASE: SpBreadcrumbItem = {label: 'Configuration'}; +}
diff --git a/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.html b/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.html index bbc29d5..a967e01 100644 --- a/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.html +++ b/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.html
@@ -16,95 +16,109 @@ ~ --> -<div fxLayout="row" class="page-container-padding"> - <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start"> - <sp-split-section title="Data Lake Settings" - subtitle="Truncate and delete persisted data streams"> - <div fxFlex="100" fxLayout="column"> - <div class="subsection-title">Existing data lake indices</div> - <table - fxFlex="100" - mat-table - data-cy="datalake-settings" - [dataSource]="dataSource" - style="width: 100%;" - matSort> - <ng-container matColumnDef="name"> - <th mat-header-cell mat-sort-header *matHeaderCellDef>Name</th> - <td mat-cell *matCellDef="let configurationEntry"> - <h4 style="margin-bottom:0px;">{{configurationEntry.name}}</h4> - </td> - </ng-container> +<sp-basic-nav-tabs [spNavigationItems]="tabs" [activeLink]="'datalake'"> + <div fxLayout="row" class="page-container-padding"> + <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start"> + <sp-split-section title="Data Lake Settings" subtitle="Truncate and delete persisted data streams"> + <div fxFlex="100" fxLayout="column"> + <div fxFlex="100" fxLayout="row"> + <div fxFlex fxLayoutAlign="start center" class="subsection-title">Existing data lake indices</div> + <div fxLayout="row" fxLayoutAlign="end center"> + <button color="accent" + mat-button + mat-icon-button + matTooltip="Refresh Schema" + (click)="loadAvailableMeasurements()"> + <mat-icon>refresh</mat-icon> + </button> + </div> + </div> + <table fxFlex="100" mat-table data-cy="datalake-settings" [dataSource]="dataSource" + style="width: 100%;" matSort> - <ng-container matColumnDef="pipeline"> - <th mat-header-cell mat-sort-header *matHeaderCellDef>Related Pipeline</th> - <td mat-cell *matCellDef="let configurationEntry"> - {{configurationEntry.pipelines}} - </td> - </ng-container> + <ng-container matColumnDef="name"> + <th mat-header-cell mat-sort-header *matHeaderCellDef>Name</th> + <td mat-cell *matCellDef="let configurationEntry"> + <h4 style="margin-bottom:0px;">{{configurationEntry.name}}</h4> + </td> + </ng-container> - <ng-container matColumnDef="events"> - <th mat-header-cell mat-sort-header *matHeaderCellDef># Events</th> - <td - mat-cell - data-cy="datalake-number-of-events" - *matCellDef="let configurationEntry"> - {{configurationEntry.events | number}} - </td> - </ng-container> + <ng-container matColumnDef="pipeline"> + <th mat-header-cell mat-sort-header *matHeaderCellDef>Related Pipeline</th> + <td mat-cell *matCellDef="let configurationEntry"> + {{configurationEntry.pipelines}} + </td> + </ng-container> - <ng-container matColumnDef="truncate"> - <th mat-header-cell *matHeaderCellDef>Truncate</th> - <td mat-cell *matCellDef="let configurationEntry"> - <div fxLayout="row"> - <span fxFlex fxFlexOrder="3" fxLayout="row" fxLayoutAlign="center center"> - <button color="accent" - mat-button - mat-icon-button - matTooltip="Truncate all data from index" - matTooltipPosition="above" + <ng-container matColumnDef="events"> + <th mat-header-cell mat-sort-header *matHeaderCellDef># Events</th> + <td mat-cell data-cy="datalake-number-of-events" *matCellDef="let configurationEntry"> + {{configurationEntry.events | number}} + </td> + </ng-container> + + <ng-container matColumnDef="download"> + <th mat-header-cell *matHeaderCellDef>Download</th> + <td mat-cell *matCellDef="let configurationEntry"> + <div fxLayout="row"> + <span fxFlex fxFlexOrder="3" fxLayout="row" fxLayoutAlign="start center"> + <button color="accent" mat-button mat-icon-button + matTooltip="Download data from index" matTooltipPosition="above" + data-cy="datalake-download-btn" + (click)="openDownloadDialog(configurationEntry.name)"> + <i class="material-icons">download</i> + </button> + </span> + </div> + </td> + </ng-container> + + <ng-container matColumnDef="truncate"> + <th mat-header-cell *matHeaderCellDef>Truncate</th> + <td mat-cell *matCellDef="let configurationEntry"> + <div fxLayout="row"> + <span fxFlex fxFlexOrder="3" fxLayout="row" fxLayoutAlign="start center"> + <button color="accent" mat-button mat-icon-button + matTooltip="Truncate all data from index" matTooltipPosition="above" data-cy="datalake-truncate-btn" (click)="cleanDatalakeIndex(configurationEntry.name)"> - <i class="material-icons">local_fire_department</i> - </button> - </span> - </div> - </td> - </ng-container> + <i class="material-icons">local_fire_department</i> + </button> + </span> + </div> + </td> + </ng-container> - <ng-container matColumnDef="remove"> - <th mat-header-cell *matHeaderCellDef>Remove</th> - <td mat-cell *matCellDef="let configurationEntry"> - <div fxLayout="row"> - <span fxFlex fxFlexOrder="3" fxLayout="row" fxLayoutAlign="center center"> - <button color="accent" - mat-button - mat-icon-button - matTooltip="Remove index from database" - data-cy="datalake-delete-btn" - matTooltipPosition="above" - [disabled]="!configurationEntry.remove" + <ng-container matColumnDef="remove"> + <th mat-header-cell *matHeaderCellDef>Remove</th> + <td mat-cell *matCellDef="let configurationEntry"> + <div fxLayout="row"> + <span fxFlex fxFlexOrder="3" fxLayout="row" fxLayoutAlign="start center"> + <button color="accent" mat-button mat-icon-button + matTooltip="Remove index from database" data-cy="datalake-delete-btn" + matTooltipPosition="above" [disabled]="!configurationEntry.remove" (click)="deleteDatalakeIndex(configurationEntry.name)"> - <i class="material-icons">delete</i> - </button> - </span> - </div> - </td> - </ng-container> + <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> + <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> + <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> - </table> - </div> - <div fxFlex="100" fxLayoutAlign="end end"> - <mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" [pageSize]="20"></mat-paginator> - </div> - <div fxFlex="100" fxLayout="column" fxLayoutAlign="center center" *ngIf="availableMeasurements.length == 0"> - <h5>(no stored measurements)</h5> - </div> - </sp-split-section> + </table> + </div> + <div fxFlex="100" fxLayoutAlign="end end"> + <mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" [pageSize]="20"></mat-paginator> + </div> + <div fxFlex="100" fxLayout="column" fxLayoutAlign="center center" + *ngIf="availableMeasurements.length == 0"> + <h5>(no stored measurements)</h5> + </div> + </sp-split-section> + </div> </div> -</div> - +</sp-basic-nav-tabs>
diff --git a/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.ts b/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.ts index 7f6986d..d1792ac 100644 --- a/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.ts +++ b/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.ts
@@ -20,18 +20,22 @@ import { MatTableDataSource } from '@angular/material/table'; import { DataLakeConfigurationEntry } from './datalake-configuration-entry'; import { + DataExplorerDataConfig, DatalakeQueryParameterBuilder, DatalakeQueryParameters, DatalakeRestService, - DataViewDataExplorerService, + DataViewDataExplorerService, DateRange, EventSchema, FieldConfig, SpQueryResult } from '@streampipes/platform-services'; import { MatPaginator } from '@angular/material/paginator'; import { MatSort } from '@angular/material/sort'; -import { DialogRef, DialogService, PanelType } from '@streampipes/shared-ui'; +import { DialogRef, DialogService, PanelType, SpBreadcrumbService } from '@streampipes/shared-ui'; import { DeleteDatalakeIndexComponent } from '../dialog/delete-datalake-index/delete-datalake-index-dialog.component'; +import { SpConfigurationTabs } from '../configuration-tabs'; +import { SpConfigurationRoutes } from '../configuration.routes'; +import { DataDownloadDialogComponent } from '../../core-ui/data-download-dialog/data-download-dialog.component'; @Component({ selector: 'sp-datalake-configuration', @@ -40,6 +44,8 @@ }) export class DatalakeConfigurationComponent implements OnInit { + tabs = SpConfigurationTabs.getTabs(); + @ViewChild(MatPaginator) paginator: MatPaginator; pageSize = 1; @ViewChild(MatSort) sort: MatSort; @@ -47,16 +53,18 @@ dataSource: MatTableDataSource<DataLakeConfigurationEntry>; availableMeasurements: DataLakeConfigurationEntry[] = []; - displayedColumns: string[] = ['name', 'pipeline', 'events', 'truncate', 'remove']; + displayedColumns: string[] = ['name', 'pipeline', 'events', 'download', 'truncate', 'remove']; constructor( // protected dataLakeRestService: DatalakeRestService, private datalakeRestService: DatalakeRestService, private dataViewDataExplorerService: DataViewDataExplorerService, - private dialogService: DialogService) { + private dialogService: DialogService, + private breadcrumbService: SpBreadcrumbService) { } ngOnInit(): void { + this.breadcrumbService.updateBreadcrumb([SpConfigurationRoutes.BASE, {label: SpConfigurationTabs.getTabs()[1].itemTitle}]); this.loadAvailableMeasurements(); } @@ -147,6 +155,17 @@ }); } + openDownloadDialog(measurementName: string) { + this.dialogService.open(DataDownloadDialogComponent, { + panelType: PanelType.SLIDE_IN_PANEL, + title: 'Download data', + width: '50vw', + data: { + 'measureName': measurementName, + } + }); + } + private buildQ(column: FieldConfig): DatalakeQueryParameters { return DatalakeQueryParameterBuilder.create(0, new Date().getTime()) .withColumnFilter([column], true)
diff --git a/ui/src/app/configuration/email-configuration/email-configuration.component.html b/ui/src/app/configuration/email-configuration/email-configuration.component.html index f1ddd7e..b6994e3 100644 --- a/ui/src/app/configuration/email-configuration/email-configuration.component.html +++ b/ui/src/app/configuration/email-configuration/email-configuration.component.html
@@ -16,114 +16,101 @@ ~ --> -<div fxLayout="column" class="page-container-padding"> - <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" *ngIf="formReady"> - <sp-split-section title="Mail Settings" - subtitle="Settings to connect to a mail server"> - <form [formGroup]="parentForm" fxFlex="100" fxLayout="column"> - <div class="subsection-title">Mail Server</div> - <mat-form-field color="accent"> - <mat-label>SMTP Host</mat-label> - <input formControlName="smtpServerHost" fxFlex - matInput - required> - </mat-form-field> - <mat-form-field color="accent"> - <mat-label>SMTP Port</mat-label> - <input type="number" formControlName="smtpServerPort" fxFlex - matInput - required> - </mat-form-field> - <div class="subsection-title">Transport</div> - <mat-radio-group fxLayout="column" formControlName="transport"> - <mat-radio-button value="SMTP" class="m-5">SMTP</mat-radio-button> - <mat-radio-button value="SMTPS" class="m-5">SMTPS</mat-radio-button> - <mat-radio-button value="SMTP_TLS" class="m-5">TLS</mat-radio-button> - </mat-radio-group> - <div class="subsection-title mt-20">Authentication</div> - <mat-checkbox formControlName="usesAuthentication">SMTP server requires authentication</mat-checkbox> - <mat-form-field color="accent" *ngIf="mailConfig.usesAuthentication"> - <mat-label>SMTP Username</mat-label> - <input formControlName="smtpUsername" fxFlex - matInput> - </mat-form-field> - <mat-form-field color="accent" *ngIf="mailConfig.usesAuthentication"> - <mat-label>SMTP Password</mat-label> - <input formControlName="smtpPassword" fxFlex type="password" - matInput> - </mat-form-field> - <div class="subsection-title mt-20">Proxy</div> - <mat-checkbox formControlName="usesProxy">Uses proxy</mat-checkbox> - <mat-form-field color="accent" *ngIf="mailConfig.usesProxy"> - <mat-label>Proxy Host</mat-label> - <input formControlName="proxyHost" fxFlex - matInput> - </mat-form-field> - <mat-form-field color="accent" *ngIf="mailConfig.usesProxy"> - <mat-label>Proxy Port</mat-label> - <input formControlName="proxyPort" fxFlex - matInput> - </mat-form-field> - <mat-checkbox formControlName="usesProxyAuthentication" *ngIf="mailConfig.usesProxy"> - Proxy requires authentication - </mat-checkbox> - <mat-form-field color="accent" *ngIf="mailConfig.usesProxy && mailConfig.usesProxyAuthentication"> - <mat-label>Proxy Username</mat-label> - <input formControlName="proxyUsername" fxFlex - matInput> - </mat-form-field> - <mat-form-field color="accent" *ngIf="mailConfig.usesProxy && mailConfig.usesProxyAuthentication"> - <mat-label>Proxy Password</mat-label> - <input formControlName="proxyPassword" fxFlex type="password" - matInput> - </mat-form-field> - <div class="subsection-title mt-20">Sender</div> - <mat-form-field color="accent"> - <mat-label>Sender Email Address</mat-label> - <input formControlName="senderAddress" fxFlex - matInput - required> - </mat-form-field> - <mat-form-field color="accent"> - <mat-label>Sender Name</mat-label> - <input formControlName="senderName" fxFlex - matInput> - </mat-form-field> - <mat-form-field color="accent"> - <mat-label>Recipient for test mail</mat-label> - <input formControlName="defaultRecipient" fxFlex - matInput> - </mat-form-field> - <div fxLayout="row"> - <button mat-button mat-raised-button color="accent" (click)="save()" style="margin-right:10px;" - [disabled]="!parentForm.valid" - data-cy="sp-element-email-config-save"> - <i class="material-icons">save</i><span> Save</span> - </button> - <button mat-button mat-raised-button class="mat-basic" (click)="sendTestMail()" style="margin-right:10px;" - [disabled]="!parentForm.valid || sendingTestMailInProgress" - data-cy="sp-element-email-config-test"> - <span>Send Test Mail</span> - </button> - </div> - <div fxLayout="column" *ngIf="attemptSendingTestMail"> - <div fxLayout="row" *ngIf="sendingTestMailInProgress"> - <mat-progress-spinner diameter="10"></mat-progress-spinner> - <h5>Trying to send test mail...</h5> - </div> +<sp-basic-nav-tabs [spNavigationItems]="tabs" [activeLink]="'email'"> + <div fxLayout="column" class="page-container-padding"> + <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" *ngIf="formReady"> + <sp-split-section title="Mail Settings" subtitle="Settings to connect to a mail server"> + <form [formGroup]="parentForm" fxFlex="100" fxLayout="column"> + <div class="subsection-title">Mail Server</div> + <mat-form-field color="accent"> + <mat-label>SMTP Host</mat-label> + <input formControlName="smtpServerHost" fxFlex matInput required> + </mat-form-field> + <mat-form-field color="accent"> + <mat-label>SMTP Port</mat-label> + <input type="number" formControlName="smtpServerPort" fxFlex matInput required> + </mat-form-field> + <div class="subsection-title">Transport</div> + <mat-radio-group fxLayout="column" formControlName="transport"> + <mat-radio-button value="SMTP" class="m-5">SMTP</mat-radio-button> + <mat-radio-button value="SMTPS" class="m-5">SMTPS</mat-radio-button> + <mat-radio-button value="SMTP_TLS" class="m-5">TLS</mat-radio-button> + </mat-radio-group> + <div class="subsection-title mt-20">Authentication</div> + <mat-checkbox formControlName="usesAuthentication">SMTP server requires authentication + </mat-checkbox> + <mat-form-field color="accent" *ngIf="mailConfig.usesAuthentication"> + <mat-label>SMTP Username</mat-label> + <input formControlName="smtpUsername" fxFlex matInput> + </mat-form-field> + <mat-form-field color="accent" *ngIf="mailConfig.usesAuthentication"> + <mat-label>SMTP Password</mat-label> + <input formControlName="smtpPassword" fxFlex type="password" matInput> + </mat-form-field> + <div class="subsection-title mt-20">Proxy</div> + <mat-checkbox formControlName="usesProxy">Uses proxy</mat-checkbox> + <mat-form-field color="accent" *ngIf="mailConfig.usesProxy"> + <mat-label>Proxy Host</mat-label> + <input formControlName="proxyHost" fxFlex matInput> + </mat-form-field> + <mat-form-field color="accent" *ngIf="mailConfig.usesProxy"> + <mat-label>Proxy Port</mat-label> + <input formControlName="proxyPort" fxFlex matInput> + </mat-form-field> + <mat-checkbox formControlName="usesProxyAuthentication" *ngIf="mailConfig.usesProxy"> + Proxy requires authentication + </mat-checkbox> + <mat-form-field color="accent" *ngIf="mailConfig.usesProxy && mailConfig.usesProxyAuthentication"> + <mat-label>Proxy Username</mat-label> + <input formControlName="proxyUsername" fxFlex matInput> + </mat-form-field> + <mat-form-field color="accent" *ngIf="mailConfig.usesProxy && mailConfig.usesProxyAuthentication"> + <mat-label>Proxy Password</mat-label> + <input formControlName="proxyPassword" fxFlex type="password" matInput> + </mat-form-field> + <div class="subsection-title mt-20">Sender</div> + <mat-form-field color="accent"> + <mat-label>Sender Email Address</mat-label> + <input formControlName="senderAddress" fxFlex matInput required> + </mat-form-field> + <mat-form-field color="accent"> + <mat-label>Sender Name</mat-label> + <input formControlName="senderName" fxFlex matInput> + </mat-form-field> + <mat-form-field color="accent"> + <mat-label>Recipient for test mail</mat-label> + <input formControlName="defaultRecipient" fxFlex matInput> + </mat-form-field> <div fxLayout="row"> - <h5 *ngIf="!sendingTestMailInProgress && sendingTestMailSuccess">Success - please check your mail inbox.</h5> - <div fxLayout="column" *ngIf="!sendingTestMailInProgress && !sendingTestMailSuccess"> - Failure - <h5>{{sendingEmailErrorMessage}}</h5> + <button mat-button mat-raised-button color="accent" (click)="save()" style="margin-right:10px;" + [disabled]="!parentForm.valid" data-cy="sp-element-email-config-save"> + <i class="material-icons">save</i><span> Save</span> + </button> + <button mat-button mat-raised-button class="mat-basic" (click)="sendTestMail()" + style="margin-right:10px;" [disabled]="!parentForm.valid || sendingTestMailInProgress" + data-cy="sp-element-email-config-test"> + <span>Send Test Mail</span> + </button> + </div> + <div fxLayout="column" *ngIf="attemptSendingTestMail"> + <div fxLayout="row" *ngIf="sendingTestMailInProgress"> + <mat-progress-spinner diameter="10"></mat-progress-spinner> + <h5>Trying to send test mail...</h5> + </div> + <div fxLayout="row"> + <h5 *ngIf="!sendingTestMailInProgress && sendingTestMailSuccess">Success - please check your + mail inbox.</h5> + <div fxLayout="column" *ngIf="!sendingTestMailInProgress && !sendingTestMailSuccess"> + Failure + <h5>{{sendingEmailErrorMessage}}</h5> + </div> </div> </div> - </div> - </form> - </sp-split-section> + </form> + </sp-split-section> + </div> + <mat-divider></mat-divider> + + </div> - <mat-divider></mat-divider> - - -</div> - +</sp-basic-nav-tabs>
diff --git a/ui/src/app/configuration/email-configuration/email-configuration.component.ts b/ui/src/app/configuration/email-configuration/email-configuration.component.ts index 698780c..4c49b40 100644 --- a/ui/src/app/configuration/email-configuration/email-configuration.component.ts +++ b/ui/src/app/configuration/email-configuration/email-configuration.component.ts
@@ -19,6 +19,9 @@ import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { EmailConfig, MailConfigService } from '@streampipes/platform-services'; +import { SpConfigurationTabs } from '../configuration-tabs'; +import { SpConfigurationRoutes } from '../configuration.routes'; +import { SpBreadcrumbService } from '@streampipes/shared-ui'; @Component({ selector: 'sp-email-configuration', @@ -27,6 +30,8 @@ }) export class EmailConfigurationComponent implements OnInit { + tabs = SpConfigurationTabs.getTabs(); + parentForm: FormGroup; mailConfig: EmailConfig; @@ -39,9 +44,11 @@ sendingEmailErrorMessage = ''; constructor(private fb: FormBuilder, - private mailConfigService: MailConfigService) {} + private mailConfigService: MailConfigService, + private breadcrumbService: SpBreadcrumbService) {} ngOnInit(): void { + this.breadcrumbService.updateBreadcrumb([SpConfigurationRoutes.BASE, {label: SpConfigurationTabs.getTabs()[2].itemTitle}]); this.loadMailConfig(true); }
diff --git a/ui/src/app/configuration/export/data-export-import.component.html b/ui/src/app/configuration/export/data-export-import.component.html new file mode 100644 index 0000000..44352f4 --- /dev/null +++ b/ui/src/app/configuration/export/data-export-import.component.html
@@ -0,0 +1,52 @@ +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~ + --> + +<sp-basic-nav-tabs [spNavigationItems]="tabs" [activeLink]="'export'"> + <div fxLayout="column" class="page-container-padding"> + <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start"> + <sp-split-section title="Export" subtitle="Export application data"> + <div class="subsection-title">Export assets and all linked resources</div> + <div fxLayout="column" *ngFor="let asset of assets"> + <mat-checkbox (change)="handleSelectionChange($event, asset._id)"><h4>{{asset.assetName}}</h4></mat-checkbox> + </div> + <div class="mt-10"> + <button mat-button + mat-raised-button + color="accent" + [disabled]="selectedAssets.length === 0" + (click)="openExportDialog()"> + <i class="material-icons">cloud_download</i><span> Start export process</span> + </button> + </div> + </sp-split-section> + </div> + <mat-divider></mat-divider> + <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start"> + <sp-split-section title="Import" subtitle="Import application data"> + <div class="subsection-title">Import from application package</div> + + <div class="mt-10"> + <button mat-button mat-raised-button color="accent" (click)="openImportDialog()"> + <i class="material-icons">cloud_upload</i><span> Start import process</span> + </button> + </div> + </sp-split-section> + </div> + </div> +</sp-basic-nav-tabs> +
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/configuration/export/data-export-import.component.scss similarity index 99% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/configuration/export/data-export-import.component.scss index 58ba04b..13cbc4a 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/configuration/export/data-export-import.component.scss
@@ -15,4 +15,3 @@ * limitations under the License. * */ -
diff --git a/ui/src/app/configuration/export/data-export-import.component.ts b/ui/src/app/configuration/export/data-export-import.component.ts new file mode 100644 index 0000000..f44891c --- /dev/null +++ b/ui/src/app/configuration/export/data-export-import.component.ts
@@ -0,0 +1,96 @@ +/* + * 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 { DialogService, PanelType, SpBreadcrumbService } from '@streampipes/shared-ui'; +import { SpConfigurationRoutes } from '../configuration.routes'; +import { SpConfigurationTabs } from '../configuration-tabs'; +import { AssetManagementService, SpAsset } from '@streampipes/platform-services'; +import { MatCheckboxChange } from '@angular/material/checkbox'; +import { SpDataExportDialogComponent } from './export-dialog/data-export-dialog.component'; +import { SpDataImportDialogComponent } from './import-dialog/data-import-dialog.component'; + +@Component({ + selector: 'sp-data-export-import', + templateUrl: './data-export-import.component.html', + styleUrls: ['./data-export-import.component.scss'] +}) +export class SpDataExportImportComponent implements OnInit { + + tabs = SpConfigurationTabs.getTabs(); + + assets: SpAsset[]; + selectedAssets: string[] = []; + + constructor(private breadcrumbService: SpBreadcrumbService, + private assetManagementService: AssetManagementService, + private dialogService: DialogService) { + + } + + ngOnInit(): void { + this.breadcrumbService + .updateBreadcrumb([SpConfigurationRoutes.BASE, {label: SpConfigurationTabs.getTabs()[3].itemTitle}]); + this.loadAssets(); + } + + loadAssets(): void { + this.assetManagementService + .getAllAssets() + .subscribe(assets => this.assets = assets.sort((a, b) => a.assetName.localeCompare(b.assetName))); + } + + handleSelectionChange(event: MatCheckboxChange, + assetId: string) { + if (event.checked) { + this.selectedAssets.push(assetId); + } else { + this.selectedAssets.splice(this.selectedAssets.indexOf(assetId), 1); + } + } + + openExportDialog(): void { + const dialogRef = this.dialogService.open(SpDataExportDialogComponent, { + panelType: PanelType.SLIDE_IN_PANEL, + title: 'Export resources', + width: '50vw', + data: { + 'selectedAssets': this.selectedAssets, + } + }); + + dialogRef.afterClosed().subscribe(() => { + + }); + } + + openImportDialog(): void { + const dialogRef = this.dialogService.open(SpDataImportDialogComponent, { + panelType: PanelType.SLIDE_IN_PANEL, + title: 'Import resources', + width: '50vw', + data: { + } + }); + + dialogRef.afterClosed().subscribe(() => { + + }); + } + +}
diff --git a/ui/src/app/configuration/export/data-export.service.ts b/ui/src/app/configuration/export/data-export.service.ts new file mode 100644 index 0000000..5f3c1d9 --- /dev/null +++ b/ui/src/app/configuration/export/data-export.service.ts
@@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { Injectable } from '@angular/core'; +import { AssetExportConfiguration, PlatformServicesCommons, ExportConfiguration } from '@streampipes/platform-services'; +import { HttpClient, HttpEvent, HttpParams, HttpRequest } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +@Injectable({providedIn: 'root'}) +export class DataExportService { + + constructor(private platformServicesCommons: PlatformServicesCommons, + private http: HttpClient) { + } + + getExportPreview(assetIds: string[]): Observable<ExportConfiguration> { + return this.http.post(this.exportBasePath + '/preview', assetIds) + .pipe(map(res => res as ExportConfiguration)); + } + + triggerExport(exportConfig: ExportConfiguration): Observable<Blob> { + return this.http.post(this.exportBasePath + '/download', exportConfig, {responseType: 'blob'}); + } + + triggerImport(file: File, + config: AssetExportConfiguration) { + const data: FormData = new FormData(); + data.append('file_upload', file, file.name); + data.append('configuration', new Blob([JSON.stringify(config)], {type: 'application/json'})); + + const params = new HttpParams(); + const options = { + params, + reportProgress: true, + }; + + const req = new HttpRequest('POST', this.importBasePath, data, options); + return this.http.request(req); + } + + getImportPreview(file: File): Observable<HttpEvent<any>> { + const data: FormData = new FormData(); + data.append('file_upload', file, file.name); + + const params = new HttpParams(); + const options = { + params, + reportProgress: true, + }; + + const req = new HttpRequest('POST', this.importBasePath + '/preview', data, options); + return this.http.request(req); + } + + private get exportBasePath(): string { + return this.platformServicesCommons.apiBasePath + '/export'; + } + + private get importBasePath(): string { + return this.platformServicesCommons.apiBasePath + '/import'; + } + +}
diff --git a/ui/src/app/configuration/export/export-dialog/data-export-dialog.component.html b/ui/src/app/configuration/export/export-dialog/data-export-dialog.component.html new file mode 100644 index 0000000..3dbfec2 --- /dev/null +++ b/ui/src/app/configuration/export/export-dialog/data-export-dialog.component.html
@@ -0,0 +1,56 @@ +<!-- + ~ 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"> + <div fxFlex="100" fxLayout="column" class="p-15" *ngIf="preview && !exportInProgress"> + <div *ngFor="let config of preview.assetExportConfiguration"> + <h4>Exported items {{config.assetName}}</h4> + <sp-data-export-item [exportItems]="config.adapters" sectionTitle="Adapters"></sp-data-export-item> + <sp-data-export-item [exportItems]="config.dashboards" sectionTitle="Dashboards"></sp-data-export-item> + <sp-data-export-item [exportItems]="config.dataViews" sectionTitle="Data Views"></sp-data-export-item> + <sp-data-export-item [exportItems]="config.dataSources" sectionTitle="Data Sources"></sp-data-export-item> + <sp-data-export-item [exportItems]="config.dataLakeMeasures" sectionTitle="Data Lake Storage"></sp-data-export-item> + <sp-data-export-item [exportItems]="config.files" sectionTitle="Files"></sp-data-export-item> + <sp-data-export-item [exportItems]="config.pipelines" sectionTitle="Pipelines"></sp-data-export-item> + </div> + </div> + <div fxFlex="100" fxLayout="column" *ngIf="exportInProgress" class="mt-10" fxLayoutAlign="center center"> + <mat-spinner [diameter]="50" color="accent"></mat-spinner> + <h4 class="mt-10">Exporting resources...</h4> + <h5 class="mt-10">Depending on number and size of exported files, this might take a while...</h5> + </div> + + </div> + <mat-divider></mat-divider> + <div class="sp-dialog-actions"> + <div fxLayout="column"> + <div fxLayout="row"> + <button mat-button + mat-raised-button + color="accent" + style="margin-right: 10px;" (click)="generateDownloadPackage()"> + <i class="material-icons">file_download</i><span> Download export</span> + </button> + <button mat-button mat-raised-button class="mat-basic" (click)="close()"> + Cancel + </button> + </div> + </div> + </div> +</div>
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/configuration/export/export-dialog/data-export-dialog.component.scss similarity index 93% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/configuration/export/export-dialog/data-export-dialog.component.scss index 58ba04b..fddade7 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/configuration/export/export-dialog/data-export-dialog.component.scss
@@ -16,3 +16,4 @@ * */ +@import '../../../../scss/sp/sp-dialog.scss';
diff --git a/ui/src/app/configuration/export/export-dialog/data-export-dialog.component.ts b/ui/src/app/configuration/export/export-dialog/data-export-dialog.component.ts new file mode 100644 index 0000000..df8d7d8 --- /dev/null +++ b/ui/src/app/configuration/export/export-dialog/data-export-dialog.component.ts
@@ -0,0 +1,66 @@ +/* + * 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, Input, OnInit } from '@angular/core'; +import { DialogRef } from '@streampipes/shared-ui'; +import { DataExportService } from '../data-export.service'; +import { ExportConfiguration } from '@streampipes/platform-services'; + +@Component({ + selector: 'sp-data-export-dialog', + templateUrl: './data-export-dialog.component.html', + styleUrls: ['./data-export-dialog.component.scss'], +}) +export class SpDataExportDialogComponent implements OnInit { + + @Input() + selectedAssets: string[]; + + preview: ExportConfiguration; + exportInProgress = false; + + constructor(private dialogRef: DialogRef<SpDataExportDialogComponent>, + private dataExportService: DataExportService) { + + } + + ngOnInit(): void { + this.dataExportService.getExportPreview(this.selectedAssets).subscribe(preview => { + this.preview = preview; + }); + } + + close(): void { + this.dialogRef.close(); + } + + generateDownloadPackage(): void { + this.exportInProgress = true; + this.dataExportService.triggerExport(this.preview).subscribe(result => { + this.downloadFile(result); + }); + } + + downloadFile(data: any) { + const blob = new Blob([data], { type: 'application/zip' }); + const url = window.URL.createObjectURL(blob); + window.open(url); + this.dialogRef.close(); + } + +}
diff --git a/ui/src/app/connect/connect.component.html b/ui/src/app/configuration/export/export-dialog/data-export-item/data-export-item.component.html similarity index 73% rename from ui/src/app/connect/connect.component.html rename to ui/src/app/configuration/export/export-dialog/data-export-item/data-export-item.component.html index 5a97b18..d9879aa 100644 --- a/ui/src/app/connect/connect.component.html +++ b/ui/src/app/configuration/export/export-dialog/data-export-item/data-export-item.component.html
@@ -1,20 +1,26 @@ -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one or more - ~ contributor license agreements. See the NOTICE file distributed with - ~ this work for additional information regarding copyright ownership. - ~ The ASF licenses this file to You under the Apache License, Version 2.0 - ~ (the "License"); you may not use this file except in compliance with - ~ the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - ~ - --> - -<sp-data-marketplace *ngIf="newAdapterFromDescription===undefined" (selectAdapterEmitter)="selectAdapter($event)"></sp-data-marketplace> - +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~ + --> + +<div fxLayout="column" fxFlex="100"> + <h5>{{sectionTitle}}</h5> + <mat-checkbox *ngFor="let exportItem of exportItems; let i = index" + [checked]="exportItem.selected" + (change)="changeItem($event, i)"> + {{exportItem.label}} + </mat-checkbox> +</div>
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/configuration/export/export-dialog/data-export-item/data-export-item.component.scss similarity index 99% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/configuration/export/export-dialog/data-export-item/data-export-item.component.scss index 58ba04b..13cbc4a 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/configuration/export/export-dialog/data-export-item/data-export-item.component.scss
@@ -15,4 +15,3 @@ * limitations under the License. * */ -
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.ts b/ui/src/app/configuration/export/export-dialog/data-export-item/data-export-item.component.ts similarity index 63% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.ts copy to ui/src/app/configuration/export/export-dialog/data-export-item/data-export-item.component.ts index 4e64c25..1d6e683 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.ts +++ b/ui/src/app/configuration/export/export-dialog/data-export-item/data-export-item.component.ts
@@ -17,22 +17,29 @@ */ import { Component, Input, OnInit } from '@angular/core'; -import { Notification } from '@streampipes/platform-services'; +import { ExportItem } from '@streampipes/platform-services'; +import { MatCheckboxChange } from '@angular/material/checkbox'; @Component({ - selector: 'sp-error-message', - templateUrl: './error-message.component.html', - styleUrls: ['./error-message.component.scss'] + selector: 'sp-data-export-item', + templateUrl: './data-export-item.component.html', + styleUrls: ['./data-export-item.component.scss'], }) -export class ErrorMessageComponent implements OnInit { +export class SpDataExportItemComponent implements OnInit { - @Input() errorMessages: Notification[]; + @Input() + exportItems: ExportItem[]; - showErrorMessage = false; - - constructor() { } + @Input() + sectionTitle: string; ngOnInit(): void { } + changeItem(event: MatCheckboxChange, + index: number) { + this.exportItems[index].selected = event.checked; + } + + }
diff --git a/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.html b/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.html new file mode 100644 index 0000000..630b7cb --- /dev/null +++ b/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.html
@@ -0,0 +1,106 @@ +<!-- + ~ 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"> + <div fxFlex="100" fxLayout="column" class="p-15" *ngIf="currentImportStep === 0"> + <h4>Upload application package file</h4> + <mat-form-field style="width: 95%" (click)="fileInput.click();" color="accent"> + <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" + color="accent"> + </mat-progress-bar> + </div> + <button color="accent" + 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 fxFlex="100" fxLayout="column" class="p-15" *ngIf="currentImportStep === 1"> + <h4>Select resources to import</h4> + <sp-data-export-item [exportItems]="importConfiguration.assets" sectionTitle="Assets"></sp-data-export-item> + <sp-data-export-item [exportItems]="importConfiguration.adapters" sectionTitle="Adapters"></sp-data-export-item> + <sp-data-export-item [exportItems]="importConfiguration.dashboards" sectionTitle="Dashboards"></sp-data-export-item> + <sp-data-export-item [exportItems]="importConfiguration.dataViews" sectionTitle="Data Views"></sp-data-export-item> + <sp-data-export-item [exportItems]="importConfiguration.dataSources" sectionTitle="Data Sources"></sp-data-export-item> + <sp-data-export-item [exportItems]="importConfiguration.dataLakeMeasures" sectionTitle="Data Lake Storage"></sp-data-export-item> + <sp-data-export-item [exportItems]="importConfiguration.files" sectionTitle="Files"></sp-data-export-item> + <sp-data-export-item [exportItems]="importConfiguration.pipelines" sectionTitle="Pipelines"></sp-data-export-item> + + <div fxFlex="100" fxLayout="column" *ngIf="currentImportStep === 1" class="mt-10"> + <h4>Import options</h4> + <div fxLayout="column"*ngIf="importConfiguration"> + <mat-checkbox [(ngModel)]="importConfiguration.overrideBrokerSettings">Use broker settings from this instance</mat-checkbox> + </div> + </div> + </div> + <div fxFlex="100" fxLayout="column" *ngIf="currentImportStep === 2" class="mt-10" fxLayoutAlign="center center"> + <mat-spinner [diameter]="50" color="accent"></mat-spinner> + <h4 class="mt-10">Importing resources...</h4> + </div> + + </div> + <mat-divider></mat-divider> + <div class="sp-dialog-actions"> + <div fxLayout="column"> + <div fxLayout="row"> + <button mat-button + mat-raised-button + color="accent" + style="margin-right: 10px;" (click)="performPreview()" + *ngIf="currentImportStep === 0" + [disabled]="!hasInput"> + <span> Next</span> + </button> + <button mat-button + mat-raised-button + color="accent" + style="margin-right: 10px;" + *ngIf="currentImportStep === 1" (click)="performImport()"> + <i class="material-icons">file_download</i><span> Import data</span> + </button> + <button mat-button + mat-raised-button + class="mat-basic" + style="margin-right: 10px;" + (click)="back()" *ngIf="currentImportStep > 0"> + Back + </button> + <button mat-button + mat-raised-button + class="mat-basic" + (click)="close()"> + Cancel + </button> + </div> + </div> + </div> +</div> +
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.scss similarity index 93% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/configuration/export/import-dialog/data-import-dialog.component.scss index 58ba04b..fddade7 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.scss
@@ -16,3 +16,4 @@ * */ +@import '../../../../scss/sp/sp-dialog.scss';
diff --git a/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.ts b/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.ts new file mode 100644 index 0000000..ea40c28 --- /dev/null +++ b/ui/src/app/configuration/export/import-dialog/data-import-dialog.component.ts
@@ -0,0 +1,95 @@ +/* + * 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 '@streampipes/shared-ui'; +import { DataExportService } from '../data-export.service'; +import { HttpEventType, HttpResponse } from '@angular/common/http'; +import { AssetExportConfiguration } from '../../../../../dist/streampipes/platform-services'; + +@Component({ + selector: 'sp-data-import-dialog', + templateUrl: './data-import-dialog.component.html', + styleUrls: ['./data-import-dialog.component.scss'], +}) +export class SpDataImportDialogComponent implements OnInit { + + currentImportStep = 0; + + inputValue: string; + fileName: string; + + selectedUploadFile: File; + importConfiguration: AssetExportConfiguration; + + hasInput = false; + errorMessage = 'Please enter a value'; + + uploadStatus = 0; + + constructor(private dialogRef: DialogRef<SpDataImportDialogComponent>, + private dataExportService: DataExportService) { + + } + + ngOnInit(): void { + } + + handleFileInput(files: any) { + this.hasInput = true; + this.selectedUploadFile = files[0]; + this.fileName = this.selectedUploadFile.name; + this.uploadStatus = 0; + } + + performPreview(): void { + this.uploadStatus = 0; + if (this.selectedUploadFile !== undefined) { + this.dataExportService.getImportPreview(this.selectedUploadFile).subscribe( + event => { + if (event.type === HttpEventType.UploadProgress) { + this.uploadStatus = Math.round(100 * event.loaded / event.total); + } else if (event instanceof HttpResponse) { + this.importConfiguration = event.body as AssetExportConfiguration; + this.importConfiguration.overrideBrokerSettings = true; + this.currentImportStep++; + } + }, + error => { + }, + ); + } + } + + performImport(): void { + this.currentImportStep = 2; + this.dataExportService.triggerImport(this.selectedUploadFile, this.importConfiguration).subscribe(result => { + this.dialogRef.close(); + }); + } + + back(): void { + this.currentImportStep--; + } + + close(): void { + this.dialogRef.close(); + } + + +}
diff --git a/ui/src/app/configuration/general-configuration/general-configuration.component.html b/ui/src/app/configuration/general-configuration/general-configuration.component.html index 2df1134..b6cfae4 100644 --- a/ui/src/app/configuration/general-configuration/general-configuration.component.html +++ b/ui/src/app/configuration/general-configuration/general-configuration.component.html
@@ -15,84 +15,78 @@ ~ limitations under the License. ~ --> - -<div fxLayout="column" class="page-container-padding"> - <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" *ngIf="formReady"> - <form [formGroup]="parentForm" fxFlex="100" fxLayout="column"> - <div class="warning mb-10" *ngIf="!generalConfig.configured">These are default values - to use features - such as email you need to store these values once. - </div> - <sp-split-section title="Basic" - subtitle="Basic settings"> - <div class="subsection-title">App Name</div> - <mat-form-field color="accent" class="ml-10"> - <mat-label>App Name</mat-label> - <input formControlName="appName" fxFlex - matInput - required> - </mat-form-field> - <div class="subsection-title">Host and Port</div> - <div fxLayout="column" fxFlex="100"> - <div fxLayout="row"> - <div> - <mat-button-toggle-group name="protocol" aria-label="Protocol" formControlName="protocol"> - <mat-button-toggle value="http">http</mat-button-toggle> - <mat-button-toggle value="https">https</mat-button-toggle> - </mat-button-toggle-group> +<sp-basic-nav-tabs [spNavigationItems]="tabs" [activeLink]="'general'"> + <div fxLayout="column" class="page-container-padding"> + <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" *ngIf="formReady"> + <form [formGroup]="parentForm" fxFlex="100" fxLayout="column"> + <div class="warning mb-10" *ngIf="!generalConfig.configured">These are default values - to use features + such as email you need to store these values once. + </div> + <sp-split-section title="Basic" subtitle="Basic settings"> + <div class="subsection-title">App Name</div> + <mat-form-field color="accent" class="ml-10"> + <mat-label>App Name</mat-label> + <input formControlName="appName" fxFlex matInput required> + </mat-form-field> + <div class="subsection-title">Host and Port</div> + <div fxLayout="column" fxFlex="100"> + <div fxLayout="row"> + <div fxLayout="row" fxLayoutAlign="start center"> + <mat-button-toggle-group name="protocol" aria-label="Protocol" + formControlName="protocol"> + <mat-button-toggle value="http">http</mat-button-toggle> + <mat-button-toggle value="https">https</mat-button-toggle> + </mat-button-toggle-group> + </div> + <mat-form-field color="accent" class="ml-10"> + <mat-label>Host</mat-label> + <input formControlName="hostname" fxFlex matInput required> + </mat-form-field> + <mat-form-field color="accent" class="ml-10"> + <mat-label>Port</mat-label> + <input formControlName="port" fxFlex matInput type="number" required> + </mat-form-field> </div> - <mat-form-field color="accent" class="ml-10"> - <mat-label>Host</mat-label> - <input formControlName="hostname" fxFlex - matInput - required> - </mat-form-field> - <mat-form-field color="accent" class="ml-10"> - <mat-label>Port</mat-label> - <input formControlName="port" fxFlex - matInput - type="number" - required> - </mat-form-field> </div> - </div> - <div class="mt-10"> - <button mat-button mat-raised-button color="accent" (click)="updateConfig()" - style="margin-right:10px;" - [disabled]="!parentForm.valid" + <div class="mt-10"> + <button mat-button mat-raised-button color="accent" (click)="updateConfig()" + style="margin-right:10px;" [disabled]="!parentForm.valid" data-cy="sp-element-general-config-save"> - <i class="material-icons">save</i><span> Save</span> - </button> - </div> - </sp-split-section> - <mat-divider></mat-divider> - <sp-split-section title="Registration" - subtitle="Registration process"> - <div class="warning mb-10" *ngIf="!generalConfig.configured || !mailConfig.emailConfigured">Requires valid - mail server settings and basic host settings. - </div> - <mat-checkbox [disabled]="!generalConfig.configured || !mailConfig.emailConfigured" - formControlName="allowSelfRegistration">Allow self-registration - </mat-checkbox> - <div *ngIf="generalConfig.allowSelfRegistration" class="mt-10 mb-10"> - <h5>Default roles for new users</h5> - <mat-select formControlName="defaultUserRoles" [multiple]="true"> - <mat-option *ngFor="let role of availableRoles" [value]="role.role">{{role.roleTitle}}</mat-option> - </mat-select> - </div> - <mat-checkbox [disabled]="!generalConfig.configured || !mailConfig.emailConfigured" - formControlName="allowPasswordRecovery">Allow self-service password recovery - </mat-checkbox> + <i class="material-icons">save</i><span> Save</span> + </button> + </div> + </sp-split-section> + <mat-divider></mat-divider> + <sp-split-section title="Registration" subtitle="Registration process"> + <div class="warning mb-10" *ngIf="!generalConfig.configured || !mailConfig.emailConfigured">Requires + valid + mail server settings and basic host settings. + </div> + <mat-checkbox [disabled]="!generalConfig.configured || !mailConfig.emailConfigured" + formControlName="allowSelfRegistration">Allow self-registration + </mat-checkbox> + <div *ngIf="generalConfig.allowSelfRegistration" class="mt-10 mb-10"> + <h5>Default roles for new users</h5> + <mat-select formControlName="defaultUserRoles" [multiple]="true"> + <mat-option *ngFor="let role of availableRoles" [value]="role.role">{{role.roleTitle}} + </mat-option> + </mat-select> + </div> + <mat-checkbox [disabled]="!generalConfig.configured || !mailConfig.emailConfigured" + formControlName="allowPasswordRecovery">Allow self-service password recovery + </mat-checkbox> - <div class="mt-10"> - <button mat-button mat-raised-button color="accent" (click)="updateConfig()" + <div class="mt-10"> + <button mat-button mat-raised-button color="accent" (click)="updateConfig()" style="margin-right:10px;" [disabled]="!generalConfig.configured || !mailConfig.emailConfigured" data-cy="sp-element-general-registration-config-save"> - <i class="material-icons">save</i><span> Save</span> - </button> - </div> - </sp-split-section> - </form> - </div> + <i class="material-icons">save</i><span> Save</span> + </button> + </div> + </sp-split-section> + </form> + </div> -</div> + </div> +</sp-basic-nav-tabs>
diff --git a/ui/src/app/configuration/general-configuration/general-configuration.component.ts b/ui/src/app/configuration/general-configuration/general-configuration.component.ts index 7c3a787..a2a5536 100644 --- a/ui/src/app/configuration/general-configuration/general-configuration.component.ts +++ b/ui/src/app/configuration/general-configuration/general-configuration.component.ts
@@ -18,12 +18,20 @@ import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; -import { GeneralConfigService, GeneralConfigModel, MailConfigService, EmailConfig } from '@streampipes/platform-services'; +import { + EmailConfig, + GeneralConfigModel, + GeneralConfigService, + MailConfigService +} from '@streampipes/platform-services'; import { zip } from 'rxjs'; import { AvailableRolesService } from '../../services/available-roles.service'; import { RoleDescription } from '../../_models/auth.model'; import { UserRole } from '../../_enums/user-role.enum'; import { AppConstants } from '../../services/app.constants'; +import { SpConfigurationTabs } from '../configuration-tabs'; +import { SpBreadcrumbService } from '@streampipes/shared-ui'; +import { SpConfigurationRoutes } from '../configuration.routes'; @Component({ selector: 'sp-general-configuration', @@ -32,6 +40,8 @@ }) export class GeneralConfigurationComponent implements OnInit { + tabs = SpConfigurationTabs.getTabs(); + parentForm: FormGroup; formReady = false; @@ -44,9 +54,11 @@ private generalConfigService: GeneralConfigService, private mailConfigService: MailConfigService, private availableRolesService: AvailableRolesService, - private appConstants: AppConstants) {} + private appConstants: AppConstants, + private breadcrumbService: SpBreadcrumbService) {} ngOnInit(): void { + this.breadcrumbService.updateBreadcrumb([SpConfigurationRoutes.BASE, {label: SpConfigurationTabs.getTabs()[0].itemTitle}]); this.availableRoles = this.availableRolesService.availableRoles.filter(role => role.role !== UserRole.ROLE_ADMIN); zip(this.generalConfigService.getGeneralConfig(), this.mailConfigService.getMailConfig()).subscribe(configs => { if (configs[0].configured) {
diff --git a/ui/src/app/configuration/messaging-configuration/messaging-configuration.component.html b/ui/src/app/configuration/messaging-configuration/messaging-configuration.component.html index 61d96e3..ed44cf6 100644 --- a/ui/src/app/configuration/messaging-configuration/messaging-configuration.component.html +++ b/ui/src/app/configuration/messaging-configuration/messaging-configuration.component.html
@@ -16,78 +16,71 @@ ~ --> -<div fxLayout="column" class="page-container-padding"> - <sp-split-section title="Kafka Settings" - subtitle="Manage Kafka settings for pipeline communication"> - <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" class="page-container-padding-inner"> - <form (ngSubmit)="updateMessagingSettings()" class="form-width" fxFlex="100" fxLayout="column" - *ngIf="loadingCompleted"> - <mat-form-field class="form-field" fxFlex="100"> - <input matInput [(ngModel)]="messagingSettings.batchSize" - [placeholder]="'Batch Size'" type="text" - [ngModelOptions]="{standalone: true}"> - </mat-form-field> - <mat-form-field class="form-field" fxFlex="100"> - <input matInput [(ngModel)]="messagingSettings.messageMaxBytes" - [placeholder]="'Message Max Bytes'" type="text" - [ngModelOptions]="{standalone: true}"> - </mat-form-field> - <mat-form-field class="form-field" fxFlex="100"> - <input matInput [(ngModel)]="messagingSettings.acks" - [placeholder]="'Acks'" type="text" - [ngModelOptions]="{standalone: true}"> - </mat-form-field> - <mat-form-field class="form-field" fxFlex="100"> - <input matInput [(ngModel)]="messagingSettings.lingerMs" - [placeholder]="'Linger MS'" type="text" - [ngModelOptions]="{standalone: true}"> - </mat-form-field> - <div fxLayoutAlign="start center" class="mt-10"> - <button mat-raised-button color="accent" type="submit" +<sp-basic-nav-tabs [spNavigationItems]="tabs" [activeLink]="'messaging'"> + <div fxLayout="column" class="page-container-padding"> + <sp-split-section title="Kafka Settings" subtitle="Manage Kafka settings for pipeline communication"> + <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" class="page-container-padding-inner"> + <form (ngSubmit)="updateMessagingSettings()" class="form-width" fxFlex="100" fxLayout="column" + *ngIf="loadingCompleted"> + <mat-form-field class="form-field" fxFlex="100"> + <input matInput [(ngModel)]="messagingSettings.batchSize" [placeholder]="'Batch Size'" + type="text" [ngModelOptions]="{standalone: true}"> + </mat-form-field> + <mat-form-field class="form-field" fxFlex="100"> + <input matInput [(ngModel)]="messagingSettings.messageMaxBytes" + [placeholder]="'Message Max Bytes'" type="text" [ngModelOptions]="{standalone: true}"> + </mat-form-field> + <mat-form-field class="form-field" fxFlex="100"> + <input matInput [(ngModel)]="messagingSettings.acks" [placeholder]="'Acks'" type="text" + [ngModelOptions]="{standalone: true}"> + </mat-form-field> + <mat-form-field class="form-field" fxFlex="100"> + <input matInput [(ngModel)]="messagingSettings.lingerMs" [placeholder]="'Linger MS'" type="text" + [ngModelOptions]="{standalone: true}"> + </mat-form-field> + <div fxLayoutAlign="start center" class="mt-10"> + <button mat-raised-button color="accent" type="submit" class="md-raised md-primary submit-button">Update + </button> + </div> + + </form> + </div> + </sp-split-section> + <mat-divider></mat-divider> + + <sp-split-section title="Message Formats" subtitle="Manage the priority of message formats used"> + <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" class="page-container-padding-inner"> + <div cdkDropList class="data-format-list" (cdkDropListDropped)="drop($event)" *ngIf="loadingCompleted"> + <div class="data-format-box" *ngFor="let format of messagingSettings.prioritizedFormats" cdkDrag> + {{format}} + </div> + </div> + <div fxLayoutAlign="start center" class="mt-10"> + <button mat-raised-button color="accent" type="submit" class="md-raised md-primary submit-button" + (click)="updateMessagingSettings()">Update </button> </div> + </div> + </sp-split-section> - </form> - </div> - </sp-split-section> - <mat-divider></mat-divider> + <mat-divider></mat-divider> - <sp-split-section title="Message Formats" - subtitle="Manage the priority of message formats used"> - <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" class="page-container-padding-inner"> - <div cdkDropList class="data-format-list" (cdkDropListDropped)="drop($event)" - *ngIf="loadingCompleted"> - <div class="data-format-box" *ngFor="let format of messagingSettings.prioritizedFormats" - cdkDrag> - {{format}} + <sp-split-section title="Protocols" subtitle="Manage the priority of protocols used"> + <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" class="page-container-padding-inner"> + <div cdkDropList class="data-format-list" (cdkDropListDropped)="dropProtocol($event)" + *ngIf="loadingCompleted"> + <div class="data-format-box" *ngFor="let protocol of messagingSettings.prioritizedProtocols" + cdkDrag> + {{protocol}} + </div> + </div> + <div fxLayoutAlign="start center" class="mt-10"> + <button mat-raised-button color="accent" type="submit" class="md-raised md-primary submit-button" + (click)="updateMessagingSettings()">Update + </button> </div> </div> - <div fxLayoutAlign="start center" class="mt-10"> - <button mat-raised-button color="accent" type="submit" - class="md-raised md-primary submit-button" (click)="updateMessagingSettings()">Update - </button> - </div> - </div> - </sp-split-section> - - <mat-divider></mat-divider> - - <sp-split-section title="Protocols" - subtitle="Manage the priority of protocols used"> - <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" class="page-container-padding-inner"> - <div cdkDropList class="data-format-list" (cdkDropListDropped)="dropProtocol($event)" - *ngIf="loadingCompleted"> - <div class="data-format-box" *ngFor="let protocol of messagingSettings.prioritizedProtocols" - cdkDrag> - {{protocol}} - </div> - </div> - <div fxLayoutAlign="start center" class="mt-10"> - <button mat-raised-button color="accent" type="submit" - class="md-raised md-primary submit-button" (click)="updateMessagingSettings()">Update - </button> - </div> - </div> - </sp-split-section> -</div> + </sp-split-section> + </div> +</sp-basic-nav-tabs>
diff --git a/ui/src/app/configuration/messaging-configuration/messaging-configuration.component.ts b/ui/src/app/configuration/messaging-configuration/messaging-configuration.component.ts index 51a79ed..4d972b3 100644 --- a/ui/src/app/configuration/messaging-configuration/messaging-configuration.component.ts +++ b/ui/src/app/configuration/messaging-configuration/messaging-configuration.component.ts
@@ -20,6 +20,9 @@ import { ConfigurationService } from '../shared/configuration.service'; import { MessagingSettings } from '../shared/messaging-settings.model'; import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; +import { SpConfigurationTabs } from '../configuration-tabs'; +import { SpBreadcrumbService } from '@streampipes/shared-ui'; +import { SpConfigurationRoutes } from '../configuration.routes'; @Component({ selector: 'messaging-configuration', @@ -28,14 +31,18 @@ }) export class MessagingConfigurationComponent implements OnInit { + tabs = SpConfigurationTabs.getTabs(); + messagingSettings: MessagingSettings; loadingCompleted = false; - constructor(private configurationService: ConfigurationService) { + constructor(private configurationService: ConfigurationService, + private breadcrumbService: SpBreadcrumbService) { } ngOnInit() { + this.breadcrumbService.updateBreadcrumb([SpConfigurationRoutes.BASE, {label: SpConfigurationTabs.getTabs()[4].itemTitle}]); this.getMessagingSettings(); }
diff --git a/ui/src/app/configuration/pipeline-element-configuration/pipeline-element-configuration.component.html b/ui/src/app/configuration/pipeline-element-configuration/pipeline-element-configuration.component.html index 339fe0a..e7caaa0 100644 --- a/ui/src/app/configuration/pipeline-element-configuration/pipeline-element-configuration.component.html +++ b/ui/src/app/configuration/pipeline-element-configuration/pipeline-element-configuration.component.html
@@ -16,60 +16,63 @@ ~ --> -<div fxLayout="row" class="page-container-padding"> - <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start"> - <sp-split-section title="Pipeline Element Configuration" - subtitle="Configure basic settings of core and extensions services"> - <table fxFlex="100" mat-table [dataSource]="dataSource" multiTemplateDataRows> +<sp-basic-nav-tabs [spNavigationItems]="tabs" [activeLink]="'pipelineelement'"> + <div fxLayout="row" class="page-container-padding"> + <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start"> + <sp-split-section title="Pipeline Element Configuration" + subtitle="Configure basic settings of core and extensions services"> + <table fxFlex="100" mat-table [dataSource]="dataSource" multiTemplateDataRows> - <ng-container matColumnDef="status"> - <th fxFlex="30" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Status</th> - <td fxFlex="30" fxLayoutAlign="start center" mat-cell *matCellDef="let element"> + <ng-container matColumnDef="status"> + <th fxFlex="30" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Status</th> + <td fxFlex="30" fxLayoutAlign="start center" mat-cell *matCellDef="let element"> <span *ngIf="element.meta.status === 'passing'" fxLayoutAlign="center center"> <mat-icon class="service-icon-passing">lens</mat-icon> </span> - <span *ngIf="element.meta.status === 'critical'" fxLayoutAlign="center center"> + <span *ngIf="element.meta.status === 'critical'" fxLayoutAlign="center center"> <mat-icon class="service-icon-critical">lens</mat-icon> </span> - </td> - </ng-container> + </td> + </ng-container> - <ng-container matColumnDef="name"> - <th fxFlex="40" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Extensions Service Group - </th> - <td fxFlex="40" fxLayoutAlign="start center" mat-cell *matCellDef="let element"> - {{element.name}} - </td> - </ng-container> + <ng-container matColumnDef="name"> + <th fxFlex="40" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Extensions + Service Group + </th> + <td fxFlex="40" fxLayoutAlign="start center" mat-cell *matCellDef="let element"> + {{element.name}} + </td> + </ng-container> - <ng-container matColumnDef="action"> - <th fxFlex="30" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Action</th> - <td fxFlex="30" fxLayoutAlign="start center" mat-cell *matCellDef="let element"> - <button mat-button mat-raised-button color="accent" (click)="expand(element)"> - Edit - </button> - </td> - </ng-container> + <ng-container matColumnDef="action"> + <th fxFlex="30" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Action</th> + <td fxFlex="30" fxLayoutAlign="start center" mat-cell *matCellDef="let element"> + <button mat-button mat-raised-button color="accent" (click)="expand(element)"> + Edit + </button> + </td> + </ng-container> - <ng-container matColumnDef="expandedDetail"> - <td mat-cell *matCellDef="let element" [attr.colspan]="displayedColumns.length"> - <div class="consul-configuration-detail" - [@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'"> - <div fxFlex="100"> - <consul-configs [consulService]="element" - (updateConsulService)="updateConsulService($event)"></consul-configs> + <ng-container matColumnDef="expandedDetail"> + <td mat-cell *matCellDef="let element" [attr.colspan]="displayedColumns.length"> + <div class="consul-configuration-detail" + [@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'"> + <div fxFlex="100"> + <consul-configs [consulService]="element" + (updateConsulService)="updateConsulService($event)"></consul-configs> + </div> </div> - </div> - </td> - </ng-container> + </td> + </ng-container> - <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> - <tr mat-row *matRowDef="let element; columns: displayedColumns;" - class="consul-configuration-row" - [class.consul-configuration-row-expanded]="expandedElement === element"> - </tr> - <tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="consul-configuration-detail-row"></tr> - </table> - </sp-split-section> + <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> + <tr mat-row *matRowDef="let element; columns: displayedColumns;" class="consul-configuration-row" + [class.consul-configuration-row-expanded]="expandedElement === element"> + </tr> + <tr mat-row *matRowDef="let row; columns: ['expandedDetail']" + class="consul-configuration-detail-row"></tr> + </table> + </sp-split-section> + </div> </div> -</div> +</sp-basic-nav-tabs>
diff --git a/ui/src/app/configuration/pipeline-element-configuration/pipeline-element-configuration.component.ts b/ui/src/app/configuration/pipeline-element-configuration/pipeline-element-configuration.component.ts index 56e2ff3..0d28979 100644 --- a/ui/src/app/configuration/pipeline-element-configuration/pipeline-element-configuration.component.ts +++ b/ui/src/app/configuration/pipeline-element-configuration/pipeline-element-configuration.component.ts
@@ -16,92 +16,104 @@ * */ -import { Component, ViewChild } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { animate, state, style, transition, trigger } from '@angular/animations'; import { ConfigurationService } from '../shared/configuration.service'; import { StreampipesPeContainer } from '../shared/streampipes-pe-container.model'; import { StreampipesPeContainerConifgs } from '../shared/streampipes-pe-container-configs'; import { MatPaginator } from '@angular/material/paginator'; import { MatTableDataSource } from '@angular/material/table'; +import { SpConfigurationTabs } from '../configuration-tabs'; +import { SpBreadcrumbService } from '@streampipes/shared-ui'; +import { SpConfigurationRoutes } from '../configuration.routes'; @Component({ - selector: 'pipeline-element-configuration', - templateUrl: './pipeline-element-configuration.component.html', - styleUrls: ['./pipeline-element-configuration.component.css'], - animations: [ - trigger('detailExpand', [ - state('collapsed', style({height: '0px', minHeight: '0', display: 'none'})), - state('expanded', style({height: '*'})), - transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')), - ]), - ] + selector: 'pipeline-element-configuration', + templateUrl: './pipeline-element-configuration.component.html', + styleUrls: ['./pipeline-element-configuration.component.css'], + animations: [ + trigger('detailExpand', [ + state('collapsed', style({height: '0px', minHeight: '0', display: 'none'})), + state('expanded', style({height: '*'})), + transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')), + ]), + ] }) -export class PipelineElementConfigurationComponent { +export class PipelineElementConfigurationComponent implements OnInit { - consulServices: StreampipesPeContainer[]; + tabs = SpConfigurationTabs.getTabs(); - displayedColumns: string[] = ['status', 'name', 'action']; - @ViewChild(MatPaginator, { static: false }) paginator: MatPaginator; - dataSource = new MatTableDataSource<StreampipesPeContainer>(); + consulServices: StreampipesPeContainer[]; - expandedElement: any; + displayedColumns: string[] = ['status', 'name', 'action']; + @ViewChild(MatPaginator, {static: false}) paginator: MatPaginator; + dataSource = new MatTableDataSource<StreampipesPeContainer>(); - selectedConsulService: StreampipesPeContainer; - consulServiceSelected = false; + expandedElement: any; - constructor(private configurationService: ConfigurationService) { - this.getConsulServices(); + selectedConsulService: StreampipesPeContainer; + consulServiceSelected = false; + + constructor(private configurationService: ConfigurationService, + private breadcrumbService: SpBreadcrumbService) { + this.getConsulServices(); + } + + ngOnInit() { + this.breadcrumbService.updateBreadcrumb([SpConfigurationRoutes.BASE, {label: SpConfigurationTabs.getTabs()[5].itemTitle}]); + } + + getConsulServices(): void { + this.configurationService.getConsulServices() + .subscribe(response => { + const sortedServices = this.sort(response); + this.consulServices = sortedServices; + this.dataSource.data = sortedServices; + }, error => { + console.error(error); + }); + } + + sort(consulServices: StreampipesPeContainer[]): StreampipesPeContainer[] { + if (!consulServices || consulServices.length === 0) { + return null; } - getConsulServices(): void { - this.configurationService.getConsulServices() - .subscribe( response => { - const sortedServices = this.sort(response); - this.consulServices = sortedServices; - this.dataSource.data = sortedServices; - }, error => { - console.error(error); - }); + consulServices.sort((a: StreampipesPeContainer, b: StreampipesPeContainer) => { + if (a.name < b.name) { + return -1; + } else if (a.name > b.name) { + return 1; + } else { + return 0; + } + }); + consulServices.forEach(cs => cs.configs.sort((a: StreampipesPeContainerConifgs, b: StreampipesPeContainerConifgs) => { + if (a.key < b.key) { + return -1; + } else if (a.key > b.key) { + return 1; + } else { + return 0; + } + })); + return consulServices; + } + + updateConsulService(consulService: StreampipesPeContainer): void { + this.configurationService.updateConsulService(consulService) + .subscribe(response => { + + }, error => { + console.error(error); + }); + } + + expand(element: StreampipesPeContainer) { + if (this.expandedElement === element) { + this.expandedElement = undefined; + } else { + this.expandedElement = element; } - - sort(consulServices: StreampipesPeContainer[]): StreampipesPeContainer[] { - if (!consulServices || consulServices.length === 0) { return null; } - - consulServices.sort((a: StreampipesPeContainer, b: StreampipesPeContainer) => { - if (a.name < b.name) { - return -1; - } else if (a.name > b.name) { - return 1; - } else { - return 0; - } - }); - consulServices.forEach(cs => cs.configs.sort((a: StreampipesPeContainerConifgs, b: StreampipesPeContainerConifgs) => { - if (a.key < b.key) { - return -1; - } else if (a.key > b.key) { - return 1; - } else { - return 0; - } - })); - return consulServices; - } - - updateConsulService(consulService: StreampipesPeContainer): void { - this.configurationService.updateConsulService(consulService) - .subscribe(response => { - - }, error => { - console.error(error); - }); - } - - expand(element: StreampipesPeContainer) { - if (this.expandedElement === element) { - this.expandedElement = undefined; - } else { - this.expandedElement = element; - } - } + } }
diff --git a/ui/src/app/configuration/security-configuration/security-configuration.component.html b/ui/src/app/configuration/security-configuration/security-configuration.component.html index 3afffc9..837e841 100644 --- a/ui/src/app/configuration/security-configuration/security-configuration.component.html +++ b/ui/src/app/configuration/security-configuration/security-configuration.component.html
@@ -16,36 +16,34 @@ ~ --> -<div fxLayout="column" class="page-container-padding"> - <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start"> - <sp-split-section title="User Accounts" - subtitle="Add and edit user accounts"> - <div class="subsection-title">Existing user accounts</div> - <sp-security-user-config></sp-security-user-config> - </sp-split-section> +<sp-basic-nav-tabs [spNavigationItems]="tabs" [activeLink]="'security'"> + <div fxLayout="column" class="page-container-padding"> + <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start"> + <sp-split-section title="User Accounts" subtitle="Add and edit user accounts"> + <div class="subsection-title">Existing user accounts</div> + <sp-security-user-config></sp-security-user-config> + </sp-split-section> + </div> + <mat-divider></mat-divider> + <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start"> + <sp-split-section title="Service Accounts" subtitle="Add and edit service accounts"> + <div class="subsection-title">Existing service accounts</div> + <sp-security-service-config></sp-security-service-config> + </sp-split-section> + </div> + <mat-divider></mat-divider> + <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start"> + <sp-split-section title="Groups" subtitle="Manage user groups"> + <div class="subsection-title">Existing groups</div> + <sp-security-user-group-config></sp-security-user-group-config> + </sp-split-section> + </div> + <mat-divider></mat-divider> + <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start"> + <sp-split-section title="Authentication" subtitle="Auth & token settings"> + <div class="subsection-title">JWT Signature</div> + <sp-authentication-configuration></sp-authentication-configuration> + </sp-split-section> + </div> </div> - <mat-divider></mat-divider> - <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start"> - <sp-split-section title="Service Accounts" - subtitle="Add and edit service accounts"> - <div class="subsection-title">Existing service accounts</div> - <sp-security-service-config></sp-security-service-config> - </sp-split-section> - </div> - <mat-divider></mat-divider> - <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start"> - <sp-split-section title="Groups" - subtitle="Manage user groups"> - <div class="subsection-title">Existing groups</div> - <sp-security-user-group-config></sp-security-user-group-config> - </sp-split-section> - </div> - <mat-divider></mat-divider> - <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start"> - <sp-split-section title="Authentication" - subtitle="Auth & token settings"> - <div class="subsection-title">JWT Signature</div> - <sp-authentication-configuration></sp-authentication-configuration> - </sp-split-section> - </div> -</div> +</sp-basic-nav-tabs>
diff --git a/ui/src/app/configuration/security-configuration/security-configuration.component.ts b/ui/src/app/configuration/security-configuration/security-configuration.component.ts index 427c982..ca30cba 100644 --- a/ui/src/app/configuration/security-configuration/security-configuration.component.ts +++ b/ui/src/app/configuration/security-configuration/security-configuration.component.ts
@@ -17,6 +17,9 @@ */ import { Component, OnInit } from '@angular/core'; +import { SpConfigurationTabs } from '../configuration-tabs'; +import { SpBreadcrumbService } from '@streampipes/shared-ui'; +import { SpConfigurationRoutes } from '../configuration.routes'; @Component({ selector: 'sp-security-configuration', @@ -25,9 +28,12 @@ }) export class SecurityConfigurationComponent implements OnInit { - constructor() {} + tabs = SpConfigurationTabs.getTabs(); + + constructor(private breadcrumbService: SpBreadcrumbService) {} ngOnInit(): void { + this.breadcrumbService.updateBreadcrumb([SpConfigurationRoutes.BASE, {label: SpConfigurationTabs.getTabs()[6].itemTitle}]); } }
diff --git a/ui/src/app/connect/components/configuration-group/configuration-group.component.html b/ui/src/app/connect/components/configuration-group/configuration-group.component.html index 2857534..04e5b2b 100644 --- a/ui/src/app/connect/components/configuration-group/configuration-group.component.html +++ b/ui/src/app/connect/components/configuration-group/configuration-group.component.html
@@ -16,7 +16,7 @@ ~ --> -<div class="sp-blue-border padding" style="padding: 15px;"> +<div style="padding: 15px;"> <form [formGroup]="configurationGroup" fxFlex="100"> <div fxFlex="100" > <app-static-property *ngFor="let config of configuration"
diff --git a/ui/src/app/connect/components/data-marketplace/adapter-description/adapter-description.component.html b/ui/src/app/connect/components/data-marketplace/adapter-description/adapter-description.component.html index 29c2b08..52aa74a 100644 --- a/ui/src/app/connect/components/data-marketplace/adapter-description/adapter-description.component.html +++ b/ui/src/app/connect/components/data-marketplace/adapter-description/adapter-description.component.html
@@ -19,13 +19,23 @@ <div [className]="className" fxFlex="100" fxLayout="column"> <div fxLayout="column"> - <div class="type" fxLayout="column" fxLayoutAlign="start start"> - <div class="type-data" fxLayout="row" fxLayoutAlign="start start"> + <div class="type" fxLayout="row" fxLayoutAlign="start start" fxFlex="100"> + <div class="type-data" fxLayout="row" fxLayoutAlign="start center" fxFlex> <mat-icon *ngIf="isDataSetDescription" class="historic">lens</mat-icon> <mat-icon *ngIf="isDataStreamDescription" class="real-time">lens</mat-icon> <p *ngIf="isDataSetDescription">Data Set</p> <p *ngIf="isDataStreamDescription">Data Stream</p> </div> + <div fxLayout="row" fxLayoutAlign="end end" style="margin-left:5px;"> + <button class="small-button-add mat-basic no-min-width" (click)="$event.stopPropagation();" + mat-raised-button mat-button [matMenuTriggerFor]="menu"><span style="font-size:12px;">...</span></button> + <mat-menu #menu="matMenu"> + <button mat-menu-item (click)="removeAdapter()"> + <mat-icon>delete</mat-icon> + <span> Remove adapter</span> + </button> + </mat-menu> + </div> </div> <div fxLayoutAlign="start center" fxLayout="column" class="icon"> <img *ngIf="getIconUrl() && !adapter.icon" [src]="getIconUrl()" class="iconImg"/>
diff --git a/ui/src/app/connect/components/data-marketplace/adapter-description/adapter-description.component.ts b/ui/src/app/connect/components/data-marketplace/adapter-description/adapter-description.component.ts index 5551963..c65fa3b 100644 --- a/ui/src/app/connect/components/data-marketplace/adapter-description/adapter-description.component.ts +++ b/ui/src/app/connect/components/data-marketplace/adapter-description/adapter-description.component.ts
@@ -18,11 +18,11 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { ConnectService } from '../../../services/connect.service'; -import { DataMarketplaceService } from '../../../services/data-marketplace.service'; import { AdapterExportDialog } from '../../../dialog/adapter-export/adapter-export-dialog.component'; import { MatDialog } from '@angular/material/dialog'; -import { AdapterDescription } from '@streampipes/platform-services'; +import { AdapterDescription, AdapterService } from '@streampipes/platform-services'; import { DialogService, PanelType } from '@streampipes/shared-ui'; +import { MatSnackBar } from '@angular/material/snack-bar'; @Component({ selector: 'sp-adapter-description', @@ -49,9 +49,10 @@ adapterLabel: string; constructor(private connectService: ConnectService, - private dataMarketplaceService: DataMarketplaceService, + private dataMarketplaceService: AdapterService, private dialogService: DialogService, - public dialog: MatDialog) { + public dialog: MatDialog, + private _snackBar: MatSnackBar) { } ngOnInit() { @@ -112,4 +113,12 @@ return `assets/img/connect/${this.adapter.iconUrl}`; } } + + removeAdapter(): void { + this.dataMarketplaceService.deleteAdapterDescription(this.adapter.elementId).subscribe(res => { + this.updateAdapterEmitter.emit(); + }, error => { + this._snackBar.open('Cannot delete an adapter which has an active instance running.'); + }); + } }
diff --git a/ui/src/app/connect/components/data-marketplace/data-marketplace.component.html b/ui/src/app/connect/components/data-marketplace/data-marketplace.component.html index 07e0171..61d9949 100644 --- a/ui/src/app/connect/components/data-marketplace/data-marketplace.component.html +++ b/ui/src/app/connect/components/data-marketplace/data-marketplace.component.html
@@ -16,98 +16,46 @@ ~ --> -<div fxLayout="column" fxFlex="100" class="page-container page-container-padding page-container-connect"> - <div fxLayout="row" style="padding:0px;" class="sp-tab-bg"> - <div fxLayout="fill" class="page-container-nav"> - <mat-tab-group [selectedIndex]="selectedIndex" (selectedIndexChange)="selectedIndexChange($event)" - color="accent"> - <mat-tab label="Data Marketplace"> - </mat-tab> - <mat-tab id="all-adapters" label="My Adapters"> - </mat-tab> - </mat-tab-group> - </div> +<sp-basic-view showBackLink="true" [backLinkTarget]="['connect']" [padding]="true"> + + <div nav fxFlex="100" fxLayoutAlign="start center" fxLayout="row"> + <sp-connect-filter-toolbar + class="filter-bar-margin" + (filterChangedEmitter)="applyFilter($event)"> + </sp-connect-filter-toolbar> <div fxFlex="100" fxLayout="row" fxLayoutAlign="end center" - style="padding-left:10px;padding-right:10px;font-size:14px;" class="page-container-nav" - *ngIf="selectedIndex === 0 && newAdapterFromDescription === undefined"> + style="padding-left:10px;padding-right:10px;font-size:14px;" class="page-container-nav"> <button mat-icon-button id="startAdapterTutorial3" (click)="startAdapterTutorial3()" matTooltip="Tutorial: Generic Adapter"> <mat-icon color="accent">school</mat-icon> </button> </div> </div> - - <div fxLayout="row" class="fixed-height data-marketplace-options"> - - <div class="data-marketplace-options-item pl-5" style="margin-top:8px;" fxLayoutAlign="start center" - fxLayout="row"> - <mat-icon color="accent">search</mat-icon> - <mat-form-field class="form-style"> - <input matInput placeholder="Find Element" value="" (input)="updateFilterTerm($event.target.value)" - name="something"> - </mat-form-field> - </div> - <div class="data-marketplace-options-item"> - <mat-form-field color="accent"> - <mat-select [(value)]="selectedType" (selectionChange)="filterAdapter($event)"> - <mat-option *ngFor="let type of adapterTypes" [value]="type"> - {{type}} - </mat-option> - </mat-select> - </mat-form-field> - </div> - <div class="data-marketplace-options-item"> - <mat-form-field color="accent"> - <mat-select [(value)]="selectedCategory" (selectionChange)="filterAdapter($event)"> - <mat-option *ngFor="let category of adapterCategories" [value]="category.code"> - {{category.label}} - </mat-option> - </mat-select> - </mat-form-field> - </div> - <span fxFlex></span> - - </div> - <div class="container-fluid marketplace-container" *ngIf="adapterLoadingError" fxFlex="100" - fxLayoutAlign="center center" fxLayout="row"> - <h4>Available adapters could not be loaded. Did you start a Connect worker node?</h4> - </div> - <div class="container-fluid marketplace-container" *ngIf="adaptersLoading" fxFlex="100" - fxLayoutAlign="center center" fxLayout="row"> - <mat-spinner [mode]="'indeterminate'" [diameter]="20" color="accent"></mat-spinner> - <h4> Searching for available adapters, please wait...</h4> - </div> - <div class="container-fluid marketplace-container" *ngIf="!adaptersLoading && !adapterLoadingError"> - <div *ngIf="selectedIndex === 0"> - - <div *ngIf="newAdapterFromDescription===undefined" fxLayout="row wrap" fxLayoutAlign="start stretch" - class="adapter-description-container"> - <sp-adapter-description attr.id="{{adapterDescription.name.replaceAll(' ', '_')}}" - class="adapter-description" - fxFlex="33" (click)="selectAdapter(adapterDescription)" - *ngFor="let adapterDescription of filteredAdapterDescriptions | filter:filterTerm" - [adapter]="adapterDescription" - (updateAdapterEmitter)="updateDescriptionsAndRunningAdatpers()"></sp-adapter-description> + <div fxLayout="column" fxFlex="100"> + <sp-basic-header-title-component title="Select Adapter"></sp-basic-header-title-component> + <div fxFlex="100" fxLayout="column" fxLayoutAlign="center start"> + <div class="container-fluid marketplace-container" *ngIf="adapterLoadingError" fxFlex="100" + fxLayoutAlign="center center" fxLayout="row"> + <h4>Available adapters could not be loaded. Did you start a Connect worker node?</h4> </div> - - - <div class="new-adapter-container" fxFlex="100" fxLayout="row" fxLayoutAlign="start start" - *ngIf="newAdapterFromDescription!==undefined"> - <sp-new-adapter fxFlex="100" (removeSelectionEmitter)="removeSelection($event)" - [adapter]="newAdapterFromDescription" - (updateAdapterEmitter)="updateDescriptionsAndRunningAdatpers()"></sp-new-adapter> + <div class="container-fluid marketplace-container" *ngIf="adaptersLoading" fxFlex="100" + fxLayoutAlign="center center" fxLayout="row"> + <mat-spinner [mode]="'indeterminate'" [diameter]="20" color="accent"></mat-spinner> + <h4> Searching for available adapters, please wait...</h4> </div> - - </div> - <div *ngIf="selectedIndex === 1"> - <div fxFlex="100" class="adapter-container"> - <sp-existing-adapters [existingAdapters]="filteredAdapters" - [filterTerm]="filterTerm" - (updateAdapterEmitter)="updateDescriptionsAndRunningAdatpers()" - (createTemplateEmitter)="templateFromRunningAdapter($event)"> - - </sp-existing-adapters> + <div class="container-fluid marketplace-container" + *ngIf="!adaptersLoading && !adapterLoadingError && currentFilter"> + <div fxLayout="row wrap" fxLayoutAlign="start stretch" + class="adapter-description-container"> + <sp-adapter-description attr.id="{{adapterDescription.name.replaceAll(' ', '_')}}" + class="adapter-description" + fxFlex="33" + (updateAdapterEmitter)="getAdapterDescriptions()" + (click)="selectAdapter(adapterDescription.appId)" + *ngFor="let adapterDescription of adapterDescriptions | adapterFilter:currentFilter" + [adapter]="adapterDescription"></sp-adapter-description> + </div> </div> </div> </div> -</div> +</sp-basic-view>
diff --git a/ui/src/app/connect/components/data-marketplace/data-marketplace.component.scss b/ui/src/app/connect/components/data-marketplace/data-marketplace.component.scss index 9034535..6f91e02 100644 --- a/ui/src/app/connect/components/data-marketplace/data-marketplace.component.scss +++ b/ui/src/app/connect/components/data-marketplace/data-marketplace.component.scss
@@ -46,38 +46,15 @@ background: #EEE; } -#categoryFilter { - margin-top: 20px; -} - -.fixed-height { - height: 50px; -} - -.form-style { - margin: 0px 5px 0px 0px; -} - .icon-style { margin: 15px 4px 0px 0px; color: var(--color-accent); } -.data-marketplace-options { - padding:0px; - background-color: var(--color-bg-1); - border-bottom: 1px solid var(--color-bg-3); +.filter-bar-margin { + margin-left: 10px; + padding-left: 10px; } -.data-marketplace-options-item { - display: inline; - margin-right: 10px; -} -::ng-deep .mat-select-panel { - background: #fff; -} -::ng-deep .mat-select-panel:not([class*=mat-elevation-z]) { - box-shadow: 0 2px 4px -1px rgba(0,0,0,.2), 0 4px 5px 0 rgba(0,0,0,.14), 0 1px 10px 0 rgba(0,0,0,.12); -}
diff --git a/ui/src/app/connect/components/data-marketplace/data-marketplace.component.ts b/ui/src/app/connect/components/data-marketplace/data-marketplace.component.ts index a49adcd..6cf253d 100644 --- a/ui/src/app/connect/components/data-marketplace/data-marketplace.component.ts +++ b/ui/src/app/connect/components/data-marketplace/data-marketplace.component.ts
@@ -16,13 +16,14 @@ * */ -import { Component, EventEmitter, OnInit, Output } from '@angular/core'; -import { DataMarketplaceService } from '../../services/data-marketplace.service'; +import { Component, OnInit } from '@angular/core'; import { ShepherdService } from '../../../services/tour/shepherd.service'; import { ConnectService } from '../../services/connect.service'; -import { FilterPipe } from '../../filter/filter.pipe'; -import { AdapterDescriptionUnion } from '@streampipes/platform-services'; -import { DialogService } from '@streampipes/shared-ui'; +import { AdapterDescriptionUnion, AdapterService } from '@streampipes/platform-services'; +import { DialogService, SpBreadcrumbService } from '@streampipes/shared-ui'; +import { Router } from '@angular/router'; +import { AdapterFilterSettingsModel } from '../../model/adapter-filter-settings.model'; +import { SpConnectRoutes } from '../../connect.routes'; @Component({ selector: 'sp-data-marketplace', @@ -30,50 +31,25 @@ styleUrls: ['./data-marketplace.component.scss'] }) export class DataMarketplaceComponent implements OnInit { + adapterDescriptions: AdapterDescriptionUnion[]; - newAdapterFromDescription: AdapterDescriptionUnion; - filteredAdapterDescriptions: AdapterDescriptionUnion[]; - adapters: AdapterDescriptionUnion[]; - filteredAdapters: AdapterDescriptionUnion[]; - visibleAdapters: AdapterDescriptionUnion[]; - - @Output() - selectAdapterEmitter: EventEmitter<AdapterDescriptionUnion> = new EventEmitter<AdapterDescriptionUnion>(); - - selectedIndex = 0; - filterTerm = ''; - pipe: FilterPipe = new FilterPipe(); - adapterTypes: string[] = ['All types', 'Data Set', 'Data Stream']; - selectedType = 'All types'; - - adapterCategories: any; - selectedCategory: any = 'All'; adaptersLoading = true; adapterLoadingError = false; - constructor(private dataMarketplaceService: DataMarketplaceService, + currentFilter: AdapterFilterSettingsModel; + + constructor(private dataMarketplaceService: AdapterService, private shepherdService: ShepherdService, private connectService: ConnectService, - private dialogService: DialogService) { + private dialogService: DialogService, + private router: Router, + private breadcrumbService: SpBreadcrumbService) { } ngOnInit() { - this.updateDescriptionsAndRunningAdatpers(); - this.loadAvailableTypeCategories(); - this.visibleAdapters = this.adapters; - } - - loadAvailableTypeCategories() { - this.dataMarketplaceService.getAdapterCategories().subscribe(res => { - this.adapterCategories = res; - this.adapterCategories.unshift({ label: 'All categories', description: '', code: 'All' }); - }); - } - - updateDescriptionsAndRunningAdatpers() { + this.breadcrumbService.updateBreadcrumb([SpConnectRoutes.BASE, this.breadcrumbService.removeLink(SpConnectRoutes.CREATE)]); this.getAdapterDescriptions(); - this.getAdaptersRunning(); } getAdapterDescriptions(): void { @@ -84,10 +60,8 @@ .getAdapterDescriptions() .subscribe((allAdapters) => { this.adapterDescriptions = allAdapters; - // this.adapterDescriptions = this.adapterDescriptions.concat(allAdapters[1]); this.adapterDescriptions .sort((a, b) => a.name.localeCompare(b.name)); - this.filteredAdapterDescriptions = this.adapterDescriptions; this.adaptersLoading = false; }, error => { console.log(error); @@ -96,17 +70,6 @@ }); } - getAdaptersRunning(): void { - this.dataMarketplaceService.getAdapters().subscribe(adapters => { - this.adapters = adapters; - this.filteredAdapters = this.adapters; - }); - } - - selectedIndexChange(index: number) { - this.selectedIndex = index; - } - startAdapterTutorial() { this.shepherdService.startAdapterTour(); } @@ -119,58 +82,12 @@ this.shepherdService.startAdapterTour3(); } - selectAdapter(adapterDescription: AdapterDescriptionUnion) { - this.newAdapterFromDescription = this.dataMarketplaceService.cloneAdapterDescription(adapterDescription); - (this.newAdapterFromDescription as any).templateTitle = this.newAdapterFromDescription.name; - this.newAdapterFromDescription.name = ''; - this.newAdapterFromDescription.description = ''; - - this.shepherdService.trigger('select-adapter'); + selectAdapter(appId: string) { + this.router.navigate(['connect', 'create', appId]); + // this.shepherdService.trigger('select-adapter'); } - templateFromRunningAdapter(adapter: AdapterDescriptionUnion) { - adapter.elementId = undefined; - adapter._rev = undefined; - this.selectedIndexChange(0); - this.selectAdapter(adapter); - + applyFilter(filter: AdapterFilterSettingsModel) { + this.currentFilter = { ...filter }; } - - removeSelection() { - this.newAdapterFromDescription = undefined; - } - - updateFilterTerm(inputValue) { - this.filterTerm = inputValue; - } - - filterAdapter(event) { - const filteredAdapterTypes = this.filterAdapterType(this.adapterDescriptions); - const filteredAdapterTemplateTypes = this.filterAdapterType(this.adapters); - - const filteredAdapterCategories = this.filterAdapterCategory(filteredAdapterTypes); - const filteredAdapterTemplateCategories = this.filterAdapterCategory(filteredAdapterTemplateTypes); - - this.filteredAdapterDescriptions = filteredAdapterCategories; - this.filteredAdapters = filteredAdapterTemplateCategories; - } - - filterAdapterCategory(currentElements: AdapterDescriptionUnion[]): AdapterDescriptionUnion[] { - if (this.selectedCategory === this.adapterCategories[0].code) { - return currentElements; - } else { - return currentElements.filter(adapterDescription => adapterDescription.category.indexOf(this.selectedCategory) !== -1); - } - } - - filterAdapterType(currentElements: AdapterDescriptionUnion[]): AdapterDescriptionUnion[] { - if (this.selectedType === this.adapterTypes[0]) { - return currentElements; - } else if (this.selectedType === this.adapterTypes[1]) { - return currentElements.filter(adapterDescription => this.connectService.isDataSetDescription(adapterDescription)); - } else if (this.selectedType === this.adapterTypes[2]) { - return currentElements.filter(adapterDescription => !this.connectService.isDataSetDescription(adapterDescription)); - } - } - }
diff --git a/ui/src/app/connect/components/data-marketplace/existing-adapters/existing-adapters.component.html b/ui/src/app/connect/components/data-marketplace/existing-adapters/existing-adapters.component.html deleted file mode 100644 index d1ee145..0000000 --- a/ui/src/app/connect/components/data-marketplace/existing-adapters/existing-adapters.component.html +++ /dev/null
@@ -1,146 +0,0 @@ -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one or more - ~ contributor license agreements. See the NOTICE file distributed with - ~ this work for additional information regarding copyright ownership. - ~ The ASF licenses this file to You under the Apache License, Version 2.0 - ~ (the "License"); you may not use this file except in compliance with - ~ the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - ~ - --> - -<div fxFlex="100" fxLayout="column"> - <div class="assemblyOptions sp-blue-bg mt-20" style="padding:5px;"> - <div fxLayout="row" fxLayoutAlign="start center"> - <h4>My adapters</h4> - <span fxFlex></span> - <button mat-button mat-icon-button matTooltip="Refresh adapters" matTooltipPosition="above" - (click)="updateAdapterEmitter.emit()"> - <i class="material-icons"> - refresh - </i> - </button> - </div> - </div> - <div class="sp-blue-border"> - <table fxFlex="100" mat-table [dataSource]="dataSource" style="width: 100%;" matSort> - <ng-container matColumnDef="start"> - <th mat-header-cell *matHeaderCellDef> Start</th> - <td mat-cell *matCellDef="let adapter"> - <button color="accent" mat-button mat-icon-button matTooltip="Start adapter" - matTooltipPosition="above" - (click)="startAdapter(adapter)" - *ngIf="(connectService.isDataStreamDescription(adapter)) && !adapter.running"> - <i class="material-icons">play_arrow</i> - </button> - <button color="accent" mat-button mat-icon-button matTooltip="Stop adapter" - matTooltipPosition="above" - (click)="stopAdapter(adapter)" - *ngIf="(connectService.isDataStreamDescription(adapter)) && adapter.running"> - <i class="material-icons">stop</i> - </button> - </td> - </ng-container> - - <ng-container matColumnDef="name"> - <th mat-header-cell mat-sort-header *matHeaderCellDef> Name</th> - <td mat-cell *matCellDef="let adapter"> - <h4 style="margin-bottom:0px;">{{adapter.name}}</h4> - <h5>{{adapter.description != '' ? adapter.description : '-'}}</h5> - </td> - </ng-container> - <ng-container matColumnDef="adapterBase"> - <th mat-header-cell *matHeaderCellDef> Adapter</th> - <td mat-cell *matCellDef="let adapter"> - <img *ngIf="getIconUrl(adapter) && !adapter.icon" [src]="getIconUrl(adapter)" class="adapter-icon"/> - <img *ngIf="adapter.icon" [src]="adapter.icon" class="adapter-icon"/> - </td> - </ng-container> - <ng-container matColumnDef="adapterType"> - <th mat-header-cell *matHeaderCellDef> Type</th> - <td mat-cell *matCellDef="let adapter"> - <div class="type-data" fxLayout="row" fxLayoutAlign="start start"> - <div fxLayout="row" fxLayoutAlign="center center"> - <mat-icon *ngIf="connectService.isDataSetDescription(adapter)" class="historic">lens - </mat-icon> - <mat-icon *ngIf="connectService.isDataStreamDescription(adapter)" class="real-time">lens - </mat-icon> - <div fxFlex="100" fxLayoutAlign="center center"> - <span *ngIf="connectService.isDataSetDescription(adapter)"> Data Set</span> - <span *ngIf="connectService.isDataStreamDescription(adapter)"> Data Stream</span> - </div> - </div> - </div> - </td> - </ng-container> - <ng-container matColumnDef="lastModified"> - <th mat-header-cell *matHeaderCellDef> Created</th> - <td mat-cell *matCellDef="let adapter"> - <h5>{{adapter.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 adapter"> - <div fxLayout="row"> - <!-- <span fxFlex fxFlexOrder="1" fxLayout="row" fxLayoutAlign="center center">--> - <!-- <button color="primary" mat-button mat-icon-button matTooltip="Show adapter"--> - <!-- matTooltipPosition="above"><i--> - <!-- class="material-icons">search</i>--> - <!-- </button>--> - <!-- </span>--> - <!-- <span fxFlex fxFlexOrder="2" fxLayout="row" fxLayoutAlign="center center">--> - <!-- <button color="primary" mat-button mat-icon-button matTooltip="Modify adapter"--> - <!-- matTooltipPosition="above"--> - <!-- [disabled]="adapter.running">--> - <!-- <i class="material-icons">mode_edit</i>--> - <!-- </button>--> - <!-- </span>--> - <span fxFlex fxFlexOrder="1" fxLayout="row" fxLayoutAlign="center center"> - <button color="accent" mat-button mat-icon-button matTooltip="Show info" - matTooltipPosition="above" (click)="openHelpDialog(adapter)"><i - class="material-icons">help_outline</i> - </button> - </span> - <span fxFlex fxFlexOrder="2" fxLayout="row" fxLayoutAlign="center center"> - <button color="accent" mat-button mat-icon-button matTooltip="Create adapter template" - matTooltipPosition="above" (click)="createTemplate(adapter)"><i - class="material-icons">content_copy</i> - </button> - </span> - <span fxFlex fxFlexOrder="3" fxLayout="row" fxLayoutAlign="center center" *ngIf="isAdmin"> - <button color="accent" mat-button mat-icon-button matTooltip="Manage permissions" - matTooltipPosition="above" (click)="showPermissionsDialog(adapter)"><i - class="material-icons">share</i> - </button> - </span> - <span fxFlex fxFlexOrder="4" fxLayout="row" fxLayoutAlign="center center"> - <button color="accent" mat-button mat-icon-button matTooltip="Delete adapter" - data-cy="delete" matTooltipPosition="above" (click)="deleteAdapter(adapter)"> - <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> - <div fxFlex="100" fxLayoutAlign="end end"> - <mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" [pageSize]="20"></mat-paginator> - </div> - <div fxFlex="100" fxLayout="column" fxLayoutAlign="center center" *ngIf="existingAdapters.length == 0"> - <h5>(no adapters available)</h5> - </div> -</div>
diff --git a/ui/src/app/connect/components/data-marketplace/existing-adapters/existing-adapters.component.ts b/ui/src/app/connect/components/data-marketplace/existing-adapters/existing-adapters.component.ts deleted file mode 100644 index 6b3f42e..0000000 --- a/ui/src/app/connect/components/data-marketplace/existing-adapters/existing-adapters.component.ts +++ /dev/null
@@ -1,167 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; -import { AdapterDescriptionUnion, PipelineElementService } from '@streampipes/platform-services'; -import { MatTableDataSource } from '@angular/material/table'; -import { ConnectService } from '../../../services/connect.service'; -import { DataMarketplaceService } from '../../../services/data-marketplace.service'; -import { DialogRef, PanelType, DialogService } from '@streampipes/shared-ui'; -import { DeleteAdapterDialogComponent } from '../../../dialog/delete-adapter-dialog/delete-adapter-dialog.component'; -import { MatPaginator } from '@angular/material/paginator'; -import { MatSort } from '@angular/material/sort'; -import { ObjectPermissionDialogComponent } from '../../../../core-ui/object-permission-dialog/object-permission-dialog.component'; -import { UserRole } from '../../../../_enums/user-role.enum'; -import { AuthService } from '../../../../services/auth.service'; -import { HelpComponent } from '../../../../editor/dialog/help/help.component'; - -@Component({ - selector: 'sp-existing-adapters', - templateUrl: './existing-adapters.component.html', - styleUrls: ['./existing-adapters.component.scss'] -}) -export class ExistingAdaptersComponent implements OnInit { - - _existingAdapters: AdapterDescriptionUnion[]; - - @Input() - filterTerm: string; - - @Output() - updateAdapterEmitter: EventEmitter<void> = new EventEmitter<void>(); - - @Output() - createTemplateEmitter: EventEmitter<AdapterDescriptionUnion> = new EventEmitter<AdapterDescriptionUnion>(); - - @ViewChild(MatPaginator) paginator: MatPaginator; - pageSize = 1; - @ViewChild(MatSort) sort: MatSort; - - displayedColumns: string[] = ['start', 'name', 'adapterBase', 'adapterType', 'lastModified', 'action']; - - dataSource: MatTableDataSource<AdapterDescriptionUnion>; - isAdmin = false; - - constructor(public connectService: ConnectService, - private dataMarketplaceService: DataMarketplaceService, - private dialogService: DialogService, - private authService: AuthService, - private pipelineElementService: PipelineElementService) { - - } - - ngOnInit(): void { - this.authService.user$.subscribe(user => { - this.isAdmin = user.roles.indexOf(UserRole.ROLE_ADMIN) > -1; - }); - this.dataSource = new MatTableDataSource(this.existingAdapters); - setTimeout(() => { - this.dataSource.paginator = this.paginator; - this.dataSource.sort = this.sort; - }); - } - - startAdapter(adapter: AdapterDescriptionUnion) { - this.dataMarketplaceService.startAdapter(adapter).subscribe(response => { - this.updateAdapterEmitter.emit(); - }); - } - - stopAdapter(adapter: AdapterDescriptionUnion) { - this.dataMarketplaceService.stopAdapter(adapter).subscribe(response => { - this.updateAdapterEmitter.emit(); - }); - } - - getIconUrl(adapter: AdapterDescriptionUnion) { - if (adapter.includedAssets.length > 0) { - return this.dataMarketplaceService.getAssetUrl(adapter.appId) + '/icon'; - } else { - return 'assets/img/connect/' + adapter.iconUrl; - } - } - - showPermissionsDialog(adapter: AdapterDescriptionUnion) { - - const dialogRef = this.dialogService.open(ObjectPermissionDialogComponent, { - panelType: PanelType.SLIDE_IN_PANEL, - title: 'Manage permissions', - width: '50vw', - data: { - 'objectInstanceId': adapter.correspondingDataStreamElementId, - 'headerTitle': 'Manage permissions for adapter ' + adapter.name - } - }); - - dialogRef.afterClosed().subscribe(refresh => { - if (refresh) { - this.updateAdapterEmitter.emit(); - } - }); - } - - deleteAdapter(adapter: AdapterDescriptionUnion): void { - const dialogRef: DialogRef<DeleteAdapterDialogComponent> = this.dialogService.open(DeleteAdapterDialogComponent, { - panelType: PanelType.STANDARD_PANEL, - title: 'Delete Adapter', - width: '70vw', - data: { - 'adapter': adapter - } - }); - - dialogRef.afterClosed().subscribe(data => { - if (data) { - this.updateAdapterEmitter.emit(); - } - }); - } - - openHelpDialog(adapter: AdapterDescriptionUnion) { - const streamId = adapter.correspondingDataStreamElementId; - - this.pipelineElementService.getDataStreamByElementId(streamId).subscribe(stream => { - if (stream) { - this.dialogService.open(HelpComponent, { - panelType: PanelType.STANDARD_PANEL, - title: stream.name, - width: '70vw', - data: { - 'pipelineElement': stream - } - }); - } - }); - } - - - createTemplate(adapter: AdapterDescriptionUnion): void { - this.createTemplateEmitter.emit(adapter); - } - - @Input() - set existingAdapters(adapters: AdapterDescriptionUnion[]) { - this._existingAdapters = adapters; - this.dataSource = new MatTableDataSource(adapters); - } - - get existingAdapters(): AdapterDescriptionUnion[] { - return this._existingAdapters; - } - -}
diff --git a/ui/src/app/connect/components/existing-adapters/existing-adapters.component.html b/ui/src/app/connect/components/existing-adapters/existing-adapters.component.html new file mode 100644 index 0000000..102666f --- /dev/null +++ b/ui/src/app/connect/components/existing-adapters/existing-adapters.component.html
@@ -0,0 +1,157 @@ +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~ + --> +<sp-basic-view [showBackLink]="false" [padding]="true"> + + <div nav fxFlex="100" fxLayoutAlign="start center" fxLayout="row" class="pl-10"> + <button mat-button + mat-raised-button + color="accent" + data-cy="connect-create-new-adapter-button" + (click)="createNewAdapter()"> + <i class="material-icons">add</i> New adapter + </button> + <sp-connect-filter-toolbar + class="filter-bar-margin" + (filterChangedEmitter)="applyFilter($event)"> + </sp-connect-filter-toolbar> + <div fxFlex fxLayout="row" fxLayoutAlign="end center"> + <button mat-button mat-icon-button matTooltip="Refresh adapters" matTooltipPosition="below" color="accent" + (click)="getAdaptersRunning()"> + <i class="material-icons"> + refresh + </i> + </button> + </div> + </div> + <div fxFlex="100" fxLayout="column"> + <sp-basic-header-title-component title="My adapters"></sp-basic-header-title-component> + <div fxFlex="100" fxLayout="row" fxLayoutAlign="center start"> + <sp-basic-inner-panel [showTitle]="false" innerPadding="0" outerMargin="0" fxFlex="90" [hideToolbar]="true"> + <div fxFlex="100" fxLayout="column" *ngIf="filteredAdapters.length > 0"> + <div fxFlex="100" fxLayout="column"> + <table fxFlex="100" mat-table [dataSource]="dataSource" style="width: 100%;" matSort> + <ng-container matColumnDef="start"> + <th mat-header-cell *matHeaderCellDef> Start</th> + <td mat-cell *matCellDef="let adapter"> + <button color="accent" mat-button mat-icon-button matTooltip="Start adapter" + matTooltipPosition="above" + (click)="startAdapter(adapter)" + *ngIf="(connectService.isDataStreamDescription(adapter)) && !adapter.running"> + <i class="material-icons">play_arrow</i> + </button> + <button color="accent" mat-button mat-icon-button matTooltip="Stop adapter" + matTooltipPosition="above" + (click)="stopAdapter(adapter)" + *ngIf="(connectService.isDataStreamDescription(adapter)) && adapter.running"> + <i class="material-icons">stop</i> + </button> + </td> + </ng-container> + + <ng-container matColumnDef="name"> + <th mat-header-cell mat-sort-header *matHeaderCellDef> Name</th> + <td mat-cell *matCellDef="let adapter"> + <h4 style="margin-bottom:0px;">{{adapter.name}}</h4> + <h5>{{adapter.description != '' ? adapter.description : '-'}}</h5> + </td> + </ng-container> + <ng-container matColumnDef="adapterBase"> + <th mat-header-cell *matHeaderCellDef> Adapter</th> + <td mat-cell *matCellDef="let adapter"> + <img *ngIf="getIconUrl(adapter) && !adapter.icon" [src]="getIconUrl(adapter)" + class="adapter-icon"/> + <img *ngIf="adapter.icon" [src]="adapter.icon" class="adapter-icon"/> + </td> + </ng-container> + <ng-container matColumnDef="adapterType"> + <th mat-header-cell *matHeaderCellDef> Type</th> + <td mat-cell *matCellDef="let adapter"> + <div class="type-data" fxLayout="row" fxLayoutAlign="start start"> + <div fxLayout="row" fxLayoutAlign="center center"> + <mat-icon *ngIf="connectService.isDataSetDescription(adapter)" + class="historic"> + lens + </mat-icon> + <mat-icon *ngIf="connectService.isDataStreamDescription(adapter)" + class="real-time"> + lens + </mat-icon> + <div fxFlex="100" fxLayoutAlign="center center"> + <span *ngIf="connectService.isDataSetDescription(adapter)"> Data Set</span> + <span *ngIf="connectService.isDataStreamDescription(adapter)"> Data Stream</span> + </div> + </div> + </div> + </td> + </ng-container> + <ng-container matColumnDef="lastModified"> + <th mat-header-cell *matHeaderCellDef> Created</th> + <td mat-cell *matCellDef="let adapter"> + <h5>{{adapter.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 adapter"> + <div fxLayout="row"> + <span fxFlex fxFlexOrder="1" fxLayout="row" fxLayoutAlign="center center"> + <button color="accent" mat-button mat-icon-button matTooltip="Show info" + matTooltipPosition="above" (click)="openHelpDialog(adapter)"><i + class="material-icons">help_outline</i> + </button> + </span> + <span fxFlex fxFlexOrder="2" fxLayout="row" fxLayoutAlign="center center" + *ngIf="isAdmin"> + <button color="accent" mat-button mat-icon-button matTooltip="Manage permissions" + matTooltipPosition="above" (click)="showPermissionsDialog(adapter)"><i + class="material-icons">share</i> + </button> + </span> + <span fxFlex fxFlexOrder="3" fxLayout="row" fxLayoutAlign="center center"> + <button color="accent" mat-button mat-icon-button matTooltip="Delete adapter" + data-cy="delete-adapter" matTooltipPosition="above" (click)="deleteAdapter(adapter)"> + <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> + <div fxFlex="100" fxLayoutAlign="end end"> + <mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" + [pageSize]="20" + color="accent"> + </mat-paginator> + </div> + </div> + <div fxFlex="100" + fxLayout="column" + fxLayoutAlign="center center" + *ngIf="existingAdapters.length == 0"> + <h5>(no adapters available)</h5> + </div> + </sp-basic-inner-panel> + </div> + </div> +</sp-basic-view>
diff --git a/ui/src/app/connect/components/data-marketplace/existing-adapters/existing-adapters.component.scss b/ui/src/app/connect/components/existing-adapters/existing-adapters.component.scss similarity index 91% rename from ui/src/app/connect/components/data-marketplace/existing-adapters/existing-adapters.component.scss rename to ui/src/app/connect/components/existing-adapters/existing-adapters.component.scss index b69117a..f38f54d 100644 --- a/ui/src/app/connect/components/data-marketplace/existing-adapters/existing-adapters.component.scss +++ b/ui/src/app/connect/components/existing-adapters/existing-adapters.component.scss
@@ -26,10 +26,10 @@ } .mat-row:nth-child(even) { - background-color: var(--color-bg-2); + background-color: var(--color-bg-1); } .mat-row:nth-child(odd) { - background-color: var(--color-bg-3); + background-color: var(--color-bg-2); } .adapter-icon { @@ -44,3 +44,9 @@ cursor: pointer; color: #FFEB3B; } + +.filter-bar-margin { + margin-left: 10px; + padding-left: 10px; +} +
diff --git a/ui/src/app/connect/components/existing-adapters/existing-adapters.component.ts b/ui/src/app/connect/components/existing-adapters/existing-adapters.component.ts new file mode 100644 index 0000000..ecee3df --- /dev/null +++ b/ui/src/app/connect/components/existing-adapters/existing-adapters.component.ts
@@ -0,0 +1,201 @@ +/* + * 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 { + AdapterDescriptionUnion, + AdapterService, + PipelineElementService, + StreamPipesErrorMessage +} from '@streampipes/platform-services'; +import { MatTableDataSource } from '@angular/material/table'; +import { ConnectService } from '../../services/connect.service'; +import { + DialogRef, + DialogService, + PanelType, + SpBreadcrumbService, + SpExceptionDetailsDialogComponent +} from '@streampipes/shared-ui'; +import { DeleteAdapterDialogComponent } from '../../dialog/delete-adapter-dialog/delete-adapter-dialog.component'; +import { MatPaginator } from '@angular/material/paginator'; +import { MatSort } from '@angular/material/sort'; +import { ObjectPermissionDialogComponent } from '../../../core-ui/object-permission-dialog/object-permission-dialog.component'; +import { UserRole } from '../../../_enums/user-role.enum'; +import { AuthService } from '../../../services/auth.service'; +import { HelpComponent } from '../../../editor/dialog/help/help.component'; +import { Router } from '@angular/router'; +import { AdapterFilterSettingsModel } from '../../model/adapter-filter-settings.model'; +import { AdapterFilterPipe } from '../../filter/adapter-filter.pipe'; +import { SpConnectRoutes } from '../../connect.routes'; + +@Component({ + selector: 'sp-existing-adapters', + templateUrl: './existing-adapters.component.html', + styleUrls: ['./existing-adapters.component.scss'] +}) +export class ExistingAdaptersComponent implements OnInit { + + existingAdapters: AdapterDescriptionUnion[] = []; + filteredAdapters: AdapterDescriptionUnion[] = []; + + currentFilter: AdapterFilterSettingsModel; + + @ViewChild(MatPaginator) paginator: MatPaginator; + pageSize = 1; + @ViewChild(MatSort) sort: MatSort; + + displayedColumns: string[] = ['start', 'name', 'adapterBase', 'adapterType', 'lastModified', 'action']; + + dataSource: MatTableDataSource<AdapterDescriptionUnion>; + isAdmin = false; + + constructor(public connectService: ConnectService, + private dataMarketplaceService: AdapterService, + private dialogService: DialogService, + private authService: AuthService, + private pipelineElementService: PipelineElementService, + private router: Router, + private adapterFilter: AdapterFilterPipe, + private breadcrumbService: SpBreadcrumbService) { + + } + + ngOnInit(): void { + this.breadcrumbService.updateBreadcrumb(this.breadcrumbService.getRootLink(SpConnectRoutes.BASE)); + this.authService.user$.subscribe(user => { + this.isAdmin = user.roles.indexOf(UserRole.ROLE_ADMIN) > -1; + this.getAdaptersRunning(); + }); + } + + startAdapter(adapter: AdapterDescriptionUnion) { + this.dataMarketplaceService.startAdapter(adapter).subscribe(response => { + this.getAdaptersRunning(); + }, error => { + this.openAdapterStatusErrorDialog(error.error, 'Could not start adapter'); + }); + } + + stopAdapter(adapter: AdapterDescriptionUnion) { + this.dataMarketplaceService.stopAdapter(adapter).subscribe(response => { + this.getAdaptersRunning(); + }, error => { + this.openAdapterStatusErrorDialog(error.error, 'Could not stop adapter'); + }); + } + + openAdapterStatusErrorDialog(message: StreamPipesErrorMessage, + title: string) { + this.dialogService.open(SpExceptionDetailsDialogComponent, { + panelType: PanelType.STANDARD_PANEL, + title: 'Adapter Status', + width: '70vw', + data: { + 'message': message, + 'title': title + } + }); + } + + getIconUrl(adapter: AdapterDescriptionUnion) { + if (adapter.includedAssets.length > 0) { + return this.dataMarketplaceService.getAssetUrl(adapter.appId) + '/icon'; + } else { + return 'assets/img/connect/' + adapter.iconUrl; + } + } + + showPermissionsDialog(adapter: AdapterDescriptionUnion) { + + const dialogRef = this.dialogService.open(ObjectPermissionDialogComponent, { + panelType: PanelType.SLIDE_IN_PANEL, + title: 'Manage permissions', + width: '50vw', + data: { + 'objectInstanceId': adapter.correspondingDataStreamElementId, + 'headerTitle': 'Manage permissions for adapter ' + adapter.name + } + }); + + dialogRef.afterClosed().subscribe(refresh => { + if (refresh) { + this.getAdaptersRunning(); + } + }); + } + + deleteAdapter(adapter: AdapterDescriptionUnion): void { + const dialogRef: DialogRef<DeleteAdapterDialogComponent> = this.dialogService.open(DeleteAdapterDialogComponent, { + panelType: PanelType.STANDARD_PANEL, + title: 'Delete Adapter', + width: '70vw', + data: { + 'adapter': adapter + } + }); + + dialogRef.afterClosed().subscribe(data => { + if (data) { + this.getAdaptersRunning(); + } + }); + } + + openHelpDialog(adapter: AdapterDescriptionUnion) { + const streamId = adapter.correspondingDataStreamElementId; + + this.pipelineElementService.getDataStreamByElementId(streamId).subscribe(stream => { + if (stream) { + this.dialogService.open(HelpComponent, { + panelType: PanelType.STANDARD_PANEL, + title: stream.name, + width: '70vw', + data: { + 'pipelineElement': stream + } + }); + } + }); + } + + getAdaptersRunning(): void { + this.dataMarketplaceService.getAdapters().subscribe(adapters => { + this.existingAdapters = adapters; + this.existingAdapters.sort((a, b) => a.name.localeCompare(b.name)); + this.filteredAdapters = this.adapterFilter.transform(this.existingAdapters, this.currentFilter); + this.dataSource = new MatTableDataSource(this.filteredAdapters); + setTimeout(() => { + this.dataSource.paginator = this.paginator; + this.dataSource.sort = this.sort; + }); + }); + } + + createNewAdapter(): void { + this.router.navigate(['connect', 'create']); + } + + applyFilter(filter: AdapterFilterSettingsModel) { + this.currentFilter = filter; + if (this.dataSource) { + this.dataSource.data = this.adapterFilter.transform(this.filteredAdapters, this.currentFilter); + } + } + +}
diff --git a/ui/src/app/connect/components/filter-toolbar/filter-toolbar.component.html b/ui/src/app/connect/components/filter-toolbar/filter-toolbar.component.html new file mode 100644 index 0000000..d6fc0b5 --- /dev/null +++ b/ui/src/app/connect/components/filter-toolbar/filter-toolbar.component.html
@@ -0,0 +1,48 @@ +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~ + --> + +<div fxLayout="row" fxFlex="100"> + + <div class="data-marketplace-options-item pl-5 form-style" fxLayoutAlign="start center" + fxLayout="row"> + <mat-icon color="accent">search</mat-icon> + <mat-form-field class="form-style" color="accent" floatLabel="never"> + <input matInput placeholder="Find Element" value="" (input)="updateFilterTerm($event.target.value)" + name="something"> + </mat-form-field> + </div> + <div class="data-marketplace-options-item"> + <mat-form-field color="accent"> + <mat-select [(value)]="currentFilter.selectedType" (selectionChange)="filterAdapter($event)"> + <mat-option *ngFor="let type of adapterTypes" [value]="type"> + {{type}} + </mat-option> + </mat-select> + </mat-form-field> + </div> + <div class="data-marketplace-options-item"> + <mat-form-field color="accent"> + <mat-select [(value)]="currentFilter.selectedCategory" (selectionChange)="filterAdapter($event)"> + <mat-option *ngFor="let category of adapterCategories" [value]="category.code"> + {{category.label}} + </mat-option> + </mat-select> + </mat-form-field> + </div> + <span fxFlex></span> +</div>
diff --git a/ui/src/app/connect/components/format-item-json/format-item-json.component.scss b/ui/src/app/connect/components/filter-toolbar/filter-toolbar.component.scss similarity index 60% copy from ui/src/app/connect/components/format-item-json/format-item-json.component.scss copy to ui/src/app/connect/components/filter-toolbar/filter-toolbar.component.scss index 30123c0..c239b47 100644 --- a/ui/src/app/connect/components/format-item-json/format-item-json.component.scss +++ b/ui/src/app/connect/components/filter-toolbar/filter-toolbar.component.scss
@@ -16,32 +16,33 @@ * */ - -.format-label { - line-height:50px; - margin: auto; - text-align: center; - font-weight: bold; - font-size: 1.3em; +::ng-deep .mat-select-panel { + background: #fff; } -.format-box { - min-height: 50px; - box-shadow: 1px 1px 2px #555; - border: 1px solid gray; - cursor: pointer; - padding: 10px; - opacity: 0.7; - margin: 10px; - background: #ffffff; +::ng-deep .mat-select-panel:not([class*=mat-elevation-z]) { + box-shadow: 0 2px 4px -1px rgba(0,0,0,.2), 0 4px 5px 0 rgba(0,0,0,.14), 0 1px 10px 0 rgba(0,0,0,.12); } -.format-box:hover { - opacity: 1; +#categoryFilter { + margin-top: 20px; } -.selectedItem { - opacity: 1; - background-color: grey; +.data-marketplace-options { + padding:0px; + background-color: var(--color-bg-1); + border-bottom: 1px solid var(--color-bg-3); } +.data-marketplace-options-item { + display: inline; + margin-right: 10px; +} + +.form-style { + margin: 0px 5px 0px 0px; +} + +.fixed-height { + height: 50px; +}
diff --git a/ui/src/app/connect/components/filter-toolbar/filter-toolbar.component.ts b/ui/src/app/connect/components/filter-toolbar/filter-toolbar.component.ts new file mode 100644 index 0000000..7e67e7d --- /dev/null +++ b/ui/src/app/connect/components/filter-toolbar/filter-toolbar.component.ts
@@ -0,0 +1,65 @@ +/* + * 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, EventEmitter, OnInit, Output } from '@angular/core'; +import { AdapterService } from '@streampipes/platform-services'; +import { MatSelectChange } from '@angular/material/select'; +import { AdapterFilterSettingsModel } from '../../model/adapter-filter-settings.model'; + +@Component({ + selector: 'sp-connect-filter-toolbar', + templateUrl: './filter-toolbar.component.html', + styleUrls: ['./filter-toolbar.component.scss'] +}) +export class SpConnectFilterToolbarComponent implements OnInit { + + @Output() + filterChangedEmitter: EventEmitter<AdapterFilterSettingsModel> = new EventEmitter<AdapterFilterSettingsModel>(); + + adapterTypes: string[] = ['All types', 'Data Set', 'Data Stream']; + adapterCategories: any; + + currentFilter: AdapterFilterSettingsModel = {textFilter: '', selectedCategory: 'All', selectedType: 'All types'}; + + constructor(private dataMarketplaceService: AdapterService) { + + } + + ngOnInit(): void { + this.loadAvailableTypeCategories(); + } + + loadAvailableTypeCategories() { + this.dataMarketplaceService.getAdapterCategories().subscribe(res => { + this.adapterCategories = res; + this.adapterCategories.unshift({ label: 'All categories', description: '', code: 'All' }); + this.filterChangedEmitter.emit(this.currentFilter); + }); + } + + filterAdapter(event: MatSelectChange) { + this.filterChangedEmitter.emit(this.currentFilter); + } + + updateFilterTerm(event: string) { + this.currentFilter.textFilter = event; + this.filterChangedEmitter.emit(this.currentFilter); + } + + +}
diff --git a/ui/src/app/connect/components/format-configuration/format-configuration.component.html b/ui/src/app/connect/components/format-configuration/format-configuration.component.html deleted file mode 100644 index 13da938..0000000 --- a/ui/src/app/connect/components/format-configuration/format-configuration.component.html +++ /dev/null
@@ -1,65 +0,0 @@ -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one or more - ~ contributor license agreements. See the NOTICE file distributed with - ~ this work for additional information regarding copyright ownership. - ~ The ASF licenses this file to You under the Apache License, Version 2.0 - ~ (the "License"); you may not use this file except in compliance with - ~ the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - ~ - --> - -<div style="margin-bottom: 2%;"> - - <div class="assemblyOptions sp-blue-bg"> - <h4>Select format</h4> - </div> - <div class="sp-blue-border padding"> - <sp-format-list fxFlex="100" - (selectedFormatEmitter)="formatSelected($event)" - [selectedFormat]="selectedFormat"> - </sp-format-list> - </div> - - <div class="assemblyOptions sp-blue-bg" - *ngIf="selectedFormat"> - <h4>Configure format</h4> - </div> - - <div *ngIf="selectedFormat"> - <div *ngIf="selectedFormat.config.length > 0"> - <sp-configuration-group - [configurationGroup]="formatForm" - [adapterId]="adapterDescription.appId" - [configuration]="selectedFormat.config"> - </sp-configuration-group> - </div> - - <div *ngIf="selectedFormat.config.length === 0" class="sp-blue-border padding" style="padding: 15px;"> - <div style="text-align:center;"> - <h5 >(no further configuration needed)</h5> - </div> - </div> - </div> -</div> - -<div fxLayoutAlign="end"> - <button class="mat-basic" mat-raised-button (click)="removeSelection()">Cancel</button> - <button class="mat-basic stepper-button" mat-raised-button (click)="goBack()">Back</button> - <button class="stepper-button" - id="format-selection-next-button" - data-cy="sp-format-selection-next-button" - [disabled]="!formatConfigurationValid" - (click)="clickNext()" - color="accent" mat-raised-button> - Next - </button> -</div> -
diff --git a/ui/src/app/connect/components/generic-adapter-configuration/generic-adapter-configuration.component.html b/ui/src/app/connect/components/generic-adapter-configuration/generic-adapter-configuration.component.html deleted file mode 100644 index 5e1418c..0000000 --- a/ui/src/app/connect/components/generic-adapter-configuration/generic-adapter-configuration.component.html +++ /dev/null
@@ -1,41 +0,0 @@ -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one or more - ~ contributor license agreements. See the NOTICE file distributed with - ~ this work for additional information regarding copyright ownership. - ~ The ASF licenses this file to You under the Apache License, Version 2.0 - ~ (the "License"); you may not use this file except in compliance with - ~ the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - ~ - --> - -<div style="margin-bottom: 2%;"> - - <div > - <div class="assemblyOptions sp-blue-bg"> - <h4 >Protocol settings</h4> - </div> - - <sp-configuration-group - [configurationGroup]="genericAdapterForm" - [adapterId]="adapterDescription.appId" - [configuration]="protocolDescription.config"> - </sp-configuration-group> - </div> -</div> - -<div fxLayoutAlign="end"> - <button class="mat-basic" mat-raised-button (click)="removeSelection()">Cancel</button> - <div id="generic-settings-next-button"> - <button class="stepper-button" [disabled]="!genericAdapterSettingsFormValid" - (click)="clickNext()" color="accent" mat-raised-button>Next - </button> - </div> -</div>
diff --git a/ui/src/app/connect/components/generic-adapter-configuration/generic-adapter-configuration.component.ts b/ui/src/app/connect/components/generic-adapter-configuration/generic-adapter-configuration.component.ts deleted file mode 100644 index 5746201..0000000 --- a/ui/src/app/connect/components/generic-adapter-configuration/generic-adapter-configuration.component.ts +++ /dev/null
@@ -1,83 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { - AdapterDescriptionUnion, - GenericAdapterSetDescription, - GenericAdapterStreamDescription, - ProtocolDescription -} from '@streampipes/platform-services'; -import { FormBuilder, FormGroup } from '@angular/forms'; -import { MatStepper } from '@angular/material/stepper'; - -@Component({ - selector: 'sp-generic-adapter-configuration', - templateUrl: './generic-adapter-configuration.component.html', - styleUrls: ['./generic-adapter-configuration.component.scss'] -}) -export class GenericAdapterConfigurationComponent implements OnInit { - - /** - * Adapter description the selected format is added to - */ - @Input() adapterDescription: AdapterDescriptionUnion; - - /** - * Cancels the adapter configuration process - */ - @Output() removeSelectionEmitter: EventEmitter<boolean> = new EventEmitter(); - - /** - * Go to next configuration step when this is complete - */ - @Output() clickNextEmitter: EventEmitter<MatStepper> = new EventEmitter(); - - - genericAdapterSettingsFormValid: boolean; - - genericAdapterForm: FormGroup; - - protocolDescription: ProtocolDescription; - - constructor( - private _formBuilder: FormBuilder - ) { } - - ngOnInit(): void { - - if (this.adapterDescription instanceof GenericAdapterSetDescription || - this.adapterDescription instanceof GenericAdapterStreamDescription) { - this.protocolDescription = this.adapterDescription.protocolDescription; - } - - // initialize form for validation - this.genericAdapterForm = this._formBuilder.group({}); - this.genericAdapterForm.statusChanges.subscribe((status) => { - this.genericAdapterSettingsFormValid = this.genericAdapterForm.valid; - }); - } - - public removeSelection() { - this.removeSelectionEmitter.emit(); - } - - public clickNext() { - this.clickNextEmitter.emit(); - } -}
diff --git a/ui/src/app/connect/components/new-adapter/adapter-configuration.directive.ts b/ui/src/app/connect/components/new-adapter/adapter-configuration.directive.ts new file mode 100644 index 0000000..b5ba397 --- /dev/null +++ b/ui/src/app/connect/components/new-adapter/adapter-configuration.directive.ts
@@ -0,0 +1,98 @@ +/* + * 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 { Directive, EventEmitter, Input, Output } from '@angular/core'; +import { MatStepper } from '@angular/material/stepper'; +import { + AdapterDescriptionUnion, + PipelineElementTemplate, + PipelineElementTemplateService +} from '@streampipes/platform-services'; +import { FormBuilder } from '@angular/forms'; +import { AdapterTemplateService } from '../../services/adapter-template.service'; +import { DialogService } from '@streampipes/shared-ui'; + +@Directive() +export abstract class AdapterConfigurationDirective { + + /** + * Adapter description the selected format is added to + */ + @Input() adapterDescription: AdapterDescriptionUnion; + + cachedAdapterDescription: AdapterDescriptionUnion; + + /** + * Cancels the adapter configuration process + */ + @Output() removeSelectionEmitter: EventEmitter<boolean> = new EventEmitter(); + + /** + * Go to next configuration step when this is complete + */ + @Output() clickNextEmitter: EventEmitter<MatStepper> = new EventEmitter(); + + @Output() updateAdapterDescriptionEmitter: EventEmitter<AdapterDescriptionUnion> = new EventEmitter<AdapterDescriptionUnion>(); + + availableTemplates: PipelineElementTemplate[]; + selectedTemplate: any = false; + + constructor(protected _formBuilder: FormBuilder, + protected dialogService: DialogService, + protected pipelineElementTemplateService: PipelineElementTemplateService, + protected adapterTemplateService: AdapterTemplateService) { + } + + onInit(): void { + this.loadPipelineElementTemplates(); + } + + public removeSelection() { + this.removeSelectionEmitter.emit(); + } + + public clickNext() { + this.clickNextEmitter.emit(); + } + + loadPipelineElementTemplates() { + this.pipelineElementTemplateService + .getPipelineElementTemplates(this.adapterDescription.appId) + .subscribe(templates => { + this.availableTemplates = templates; + }); + } + + loadTemplate(event: any) { + if (!event.value) { + this.adapterDescription = {...this.cachedAdapterDescription}; + this.selectedTemplate = false; + } else { + this.selectedTemplate = event.value; + this.pipelineElementTemplateService.getConfiguredAdapterForTemplate(event.value._id, this.adapterDescription) + .subscribe(adapterDescription => { + this.afterTemplateReceived(adapterDescription); + }); + } + } + + abstract openTemplateDialog(): void; + + abstract afterTemplateReceived(adapterDescription: any); + +}
diff --git a/ui/src/app/connect/components/new-adapter/format-configuration/format-configuration.component.html b/ui/src/app/connect/components/new-adapter/format-configuration/format-configuration.component.html new file mode 100644 index 0000000..7a998c5 --- /dev/null +++ b/ui/src/app/connect/components/new-adapter/format-configuration/format-configuration.component.html
@@ -0,0 +1,58 @@ +<!-- + ~ 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"> + <sp-basic-inner-panel panelTitle="Select format" outerMargin="20px 0px"> + <sp-format-list fxFlex="100" + (selectedFormatEmitter)="formatSelected($event)" + [selectedFormat]="selectedFormat"> + </sp-format-list> + </sp-basic-inner-panel> + + <sp-basic-inner-panel panelTitle="Configure Format" outerMargin="10px 0px 20px 0px" *ngIf="selectedFormat"> + + <div *ngIf="selectedFormat"> + <div *ngIf="selectedFormat.config.length > 0"> + <sp-configuration-group + [configurationGroup]="formatForm" + [adapterId]="adapterDescription.appId" + [configuration]="selectedFormat.config"> + </sp-configuration-group> + </div> + + <div *ngIf="selectedFormat.config.length === 0" style="padding: 15px;"> + <div style="text-align:center;"> + <h5>(no further configuration needed)</h5> + </div> + </div> + </div> + </sp-basic-inner-panel> + + <div fxLayoutAlign="end"> + <button class="mat-basic" mat-raised-button (click)="removeSelection()">Cancel</button> + <button class="mat-basic stepper-button" mat-raised-button (click)="goBack()">Back</button> + <button class="stepper-button" + id="format-selection-next-button" + data-cy="sp-format-selection-next-button" + [disabled]="!formatConfigurationValid" + (click)="clickNext()" + color="accent" mat-raised-button> + Next + </button> + </div> +</div>
diff --git a/ui/src/app/connect/components/format-configuration/format-configuration.component.scss b/ui/src/app/connect/components/new-adapter/format-configuration/format-configuration.component.scss similarity index 100% rename from ui/src/app/connect/components/format-configuration/format-configuration.component.scss rename to ui/src/app/connect/components/new-adapter/format-configuration/format-configuration.component.scss
diff --git a/ui/src/app/connect/components/format-configuration/format-configuration.component.ts b/ui/src/app/connect/components/new-adapter/format-configuration/format-configuration.component.ts similarity index 98% rename from ui/src/app/connect/components/format-configuration/format-configuration.component.ts rename to ui/src/app/connect/components/new-adapter/format-configuration/format-configuration.component.ts index 87a8c7c..b129651 100644 --- a/ui/src/app/connect/components/format-configuration/format-configuration.component.ts +++ b/ui/src/app/connect/components/new-adapter/format-configuration/format-configuration.component.ts
@@ -24,7 +24,7 @@ GenericAdapterStreamDescription } from '@streampipes/platform-services'; import { FormBuilder, FormGroup } from '@angular/forms'; -import { RestService } from '../../services/rest.service'; +import { RestService } from '../../../services/rest.service'; import { MatStepper } from '@angular/material/stepper'; @Component({
diff --git a/ui/src/app/connect/components/format-item-json/format-item-json.component.html b/ui/src/app/connect/components/new-adapter/format-configuration/format-item-json/format-item-json.component.html similarity index 100% rename from ui/src/app/connect/components/format-item-json/format-item-json.component.html rename to ui/src/app/connect/components/new-adapter/format-configuration/format-item-json/format-item-json.component.html
diff --git a/ui/src/app/connect/components/format-item-json/format-item-json.component.scss b/ui/src/app/connect/components/new-adapter/format-configuration/format-item-json/format-item-json.component.scss similarity index 94% rename from ui/src/app/connect/components/format-item-json/format-item-json.component.scss rename to ui/src/app/connect/components/new-adapter/format-configuration/format-item-json/format-item-json.component.scss index 30123c0..2d626c4 100644 --- a/ui/src/app/connect/components/format-item-json/format-item-json.component.scss +++ b/ui/src/app/connect/components/new-adapter/format-configuration/format-item-json/format-item-json.component.scss
@@ -42,6 +42,7 @@ .selectedItem { opacity: 1; - background-color: grey; + background-color: var(--color-accent); + color: var(--color-bg-2); }
diff --git a/ui/src/app/connect/components/format-item-json/format-item-json.component.ts b/ui/src/app/connect/components/new-adapter/format-configuration/format-item-json/format-item-json.component.ts similarity index 100% rename from ui/src/app/connect/components/format-item-json/format-item-json.component.ts rename to ui/src/app/connect/components/new-adapter/format-configuration/format-item-json/format-item-json.component.ts
diff --git a/ui/src/app/connect/components/format-item/format-item.component.html b/ui/src/app/connect/components/new-adapter/format-configuration/format-item/format-item.component.html similarity index 100% rename from ui/src/app/connect/components/format-item/format-item.component.html rename to ui/src/app/connect/components/new-adapter/format-configuration/format-item/format-item.component.html
diff --git a/ui/src/app/connect/components/format-item/format-item.component.scss b/ui/src/app/connect/components/new-adapter/format-configuration/format-item/format-item.component.scss similarity index 94% rename from ui/src/app/connect/components/format-item/format-item.component.scss rename to ui/src/app/connect/components/new-adapter/format-configuration/format-item/format-item.component.scss index db43ef1..3aa1b93 100644 --- a/ui/src/app/connect/components/format-item/format-item.component.scss +++ b/ui/src/app/connect/components/new-adapter/format-configuration/format-item/format-item.component.scss
@@ -41,5 +41,6 @@ .selectedItem { opacity: 1; - background-color: grey; + background-color: var(--color-accent); + color: var(--color-bg-2); }
diff --git a/ui/src/app/connect/components/format-item/format-item.component.ts b/ui/src/app/connect/components/new-adapter/format-configuration/format-item/format-item.component.ts similarity index 95% rename from ui/src/app/connect/components/format-item/format-item.component.ts rename to ui/src/app/connect/components/new-adapter/format-configuration/format-item/format-item.component.ts index 6d7db60..77f2662 100644 --- a/ui/src/app/connect/components/format-item/format-item.component.ts +++ b/ui/src/app/connect/components/new-adapter/format-configuration/format-item/format-item.component.ts
@@ -17,7 +17,7 @@ */ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { ShepherdService } from '../../../services/tour/shepherd.service'; +import { ShepherdService } from '../../../../../services/tour/shepherd.service'; import { FormatDescription } from '@streampipes/platform-services'; @Component({
diff --git a/ui/src/app/connect/components/format-list/format-list.component.html b/ui/src/app/connect/components/new-adapter/format-configuration/format-list/format-list.component.html similarity index 95% rename from ui/src/app/connect/components/format-list/format-list.component.html rename to ui/src/app/connect/components/new-adapter/format-configuration/format-list/format-list.component.html index 59d46c2..81eefc0 100644 --- a/ui/src/app/connect/components/format-list/format-list.component.html +++ b/ui/src/app/connect/components/new-adapter/format-configuration/format-list/format-list.component.html
@@ -33,9 +33,9 @@ </div> <div fxFlex="100" - class="assemblyOptions sp-blue-bg" + class="format-title" *ngIf="selectJsonFormats"> - <h4>Select json format</h4> + <h4>Select JSON format</h4> </div> <div fxFlex="25"
diff --git a/ui/src/app/connect/components/format-list/format-list.component.scss b/ui/src/app/connect/components/new-adapter/format-configuration/format-list/format-list.component.scss similarity index 78% rename from ui/src/app/connect/components/format-list/format-list.component.scss rename to ui/src/app/connect/components/new-adapter/format-configuration/format-list/format-list.component.scss index 9db395a..61c683a 100644 --- a/ui/src/app/connect/components/format-list/format-list.component.scss +++ b/ui/src/app/connect/components/new-adapter/format-configuration/format-list/format-list.component.scss
@@ -17,6 +17,16 @@ */ .fullWidth { - width: 100%; - height: 100%; - } \ No newline at end of file + width: 100%; + height: 100%; +} + +.format-title { + margin-top: 10px; + margin-left: 5px; + padding-left: 5px; + border-left: 4px solid var(--color-accent); + font-weight: 600; + font-size: 13pt; + white-space: nowrap; +}
diff --git a/ui/src/app/connect/components/format-list/format-list.component.ts b/ui/src/app/connect/components/new-adapter/format-configuration/format-list/format-list.component.ts similarity index 97% rename from ui/src/app/connect/components/format-list/format-list.component.ts rename to ui/src/app/connect/components/new-adapter/format-configuration/format-list/format-list.component.ts index bcc1afd..65d18a4 100644 --- a/ui/src/app/connect/components/format-list/format-list.component.ts +++ b/ui/src/app/connect/components/new-adapter/format-configuration/format-list/format-list.component.ts
@@ -18,7 +18,7 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { FormatDescription } from '@streampipes/platform-services'; -import { RestService } from '../../services/rest.service'; +import { RestService } from '../../../../services/rest.service'; @Component({ selector: 'sp-format-list',
diff --git a/ui/src/app/connect/components/new-adapter/generic-adapter-configuration/generic-adapter-configuration.component.html b/ui/src/app/connect/components/new-adapter/generic-adapter-configuration/generic-adapter-configuration.component.html new file mode 100644 index 0000000..9dd1a3d --- /dev/null +++ b/ui/src/app/connect/components/new-adapter/generic-adapter-configuration/generic-adapter-configuration.component.html
@@ -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. + ~ + --> + +<div fxFlex="100" fxLayout="column"> + <div fxFlex="100" fxLayout="column"> + <div fxFlex="100" fxLayout="column"> + <sp-basic-inner-panel panelTitle="Protocol Settings" outerMargin="20px 0px"> + <div header fxFlex="100" fxLayout="row" fxLayoutAlign="end center" class="pr-5"> + <div fxFlex="100" fxLayout="row" fxLayoutAlign="end center" + *ngIf="availableTemplates && availableTemplates.length > 0"> + <mat-form-field class="form-field" floatLabel="never" color="accent"> + <mat-label>Use template</mat-label> + <mat-select (selectionChange)="loadTemplate($event)" + [(value)]="selectedTemplate"> + <mat-option>--</mat-option> + <mat-option [value]="template" *ngFor="let template of availableTemplates"> + {{template.templateName}} + </mat-option> + </mat-select> + </mat-form-field> + </div> + </div> + <sp-configuration-group + [configurationGroup]="genericAdapterForm" + [adapterId]="adapterDescription.appId" + [configuration]="protocolDescription.config"> + </sp-configuration-group> + </sp-basic-inner-panel> + </div> + </div> + + <div fxLayoutAlign="end"> + <button class="mat-basic" + mat-raised-button + (click)="removeSelection()" + style="margin-right: 10px;">Cancel + </button> + <button mat-button mat-raised-button + class="mat-basic" + (click)="openTemplateDialog()">Store config as template + </button> + <div id="generic-settings-next-button"> + <button class="stepper-button" [disabled]="!genericAdapterSettingsFormValid" + (click)="clickNext()" color="accent" mat-raised-button>Next + </button> + </div> + </div> +</div>
diff --git a/ui/src/app/connect/components/generic-adapter-configuration/generic-adapter-configuration.component.scss b/ui/src/app/connect/components/new-adapter/generic-adapter-configuration/generic-adapter-configuration.component.scss similarity index 100% rename from ui/src/app/connect/components/generic-adapter-configuration/generic-adapter-configuration.component.scss rename to ui/src/app/connect/components/new-adapter/generic-adapter-configuration/generic-adapter-configuration.component.scss
diff --git a/ui/src/app/connect/components/new-adapter/generic-adapter-configuration/generic-adapter-configuration.component.ts b/ui/src/app/connect/components/new-adapter/generic-adapter-configuration/generic-adapter-configuration.component.ts new file mode 100644 index 0000000..80b9301 --- /dev/null +++ b/ui/src/app/connect/components/new-adapter/generic-adapter-configuration/generic-adapter-configuration.component.ts
@@ -0,0 +1,82 @@ +/* + * 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 { + GenericAdapterSetDescription, + GenericAdapterStreamDescription, + ProtocolDescription, + PipelineElementTemplateService +} from '@streampipes/platform-services'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { AdapterConfigurationDirective } from '../adapter-configuration.directive'; +import { AdapterTemplateService } from '../../../services/adapter-template.service'; +import { DialogService } from '@streampipes/shared-ui'; + +@Component({ + selector: 'sp-generic-adapter-configuration', + templateUrl: './generic-adapter-configuration.component.html', + styleUrls: ['./generic-adapter-configuration.component.scss'] +}) +export class GenericAdapterConfigurationComponent extends AdapterConfigurationDirective implements OnInit { + + genericAdapterSettingsFormValid: boolean; + + genericAdapterForm: FormGroup; + + protocolDescription: ProtocolDescription; + + constructor(_formBuilder: FormBuilder, + dialogService: DialogService, + pipelineElementTemplateService: PipelineElementTemplateService, + adapterTemplateService: AdapterTemplateService) { + super(_formBuilder, dialogService, pipelineElementTemplateService, adapterTemplateService); + } + + ngOnInit(): void { + super.onInit(); + if (this.adapterDescription instanceof GenericAdapterSetDescription || + this.adapterDescription instanceof GenericAdapterStreamDescription) { + this.protocolDescription = this.adapterDescription.protocolDescription; + } + + // initialize form for validation + this.genericAdapterForm = this._formBuilder.group({}); + this.genericAdapterForm.statusChanges.subscribe((status) => { + this.genericAdapterSettingsFormValid = this.genericAdapterForm.valid; + }); + } + + openTemplateDialog(): void { + const dialogRef = this.adapterTemplateService.getDialog(this.protocolDescription.config, this.protocolDescription.appId); + + dialogRef.afterClosed().subscribe(refresh => { + this.loadPipelineElementTemplates(); + }); + } + + afterTemplateReceived(adapterDescription: any) { + this.protocolDescription = ProtocolDescription.fromData(adapterDescription.protocolDescription); + if (this.adapterDescription instanceof GenericAdapterSetDescription || + this.adapterDescription instanceof GenericAdapterStreamDescription) { + this.adapterDescription.protocolDescription = this.protocolDescription; + this.updateAdapterDescriptionEmitter.emit(this.adapterDescription); + } + } + +}
diff --git a/ui/src/app/connect/components/new-adapter/new-adapter.component.html b/ui/src/app/connect/components/new-adapter/new-adapter.component.html index c2777ee..9c1a1ae 100644 --- a/ui/src/app/connect/components/new-adapter/new-adapter.component.html +++ b/ui/src/app/connect/components/new-adapter/new-adapter.component.html
@@ -16,80 +16,85 @@ ~ --> -<div fxLayout="column" fxLayoutAlign="center stretch"> - <div fxLayout="column" fxFlex="100" class="p-10"> - <div fxLayout="row" fxLayoutAlign="start center"> - <mat-icon *ngIf="isDataSetDescription" class="historic">lens</mat-icon> - <mat-icon *ngIf="isDataStreamDescription" class="real-time">lens - </mat-icon> - <div fxLayoutAlign="start center"> - <p *ngIf="isDataSetDescription">Data Set</p> - <p *ngIf="isDataStreamDescription">Data Stream</p> - </div> - <span fxFlex></span> - <div fxLayoutAlign="end start"> - <button mat-icon-button (click)="removeSelection()"> - <i class="material-icons">close</i> - </button> - </div> - </div> - <h1 *ngIf="!fromTemplate" class="new-adapter-title">New Source: {{adapter.templateTitle}}</h1> - <h1 *ngIf="fromTemplate" class="new-adapter-title">From Template: {{adapter.templateTitle}}</h1> +<sp-basic-view [padding]="true" [showBackLink]="false"> + + <div nav fxFlex="100" fxLayout="row" fxLayoutAlign="end center"> + <button mat-icon-button (click)="removeSelection()" matTooltip="Cancel"> + <i class="material-icons">close</i> + </button> </div> + <div fxLayout="column" fxLayoutAlign="center stretch" *ngIf="adapter"> + <div fxLayout="column" fxFlex="100"> + <div fxLayout="row" fxLayoutAlign="start center"> + <mat-icon *ngIf="isDataSetDescription" class="historic">lens</mat-icon> + <mat-icon *ngIf="isDataStreamDescription" class="real-time">lens + </mat-icon> + <div fxLayoutAlign="start center"> + <p *ngIf="isDataSetDescription">Data Set</p> + <p *ngIf="isDataStreamDescription">Data Stream</p> + </div> + <span fxFlex></span> + </div> + <h1 *ngIf="!fromTemplate" class="new-adapter-title">New Source: {{adapter.templateTitle}}</h1> + <h1 *ngIf="fromTemplate" class="new-adapter-title">From Template: {{adapter.templateTitle}}</h1> + </div> - <mat-horizontal-stepper [linear]="true" #stepper color="accent" class="stepper"> - <mat-step *ngIf="!isGenericAdapter"> - <ng-template matStepLabel>Settings</ng-template> - <sp-specific-adapter-configuration - [adapterDescription]="adapter" - (clickNextEmitter)="clickSpecificSettingsNextButton()" - (removeSelectionEmitter)="removeSelection()"> - </sp-specific-adapter-configuration> - </mat-step> + <mat-horizontal-stepper [linear]="true" #stepper color="accent" class="stepper"> + <mat-step *ngIf="!isGenericAdapter"> + <ng-template matStepLabel>Settings</ng-template> + <sp-specific-adapter-configuration + [adapterDescription]="adapter" + (updateAdapterDescriptionEmitter)="adapter = $event" + (clickNextEmitter)="clickSpecificSettingsNextButton()" + (removeSelectionEmitter)="removeSelection()"> + </sp-specific-adapter-configuration> + </mat-step> - <mat-step *ngIf="isGenericAdapter"> - <ng-template matStepLabel>Settings</ng-template> - <sp-generic-adapter-configuration - [adapterDescription]="adapter" - (clickNextEmitter)="clickProtocolSettingsNextButton()" - (removeSelectionEmitter)="removeSelection()"> - </sp-generic-adapter-configuration> - </mat-step> + <mat-step *ngIf="isGenericAdapter"> + <ng-template matStepLabel>Settings</ng-template> + <sp-generic-adapter-configuration + [adapterDescription]="adapter" + (updateAdapterDescriptionEmitter)="adapter = $event" + (clickNextEmitter)="clickProtocolSettingsNextButton()" + (removeSelectionEmitter)="removeSelection()"> + </sp-generic-adapter-configuration> + </mat-step> - <mat-step *ngIf="isGenericAdapter"> - <ng-template matStepLabel>Select Format</ng-template> - <sp-format-configuration - [adapterDescription]="adapter" - (clickNextEmitter)="clickFormatSelectionNextButton()" - (goBackEmitter)="goBack()" - (removeSelectionEmitter)="removeSelection()"> - </sp-format-configuration> - </mat-step> + <mat-step *ngIf="isGenericAdapter"> + <ng-template matStepLabel>Select Format</ng-template> + <sp-format-configuration + [adapterDescription]="adapter" + (clickNextEmitter)="clickFormatSelectionNextButton()" + (goBackEmitter)="goBack()" + (removeSelectionEmitter)="removeSelection()"> + </sp-format-configuration> + </mat-step> - <mat-step> - <ng-template matStepLabel>Define Event Schema</ng-template> - <sp-event-schema #eschema fxLayout="column" fxFlex="100" - [(isEditable)]="isEditable" - [adapterDescription]="adapter" - [(eventSchema)]="eventSchema" - [(oldEventSchema)]="oldEventSchema" - (clickNextEmitter)="clickEventSchemaNextButtonButton()" - (goBackEmitter)="goBack()" - (removeSelectionEmitter)="removeSelection()"> - </sp-event-schema> - </mat-step> + <mat-step> + <ng-template matStepLabel>Configure fields</ng-template> + <sp-event-schema #eschema fxLayout="column" fxFlex="100" + [(isEditable)]="isEditable" + [adapterDescription]="adapter" + [(eventSchema)]="eventSchema" + [(oldEventSchema)]="oldEventSchema" + (clickNextEmitter)="clickEventSchemaNextButtonButton()" + (goBackEmitter)="goBack()" + (removeSelectionEmitter)="removeSelection()"> + </sp-event-schema> + </mat-step> - <mat-step> - <ng-template matStepLabel>Start Adapter</ng-template> - <sp-start-adapter-configuration - [adapterDescription]="adapter" - [eventSchema]="eventSchema" - (removeSelectionEmitter)="removeSelection()" - (goBackEmitter)="goBack()" - (adapterStartedEmitter)="adapterWasStarted()"> - </sp-start-adapter-configuration> - </mat-step> + <mat-step> + <ng-template matStepLabel>Start Adapter</ng-template> + <sp-start-adapter-configuration + [adapterDescription]="adapter" + [eventSchema]="eventSchema" + (removeSelectionEmitter)="removeSelection()" + (goBackEmitter)="goBack()" + (adapterStartedEmitter)="adapterWasStarted()"> + </sp-start-adapter-configuration> + </mat-step> - </mat-horizontal-stepper> + </mat-horizontal-stepper> -</div> + </div> +</sp-basic-view>
diff --git a/ui/src/app/connect/components/new-adapter/new-adapter.component.ts b/ui/src/app/connect/components/new-adapter/new-adapter.component.ts index 1b593b5..2a0566e 100644 --- a/ui/src/app/connect/components/new-adapter/new-adapter.component.ts +++ b/ui/src/app/connect/components/new-adapter/new-adapter.component.ts
@@ -16,25 +16,29 @@ * */ -import { AfterViewInit, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; +import { AfterViewInit, ChangeDetectorRef, Component, Input, OnInit, ViewChild } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; import { MatStepper } from '@angular/material/stepper'; import { - AdapterDescriptionUnion, - EventSchema, - GenericAdapterSetDescription, - GenericAdapterStreamDescription, - SpecificAdapterSetDescription, - SpecificAdapterStreamDescription, - TransformationRuleDescriptionUnion + AdapterDescriptionUnion, + AdapterService, + EventSchema, + GenericAdapterSetDescription, + GenericAdapterStreamDescription, + SpecificAdapterSetDescription, + SpecificAdapterStreamDescription, + TransformationRuleDescriptionUnion } from '@streampipes/platform-services'; import { ShepherdService } from '../../../services/tour/shepherd.service'; import { ConnectService } from '../../services/connect.service'; import { ConfigurationInfo } from '../../model/ConfigurationInfo'; import { RestService } from '../../services/rest.service'; -import { EventSchemaComponent } from '../schema-editor/event-schema/event-schema.component'; +import { EventSchemaComponent } from './schema-editor/event-schema/event-schema.component'; import { TransformationRuleService } from '../../services/transformation-rule.service'; import { IconService } from '../../services/icon.service'; +import { ActivatedRoute, Router } from '@angular/router'; +import { SpBreadcrumbService } from '@streampipes/shared-ui'; +import { SpConnectRoutes } from '../../connect.routes'; @Component({ selector: 'sp-new-adapter', @@ -54,15 +58,7 @@ @Input() adapter: AdapterDescriptionUnion; - @Output() - removeSelectionEmitter: EventEmitter<void> = new EventEmitter<void>(); - - @Output() - updateAdapterEmitter: EventEmitter<void> = new EventEmitter<void>(); - - - @ViewChild('stepper', { static: true }) myStepper: MatStepper; - + myStepper: MatStepper; protocolConfigurationValid: boolean; formatConfigurationValid: boolean; @@ -79,10 +75,8 @@ // deactivates all edit functions when user starts a template isEditable = true; - @ViewChild(EventSchemaComponent, { static: true }) private eventSchemaComponent: EventSchemaComponent; - completedStaticProperty: ConfigurationInfo; isPreviewEnabled = false; @@ -98,7 +92,11 @@ private connectService: ConnectService, private _formBuilder: FormBuilder, private iconService: IconService, - private changeDetectorRef: ChangeDetectorRef) { + private changeDetectorRef: ChangeDetectorRef, + private route: ActivatedRoute, + private dataMarketplaceService: AdapterService, + private router: Router, + private breadcrumbService: SpBreadcrumbService) { } handleFileInput(files: any) { @@ -115,36 +113,45 @@ ngOnInit() { - this.parentForm = this._formBuilder.group({}); + this.dataMarketplaceService.getAdapterDescriptions().subscribe(adapters => { + const adapter = adapters.find(a => a.appId === this.route.snapshot.params.appId); + this.adapter = this.connectService.cloneAdapterDescription(adapter); + this.breadcrumbService.updateBreadcrumb(this.breadcrumbService.makeRoute([SpConnectRoutes.BASE, SpConnectRoutes.CREATE], this.adapter.name)); + (this.adapter as any).templateTitle = this.adapter.name; + this.adapter.name = ''; + this.adapter.description = ''; + this.parentForm = this._formBuilder.group({}); - this.isGenericAdapter = this.connectService.isGenericDescription(this.adapter); - this.isDataSetDescription = this.connectService.isDataSetDescription(this.adapter); - this.isDataStreamDescription = this.connectService.isDataStreamDescription(this.adapter); - this.formatConfigurationValid = false; + this.isGenericAdapter = this.connectService.isGenericDescription(this.adapter); + this.isDataSetDescription = this.connectService.isDataSetDescription(this.adapter); + this.isDataStreamDescription = this.connectService.isDataStreamDescription(this.adapter); + this.formatConfigurationValid = false; - // this.startAdapterFormGroup = this._formBuilder.group({ - // startAdapterFormCtrl: ['', Validators.required] - // }); + // this.startAdapterFormGroup = this._formBuilder.group({ + // startAdapterFormCtrl: ['', Validators.required] + // }); - this.protocolConfigurationValid = false; + this.protocolConfigurationValid = false; - this.eventSchema = this.connectService.getEventSchema(this.adapter); + this.eventSchema = this.connectService.getEventSchema(this.adapter); - if (this.eventSchema.eventProperties.length > 0) { + if (this.eventSchema.eventProperties.length > 0) { - // Timeout is needed for stepper to work correctly. Without the stepper is frozen when initializing with - // step 2. Can be removed when a better solution is found. - setTimeout(() => { - this.goForward(); - this.goForward(); - }, 1); + // Timeout is needed for stepper to work correctly. Without the stepper is frozen when initializing with + // step 2. Can be removed when a better solution is found. + setTimeout(() => { + this.goForward(); + this.goForward(); + }, 1); - this.fromTemplate = true; - this.isEditable = false; - this.oldEventSchema = this.eventSchema; - } + this.fromTemplate = true; + this.isEditable = false; + this.oldEventSchema = this.eventSchema; + } + }); + // this.parentForm.statusChanges.subscribe((status) => { // this.genericadapterSettingsFormValid = this.viewInitialized && this.parentForm.valid; @@ -159,7 +166,7 @@ removeSelection() { - this.removeSelectionEmitter.emit(); + this.router.navigate(['connect', 'create']); } clickProtocolSettingsNextButton() { @@ -230,7 +237,14 @@ } public adapterWasStarted() { - this.updateAdapterEmitter.emit(); - this.removeSelectionEmitter.emit(); + this.router.navigate(['connect']); + } + + @ViewChild(EventSchemaComponent) set schemaComponent(eventSchemaComponent: EventSchemaComponent) { + this.eventSchemaComponent = eventSchemaComponent; + } + + @ViewChild('stepper') set stepperComponent(stepperComponent: MatStepper) { + this.myStepper = stepperComponent; } }
diff --git a/ui/src/app/connect/components/schema-editor/loading-message/loading-message.component.html b/ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.html similarity index 67% copy from ui/src/app/connect/components/schema-editor/loading-message/loading-message.component.html copy to ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.html index 639fd6c..ecfdf15 100644 --- a/ui/src/app/connect/components/schema-editor/loading-message/loading-message.component.html +++ b/ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.html
@@ -16,11 +16,11 @@ ~ --> -<div fxLayout="column" > - <div fxLayoutAlign="center"> - <mat-spinner fxLayoutAlign="center" style="margin: 10px 0 5px 0" color="accent">Loading</mat-spinner> +<div fxLayout="column" fxFlex="100"> + <div fxLayout="row" fxLayoutAlign="center center" fxFlex="100"> + <div fxLayoutAlign="start center" class="error-text"> There was an error while guessing the schema of your configured data source:</div> </div> - <div fxLayoutAlign="center"> - <h3>Guessing the event schema...</h3> + <div fxLayout="row" fxLayoutAlign="center center" class="mt-10"> + <sp-exception-message [message]="errorMessage"></sp-exception-message> </div> </div>
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.scss similarity index 91% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.scss index 58ba04b..8eec370 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.scss
@@ -16,3 +16,10 @@ * */ +.error-color { + color: #963e3e; +} + +.error-text { + font-size: 12pt; +}
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.ts b/ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.ts similarity index 86% rename from ui/src/app/connect/components/schema-editor/error-message/error-message.component.ts rename to ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.ts index 4e64c25..b6dc01d 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.ts +++ b/ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.ts
@@ -18,6 +18,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { Notification } from '@streampipes/platform-services'; +import { StreamPipesErrorMessage } from '../../../../../../../projects/streampipes/platform-services/src/lib/model/gen/streampipes-model'; @Component({ selector: 'sp-error-message', @@ -26,7 +27,7 @@ }) export class ErrorMessageComponent implements OnInit { - @Input() errorMessages: Notification[]; + @Input() errorMessage: StreamPipesErrorMessage; showErrorMessage = false;
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.html b/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.html new file mode 100644 index 0000000..cf07a44 --- /dev/null +++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.html
@@ -0,0 +1,96 @@ +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~ + --> + +<div fxLayout="row" fxFlex="100" fxLayoutGap="10px"> + <div fxLayout="row" fxLayoutAlign="start center"> + <div> + <b style="white-space: nowrap"> + {{ label }} + </b> + </div> + <div fxLayoutAlign="start center" *ngIf="originalRuntimeName" class="ml-5"> + <span class="runtime-info">{{originalRuntimeName}}</span> + <span fxLayoutAlign="center center" + *ngIf="originalRuntimeName !== node.data.runtimeName"> + <i class="material-icons">arrow_right</i> + </span> + <span class="runtime-info" + *ngIf="originalRuntimeName !== node.data.runtimeName">{{node.data.runtimeName}} + </span> + </div> + <p style="margin: 0px 10px 10px;" *ngIf="isList">[List]</p> + </div> + + <div fxLayout="row" fxLayoutAlign="end center" fxFlex="100" fxLayoutGap="20px"> + <div class="timestamp-property" *ngIf="timestampProperty" fxLayoutAlign="end center" fxLayout="row"> + <mat-icon *ngIf="timestampProperty" class="timestamp-icon" fxLayout="row" fxLayoutAlign="start center"> + access_time + </mat-icon> + <span style="margin-left: -5px;">marked as timestamp</span> + </div> + <div fxLayoutAlign="end center" class="runtime-type-info-outer"> + <div fxLayout="row" fxLayoutAlign="start center" fxFlex="100" *ngIf="runtimeType" > + <span class="runtime-info runtime-type-info">{{originalRuntimeType}}</span> + <span fxLayoutAlign="center center" *ngIf="originalRuntimeType !== runtimeType"><i class="material-icons">arrow_right</i></span> + <span class="runtime-info runtime-type-info" *ngIf="originalRuntimeType !== runtimeType">{{runtimeType}}</span> + </div> + </div> + <div fxLayoutAlign="end center" class="status-outer"> + <span *ngIf="showFieldStatus" + [ngClass]="'status status-' +fieldStatusInfo[originalRuntimeName].fieldStatus.toLowerCase()" + [matTooltip]="fieldStatusInfo[originalRuntimeName].additionalInfo">{{fieldStatusInfo[originalRuntimeName].fieldStatus}}</span> + </div> + <div *ngIf="isPrimitive" fxLayoutAlign="end center"> + <mat-form-field class="small-select" color="accent"> + <mat-select [(ngModel)]="node.data.propertyScope" panelClass="small-select" + [attr.data-cy]="'property-scope-' + label"> + <mat-option value="MEASUREMENT_PROPERTY">Measurement</mat-option> + <mat-option value="DIMENSION_PROPERTY">Dimension</mat-option> + <mat-option value="HEADER_PROPERTY">Header</mat-option> + </mat-select> + </mat-form-field> + </div> + + <div fxLayoutAlign="end center" + *ngIf="isNested"> + <button [disabled]="!isEditable" color="accent" mat-button (click)=addNestedProperty(node.data)> + <mat-icon matTooltip="Add a Nested Property">queue</mat-icon> + </button> + </div> + <div + fxLayoutAlign="end center" + class="ml-5 mr-5" + *ngIf="isNested || isPrimitive || isList"> + <button [disabled]="!isEditable" color="accent" mat-button + (click)="openEditDialog(node.data)" + [attr.data-cy]="'edit-' + label.toLowerCase()"> + <mat-icon>edit</mat-icon> Edit field + </button> + </div> + <div fxLayoutAlign="end center"> + <mat-checkbox + *ngIf="isNested || isPrimitive || isList" + (click)="selectProperty(node.data.id, undefined)" + [disabled]="!isEditable" + [class.checkbox-selected]="node.data.selected" + [checked]="node.data.selected" + [attr.data-cy]="'delete-property-' + label.toLowerCase()"> + </mat-checkbox> + </div> + </div> +</div>
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.scss b/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.scss new file mode 100644 index 0000000..ec24661 --- /dev/null +++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.scss
@@ -0,0 +1,92 @@ +/* + * 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. + * + */ + + +::ng-deep .mat-checkbox-checked.mat-accent .mat-checkbox-background, .mat-checkbox-indeterminate.mat-accent .mat-checkbox-background { + background-color: var(--color-accent) !important; +} + +::ng-deep .mat-checkbox:not(.mat-checkbox-disabled).mat-accent .mat-checkbox-ripple .mat-ripple-element { + background-color: var(--color-accent) !important; +} + +.checkbox-selected { + opacity: 1 !important; +} + +.timestamp-property { + margin-left: 15px; + border-radius: 10px; + background: var(--color-processor); + padding: 0px 10px; + font-size: 12px; + color: #FFFFFF; +} + +.timestamp-icon { + font-size: 12px; +} + +.status-good { + background: #75c575; + color: white; +} + +.status-bad { + background: #d2a169; + color: white; +} + +.status { + width: 70px; + min-width: 70px; + text-align: center; + padding: 5px; + border-radius: 5px; +} + +.status-outer { + width: 70px; + min-width: 70px; +} + +.runtime-info { + border-radius: 5px; + color: var(--color-default-text); + font-size: 10pt; + text-align: center; +} + +.runtime-type-info { + border-radius: 5px; + color: var(--color-default-text); + font-size: 10pt; + width: 70px; + border: 1px solid var(--color-bg-3); + text-align: center; +} + +.runtime-type-info-outer { + padding: 3px; + border-radius: 5px; + width: 170px; + text-align: center; + +} + +
diff --git a/ui/src/app/connect/components/schema-editor/event-property-row/event-property-row.component.ts b/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.ts similarity index 71% rename from ui/src/app/connect/components/schema-editor/event-property-row/event-property-row.component.ts rename to ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.ts index 4186a36..cd561af 100644 --- a/ui/src/app/connect/components/schema-editor/event-property-row/event-property-row.component.ts +++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.ts
@@ -21,30 +21,38 @@ import { TreeNode } from '@circlon/angular-tree-component'; import { MatDialog } from '@angular/material/dialog'; import { - EventProperty, - EventPropertyList, - EventPropertyNested, - EventPropertyPrimitive, - EventPropertyUnion, - EventSchema + EventProperty, + EventPropertyList, + EventPropertyNested, + EventPropertyPrimitive, + EventPropertyUnion, + EventSchema, + FieldStatusInfo, + GuessTypeInfo + } from '@streampipes/platform-services'; -import { EditEventPropertyComponent } from '../../../dialog/edit-event-property/edit-event-property.component'; +import { EditEventPropertyComponent } from '../../../../dialog/edit-event-property/edit-event-property.component'; +import { DialogService, PanelType } from '@streampipes/shared-ui'; @Component({ selector: 'event-property-row', templateUrl: './event-property-row.component.html', styleUrls: ['./event-property-row.component.scss'] }) -export class EventPropertyRowComponent implements OnInit, OnChanges { +export class EventPropertyRowComponent implements OnInit { @Input() node: TreeNode; @Input() isEditable = true; @Input() eventSchema: EventSchema = new EventSchema(); + @Input() originalEventSchema: EventSchema; @Input() countSelected: number; + @Input() eventPreview: Record<string, GuessTypeInfo>[]; + @Input() fieldStatusInfo: Record<string, FieldStatusInfo>; @Output() isEditableChange = new EventEmitter<boolean>(); @Output() eventSchemaChange = new EventEmitter<EventSchema>(); - @Output() refreshTreeEmitter = new EventEmitter<void>(); + @Output() originalEventSchemaChange = new EventEmitter<EventSchema>(); + @Output() refreshTreeEmitter = new EventEmitter<boolean>(); @Output() countSelectedChange = new EventEmitter<number>(); label: string; @@ -52,8 +60,15 @@ isNested = false; isList = false; timestampProperty = false; + showEventPreview = false; + showFieldStatus = false; - constructor(private dialog: MatDialog) { + runtimeType: string; + originalRuntimeType: string; + originalRuntimeName: string; + + constructor(private dialog: MatDialog, + private dialogService: DialogService) { } @@ -64,12 +79,28 @@ this.isNested = this.isEventPropertyNested(this.node.data); this.timestampProperty = this.isTimestampProperty(this.node.data); + if (this.node.data instanceof EventProperty) { + this.originalRuntimeName = this.findOriginalProperty().runtimeName; + this.showFieldStatus = this.fieldStatusInfo && this.fieldStatusInfo[this.originalRuntimeName] !== undefined; + this.showEventPreview = this.eventPreview && this.eventPreview.length > 0 && this.eventPreview[0][this.originalRuntimeName] !== undefined; + if (this.isPrimitive) { + this.originalRuntimeType = this.parseType(this.findOriginalProperty().runtimeType); + this.runtimeType = this.parseType((this.node.data as EventPropertyPrimitive).runtimeType); + } + } + if (!this.node.data.propertyScope) { this.node.data.propertyScope = 'MEASUREMENT_PROPERTY'; } } - ngOnChanges(changes: SimpleChanges): void { + private findOriginalProperty(): any { + return this.originalEventSchema.eventProperties + .find(ep => ep.elementId === this.node.data.elementId); + } + + private parseType(runtimeType: string) { + return runtimeType.split('#')[1].toUpperCase(); } private isEventPropertyPrimitive(instance: EventProperty): boolean { @@ -109,15 +140,19 @@ } public openEditDialog(data): void { - const dialogRef = this.dialog.open(EditEventPropertyComponent, { + const dialogRef = this.dialogService.open(EditEventPropertyComponent, { + panelType: PanelType.SLIDE_IN_PANEL, + title: 'Edit field ' + data.runtimeName, + width: '50vw', data: { - property: data, - isEditable: this.isEditable + 'property': data, + 'isEditable': this.isEditable } }); - dialogRef.afterClosed().subscribe(result => { + + dialogRef.afterClosed().subscribe(refresh => { this.timestampProperty = this.isTimestampProperty(this.node.data); - this.refreshTreeEmitter.emit(); + this.refreshTreeEmitter.emit(true); }); } @@ -169,7 +204,7 @@ } } this.countSelectedChange.emit(this.countSelected); - this.refreshTreeEmitter.emit(); + this.refreshTreeEmitter.emit(false); } public addNestedProperty(eventProperty: EventPropertyNested): void { @@ -180,6 +215,6 @@ const property: EventPropertyNested = new EventPropertyNested(); property.elementId = uuid; eventProperty.eventProperties.push(property); - this.refreshTreeEmitter.emit(); + this.refreshTreeEmitter.emit(false); } }
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.html b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.html new file mode 100644 index 0000000..d3cad53 --- /dev/null +++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.html
@@ -0,0 +1,41 @@ +<!-- + ~ 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="row" fxLayoutGap="15px"> + <div fxFlex="50" fxLayout="column"> + <sp-basic-inner-panel [showTitle]="true" panelTitle="Original (Parsed)"> + <pre [innerHTML]="originalField | jsonpretty" class="preview-text"></pre> + </sp-basic-inner-panel> + </div> + + <div fxFlex="50" fxLayout="column"> + <sp-basic-inner-panel [showTitle]="true" panelTitle="Result" fxFlex="100"> + <div header fxLayoutAlign="end center" fxFlex="100"> + <button color="accent" + mat-button + data-cy="connect-schema-update-preview-btn" + matTooltip="Update event preview" + (click)="updateEventPreview()"> + <mat-icon>refresh</mat-icon> + <span> Update result preview</span> + </button> + </div> + <pre [innerHTML]="desiredField | jsonpretty" class="preview-text"></pre> + </sp-basic-inner-panel> + </div> +</div>
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.scss b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.scss similarity index 78% copy from ui/src/app/pipeline-details/pipeline-details.component.scss copy to ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.scss index a375af7..eddad5e 100644 --- a/ui/src/app/pipeline-details/pipeline-details.component.scss +++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.scss
@@ -16,7 +16,14 @@ * */ -.md-padding { +.preview-text { + background-color: black; + font: 9pt Inconsolata, monospace; + text-shadow: 0 0 5px #C8C8C8; + color: white; padding: 10px; + max-width: 100%; + max-height: 300px; + overflow-y: scroll; + white-space: pre-wrap; } -
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.ts b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.ts new file mode 100644 index 0000000..d7dc13c --- /dev/null +++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.ts
@@ -0,0 +1,66 @@ +/* + * 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, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { EventSchema, GuessTypeInfo } from '@streampipes/platform-services'; + +@Component({ + selector: 'sp-event-schema-preview', + templateUrl: './event-schema-preview.component.html', + styleUrls: ['./event-schema-preview.component.scss'] +}) +export class EventSchemaPreviewComponent implements OnInit { + + @Input() originalEventSchema: EventSchema; + @Input() desiredEventSchema: EventSchema; + + @Input() originalPreview: Record<string, GuessTypeInfo>; + @Input() desiredPreview: Record<string, GuessTypeInfo>; + + @Output() updatePreviewEmitter = new EventEmitter(); + + originalField: Record<string, any>; + desiredField: Record<string, any>; + + ngOnInit(): void { + this.originalField = this.toSimpleMap(this.originalPreview); + this.desiredField = this.toSimpleMap(this.desiredPreview); + } + + toSimpleMap(event: Record<string, GuessTypeInfo>): Record<string, any> { + let result: Record<string, any> = {}; + + for (const key in event) { + result[key] = event[key].value; + } + + result = Object.keys(result).sort().reduce( + (obj, key) => { + obj[key] = result[key]; + return obj; + }, + {} + ); + + return result; + } + + public updateEventPreview() { + this.updatePreviewEmitter.emit(); + } +}
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.html b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.html new file mode 100644 index 0000000..5990ea8 --- /dev/null +++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.html
@@ -0,0 +1,129 @@ +<!-- + ~ 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" fxLayoutAlign="center" class="mt-20"> + <div fxFlex="90" fxLayout="column"> + <div fxLayout="column" + fxFlex="100" + fxLayoutAlign="start center" + *ngIf="!isLoading && !isError && schemaErrorHints.length === 0" + class="schema-validation schema-validation-ok"> + <div fxFlex="100" + fxLayout="row" + fxLayoutAlign="start center" + class="schema-validation-text-ok"> + <i class="material-icons">check_circle</i> <b>Schema ok</b> + </div> + </div> + + <div fxLayout="column" fxFlex="100" *ngIf="!isLoading && !isError && schemaErrorHints.length > 0"> + <div fxFlex="100" + fxLayout="column" + [ngClass]="schemaErrorHint.level === 'error' ? 'schema-validation schema-validation-error' : 'schema-validation schema-validation-warning'" + fxLayoutAlign="start center" *ngFor="let schemaErrorHint of schemaErrorHints"> + <div fxFlex="100" fxLayout="row" fxLayoutAlign="center start" + [ngClass]="schemaErrorHint.level === 'error' ? 'schema-validation-text-error' : 'schema-validation-text-warning'"> + <i class="material-icons">warning</i> + <b>{{schemaErrorHint.title}}</b> + </div> + <div> + <span>{{schemaErrorHint.content}}</span> + </div> + </div> + </div> + <sp-basic-inner-panel [showTitle]="false" outerMargin="0px 0px 20px 0px"> + <div header *ngIf="!isLoading && !isError" fxFlex="100"> + <sp-schema-editor-header fxFlex="100" + [countSelected]="countSelected" + (addNestedPropertyEmitter)="addNestedProperty()" + (addStaticValuePropertyEmitter)="addStaticValueProperty()" + (addTimestampPropertyEmitter)="addTimestampProperty()" + (guessSchemaEmitter)="guessSchema()" + (updatePreviewEmitter)="updatePreview()" + (removeSelectedPropertiesEmitter)="removeSelectedProperties()"> + </sp-schema-editor-header> + </div> + <div header *ngIf="!isLoading && isError" fxFlex="100"> + <div fxLayout="row" fxLayoutAlign="end center"> + <button color="accent" + mat-button + mat-icon-button + matTooltip="Refresh Schema" + (click)="guessSchema()"> + <mat-icon>refresh</mat-icon> + </button> + </div> + </div> + + <div fxFlex="100"> + + <sp-loading-message *ngIf="isLoading"></sp-loading-message> + + <sp-error-message + [errorMessage]="errorMessage" + *ngIf="isError && !isLoading"> + </sp-error-message> + + <div *ngIf="!isError && !isLoading && eventSchema && oldEventSchema && nodes" + fxLayout="column" + fxLayoutAlign="space-evenly stretched" + class="drag-drop-tree" + data-cy="sp-connect-schema-editor"> + <tree-root #tree + [nodes]="nodes" + [options]="options" + (updateData)="onUpdateData(tree)"> + <ng-template #treeNodeTemplate let-node let-index="index"> + <event-property-row + [node]="node" + [(isEditable)]="isEditable" + [(eventSchema)]="eventSchema" + [(originalEventSchema)]="oldEventSchema" + [eventPreview]="eventPreview" + [fieldStatusInfo]="fieldStatusInfo" + (refreshTreeEmitter)="refreshTree($event)" + [(countSelected)]="countSelected"></event-property-row> + </ng-template> + </tree-root> + </div> + </div> + </sp-basic-inner-panel> + </div> + <div fxFlex="100" *ngIf="desiredPreview && isPreviewEnabled && !isLoading && !isError"> + <sp-event-schema-preview [originalEventSchema]="oldEventSchema" + [desiredEventSchema]="eventSchema" + [originalPreview]="eventPreview[0]" + [desiredPreview]="desiredPreview" + (updatePreviewEmitter)="updatePreview()"></sp-event-schema-preview> + </div> +</div> + + +<div fxLayoutAlign="end" class="mt-10"> + <button class="mat-basic" mat-raised-button (click)="removeSelection()">Cancel</button> + <button class="mat-basic stepper-button" mat-raised-button (click)="goBack()">Back</button> + <button class="stepper-button" + id="event-schema-next-button" + data-cy="sp-event-schema-next-button" + color="accent" mat-raised-button + (click)="clickNext()" + [disabled]="!validEventSchema"> + Next + </button> +</div>
diff --git a/ui/src/app/connect/components/schema-editor/event-schema/event-schema.component.scss b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.scss similarity index 87% rename from ui/src/app/connect/components/schema-editor/event-schema/event-schema.component.scss rename to ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.scss index ff253bb..228a3ae 100644 --- a/ui/src/app/connect/components/schema-editor/event-schema/event-schema.component.scss +++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.scss
@@ -171,3 +171,39 @@ .add-schema button:disabled { color: rgba(0, 0, 0, 0.26); } + +.mt-20 { + margin-top: 20px; +} + +.schema-validation { + margin-bottom: 10px; + border: 2px solid var(--color-bg-3); + padding: 10px; + min-height: 50px; + text-align: center; +} + +.schema-validation-ok { + border: 2px solid #629f62; +} + +.schema-validation-error { + border: 2px solid #963e3e; +} + +.schema-validation-warning { + border: 2px solid #d09836; +} + +.schema-validation-text-ok { + color: #629f62; +} + +.schema-validation-text-error { + color: #963e3e; +} + +.schema-validation-text-warning { + color: #d09836; +}
diff --git a/ui/src/app/connect/components/schema-editor/event-schema/event-schema.component.ts b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.ts similarity index 73% rename from ui/src/app/connect/components/schema-editor/event-schema/event-schema.component.ts rename to ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.ts index 8cf453f..30c340a 100644 --- a/ui/src/app/connect/components/schema-editor/event-schema/event-schema.component.ts +++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.ts
@@ -17,10 +17,10 @@ */ import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild } from '@angular/core'; -import { RestService } from '../../../services/rest.service'; +import { RestService } from '../../../../services/rest.service'; import { ITreeOptions, TreeComponent } from '@circlon/angular-tree-component'; import { UUID } from 'angular2-uuid'; -import { DataTypesService } from '../../../services/data-type.service'; +import { DataTypesService } from '../../../../services/data-type.service'; import { AdapterDescription, EventProperty, @@ -31,7 +31,12 @@ Notification } from '@streampipes/platform-services'; import { MatStepper } from '@angular/material/stepper'; -import { UserErrorMessage } from '../../../../core-model/base/UserErrorMessage'; +import { UserErrorMessage } from '../../../../../core-model/base/UserErrorMessage'; +import { + FieldStatusInfo, GuessTypeInfo, + StreamPipesErrorMessage +} from '../../../../../../../projects/streampipes/platform-services/src/lib/model/gen/streampipes-model'; +import { TransformationRuleService } from '../../../../services/transformation-rule.service'; @Component({ selector: 'sp-event-schema', @@ -40,7 +45,9 @@ }) export class EventSchemaComponent implements OnChanges { - constructor(private restService: RestService, private dataTypesService: DataTypesService) { + constructor(private restService: RestService, + private dataTypesService: DataTypesService, + private transformationRuleService: TransformationRuleService ) { } @Input() adapterDescription: AdapterDescription; @@ -73,11 +80,15 @@ isLoading = false; isError = false; isPreviewEnabled = false; - errorMessages: Notification[]; + errorMessage: StreamPipesErrorMessage; nodes: EventProperty[] = new Array<EventProperty>(); validEventSchema = false; schemaErrorHints: UserErrorMessage[] = []; + eventPreview: Record<string, GuessTypeInfo>[]; + desiredPreview: Record<string, GuessTypeInfo>; + fieldStatusInfo: Record<string, FieldStatusInfo>; + options: ITreeOptions = { childrenField: 'eventProperties', allowDrag: () => { @@ -98,6 +109,8 @@ this.isLoading = true; this.isError = false; this.restService.getGuessSchema(this.adapterDescription).subscribe(guessSchema => { + this.eventPreview = guessSchema.eventPreview; + this.fieldStatusInfo = guessSchema.fieldStatusInfo; this.eventSchema = guessSchema.eventSchema; this.eventSchema.eventProperties.sort((a, b) => { return a.runtimeName < b.runtimeName ? -1 : 1; @@ -115,9 +128,13 @@ this.isEditable = true; this.isEditableChange.emit(true); this.isLoading = false; + + if (guessSchema.eventPreview && guessSchema.eventPreview.length > 0) { + this.updatePreview(); + } }, errorMessage => { - this.errorMessages = errorMessage.error.notifications; + this.errorMessage = errorMessage.error; this.isError = true; this.isLoading = false; this.eventSchema = new EventSchema(); @@ -125,11 +142,13 @@ } - private refreshTree(): void { + private refreshTree(refreshPreview = true): void { this.nodes = new Array<EventProperty>(); this.nodes.push(this.eventSchema as unknown as EventProperty); this.validEventSchema = this.checkIfValid(this.eventSchema); - // this.tree.treeModel.update(); + if (refreshPreview) { + this.updatePreview(); + } } public addNestedProperty(eventProperty?: EventPropertyNested): void { @@ -192,8 +211,20 @@ this.refreshTree(); } - public togglePreview(): void { - this.isPreviewEnabled = !this.isPreviewEnabled; + public updatePreview(): void { + this.isPreviewEnabled = false; + this.transformationRuleService.setOldEventSchema(this.oldEventSchema); + this.transformationRuleService.setNewEventSchema(this.eventSchema); + const ruleDescriptions = this.transformationRuleService.getTransformationRuleDescriptions(); + if (this.eventPreview && this.eventPreview.length > 0) { + this.restService.getAdapterEventPreview({ + rules: ruleDescriptions, + inputData: this.eventPreview[0] + }).subscribe(preview => { + this.desiredPreview = preview; + this.isPreviewEnabled = true; + }); + } } ngOnChanges(changes: SimpleChanges) { @@ -226,7 +257,20 @@ this.schemaErrorHints = []; if (!hasTimestamp) { - this.schemaErrorHints.push(new UserErrorMessage('Missing Timestamp', 'The timestamp must be a UNIX timestamp in milliseconds. Edit the timestamp event property or add a timestamp with the button on the top left.')); + this.schemaErrorHints.push(new UserErrorMessage('Missing Timestamp', 'The timestamp must be a UNIX timestamp in milliseconds. Edit the timestamp field or add an ingestion timestamp.')); + } + + if (this.fieldStatusInfo) { + const badFields = eventSchema.eventProperties + .filter(ep => this.fieldStatusInfo[ep.runtimeName] !== undefined) + .map(ep => this.fieldStatusInfo[ep.runtimeName]) + .find(field => field.fieldStatus !== 'GOOD'); + if (badFields !== undefined) { + this.schemaErrorHints.push(new UserErrorMessage( + 'Bad reading', + 'At least one field could not be properly read. If this is a permanent problem, consider removing it - keeping this field might cause the adapter to fail or to omit sending events.', + 'warning')); + } } return hasTimestamp;
diff --git a/ui/src/app/connect/components/schema-editor/loading-message/loading-message.component.html b/ui/src/app/connect/components/new-adapter/schema-editor/loading-message/loading-message.component.html similarity index 90% rename from ui/src/app/connect/components/schema-editor/loading-message/loading-message.component.html rename to ui/src/app/connect/components/new-adapter/schema-editor/loading-message/loading-message.component.html index 639fd6c..4ef8106 100644 --- a/ui/src/app/connect/components/schema-editor/loading-message/loading-message.component.html +++ b/ui/src/app/connect/components/new-adapter/schema-editor/loading-message/loading-message.component.html
@@ -18,9 +18,9 @@ <div fxLayout="column" > <div fxLayoutAlign="center"> - <mat-spinner fxLayoutAlign="center" style="margin: 10px 0 5px 0" color="accent">Loading</mat-spinner> + <mat-spinner fxLayoutAlign="center" style="margin: 10px 0 5px 0" color="accent" [diameter]="30">Loading</mat-spinner> </div> <div fxLayoutAlign="center"> - <h3>Guessing the event schema...</h3> + <h4>Guessing the event schema...</h4> </div> </div>
diff --git a/ui/src/app/connect/components/schema-editor/loading-message/loading-message.component.scss b/ui/src/app/connect/components/new-adapter/schema-editor/loading-message/loading-message.component.scss similarity index 100% rename from ui/src/app/connect/components/schema-editor/loading-message/loading-message.component.scss rename to ui/src/app/connect/components/new-adapter/schema-editor/loading-message/loading-message.component.scss
diff --git a/ui/src/app/connect/components/schema-editor/loading-message/loading-message.component.ts b/ui/src/app/connect/components/new-adapter/schema-editor/loading-message/loading-message.component.ts similarity index 100% rename from ui/src/app/connect/components/schema-editor/loading-message/loading-message.component.ts rename to ui/src/app/connect/components/new-adapter/schema-editor/loading-message/loading-message.component.ts
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/schema-editor-header/schema-editor-header.component.html b/ui/src/app/connect/components/new-adapter/schema-editor/schema-editor-header/schema-editor-header.component.html new file mode 100644 index 0000000..8418201 --- /dev/null +++ b/ui/src/app/connect/components/new-adapter/schema-editor/schema-editor-header/schema-editor-header.component.html
@@ -0,0 +1,66 @@ +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~ + --> + +<div fxLayout="row" fxFlex="100"> + <div fxFlex fxLayoutAlign="start center" fxLayout="row"> + <button color="accent" + mat-button + data-cy="connect-add-nested-property" + matTooltip="Add a Nested Property" + (click)=addNestedProperty()> + <mat-icon>queue</mat-icon> + <span> Add nested</span> + </button> + <button color="accent" + mat-button + data-cy="connect-add-static-property" + matTooltip="Add a static value to event" + (click)="addStaticValueProperty()"> + <mat-icon>add</mat-icon> + <span> Add static value</span> + </button> + <button color="accent" + mat-button + data-cy="connect-schema-add-timestamp-btn" + matTooltip="Add timestamp to event schema" + (click)="addTimestampProperty()"> + <mat-icon>access_time</mat-icon> + <span> Add timestamp</span> + </button> + </div> + <div fxLayout="row" fxLayoutAlign="end center"> + <button color="accent" + mat-button + mat-icon-button + matTooltip="Refresh Schema" + (click)="guessSchema()"> + <mat-icon>refresh</mat-icon> + </button> + + <button style="padding-right:0" + color="accent" + mat-button + mat-icon-button + matTooltip="Remove selected Properties" + [disabled]="countSelected == 0" + (click)="removeSelectedProperties()" + data-cy="connect-schema-delete-properties-btn"> + <mat-icon>delete</mat-icon> + </button> + </div> +</div>
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/connect/components/new-adapter/schema-editor/schema-editor-header/schema-editor-header.component.scss similarity index 99% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/connect/components/new-adapter/schema-editor/schema-editor-header/schema-editor-header.component.scss index 58ba04b..13cbc4a 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/connect/components/new-adapter/schema-editor/schema-editor-header/schema-editor-header.component.scss
@@ -15,4 +15,3 @@ * limitations under the License. * */ -
diff --git a/ui/src/app/connect/components/schema-editor/schema-editor-header/schema-editor-header.component.ts b/ui/src/app/connect/components/new-adapter/schema-editor/schema-editor-header/schema-editor-header.component.ts similarity index 86% rename from ui/src/app/connect/components/schema-editor/schema-editor-header/schema-editor-header.component.ts rename to ui/src/app/connect/components/new-adapter/schema-editor/schema-editor-header/schema-editor-header.component.ts index 1b757ba..7bcd8cc 100644 --- a/ui/src/app/connect/components/schema-editor/schema-editor-header/schema-editor-header.component.ts +++ b/ui/src/app/connect/components/new-adapter/schema-editor/schema-editor-header/schema-editor-header.component.ts
@@ -17,7 +17,7 @@ */ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { UserErrorMessage } from '../../../../core-model/base/UserErrorMessage'; +import { UserErrorMessage } from '../../../../../core-model/base/UserErrorMessage'; @Component({ selector: 'sp-schema-editor-header', @@ -28,14 +28,12 @@ @Input() countSelected: number; - @Input() schemaErrorHints: UserErrorMessage[]; - @Input() displayMessages: boolean; @Output() addNestedPropertyEmitter = new EventEmitter(); @Output() addStaticValuePropertyEmitter = new EventEmitter(); @Output() addTimestampPropertyEmitter = new EventEmitter(); @Output() guessSchemaEmitter = new EventEmitter(); - @Output() togglePreviewEmitter = new EventEmitter(); + @Output() updatePreviewEmitter = new EventEmitter(); @Output() removeSelectedPropertiesEmitter = new EventEmitter(); constructor() { } @@ -59,10 +57,6 @@ this.guessSchemaEmitter.emit(); } - public togglePreview() { - this.togglePreviewEmitter.emit(); - } - public removeSelectedProperties() { this.removeSelectedPropertiesEmitter.emit(); }
diff --git a/ui/src/app/connect/components/new-adapter/specific-adapter-configuration/specific-adapter-configuration.component.html b/ui/src/app/connect/components/new-adapter/specific-adapter-configuration/specific-adapter-configuration.component.html new file mode 100644 index 0000000..5754e1c --- /dev/null +++ b/ui/src/app/connect/components/new-adapter/specific-adapter-configuration/specific-adapter-configuration.component.html
@@ -0,0 +1,58 @@ +<!-- + ~ 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"> + <div fxFlex="100" fxLayout="column"> + <sp-basic-inner-panel panelTitle="Basic Settings" outerMargin="20px 0px"> + <div header fxFlex="100" fxLayout="row" fxLayoutAlign="end center" class="pr-5"> + <div fxFlex="100" fxLayout="row" fxLayoutAlign="end center" *ngIf="availableTemplates && availableTemplates.length > 0"> + <mat-form-field class="form-field" floatLabel="never" color="accent"> + <mat-label>Use template</mat-label> + <mat-select (selectionChange)="loadTemplate($event)" + [(value)]="selectedTemplate"> + <mat-option>--</mat-option> + <mat-option [value]="template" *ngFor="let template of availableTemplates"> + {{template.templateName}} + </mat-option> + </mat-select> + </mat-form-field> + </div> + </div> + <sp-configuration-group + [configurationGroup]="specificAdapterForm" + [adapterId]="adapterDescription.appId" + [configuration]="adapterDescription.config"> + </sp-configuration-group> + </sp-basic-inner-panel> + </div> + + <div fxLayoutAlign="end"> + <button class="mat-basic" + mat-raised-button + style="margin-right: 10px;" + (click)="removeSelection()">Cancel</button> + <button mat-button mat-raised-button + class="mat-basic" + (click)="openTemplateDialog()">Store config as template</button> + <div id="specific-settings-next-button"> + <button class="stepper-button" [disabled]="!specificAdapterSettingsFormValid" + (click)="clickNext()" color="accent" mat-raised-button>Next + </button> + </div> + </div> +</div>
diff --git a/ui/src/app/connect/components/specific-adapter-configuration/specific-adapter-configuration.component.scss b/ui/src/app/connect/components/new-adapter/specific-adapter-configuration/specific-adapter-configuration.component.scss similarity index 100% rename from ui/src/app/connect/components/specific-adapter-configuration/specific-adapter-configuration.component.scss rename to ui/src/app/connect/components/new-adapter/specific-adapter-configuration/specific-adapter-configuration.component.scss
diff --git a/ui/src/app/connect/components/new-adapter/specific-adapter-configuration/specific-adapter-configuration.component.ts b/ui/src/app/connect/components/new-adapter/specific-adapter-configuration/specific-adapter-configuration.component.ts new file mode 100644 index 0000000..2ef6de8 --- /dev/null +++ b/ui/src/app/connect/components/new-adapter/specific-adapter-configuration/specific-adapter-configuration.component.ts
@@ -0,0 +1,74 @@ +/* + * 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 { AdapterDescription, PipelineElementTemplateService } from '@streampipes/platform-services'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { DialogService } from '@streampipes/shared-ui'; +import { AdapterTemplateService } from '../../../services/adapter-template.service'; +import { AdapterConfigurationDirective } from '../adapter-configuration.directive'; + +@Component({ + selector: 'sp-specific-adapter-configuration', + templateUrl: './specific-adapter-configuration.component.html', + styleUrls: ['./specific-adapter-configuration.component.scss'] +}) +export class SpecificAdapterConfigurationComponent extends AdapterConfigurationDirective implements OnInit { + + specificAdapterSettingsFormValid: boolean; + + specificAdapterForm: FormGroup; + + + constructor(_formBuilder: FormBuilder, + dialogService: DialogService, + pipelineElementTemplateService: PipelineElementTemplateService, + adapterTemplateService: AdapterTemplateService) { + super(_formBuilder, dialogService, pipelineElementTemplateService, adapterTemplateService); + } + + ngOnInit(): void { + super.onInit(); + this.cachedAdapterDescription = {...this.adapterDescription}; + // initialize form for validation + this.specificAdapterForm = this._formBuilder.group({}); + this.specificAdapterForm.statusChanges.subscribe((status) => { + this.specificAdapterSettingsFormValid = this.specificAdapterForm.valid; + }); + + // Go directly to event schema configuration when adapter has no configuration properties + if (this.adapterDescription.config.length === 0) { + this.specificAdapterSettingsFormValid = true; + } + } + + openTemplateDialog(): void { + const dialogRef = this.adapterTemplateService.getDialog(this.adapterDescription.config, this.adapterDescription.appId); + + dialogRef.afterClosed().subscribe(refresh => { + this.loadPipelineElementTemplates(); + }); + } + + afterTemplateReceived(adapterDescription: any) { + this.adapterDescription = AdapterDescription.fromDataUnion(adapterDescription); + this.updateAdapterDescriptionEmitter.emit(this.adapterDescription); + } + +} +
diff --git a/ui/src/app/connect/components/new-adapter/start-adapter-configuration/adapter-options-panel/adapter-options-panel.component.html b/ui/src/app/connect/components/new-adapter/start-adapter-configuration/adapter-options-panel/adapter-options-panel.component.html new file mode 100644 index 0000000..4a769b4 --- /dev/null +++ b/ui/src/app/connect/components/new-adapter/start-adapter-configuration/adapter-options-panel/adapter-options-panel.component.html
@@ -0,0 +1,41 @@ +<!-- + ~ 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" class="options-panel"> + <div fxLayout="row" fxFlex="100" fxLayoutAlign="start start"> + <div class="mr-15" fxLayoutAlign="start start"> + <mat-icon class="icon">{{optionIcon}}</mat-icon> + </div> + <div fxFlex fxLayout="column"> + <div fxFlex="100" class="title" fxLayout="row"> + <div fxLayoutAlign="start start" class="mr-15"> + <mat-checkbox (change)="optionSelectedEmitter.emit($event.checked)" + [attr.data-cy]="dataCy" class="large-checkbox"> + </mat-checkbox> + </div> + <div fxFlex fxLayout="column"> + <div>{{optionTitle}}</div> + <mat-hint class="description">{{optionDescription}}</mat-hint> + </div> + </div> + + <ng-content></ng-content> + </div> + </div> + +</div>
diff --git a/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.scss b/ui/src/app/connect/components/new-adapter/start-adapter-configuration/adapter-options-panel/adapter-options-panel.component.scss similarity index 62% copy from ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.scss copy to ui/src/app/connect/components/new-adapter/start-adapter-configuration/adapter-options-panel/adapter-options-panel.component.scss index 2c1a70e..60e5397 100644 --- a/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.scss +++ b/ui/src/app/connect/components/new-adapter/start-adapter-configuration/adapter-options-panel/adapter-options-panel.component.scss
@@ -16,19 +16,30 @@ * */ -@import '../../../../scss/sp/sp-dialog.scss'; +.options-panel { + border-left: 4px solid var(--color-accent); + border-bottom: 1px solid var(--color-bg-2); + border-top: 1px solid var(--color-bg-2); + border-right: 1px solid var(--color-bg-2); + padding: 8px; + background: var(--color-bg-1); + margin-top: 6px; + margin-bottom: 6px; +} -.divider { - margin-top: 10px; +.title { + color: var(--color-default-text); + font-weight: 600; + font-size: 13pt; margin-bottom: 10px; } -.static-property-panel { - padding-left: 10px; - margin-bottom: 10px; - margin-top: 10px; +.description { + font-size: 10pt; } -.static-property-panel-border { - border-left:5px solid gray; +.icon { + margin-right: 10px; + color: var(--color-accent); + font-size: 22pt; }
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.ts b/ui/src/app/connect/components/new-adapter/start-adapter-configuration/adapter-options-panel/adapter-options-panel.component.ts similarity index 61% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.ts copy to ui/src/app/connect/components/new-adapter/start-adapter-configuration/adapter-options-panel/adapter-options-panel.component.ts index 4e64c25..399ff42 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.ts +++ b/ui/src/app/connect/components/new-adapter/start-adapter-configuration/adapter-options-panel/adapter-options-panel.component.ts
@@ -16,23 +16,30 @@ * */ -import { Component, Input, OnInit } from '@angular/core'; -import { Notification } from '@streampipes/platform-services'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; @Component({ - selector: 'sp-error-message', - templateUrl: './error-message.component.html', - styleUrls: ['./error-message.component.scss'] + selector: 'sp-adapter-options-panel', + templateUrl: './adapter-options-panel.component.html', + styleUrls: ['./adapter-options-panel.component.scss'] }) -export class ErrorMessageComponent implements OnInit { +export class SpAdapterOptionsPanelComponent { - @Input() errorMessages: Notification[]; + @Input() + optionTitle: string; - showErrorMessage = false; + @Input() + optionDescription: string; - constructor() { } + @Input() + optionIcon: string; - ngOnInit(): void { - } + @Input() + dataCy: string; + + @Output() + optionSelectedEmitter: EventEmitter<boolean> = new EventEmitter<boolean>(); } + +
diff --git a/ui/src/app/connect/components/new-adapter/start-adapter-configuration/start-adapter-configuration.component.html b/ui/src/app/connect/components/new-adapter/start-adapter-configuration/start-adapter-configuration.component.html new file mode 100644 index 0000000..46da68a --- /dev/null +++ b/ui/src/app/connect/components/new-adapter/start-adapter-configuration/start-adapter-configuration.component.html
@@ -0,0 +1,104 @@ +<!-- + ~ 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 [formGroup]="startAdapterForm" fxLayout="column" fxFlex="100"> + <sp-basic-inner-panel panelTitle="Adapter settings" outerMargin="20px 0px 10px 0px"> + <div fxFlex="100"> + <div fxLayoutAlign="center" fxLayout="column" fxFlex="100"> + <mat-form-field color="accent"> + <input formControlName="adapterName" + matInput id="input-AdapterName" placeholder="Adapter Name" + data-cy="sp-adapter-name" required> + </mat-form-field> + <mat-form-field color="accent"> + <input matInput id="input-AdapterDescription" [ngModelOptions]="{standalone: true}" + placeholder="Adapter Description" [(ngModel)]="adapterDescription.description"> + </mat-form-field> + </div> + </div> + </sp-basic-inner-panel> + + <div fxFlex="100" fxLayout="column"> + <sp-adapter-options-panel optionTitle="Remove Duplicates" + optionDescription="Avoid duplicated events within a certain time interval" + optionIcon="cleaning_services" + dataCy="connect-remove-duplicates-box" + (optionSelectedEmitter)="removeDuplicates = $event"> + <mat-form-field *ngIf="removeDuplicates" color="accent"> + <input matInput id="input-removeDuplicatesTime" + [ngModelOptions]="{standalone: true}" placeholder="Remove Duplicates Time Window" + [(ngModel)]="removeDuplicatesTime" + data-cy="connect-remove-duplicates-input"> + </mat-form-field> + </sp-adapter-options-panel> + + + <sp-adapter-options-panel optionTitle="Reduce event rate" + optionDescription="Send maximum one event in the specified time window" + optionIcon="speed" + dataCy="connect-reduce-event-rate-box" + (optionSelectedEmitter)="eventRateReduction = $event"> + <mat-form-field *ngIf="eventRateReduction" color="accent"> + <input type="number" matInput id="input-evenRateTime" + [ngModelOptions]="{standalone: true}" [(ngModel)]="eventRateTime" + placeholder="Time Window (Milliseconds)" matTooltipPosition="above" + data-cy="connect-reduce-event-input"> + </mat-form-field> + <mat-form-field *ngIf="eventRateReduction" color="accent"> + <mat-label>Event Aggregation</mat-label> + <mat-select [(ngModel)]="eventRateMode" [ngModelOptions]="{standalone: true}"> + <mat-option class="md-elevation-z1" style="background: white;" + matTooltip="Last Event in Time Window" value="none"> + None + </mat-option> + </mat-select> + </mat-form-field> + </sp-adapter-options-panel> + + <!-- Start pipeline template to store raw events in data lake --> + <sp-adapter-options-panel optionTitle="Persist events" + optionDescription="Store all events of this source in the internal data store" + optionIcon="save" + dataCy="sp-store-in-datalake" + (optionSelectedEmitter)="handlePersistOption($event)"> + <mat-form-field *ngIf="saveInDataLake" color="accent"> + <mat-label>Select Time Field</mat-label> + <mat-select [(ngModel)]="dataLakeTimestampField" + [ngModelOptions]="{standalone: true}" + data-cy="sp-store-in-datalake-timestamp"> + <mat-option class="md-elevation-z1" style="background: white;" + *ngFor="let timestampField of eventSchema.eventProperties | timestampFilter" + [value]="timestampField.runtimeName"> + {{timestampField.runtimeName}} + </mat-option> + </mat-select> + </mat-form-field> + </sp-adapter-options-panel> + </div> + + <div fxLayoutAlign="end" style="margin-top: 10px;"> + <button class="mat-basic" mat-raised-button (click)="removeSelection()">Cancel</button> + <button style="margin-left:10px;" class="mat-basic stepper-button" mat-raised-button (click)="goBack()">Back + </button> + <button [disabled]="!(startAdapterSettingsFormValid)" mat-raised-button id="button-startAdapter" + color="accent" (click)="startAdapter()" mat-button style="margin-left:10px;"> + Start Adapter + </button> + </div> +</div> +
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/connect/components/new-adapter/start-adapter-configuration/start-adapter-configuration.component.scss similarity index 99% rename from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss rename to ui/src/app/connect/components/new-adapter/start-adapter-configuration/start-adapter-configuration.component.scss index 58ba04b..c2ade4c 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/connect/components/new-adapter/start-adapter-configuration/start-adapter-configuration.component.scss
@@ -16,3 +16,4 @@ * */ +
diff --git a/ui/src/app/connect/components/start-adapter-configuration/start-adapter-configuration.component.ts b/ui/src/app/connect/components/new-adapter/start-adapter-configuration/start-adapter-configuration.component.ts similarity index 88% rename from ui/src/app/connect/components/start-adapter-configuration/start-adapter-configuration.component.ts rename to ui/src/app/connect/components/new-adapter/start-adapter-configuration/start-adapter-configuration.component.ts index 5c59ac0..a498ca4 100644 --- a/ui/src/app/connect/components/start-adapter-configuration/start-adapter-configuration.component.ts +++ b/ui/src/app/connect/components/new-adapter/start-adapter-configuration/start-adapter-configuration.component.ts
@@ -22,18 +22,14 @@ EventProperty, EventRateTransformationRuleDescription, EventSchema, - GenericAdapterSetDescription, RemoveDuplicatesTransformationRuleDescription, - SpecificAdapterSetDescription } from '@streampipes/platform-services'; import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { MatStepper } from '@angular/material/stepper'; -import { AdapterStartedDialog } from '../../dialog/adapter-started/adapter-started-dialog.component'; +import { AdapterStartedDialog } from '../../../dialog/adapter-started/adapter-started-dialog.component'; import { PanelType, DialogService } from '@streampipes/shared-ui'; -import { ShepherdService } from '../../../services/tour/shepherd.service'; -import { ConnectService } from '../../services/connect.service'; -import { TimestampPipe } from '../../filter/timestamp.pipe'; -import { MatCheckboxChange } from '@angular/material/checkbox'; +import { ShepherdService } from '../../../../services/tour/shepherd.service'; +import { TimestampPipe } from '../../../filter/timestamp.pipe'; @Component({ selector: 'sp-start-adapter-configuration', @@ -90,7 +86,6 @@ constructor( private dialogService: DialogService, private shepherdService: ShepherdService, - private connectService: ConnectService, private _formBuilder: FormBuilder, private timestampPipe: TimestampPipe) { } @@ -100,13 +95,13 @@ this.startAdapterForm = this._formBuilder.group({}); this.startAdapterForm.addControl('adapterName', new FormControl(this.adapterDescription.name, Validators.required)); this.startAdapterForm.valueChanges.subscribe(v => this.adapterDescription.name = v.adapterName); - this.startAdapterForm.statusChanges.subscribe((status) => { + this.startAdapterForm.statusChanges.subscribe(() => { this.startAdapterSettingsFormValid = this.startAdapterForm.valid; }); } - findDefaultTimestamp(event: MatCheckboxChange) { - if (event.checked) { + findDefaultTimestamp(selected: boolean) { + if (selected) { const timestampFields = this.timestampPipe.transform(this.eventSchema.eventProperties); if (timestampFields.length > 0) { this.dataLakeTimestampField = timestampFields[0].runtimeName; @@ -144,7 +139,7 @@ this.shepherdService.trigger('button-startAdapter'); - dialogRef.afterClosed().subscribe(result => { + dialogRef.afterClosed().subscribe(() => { this.adapterStartedEmitter.emit(); }); } @@ -161,4 +156,8 @@ this.goBackEmitter.emit(); } + handlePersistOption(selected: boolean) { + this.saveInDataLake = selected; + this.findDefaultTimestamp(selected); + } }
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.html b/ui/src/app/connect/components/schema-editor/error-message/error-message.component.html deleted file mode 100644 index 3c7e8b0..0000000 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.html +++ /dev/null
@@ -1,39 +0,0 @@ -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one or more - ~ contributor license agreements. See the NOTICE file distributed with - ~ this work for additional information regarding copyright ownership. - ~ The ASF licenses this file to You under the Apache License, Version 2.0 - ~ (the "License"); you may not use this file except in compliance with - ~ the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - ~ - --> - -<div fxLayout="column" > - <div fxLayout="row" fxLayoutAlign="center center"> - <mat-icon style="margin-top: 10px" class="md-accent">warning</mat-icon> - <span style="width: 10px;"></span> - <h3>Sorry, there was an error while guessing the schema of your configured data source...</h3> - </div> - <div fxLayout="row" fxLayoutAlign="center center"> - <button mat-button class="md-accent"> - <div *ngIf="!showErrorMessage" (click)="showErrorMessage = true">Show Details</div> - <div *ngIf="showErrorMessage" (click)="showErrorMessage = false">Hide Details</div> - </button> - </div> - <div fxLayoutAlign="center center" *ngIf="showErrorMessage"> - <div class="error-message"> - <div *ngFor="let error of errorMessages" style="margin-bottom: 5px; margin-top: 5px"> - <div>{{error.title}}</div> - <div>{{error.description}}</div> - </div> - </div> - </div> -</div>
diff --git a/ui/src/app/connect/components/schema-editor/event-property-row/event-property-row.component.html b/ui/src/app/connect/components/schema-editor/event-property-row/event-property-row.component.html deleted file mode 100644 index df17659..0000000 --- a/ui/src/app/connect/components/schema-editor/event-property-row/event-property-row.component.html +++ /dev/null
@@ -1,64 +0,0 @@ -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one or more - ~ contributor license agreements. See the NOTICE file distributed with - ~ this work for additional information regarding copyright ownership. - ~ The ASF licenses this file to You under the Apache License, Version 2.0 - ~ (the "License"); you may not use this file except in compliance with - ~ the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - ~ - --> - -<div fxLayout="row"> - <div fxFlex="1 1 auto" fxLayout="row"> - <b> - {{ label }} - </b> - <mat-icon *ngIf="timestampProperty" - style="font-size: 15px; padding: 4px;"> - access_time - </mat-icon> - <p style="margin: 0px 10px 10px;" *ngIf="isList">[List]</p> - </div> - - <div fxFlex="15" *ngIf="isPrimitive"> - <mat-select [(ngModel)]="node.data.propertyScope" - [attr.data-cy]="'property-scope-' + label"> - <mat-option value="MEASUREMENT_PROPERTY">Measurement</mat-option> - <mat-option value="DIMENSION_PROPERTY">Dimension</mat-option> - <mat-option value="HEADER_PROPERTY">Header</mat-option> - </mat-select> - </div> - - <div fxFlex="0 1 auto" fxLayoutAlign="center center" - *ngIf="isNested"> - <button [disabled]="!isEditable" color="accent" mat-button (click)=addNestedProperty(node.data)> - <mat-icon matTooltip="Add a Nested Property">queue</mat-icon> - </button> - </div> - <div fxFlex="0 1 auto" fxLayoutAlign="center center" - *ngIf="isNested || isPrimitive || isList"> - <button [disabled]="!isEditable" color="accent" mat-button - (click)="openEditDialog(node.data)" - [attr.data-cy]="'edit-' + label.toLowerCase()"> - <mat-icon>edit</mat-icon> - </button> - </div> - <div fxFlex="0 1 auto" fxLayoutAlign="center center"> - <mat-checkbox - *ngIf="isNested || isPrimitive || isList" - (click)="selectProperty(node.data.id, undefined)" - [disabled]="!isEditable" - [class.checkbox-selected]="node.data.selected" - [checked]="node.data.selected" - [attr.data-cy]="'delete-property-' + label.toLowerCase()"> - </mat-checkbox> - </div> -</div>
diff --git a/ui/src/app/connect/components/schema-editor/event-property-row/event-property-row.component.scss b/ui/src/app/connect/components/schema-editor/event-property-row/event-property-row.component.scss deleted file mode 100644 index a3becc8..0000000 --- a/ui/src/app/connect/components/schema-editor/event-property-row/event-property-row.component.scss +++ /dev/null
@@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - - -::ng-deep .mat-checkbox-checked.mat-accent .mat-checkbox-background, .mat-checkbox-indeterminate.mat-accent .mat-checkbox-background { - background-color: var(--color-accent) !important; -} - -::ng-deep .mat-checkbox:not(.mat-checkbox-disabled).mat-accent .mat-checkbox-ripple .mat-ripple-element { - background-color: var(--color-accent) !important; -} - -.checkbox-selected { - opacity: 1 !important; -}
diff --git a/ui/src/app/connect/components/schema-editor/event-schema-preview/event-schema-preview.component.scss b/ui/src/app/connect/components/schema-editor/event-schema-preview/event-schema-preview.component.scss deleted file mode 100644 index 58ba04b..0000000 --- a/ui/src/app/connect/components/schema-editor/event-schema-preview/event-schema-preview.component.scss +++ /dev/null
@@ -1,18 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -
diff --git a/ui/src/app/connect/components/schema-editor/event-schema/event-schema.component.html b/ui/src/app/connect/components/schema-editor/event-schema/event-schema.component.html deleted file mode 100644 index 54c5fee..0000000 --- a/ui/src/app/connect/components/schema-editor/event-schema/event-schema.component.html +++ /dev/null
@@ -1,84 +0,0 @@ -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one or more - ~ contributor license agreements. See the NOTICE file distributed with - ~ this work for additional information regarding copyright ownership. - ~ The ASF licenses this file to You under the Apache License, Version 2.0 - ~ (the "License"); you may not use this file except in compliance with - ~ the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - ~ - --> - - -<div fxLayout="row" fxLayoutAlign="center"> - <div fxFlex="0 1 80%"> - - <div class="assemblyOptions sp-blue-bg" *ngIf="!isLoading && !isError"> - <sp-schema-editor-header - [countSelected]="countSelected" - [schemaErrorHints]="schemaErrorHints" - [displayMessages]="validEventSchema" - (addNestedPropertyEmitter)="addNestedProperty()" - (addStaticValuePropertyEmitter)="addStaticValueProperty()" - (addTimestampPropertyEmitter)="addTimestampProperty()" - (guessSchemaEmitter)="guessSchema()" - (togglePreviewEmitter)="togglePreview()" - (removeSelectedPropertiesEmitter)="removeSelectedProperties()"> - </sp-schema-editor-header> - </div> - - <div class="sp-blue-border padding"> - - <sp-loading-message *ngIf="isLoading"></sp-loading-message> - - <sp-error-message - [errorMessages]="errorMessages" - *ngIf="isError"> - </sp-error-message> - - <div *ngIf="!isError && !isLoading" - fxLayout="column" - fxLayoutAlign="space-evenly stretched" - class="drag-drop-tree" - data-cy="sp-connect-schema-editor"> - <tree-root #tree - [nodes]="nodes" - [options]="options" - (updateData)="onUpdateData(tree)"> - <ng-template #treeNodeTemplate let-node let-index="index"> - <event-property-row - [node]="node" - [(isEditable)]="isEditable" - [(eventSchema)]="eventSchema" - (refreshTreeEmitter)="refreshTree()" - [(countSelected)]="countSelected"></event-property-row> - </ng-template> - </tree-root> - </div> - </div> - </div> - <div fxFlex="0 1 50%" *ngIf="isPreviewEnabled"> - <sp-event-schema-preview [eventSchema]="eventSchema"></sp-event-schema-preview> - </div> -</div> - - -<div fxLayoutAlign="end"> - <button class="mat-basic" mat-raised-button (click)="removeSelection()">Cancel</button> - <button class="mat-basic stepper-button" mat-raised-button (click)="goBack()">Back</button> - <button class="stepper-button" - id="event-schema-next-button" - data-cy="sp-event-schema-next-button" - color="accent" mat-raised-button - (click)="clickNext()" - [disabled]="!validEventSchema"> - Next - </button> -</div>
diff --git a/ui/src/app/connect/components/schema-editor/schema-editor-header/schema-editor-header.component.html b/ui/src/app/connect/components/schema-editor/schema-editor-header/schema-editor-header.component.html deleted file mode 100644 index 2c30634..0000000 --- a/ui/src/app/connect/components/schema-editor/schema-editor-header/schema-editor-header.component.html +++ /dev/null
@@ -1,67 +0,0 @@ -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one or more - ~ contributor license agreements. See the NOTICE file distributed with - ~ this work for additional information regarding copyright ownership. - ~ The ASF licenses this file to You under the Apache License, Version 2.0 - ~ (the "License"); you may not use this file except in compliance with - ~ the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - ~ - --> - -<div fxLayout="row"> - <div fxLayoutAlign="space-between center" class="add-schema" fxFlex="0 1 100%"> - <div> - <button color="primary" - mat-button - data-cy="connect-add-nested-property" - (click)=addNestedProperty()> - <mat-icon matTooltip="Add a Nested Property">queue</mat-icon> - </button> - <button color="primary" - mat-button - data-cy="connect-add-static-property" - (click)="addStaticValueProperty()"> - <mat-icon matTooltip="Add a static value to event">add</mat-icon> - </button> - <button color="primary" - mat-button - data-cy="connect-add-timestamp-property" - (click)=addTimestampProperty() - data-cy="connect-schema-add-timestamp-btn"> - <mat-icon matTooltip="Add timestamp to event schema">access_time</mat-icon> - </button> - <button color="primary" - mat-button - (click)=guessSchema()> - <mat-icon matTooltip="Refresh Schema">refresh</mat-icon> - </button> - <!-- <button color="primary" mat-button (click)=togglePreview()>--> - <!-- <mat-icon matTooltip="Show preview of schema">play_arrow</mat-icon>--> - <!-- </button>--> - </div> - <div fxLayout="row" style="align-items: center;"> - <sp-error-hint - [errorMessages]="schemaErrorHints" - [displayMessages]="!displayMessages"> - </sp-error-hint> - - - <button style="padding-right:0" - color="primary" - mat-button - [disabled]="countSelected == 0" - (click)="removeSelectedProperties()" - data-cy="connect-schema-delete-properties-btn"> - <mat-icon matTooltip="Remove selected Properties">delete</mat-icon> - </button> - </div> - </div> -</div>
diff --git a/ui/src/app/connect/components/schema-editor/schema-editor-header/schema-editor-header.component.scss b/ui/src/app/connect/components/schema-editor/schema-editor-header/schema-editor-header.component.scss deleted file mode 100644 index 52bd5d6..0000000 --- a/ui/src/app/connect/components/schema-editor/schema-editor-header/schema-editor-header.component.scss +++ /dev/null
@@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -.add-schema button { - color: white; -} \ No newline at end of file
diff --git a/ui/src/app/connect/components/specific-adapter-configuration/specific-adapter-configuration.component.html b/ui/src/app/connect/components/specific-adapter-configuration/specific-adapter-configuration.component.html deleted file mode 100644 index e5923e3..0000000 --- a/ui/src/app/connect/components/specific-adapter-configuration/specific-adapter-configuration.component.html +++ /dev/null
@@ -1,41 +0,0 @@ -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one or more - ~ contributor license agreements. See the NOTICE file distributed with - ~ this work for additional information regarding copyright ownership. - ~ The ASF licenses this file to You under the Apache License, Version 2.0 - ~ (the "License"); you may not use this file except in compliance with - ~ the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - ~ - --> - -<div style="margin-bottom: 2%;"> - <div> - <div class="assemblyOptions sp-blue-bg"> - <h4>Basic settings</h4> - </div> - - <sp-configuration-group - [configurationGroup]="specificAdapterForm" - [adapterId]="adapterDescription.appId" - [configuration]="adapterDescription.config"> - </sp-configuration-group> - - </div> -</div> - -<div fxLayoutAlign="end"> - <button class="mat-basic" mat-raised-button (click)="removeSelection()">Cancel</button> - <div id="specific-settings-next-button"> - <button class="stepper-button" [disabled]="!specificAdapterSettingsFormValid" - (click)="clickNext()" color="accent" mat-raised-button>Next - </button> - </div> -</div>
diff --git a/ui/src/app/connect/components/specific-adapter-configuration/specific-adapter-configuration.component.ts b/ui/src/app/connect/components/specific-adapter-configuration/specific-adapter-configuration.component.ts deleted file mode 100644 index e848ed1..0000000 --- a/ui/src/app/connect/components/specific-adapter-configuration/specific-adapter-configuration.component.ts +++ /dev/null
@@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { AdapterDescriptionUnion } from '@streampipes/platform-services'; -import { FormBuilder, FormGroup } from '@angular/forms'; -import { MatStepper } from '@angular/material/stepper'; - -@Component({ - selector: 'sp-specific-adapter-configuration', - templateUrl: './specific-adapter-configuration.component.html', - styleUrls: ['./specific-adapter-configuration.component.scss'] -}) -export class SpecificAdapterConfigurationComponent implements OnInit { - - /** - * Adapter description the selected format is added to - */ - @Input() adapterDescription: AdapterDescriptionUnion; - - /** - * Cancels the adapter configuration process - */ - @Output() removeSelectionEmitter: EventEmitter<boolean> = new EventEmitter(); - - /** - * Go to next configuration step when this is complete - */ - @Output() clickNextEmitter: EventEmitter<MatStepper> = new EventEmitter(); - - specificAdapterSettingsFormValid: boolean; - - specificAdapterForm: FormGroup; - - constructor(private _formBuilder: FormBuilder) { - } - - ngOnInit(): void { - // initialize form for validation - this.specificAdapterForm = this._formBuilder.group({}); - this.specificAdapterForm.statusChanges.subscribe((status) => { - this.specificAdapterSettingsFormValid = this.specificAdapterForm.valid; - }); - - // Go directly to event schema configuration when adapter has no configuration properties - if (this.adapterDescription.config.length === 0) { - this.specificAdapterSettingsFormValid = true; - } - } - - public removeSelection() { - this.removeSelectionEmitter.emit(); - } - - public clickNext() { - this.clickNextEmitter.emit(); - } -}
diff --git a/ui/src/app/connect/components/start-adapter-configuration/start-adapter-configuration.component.html b/ui/src/app/connect/components/start-adapter-configuration/start-adapter-configuration.component.html deleted file mode 100644 index f5fabf7..0000000 --- a/ui/src/app/connect/components/start-adapter-configuration/start-adapter-configuration.component.html +++ /dev/null
@@ -1,100 +0,0 @@ -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one or more - ~ contributor license agreements. See the NOTICE file distributed with - ~ this work for additional information regarding copyright ownership. - ~ The ASF licenses this file to You under the Apache License, Version 2.0 - ~ (the "License"); you may not use this file except in compliance with - ~ the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - ~ - --> - -<div [formGroup]="startAdapterForm"> - <div class="assemblyOptions sp-blue-bg"> - <h4>Adapter settings</h4> - </div> - - <div class="sp-blue-border padding" style="padding: 15px; margin-bottom: 2%;"> - <div fxLayoutAlign="center" fxLayout="column" fxFlex="100"> - <mat-form-field color="accent"> - <input formControlName="adapterName" - matInput id="input-AdapterName" placeholder="Adapter Name" - data-cy="sp-adapter-name" required> - </mat-form-field> - <mat-form-field color="accent"> - <input matInput id="input-AdapterDescription" [ngModelOptions]="{standalone: true}" - placeholder="Adapter Description" [(ngModel)]="adapterDescription.description"> - </mat-form-field> - - <mat-checkbox [(ngModel)]="removeDuplicates" - [ngModelOptions]="{standalone: true}" - data-cy="connect-remove-duplicates-box">Remove Duplicates - </mat-checkbox> - <mat-form-field *ngIf="removeDuplicates" color="accent"> - <input matInput id="input-removeDuplicatesTime" - [ngModelOptions]="{standalone: true}" placeholder="Remove Duplicates Time Window" - [(ngModel)]="removeDuplicatesTime" - data-cy="connect-remove-duplicates-input"> - </mat-form-field> - - <mat-checkbox [(ngModel)]="eventRateReduction" - [ngModelOptions]="{standalone: true}" - matTooltip="Send maximum one event in the specified time window" - data-cy="connect-reduce-event-rate-box">Reduce the event rate - </mat-checkbox> - <mat-form-field *ngIf="eventRateReduction" color="accent"> - <input type="number" matInput id="input-evenRateTime" - [ngModelOptions]="{standalone: true}" [(ngModel)]="eventRateTime" - placeholder="Time Window (Milliseconds)" matTooltipPosition="above" - data-cy="connect-reduce-event-input"> - </mat-form-field> - <mat-form-field *ngIf="eventRateReduction" color="accent"> - <mat-label>Event Aggregation</mat-label> - <mat-select [(ngModel)]="eventRateMode" [ngModelOptions]="{standalone: true}"> - <mat-option class="md-elevation-z1" style="background: white;" - matTooltip="Last Event in Time Window" value="none"> - None - </mat-option> - </mat-select> - </mat-form-field> - - <!-- Start pipeline template to store raw events in data lake --> - <mat-checkbox [(ngModel)]="saveInDataLake" - (change)="findDefaultTimestamp($event)" - [ngModelOptions]="{standalone: true}" - data-cy="sp-store-in-datalake"> - Store in Datalake - </mat-checkbox> - <mat-form-field *ngIf="saveInDataLake" color="accent"> - <mat-label>Select Time Field</mat-label> - <mat-select [(ngModel)]="dataLakeTimestampField" - [ngModelOptions]="{standalone: true}" - data-cy="sp-store-in-datalake-timestamp"> - <mat-option class="md-elevation-z1" style="background: white;" - *ngFor="let timestampField of eventSchema.eventProperties | timestampFilter" - [value]="timestampField.runtimeName"> - {{timestampField.runtimeName}} - </mat-option> - </mat-select> - </mat-form-field> - </div> - </div> - - <div fxLayoutAlign="end"> - <button class="mat-basic" mat-raised-button (click)="removeSelection()">Cancel</button> - <button style="margin-left:10px;" class="mat-basic stepper-button" mat-raised-button (click)="goBack()">Back - </button> - <button [disabled]="!(startAdapterSettingsFormValid)" mat-raised-button id="button-startAdapter" - color="accent" (click)="startAdapter()" mat-button style="margin-left:10px;"> - Start Adapter - </button> - </div> -</div> -
diff --git a/ui/src/app/connect/components/start-adapter-configuration/start-adapter-configuration.component.scss b/ui/src/app/connect/components/start-adapter-configuration/start-adapter-configuration.component.scss deleted file mode 100644 index 58ba04b..0000000 --- a/ui/src/app/connect/components/start-adapter-configuration/start-adapter-configuration.component.scss +++ /dev/null
@@ -1,18 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -
diff --git a/ui/src/app/connect/connect.component.css b/ui/src/app/connect/connect.component.css deleted file mode 100644 index 58ba04b..0000000 --- a/ui/src/app/connect/connect.component.css +++ /dev/null
@@ -1,18 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -
diff --git a/ui/src/app/connect/connect.component.ts b/ui/src/app/connect/connect.component.ts deleted file mode 100644 index 7313e1d..0000000 --- a/ui/src/app/connect/connect.component.ts +++ /dev/null
@@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Component } from '@angular/core'; -import { AdapterDescriptionUnion } from '@streampipes/platform-services'; - -@Component({ - selector: 'sp-connect', - templateUrl: './connect.component.html', - styleUrls: ['./connect.component.css'], -}) -export class ConnectComponent { - newAdapterFromDescription: AdapterDescriptionUnion; - - selectAdapter(adapterDescription: AdapterDescriptionUnion) { - this.newAdapterFromDescription = adapterDescription; - } - - removeSelection() { - this.newAdapterFromDescription = undefined; - } -}
diff --git a/ui/src/app/connect/connect.module.ts b/ui/src/app/connect/connect.module.ts index cad1e33..8d7bc12 100644 --- a/ui/src/app/connect/connect.module.ts +++ b/ui/src/app/connect/connect.module.ts
@@ -17,18 +17,15 @@ */ import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { FlexLayoutModule } from '@angular/flex-layout'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatGridListModule } from '@angular/material/grid-list'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; -import { ConnectComponent } from './connect.component'; import { NewAdapterComponent } from './components/new-adapter/new-adapter.component'; - -import { EditEventPropertyPrimitiveComponent } from './dialog/edit-event-property/components/edit-event-property-primitive/edit-event-property-primitive.component'; -import { EventSchemaComponent } from './components/schema-editor/event-schema/event-schema.component'; +import { EventSchemaComponent } from './components/new-adapter/schema-editor/event-schema/event-schema.component'; import { CustomMaterialModule } from '../CustomMaterial/custom-material.module'; @@ -42,114 +39,147 @@ import { ConnectService } from './services/connect.service'; import { AdapterDescriptionComponent } from './components/data-marketplace/adapter-description/adapter-description.component'; import { DataMarketplaceComponent } from './components/data-marketplace/data-marketplace.component'; -import { DataMarketplaceService } from './services/data-marketplace.service'; -import { FormatItemComponent } from './components/format-item/format-item.component'; -import { FormatListComponent } from './components/format-list/format-list.component'; +import { FormatItemComponent } from './components/new-adapter/format-configuration/format-item/format-item.component'; +import { FormatListComponent } from './components/new-adapter/format-configuration/format-list/format-list.component'; import { IconService } from './services/icon.service'; import { UnitProviderService } from './services/unit-provider.service'; -import { FilterPipe } from './filter/filter.pipe'; +import { AdapterFilterPipe } from './filter/adapter-filter.pipe'; import { AdapterExportDialog } from './dialog/adapter-export/adapter-export-dialog.component'; import { AdapterUploadDialog } from './dialog/adapter-upload/adapter-upload-dialog.component'; -import { EditEventPropertyListComponent } from './dialog/edit-event-property/components/edit-event-property-list/edit-event-property-list.component'; import { TimestampPipe } from './filter/timestamp.pipe'; import { MatChipsModule } from '@angular/material/chips'; import { MatSliderModule } from '@angular/material/slider'; import { TreeModule } from '@circlon/angular-tree-component'; import { XsService } from '../NS/xs.service'; -import { EditDataTypeComponent } from './dialog/edit-event-property/components/edit-data-type/edit-data-type.component'; -import { EditTimestampPropertyComponent } from './dialog/edit-event-property/components/edit-timestamp-property/edit-timestamp-property.component'; +import { EditDataTypeComponent } from './dialog/edit-event-property/components/edit-schema-transformation/edit-data-type/edit-data-type.component'; +import { EditTimestampPropertyComponent } from './dialog/edit-event-property/components/edit-value-transformation/edit-timestamp-property/edit-timestamp-property.component'; import { EditUnitTransformationComponent } from './dialog/edit-event-property/components/edit-unit-transformation/edit-unit-transformation.component'; import { EditEventPropertyComponent } from './dialog/edit-event-property/edit-event-property.component'; import { PipelineElementRuntimeInfoComponent } from './components/runtime-info/pipeline-element-runtime-info.component'; -import { EventPropertyRowComponent } from './components/schema-editor/event-property-row/event-property-row.component'; -import { EventSchemaPreviewComponent } from './components/schema-editor/event-schema-preview/event-schema-preview.component'; +import { EventPropertyRowComponent } from './components/new-adapter/schema-editor/event-property-row/event-property-row.component'; +import { EventSchemaPreviewComponent } from './components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component'; import { CoreUiModule } from '../core-ui/core-ui.module'; // tslint:disable-next-line:max-line-length -import { EditCorrectionValueComponent } from './dialog/edit-event-property/components/edit-correction-value/edit-correction-value.component'; -import { ExistingAdaptersComponent } from './components/data-marketplace/existing-adapters/existing-adapters.component'; +import { EditCorrectionValueComponent } from './dialog/edit-event-property/components/edit-value-transformation/edit-correction-value/edit-correction-value.component'; +import { ExistingAdaptersComponent } from './components/existing-adapters/existing-adapters.component'; // tslint:disable-next-line:max-line-length -import { SpecificAdapterConfigurationComponent } from './components/specific-adapter-configuration/specific-adapter-configuration.component'; +import { SpecificAdapterConfigurationComponent } from './components/new-adapter/specific-adapter-configuration/specific-adapter-configuration.component'; import { ConfigurationGroupComponent } from './components/configuration-group/configuration-group.component'; -import { FormatConfigurationComponent } from './components/format-configuration/format-configuration.component'; -import { GenericAdapterConfigurationComponent } from './components/generic-adapter-configuration/generic-adapter-configuration.component'; -import { ErrorMessageComponent } from './components/schema-editor/error-message/error-message.component'; -import { LoadingMessageComponent } from './components/schema-editor/loading-message/loading-message.component'; -import { SchemaEditorHeaderComponent } from './components/schema-editor/schema-editor-header/schema-editor-header.component'; -import { StartAdapterConfigurationComponent } from './components/start-adapter-configuration/start-adapter-configuration.component'; +import { FormatConfigurationComponent } from './components/new-adapter/format-configuration/format-configuration.component'; +import { GenericAdapterConfigurationComponent } from './components/new-adapter/generic-adapter-configuration/generic-adapter-configuration.component'; +import { ErrorMessageComponent } from './components/new-adapter/schema-editor/error-message/error-message.component'; +import { LoadingMessageComponent } from './components/new-adapter/schema-editor/loading-message/loading-message.component'; +import { SchemaEditorHeaderComponent } from './components/new-adapter/schema-editor/schema-editor-header/schema-editor-header.component'; +import { StartAdapterConfigurationComponent } from './components/new-adapter/start-adapter-configuration/start-adapter-configuration.component'; import { DeleteAdapterDialogComponent } from './dialog/delete-adapter-dialog/delete-adapter-dialog.component'; import { PlatformServicesModule } from '@streampipes/platform-services'; -import { FormatItemJsonComponent } from './components/format-item-json/format-item-json.component'; +import { FormatItemJsonComponent } from './components/new-adapter/format-configuration/format-item-json/format-item-json.component'; +import { RouterModule } from '@angular/router'; +import { SharedUiModule } from '@streampipes/shared-ui'; +import { SpConnectFilterToolbarComponent } from './components/filter-toolbar/filter-toolbar.component'; +import { EditSchemaTransformationComponent } from './dialog/edit-event-property/components/edit-schema-transformation/edit-schema-transformation.component'; +import { EditValueTransformationComponent } from './dialog/edit-event-property/components/edit-value-transformation/edit-value-transformation.component'; +import { SpEpSettingsSectionComponent } from './dialog/edit-event-property/components/ep-settings-section/ep-settings-section.component'; +import { SpAdapterOptionsPanelComponent } from './components/new-adapter/start-adapter-configuration/adapter-options-panel/adapter-options-panel.component'; +import { SpAdapterTemplateDialogComponent } from './dialog/adapter-template/adapter-template-dialog.component'; +import { JsonPrettyPrintPipe } from './filter/json-pretty-print.pipe'; +import { MatSnackBarModule } from '@angular/material/snack-bar'; @NgModule({ - imports: [ - CoreUiModule, - FormsModule, - ReactiveFormsModule, - CommonModule, - FlexLayoutModule, - MatGridListModule, - CustomMaterialModule, - MatProgressSpinnerModule, - MatChipsModule, - MatInputModule, - MatFormFieldModule, - MatSliderModule, - PlatformServicesModule, - CoreUiModule, - TreeModule - ], - exports: [ - PipelineElementRuntimeInfoComponent - ], - declarations: [ - AdapterDescriptionComponent, - AdapterExportDialog, - AdapterStartedDialog, - AdapterUploadDialog, - ConnectComponent, - DataMarketplaceComponent, - DeleteAdapterDialogComponent, - EventSchemaComponent, - EditEventPropertyPrimitiveComponent, - EditEventPropertyComponent, - EventPropertyRowComponent, - EditEventPropertyListComponent, - EditUnitTransformationComponent, - EditTimestampPropertyComponent, - EditDataTypeComponent, - EventSchemaPreviewComponent, - ExistingAdaptersComponent, - FilterPipe, - FormatItemComponent, - FormatListComponent, - NewAdapterComponent, - PipelineElementRuntimeInfoComponent, - TimestampPipe, - EditCorrectionValueComponent, - FormatConfigurationComponent, - GenericAdapterConfigurationComponent, - SpecificAdapterConfigurationComponent, - ConfigurationGroupComponent, - ErrorMessageComponent, - LoadingMessageComponent, - SchemaEditorHeaderComponent, - StartAdapterConfigurationComponent, - FormatItemJsonComponent - ], - providers: [ - RestService, - ConnectService, - DataTypesService, - TransformationRuleService, - StaticPropertyUtilService, - DataMarketplaceService, - IconService, - UnitProviderService, - TimestampPipe, - XsService - ] + imports: [ + CoreUiModule, + FormsModule, + ReactiveFormsModule, + CommonModule, + FlexLayoutModule, + MatGridListModule, + CustomMaterialModule, + MatProgressSpinnerModule, + MatChipsModule, + MatInputModule, + MatFormFieldModule, + MatSliderModule, + MatSnackBarModule, + PlatformServicesModule, + CoreUiModule, + TreeModule, + RouterModule.forChild([ + { + path: 'connect', + children: [ + { + path: '', + component: ExistingAdaptersComponent, + pathMatch: 'full' + }, + { + path: 'create', + component: DataMarketplaceComponent, + }, + { + path: 'create/:appId', + component: NewAdapterComponent, + }] + }]), + SharedUiModule + ], + exports: [ + PipelineElementRuntimeInfoComponent, + ErrorMessageComponent + ], + declarations: [ + AdapterDescriptionComponent, + AdapterExportDialog, + AdapterStartedDialog, + AdapterUploadDialog, + DataMarketplaceComponent, + DeleteAdapterDialogComponent, + EventSchemaComponent, + EditEventPropertyComponent, + EventPropertyRowComponent, + EditUnitTransformationComponent, + EditSchemaTransformationComponent, + EditValueTransformationComponent, + EditTimestampPropertyComponent, + EditDataTypeComponent, + EventSchemaPreviewComponent, + ExistingAdaptersComponent, + AdapterFilterPipe, + FormatItemComponent, + FormatListComponent, + JsonPrettyPrintPipe, + NewAdapterComponent, + SpAdapterTemplateDialogComponent, + PipelineElementRuntimeInfoComponent, + TimestampPipe, + EditCorrectionValueComponent, + FormatConfigurationComponent, + GenericAdapterConfigurationComponent, + SpecificAdapterConfigurationComponent, + ConfigurationGroupComponent, + ErrorMessageComponent, + LoadingMessageComponent, + SchemaEditorHeaderComponent, + SpEpSettingsSectionComponent, + StartAdapterConfigurationComponent, + FormatItemJsonComponent, + SpConnectFilterToolbarComponent, + SpAdapterOptionsPanelComponent + ], + providers: [ + RestService, + ConnectService, + DataTypesService, + TransformationRuleService, + StaticPropertyUtilService, + IconService, + UnitProviderService, + TimestampPipe, + XsService + ], + schemas: [ CUSTOM_ELEMENTS_SCHEMA ] }) export class ConnectModule { }
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/connect/connect.routes.ts similarity index 75% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/connect/connect.routes.ts index 58ba04b..9ddbb18 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/connect/connect.routes.ts
@@ -16,3 +16,11 @@ * */ +import { SpBreadcrumbItem, } from '@streampipes/shared-ui'; + +export class SpConnectRoutes { + + static BASE: SpBreadcrumbItem = {label: 'Connect', link: ['connect']}; + static CREATE: SpBreadcrumbItem = {label: 'New Adapter', link: ['connect', 'create']}; + +}
diff --git a/ui/src/app/connect/dialog/adapter-started/adapter-started-dialog.component.ts b/ui/src/app/connect/dialog/adapter-started/adapter-started-dialog.component.ts index e4c3e67..a6aa9a0 100644 --- a/ui/src/app/connect/dialog/adapter-started/adapter-started-dialog.component.ts +++ b/ui/src/app/connect/dialog/adapter-started/adapter-started-dialog.component.ts
@@ -42,7 +42,7 @@ adapterInstalled = false; public adapterStatus: Message; public streamDescription: SpDataStream; - private pollingActive = false; + pollingActive = false; public runtimeData: any; public isSetAdapter = false; public isTemplate = false; @@ -92,14 +92,6 @@ const pipelineName = 'Persist ' + this.adapter.name; let indexName = this.adapter.name - .toLowerCase() - .replace(/ /g, '') - .replace(/\./g, ''); - - // Ensure that index name is no number - if (this.isNumber(indexName)) { - indexName = 'sp' + indexName; - } const pipelineInvocation = PipelineInvocationBuilder .create(res) @@ -127,9 +119,4 @@ this.shepherdService.trigger('confirm_adapter_started_button'); } - private isNumber(value: string | number): boolean { - return ((value != null) && - (value !== '') && - !isNaN(Number(value.toString()))); - } }
diff --git a/ui/src/app/connect/dialog/adapter-template/adapter-template-dialog.component.html b/ui/src/app/connect/dialog/adapter-template/adapter-template-dialog.component.html new file mode 100644 index 0000000..7d39534 --- /dev/null +++ b/ui/src/app/connect/dialog/adapter-template/adapter-template-dialog.component.html
@@ -0,0 +1,39 @@ +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~ + --> + +<div class="sp-dialog-container"> + <div class="sp-dialog-content p-15"> + <div fxFlex="100" + fxLayout="column"> + <pipeline-element-template-config [staticProperties]="configs" + [template]="template" + [templateConfigs]="templateConfigs" + [appId]="appId"> + </pipeline-element-template-config> + </div> + </div> + <mat-divider></mat-divider> + <div class="sp-dialog-actions"> + <button mat-button mat-raised-button color="accent" + (click)="saveTemplate()" + style="margin-right: 10px;"> + Create template + </button> + <button mat-button mat-raised-button class="mat-basic" (click)="dialogRef.close()">Close</button> + </div> +</div>
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/connect/dialog/adapter-template/adapter-template-dialog.component.scss similarity index 93% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/connect/dialog/adapter-template/adapter-template-dialog.component.scss index 58ba04b..fddade7 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/connect/dialog/adapter-template/adapter-template-dialog.component.scss
@@ -16,3 +16,4 @@ * */ +@import '../../../../scss/sp/sp-dialog.scss';
diff --git a/ui/src/app/connect/dialog/adapter-template/adapter-template-dialog.component.ts b/ui/src/app/connect/dialog/adapter-template/adapter-template-dialog.component.ts new file mode 100644 index 0000000..76f3ce7 --- /dev/null +++ b/ui/src/app/connect/dialog/adapter-template/adapter-template-dialog.component.ts
@@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { Component, Input, OnInit } from '@angular/core'; +import { + PipelineElementTemplate, + PipelineElementTemplateConfig, + PipelineElementTemplateService, + StaticPropertyUnion +} from '@streampipes/platform-services'; +import { DialogRef } from '@streampipes/shared-ui'; + +@Component({ + selector: 'sp-adapter-template-dialog', + templateUrl: './adapter-template-dialog.component.html', + styleUrls: ['./adapter-template-dialog.component.scss'] +}) +export class SpAdapterTemplateDialogComponent implements OnInit { + + @Input() + configs: StaticPropertyUnion[]; + + @Input() + appId: string; + + template: PipelineElementTemplate; + templateConfigs: Map<string, any> = new Map(); + + constructor(public dialogRef: DialogRef<SpAdapterTemplateDialogComponent>, + private pipelineElementTemplateService: PipelineElementTemplateService) { + + } + + ngOnInit(): void { + this.template = new PipelineElementTemplate(); + } + + saveTemplate() { + this.template.templateConfigs = this.convert(this.templateConfigs); + this.pipelineElementTemplateService.storePipelineElementTemplate(this.template).subscribe(result => { + this.dialogRef.close(true); + }); + } + + convert(templateConfigs: Map<string, any>): any { + const configs: { [index: string]: PipelineElementTemplateConfig } = {}; + templateConfigs.forEach((value, key) => { + configs[key] = new PipelineElementTemplateConfig(); + configs[key].editable = value.editable; + configs[key].displayed = value.displayed; + configs[key].value = value.value; + }); + return configs; + } + +}
diff --git a/ui/src/app/connect/dialog/delete-adapter-dialog/delete-adapter-dialog.component.html b/ui/src/app/connect/dialog/delete-adapter-dialog/delete-adapter-dialog.component.html index 9f8beed..72ca41f 100644 --- a/ui/src/app/connect/dialog/delete-adapter-dialog/delete-adapter-dialog.component.html +++ b/ui/src/app/connect/dialog/delete-adapter-dialog/delete-adapter-dialog.component.html
@@ -33,7 +33,7 @@ <div fxFlex="100" fxLayoutAlign="center center" fxLayout="column"> <button mat-button mat-raised-button color="accent" (click)="deleteAdapter()" - data-cy="delete-adapter">Delete + data-cy="delete-adapter-confirmation">Delete adapter </button> </div>
diff --git a/ui/src/app/connect/dialog/delete-adapter-dialog/delete-adapter-dialog.component.ts b/ui/src/app/connect/dialog/delete-adapter-dialog/delete-adapter-dialog.component.ts index ce05016..dc61d38 100644 --- a/ui/src/app/connect/dialog/delete-adapter-dialog/delete-adapter-dialog.component.ts +++ b/ui/src/app/connect/dialog/delete-adapter-dialog/delete-adapter-dialog.component.ts
@@ -17,9 +17,8 @@ */ import { Component, Input } from '@angular/core'; -import { AdapterDescriptionUnion } from '@streampipes/platform-services'; +import { AdapterDescriptionUnion, AdapterService } from '@streampipes/platform-services'; import { DialogRef } from '@streampipes/shared-ui'; -import { DataMarketplaceService } from '../../services/data-marketplace.service'; @Component({ selector: 'sp-delete-adapter-dialog', @@ -37,7 +36,7 @@ numberOfPipelinesWithAdapter = 0; constructor(private dialogRef: DialogRef<DeleteAdapterDialogComponent>, - private dataMarketplaceService: DataMarketplaceService) { + private dataMarketplaceService: AdapterService) { } close(refreshAdapters: boolean) {
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-event-property-list/edit-event-property-list.component.scss b/ui/src/app/connect/dialog/edit-event-property/components/edit-event-property-list/edit-event-property-list.component.scss deleted file mode 100644 index 58ba04b..0000000 --- a/ui/src/app/connect/dialog/edit-event-property/components/edit-event-property-list/edit-event-property-list.component.scss +++ /dev/null
@@ -1,18 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-event-property-list/edit-event-property-list.component.ts b/ui/src/app/connect/dialog/edit-event-property/components/edit-event-property-list/edit-event-property-list.component.ts deleted file mode 100644 index 6c95c13..0000000 --- a/ui/src/app/connect/dialog/edit-event-property/components/edit-event-property-list/edit-event-property-list.component.ts +++ /dev/null
@@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Component, Input } from '@angular/core'; - -@Component({ - selector: 'sp-edit-event-property-list', - templateUrl: './edit-event-property-list.component.html', - styleUrls: ['./edit-event-property-list.component.scss'] -}) -export class EditEventPropertyListComponent { - - constructor() { } - - @Input() cachedProperty: any; - -}
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-event-property-primitive/edit-event-property-primitive.component.html b/ui/src/app/connect/dialog/edit-event-property/components/edit-event-property-primitive/edit-event-property-primitive.component.html deleted file mode 100644 index def4039..0000000 --- a/ui/src/app/connect/dialog/edit-event-property/components/edit-event-property-primitive/edit-event-property-primitive.component.html +++ /dev/null
@@ -1,49 +0,0 @@ -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one or more - ~ contributor license agreements. See the NOTICE file distributed with - ~ this work for additional information regarding copyright ownership. - ~ The ASF licenses this file to You under the Apache License, Version 2.0 - ~ (the "License"); you may not use this file except in compliance with - ~ the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - ~ - --> - -<div class="divBorder"> - <sp-edit-timestamp-property - *ngIf="isTimestampProperty" - [cachedProperty]= "cachedProperty" - showEditTimestampProperty="!isTimestampProperty"> - </sp-edit-timestamp-property> - - <sp-edit-data-type - *ngIf="!isTimestampProperty" - [cachedProperty]= "cachedProperty" - (dataTypeChanged)="setShowUnitTransformation()"> - </sp-edit-data-type> - - <sp-edit-unit-transformation - *ngIf="!isTimestampProperty" - [cachedProperty]= "cachedProperty" - [showUnitTransformation]="!hideUnitTransformation"> - </sp-edit-unit-transformation> - - <div fxLayout="row" fxLayoutAlign="start" *ngIf="addedByUser"> - <mat-form-field class="doubleWidth"> - <input matInput - placeholder="Static Value" - name="static_value" - id="static_value" - data-cy="connect-edit-field-static-value" - [(ngModel)]="cachedProperty.staticValue"> - </mat-form-field> - </div> - -</div>
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-event-property-primitive/edit-event-property-primitive.component.scss b/ui/src/app/connect/dialog/edit-event-property/components/edit-event-property-primitive/edit-event-property-primitive.component.scss deleted file mode 100644 index 7a945ed..0000000 --- a/ui/src/app/connect/dialog/edit-event-property/components/edit-event-property-primitive/edit-event-property-primitive.component.scss +++ /dev/null
@@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -.doubleWidth { - width: 370px !important; -}
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-event-property-primitive/edit-event-property-primitive.component.ts b/ui/src/app/connect/dialog/edit-event-property/components/edit-event-property-primitive/edit-event-property-primitive.component.ts deleted file mode 100644 index 182685e..0000000 --- a/ui/src/app/connect/dialog/edit-event-property/components/edit-event-property-primitive/edit-event-property-primitive.component.ts +++ /dev/null
@@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { DataTypesService } from '../../../../services/data-type.service'; - -@Component({ - selector: 'sp-edit-event-property-primitive', - templateUrl: './edit-event-property-primitive.component.html', - styleUrls: ['./edit-event-property-primitive.component.scss'] -}) -export class EditEventPropertyPrimitiveComponent implements OnInit { - - @Input() cachedProperty: any; - @Input() index: number; - @Input() isTimestampProperty: boolean; - @Output() isNumericDataType = new EventEmitter<boolean>(); - - hideUnitTransformation: boolean; - - addedByUser: boolean; - - constructor(private dataTypesService: DataTypesService) { - } - - ngOnInit(): void { - this.setShowUnitTransformation(); - this.addedByUser = this.staticValueAddedByUser(); - if (!this.cachedProperty.staticValue) { - this.cachedProperty.staticValue = ''; - } - } - - setShowUnitTransformation() { - this.hideUnitTransformation = this.isTimestampProperty || - !this.dataTypesService.isNumeric(this.cachedProperty.runtimeType); - - if (this.dataTypesService.isNumeric(this.cachedProperty.runtimeType)) { - this.isNumericDataType.emit(true); - } else { - this.isNumericDataType.emit(false); - } - } - - staticValueAddedByUser() { - return this.cachedProperty.elementId.startsWith('http://eventProperty.de/staticValue/'); - } - -}
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-data-type/edit-data-type.component.html b/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-data-type/edit-data-type.component.html similarity index 89% rename from ui/src/app/connect/dialog/edit-event-property/components/edit-data-type/edit-data-type.component.html rename to ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-data-type/edit-data-type.component.html index 7e8c9f4..05ed0e3 100644 --- a/ui/src/app/connect/dialog/edit-event-property/components/edit-data-type/edit-data-type.component.html +++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-data-type/edit-data-type.component.html
@@ -16,8 +16,9 @@ ~ --> -<mat-form-field class="doubleWidth" color="accent"> - <mat-select placeholder="Runtime Type" +<mat-form-field class="w-100" color="accent" fxFlex="100"> + <mat-label>Field data type</mat-label> + <mat-select placeholder="Data Type" [(ngModel)]="cachedProperty.runtimeType" (selectionChange)="valueChanged()" data-cy="connect-change-runtime-type">
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-data-type/edit-data-type.component.scss b/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-data-type/edit-data-type.component.scss similarity index 100% rename from ui/src/app/connect/dialog/edit-event-property/components/edit-data-type/edit-data-type.component.scss rename to ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-data-type/edit-data-type.component.scss
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-data-type/edit-data-type.component.ts b/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-data-type/edit-data-type.component.ts similarity index 94% rename from ui/src/app/connect/dialog/edit-event-property/components/edit-data-type/edit-data-type.component.ts rename to ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-data-type/edit-data-type.component.ts index 77e0d82..b303e8c 100644 --- a/ui/src/app/connect/dialog/edit-event-property/components/edit-data-type/edit-data-type.component.ts +++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-data-type/edit-data-type.component.ts
@@ -17,7 +17,7 @@ */ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { DataTypesService } from '../../../../services/data-type.service'; +import { DataTypesService } from '../../../../../services/data-type.service'; @Component({ selector: 'sp-edit-data-type',
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-schema-transformation.component.html b/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-schema-transformation.component.html new file mode 100644 index 0000000..98cc26f --- /dev/null +++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-schema-transformation.component.html
@@ -0,0 +1,80 @@ +<!-- + ~ 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="general-options-panel" fxLayout="column"> + <div class="general-options-header"><span>Schema</span></div> + <sp-ep-settings-section sectionTitle="Field runtime name" + sectionDescription="Identifies the field in the underlying runtime format"> + <div attr.id="input-runtime-name-{{cachedProperty.label}}" + fxFlex="100"> + <mat-form-field class="w-100" color="accent"> + <mat-label>Field runtime name</mat-label> + <input matInput + placeholder="RuntimeName" + name="runtimename" + id="runtimename" + data-cy="connect-edit-field-runtime-name" + [(ngModel)]="cachedProperty.runtimeName"> + </mat-form-field> + </div> + </sp-ep-settings-section> + + <sp-ep-settings-section sectionTitle="Field semantic type" + sectionDescription="Identifies field semantics, e.g., oil temperature" + fxLayout="column" + fxFlex="100" + *ngIf="isPrimitiveProperty"> + <div fxFlex="100" fxLayout="column" style="margin-bottom: 5px;"> + <mat-checkbox name="timestampCheckbox" + (change)="editTimestampDomainProperty($event.checked)" + [checked]="isTimestampProperty" + color="accent" + data-cy="sp-mark-as-timestamp"> + Mark as timestamp + </mat-checkbox> + </div> + <div *ngIf="isPrimitiveProperty" fxFlex="100" fxLayout="column"> + <mat-form-field class="w-100" color="accent" fxFlex="100"> + <input matInput placeholder="Semantic Type" + class="dmainProperty" + name="domainproperty" + id="domainproperty" + [(ngModel)]="cachedProperty.domainProperties[0]" + [matAutocomplete]="st" + [disabled]="isTimestampProperty" + [matAutocompleteDisabled]="isTimestampProperty" + [formControl]="domainPropertyControl"> + <mat-autocomplete #st="matAutocomplete" [panelWidth]="'300px'"> + <mat-option *ngFor="let semanticType of semanticTypes | async" [value]="semanticType" + style="font-size: 10pt;"> + {{semanticType}} + </mat-option> + </mat-autocomplete> + </mat-form-field> + </div> + </sp-ep-settings-section> + + <sp-ep-settings-section sectionTitle="Field data type" + sectionDescription="The data type of the field values" + *ngIf="!isTimestampProperty"> + <sp-edit-data-type + [cachedProperty]="cachedProperty" + (dataTypeChanged)="dataTypeChanged.emit($event)"> + </sp-edit-data-type> + </sp-ep-settings-section> +</div>
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-schema-transformation.component.scss similarity index 99% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-schema-transformation.component.scss index 58ba04b..13cbc4a 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-schema-transformation.component.scss
@@ -15,4 +15,3 @@ * limitations under the License. * */ -
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-schema-transformation.component.ts b/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-schema-transformation.component.ts new file mode 100644 index 0000000..b58d499 --- /dev/null +++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-schema-transformation.component.ts
@@ -0,0 +1,78 @@ +/* + * 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, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { EventPropertyUnion, SemanticTypesService } from '@streampipes/platform-services'; +import { debounceTime, distinctUntilChanged, startWith, switchMap } from 'rxjs/operators'; +import { FormControl } from '@angular/forms'; +import { Observable } from 'rxjs'; + +@Component({ + selector: 'sp-edit-schema-transformation', + templateUrl: './edit-schema-transformation.component.html', + styleUrls: ['./edit-schema-transformation.component.scss'] +}) +export class EditSchemaTransformationComponent implements OnInit { + + soTimestamp = 'http://schema.org/DateTime'; + + @Input() + cachedProperty: any; + + @Input() isTimestampProperty: boolean; + @Input() isNestedProperty: boolean; + @Input() isListProperty: boolean; + @Input() isPrimitiveProperty: boolean; + + @Output() dataTypeChanged = new EventEmitter<boolean>(); + @Output() timestampSemanticsChanged = new EventEmitter<boolean>(); + + domainPropertyControl = new FormControl(); + semanticTypes: Observable<string[]>; + + constructor(private semanticTypesService: SemanticTypesService) { + + } + + ngOnInit(): void { + this.semanticTypes = this.domainPropertyControl.valueChanges + .pipe( + startWith(''), + debounceTime(400), + distinctUntilChanged(), + switchMap(val => { + return val ? this.semanticTypesService.getSemanticTypes(val) : []; + }) + ); + } + + editTimestampDomainProperty(checked: boolean) { + if (checked) { + this.isTimestampProperty = true; + this.cachedProperty.domainProperties = [this.soTimestamp]; + this.cachedProperty.propertyScope = 'HEADER_PROPERTY'; + this.cachedProperty.runtimeType = 'http://www.w3.org/2001/XMLSchema#long'; + } else { + this.cachedProperty.domainProperties = []; + this.cachedProperty.propertyScope = 'MEASUREMENT_PROPERTY'; + this.isTimestampProperty = false; + } + this.timestampSemanticsChanged.emit(this.isTimestampProperty); + } + +}
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-unit-transformation/edit-unit-transformation.component.html b/ui/src/app/connect/dialog/edit-event-property/components/edit-unit-transformation/edit-unit-transformation.component.html index edc51e2..2d25621 100644 --- a/ui/src/app/connect/dialog/edit-event-property/components/edit-unit-transformation/edit-unit-transformation.component.html +++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-unit-transformation/edit-unit-transformation.component.html
@@ -16,57 +16,70 @@ ~ --> -<div fxLayout="row" fxLayoutAlign="start" *ngIf="showUnitTransformation"> - <div class="form-group" fxFlexAlign="center" style="width: 155px"> - <mat-form-field *ngIf="!hadMeasurementUnit" class="example-full-width" style="width: 155px" color="accent"> - <input matInput - placeholder="Unit" - [matAutocomplete]="auto" - [formControl]="stateCtrl" - [attr.disabled]="transformUnitEnable ? '' : null" - data-cy="connect-schema-unit-from-dropdown"> - <mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn" [panelWidth]="'300px'"> - <mat-option - *ngFor="let unit of filteredUnits | async" - [value]="unit.label" - [attr.data-cy]="unit.resource"> - {{unit.label}} - </mat-option> - </mat-autocomplete> - </mat-form-field> - <mat-form-field *ngIf="hadMeasurementUnit" - class="example-full-width" - style="width: 155px" - color="accent"> - <input matInput - placeholder="Unit" - disabled - [(ngModel)]="oldMeasurementUnitDipsplay" - data-cy="connect-schema-unit-from-input"> - </mat-form-field> +<div class="general-options-panel" fxLayout="column"> + <span class="general-options-header">Unit Transformation</span> - </div> - <button mat-button - (click)="transformUnit()" - color="accent" - class="form-group" - fxFlexAlign="center" - style="min-width: 60px; max-width: 60px" - data-cy="connect-schema-unit-transform-btn"> - <mat-icon *ngIf="!transformUnitEnable">arrow_forward</mat-icon> - <mat-icon *ngIf="transformUnitEnable" style="transform: rotate(180deg)">arrow_forward</mat-icon> - </button> - <mat-form-field class="example-full-width" style="width: 155px" *ngIf="transformUnitEnable" color="accent"> - <mat-select placeholder="New Unit" - [(ngModel)]="selectUnit" - [formControl]="newUnitStateCtrl" - [compareWith]="compareFn" - data-cy="connect-schema-unit-to-dropdown"> - <mat-option *ngFor="let unit of possibleUnitTransformations" [value]="unit" - (click)="changeTargetUnit(unit)"> - {{unit.label}} - </mat-option> - </mat-select> - </mat-form-field> + <sp-ep-settings-section sectionTitle="Unit conversion" + sectionDescription="Converts the field value from the given measurement unit to the provided target unit" + fxFlex="100" + *ngIf="isPrimitiveProperty && !isTimestampProperty && isNumericProperty"> + <div fxLayout="row"> + <div class="w-100" fxLayoutAlign="start center" fxFlex="45"> + <mat-form-field *ngIf="!hadMeasurementUnit" class="w-100" color="accent" fxFlex="100"> + <input matInput + placeholder="Unit" + [matAutocomplete]="auto" + [formControl]="stateCtrl" + [attr.disabled]="transformUnitEnable ? '' : null" + data-cy="connect-schema-unit-from-dropdown"> + <mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn" [panelWidth]="'300px'"> + <mat-option + *ngFor="let unit of filteredUnits | async" + [value]="unit.label" + [attr.data-cy]="unit.resource"> + {{unit.label}} + </mat-option> + </mat-autocomplete> + </mat-form-field> + <mat-form-field *ngIf="hadMeasurementUnit" + class="example-full-width" + style="width: 155px" + color="accent"> + <input matInput + placeholder="Unit" + disabled + [(ngModel)]="oldMeasurementUnitDipsplay" + data-cy="connect-schema-unit-from-input"> + </mat-form-field> + + </div> + <div fxFlex="10" fxLayoutAlign="center center"> + <button mat-button + (click)="transformUnit()" + color="accent" + class="form-group" + fxFlexAlign="center" + style="min-width: 60px; max-width: 60px" + data-cy="connect-schema-unit-transform-btn"> + <mat-icon *ngIf="!transformUnitEnable">arrow_forward</mat-icon> + <mat-icon *ngIf="transformUnitEnable" style="transform: rotate(180deg)">arrow_forward</mat-icon> + </button> + </div> + <div fxFlex="45" fxLayoutAlign="start center"> + <mat-form-field class="w-100" *ngIf="transformUnitEnable" color="accent" fxFlex="100"> + <mat-select placeholder="New Unit" + [(ngModel)]="selectUnit" + [formControl]="newUnitStateCtrl" + [compareWith]="compareFn" + data-cy="connect-schema-unit-to-dropdown"> + <mat-option *ngFor="let unit of possibleUnitTransformations" [value]="unit" + (click)="changeTargetUnit(unit)"> + {{unit.label}} + </mat-option> + </mat-select> + </mat-form-field> + </div> + </div> + </sp-ep-settings-section> </div>
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-unit-transformation/edit-unit-transformation.component.ts b/ui/src/app/connect/dialog/edit-event-property/components/edit-unit-transformation/edit-unit-transformation.component.ts index 3c04151..a796c5c 100644 --- a/ui/src/app/connect/dialog/edit-event-property/components/edit-unit-transformation/edit-unit-transformation.component.ts +++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-unit-transformation/edit-unit-transformation.component.ts
@@ -32,6 +32,13 @@ export class EditUnitTransformationComponent implements OnInit { @Input() cachedProperty: any; + + @Input() isTimestampProperty: boolean; + @Input() isNestedProperty: boolean; + @Input() isListProperty: boolean; + @Input() isPrimitiveProperty: boolean; + @Input() isNumericProperty: boolean; + @Input() showUnitTransformation: boolean; private transformUnitEnable = false; @@ -133,5 +140,16 @@ (this.cachedProperty as any).measurementUnitTmp = unit.resource; this.newUnitStateCtrl.setValue(unit); } + + // setShowUnitTransformation() { + // this.hideUnitTransformation = this.isTimestampProperty || + // !this.dataTypesService.isNumeric(this.cachedProperty.runtimeType); + // + // if (this.dataTypesService.isNumeric(this.cachedProperty.runtimeType)) { + // this.isNumericDataType.emit(true); + // } else { + // this.isNumericDataType.emit(false); + // } + // } }
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-correction-value/edit-correction-value.component.html b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-correction-value/edit-correction-value.component.html similarity index 83% rename from ui/src/app/connect/dialog/edit-event-property/components/edit-correction-value/edit-correction-value.component.html rename to ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-correction-value/edit-correction-value.component.html index 049ebd8..c09542b 100644 --- a/ui/src/app/connect/dialog/edit-event-property/components/edit-correction-value/edit-correction-value.component.html +++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-correction-value/edit-correction-value.component.html
@@ -17,18 +17,18 @@ --> <div fxLayout="row" fxLayoutAlign="start"> - <div class="form-group" fxFlexAlign="center"> - <mat-form-field class="example-full-width" style="margin-right: 10px" color="accent"> + <div fxFlex="70" fxLayoutAlign="start center"> + <mat-form-field class="w-100" style="margin-right: 10px" color="accent"> <input matInput name="correction" placeholder="Correction Value" [(ngModel)]="cachedProperty.correctionValue" (change)="valueChanged()" - data-cy="connect-schema-correction-value"> + data-cy="connect-schema-correction-value"> </mat-form-field> </div> - <div class="form-group" fxFlexAlign="center"> - <mat-form-field class="example-full-width" color="accent"> + <div fxFlex="30" fxLayoutAlign="start center"> + <mat-form-field class="w-100" color="accent"> <mat-select required placeholder="Math Operator"
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-correction-value/edit-correction-value.component.scss b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-correction-value/edit-correction-value.component.scss similarity index 100% rename from ui/src/app/connect/dialog/edit-event-property/components/edit-correction-value/edit-correction-value.component.scss rename to ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-correction-value/edit-correction-value.component.scss
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-correction-value/edit-correction-value.component.ts b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-correction-value/edit-correction-value.component.ts similarity index 100% rename from ui/src/app/connect/dialog/edit-event-property/components/edit-correction-value/edit-correction-value.component.ts rename to ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-correction-value/edit-correction-value.component.ts
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-timestamp-property/edit-timestamp-property.component.html b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-timestamp-property/edit-timestamp-property.component.html similarity index 75% rename from ui/src/app/connect/dialog/edit-event-property/components/edit-timestamp-property/edit-timestamp-property.component.html rename to ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-timestamp-property/edit-timestamp-property.component.html index 111b137..12c9ea6 100644 --- a/ui/src/app/connect/dialog/edit-event-property/components/edit-timestamp-property/edit-timestamp-property.component.html +++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-timestamp-property/edit-timestamp-property.component.html
@@ -17,7 +17,7 @@ --> <div fxLayout="row" fxLayoutAlign="start"> - <mat-form-field class="doubleWidth" color="accent"> + <mat-form-field class="w-100" color="accent" fxFlex="100"> <mat-select placeholder="Timestamp converter (unix timestamp)" [(value)]="cachedProperty.timestampTransformationMode" data-cy="connect-timestamp-converter"> @@ -30,17 +30,24 @@ <div fxLayout="row" fxLayoutAlign="start"> - <div class="form-group" fxFlexAlign="center"> - <mat-form-field class="doubleWidth" *ngIf="cachedProperty.timestampTransformationMode === 'formatString'" color="accent"> - <input matInput + <div class="form-group" fxFlexAlign="center" fxFlex="100"> + <mat-form-field class="w-100" + *ngIf="cachedProperty.timestampTransformationMode === 'formatString'" + color="accent" + fxFlex="100"> + <input class="w-100" matInput placeholder="E.g. yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" data-cy="connect-timestamp-string-regex" [(ngModel)]="cachedProperty.timestampTransformationFormatString"> </mat-form-field> - <mat-form-field class="doubleWidth" *ngIf="cachedProperty.timestampTransformationMode === 'timeUnit'" color="accent"> + <mat-form-field class="w-100" + *ngIf="cachedProperty.timestampTransformationMode === 'timeUnit'" + color="accent" + fxFlex="100"> <mat-select placeholder="Current time unit" [(value)]="selectedTimeMultiplier"> <mat-option value="milliseconds" (click)="cachedProperty.timestampTransformationMultiplier = 0"> - Milliseconds</mat-option> + Milliseconds + </mat-option> <mat-option value="second" (click)="cachedProperty.timestampTransformationMultiplier = 1000">Seconds </mat-option> </mat-select>
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-timestamp-property/edit-timestamp-property.component.scss b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-timestamp-property/edit-timestamp-property.component.scss similarity index 100% rename from ui/src/app/connect/dialog/edit-event-property/components/edit-timestamp-property/edit-timestamp-property.component.scss rename to ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-timestamp-property/edit-timestamp-property.component.scss
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-timestamp-property/edit-timestamp-property.component.ts b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-timestamp-property/edit-timestamp-property.component.ts similarity index 100% rename from ui/src/app/connect/dialog/edit-event-property/components/edit-timestamp-property/edit-timestamp-property.component.ts rename to ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-timestamp-property/edit-timestamp-property.component.ts
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-value-transformation.component.html b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-value-transformation.component.html new file mode 100644 index 0000000..9703ccf --- /dev/null +++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-value-transformation.component.html
@@ -0,0 +1,55 @@ +<!-- + ~ 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="general-options-panel" fxLayout="column"> + <span class="general-options-header">Value Transformation</span> + <sp-ep-settings-section sectionTitle="Timestamp conversion" + sectionDescription="Formula to convert the field value to a UNIX timestamp in milliseconds" + fxLayout="column" + fxFlex="100" + *ngIf="isTimestampProperty"> + <sp-edit-timestamp-property + [cachedProperty]="cachedProperty" + showEditTimestampProperty="!isTimestampProperty"> + </sp-edit-timestamp-property> + </sp-ep-settings-section> + <sp-ep-settings-section sectionTitle="Value conversion" + sectionDescription="Converts the original field values using the provided formula" + fxLayout="column" + fxFlex="100" + *ngIf="isNumericProperty && !isTimestampProperty"> + <sp-edit-correction-value + [cachedProperty]="cachedProperty"> + <!--(correctionValueChanged)="enableSaveBtn($event)"--> + </sp-edit-correction-value> + </sp-ep-settings-section> + <sp-ep-settings-section sectionTitle="Static value assignment" + sectionDescription="Assigns a static value to each incoming event" + fxLayout="column" + fxFlex="100" + *ngIf="addedByUser"> + <mat-form-field class="w-100" fxFlex="100"> + <input matInput + placeholder="Static Value" + name="static_value" + id="static_value" + data-cy="connect-edit-field-static-value" + [(ngModel)]="cachedProperty.staticValue"> + </mat-form-field> + </sp-ep-settings-section> +</div>
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-value-transformation.component.scss similarity index 99% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-value-transformation.component.scss index 58ba04b..13cbc4a 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-value-transformation.component.scss
@@ -15,4 +15,3 @@ * limitations under the License. * */ -
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-value-transformation.component.ts b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-value-transformation.component.ts new file mode 100644 index 0000000..ec035d9 --- /dev/null +++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-value-transformation.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, Input, OnInit } from '@angular/core'; + +@Component({ + selector: 'sp-edit-value-transformation', + templateUrl: './edit-value-transformation.component.html', + styleUrls: ['./edit-value-transformation.component.scss'] +}) +export class EditValueTransformationComponent implements OnInit { + + @Input() + cachedProperty: any; + + @Input() isTimestampProperty: boolean; + @Input() isNestedProperty: boolean; + @Input() isListProperty: boolean; + @Input() isPrimitiveProperty: boolean; + @Input() isNumericProperty: boolean; + + addedByUser: boolean; + + ngOnInit(): void { + this.addedByUser = this.staticValueAddedByUser(); + if (!this.cachedProperty.staticValue) { + this.cachedProperty.staticValue = ''; + } + } + + staticValueAddedByUser() { + return this.cachedProperty.elementId.startsWith('http://eventProperty.de/staticValue/'); + } + +}
diff --git a/ui/src/app/connect/components/schema-editor/loading-message/loading-message.component.html b/ui/src/app/connect/dialog/edit-event-property/components/ep-settings-section/ep-settings-section.component.html similarity index 60% copy from ui/src/app/connect/components/schema-editor/loading-message/loading-message.component.html copy to ui/src/app/connect/dialog/edit-event-property/components/ep-settings-section/ep-settings-section.component.html index 639fd6c..be870a1 100644 --- a/ui/src/app/connect/components/schema-editor/loading-message/loading-message.component.html +++ b/ui/src/app/connect/dialog/edit-event-property/components/ep-settings-section/ep-settings-section.component.html
@@ -15,12 +15,17 @@ ~ limitations under the License. ~ --> - -<div fxLayout="column" > - <div fxLayoutAlign="center"> - <mat-spinner fxLayoutAlign="center" style="margin: 10px 0 5px 0" color="accent">Loading</mat-spinner> +<div fxLayout="column" fxFlex="100"> + <div fxLayout="row" fxFlex="100" class="ep-settings-section ep-settings-section-border"> + <div fxFlex="30" style="margin-right: 10px;"> + <div fxLayout="column" fxFlex="100"> + <b>{{sectionTitle}}</b> + <mat-hint class="description">{{sectionDescription}}</mat-hint> + </div> + </div> + <div fxFlex fxLayout="column"> + <ng-content fxLayout="column" fxFlex="100"></ng-content> + </div> </div> - <div fxLayoutAlign="center"> - <h3>Guessing the event schema...</h3> - </div> +<!-- <mat-divider></mat-divider>--> </div>
diff --git a/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.scss b/ui/src/app/connect/dialog/edit-event-property/components/ep-settings-section/ep-settings-section.component.scss similarity index 84% copy from ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.scss copy to ui/src/app/connect/dialog/edit-event-property/components/ep-settings-section/ep-settings-section.component.scss index 2c1a70e..5074a34 100644 --- a/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.scss +++ b/ui/src/app/connect/dialog/edit-event-property/components/ep-settings-section/ep-settings-section.component.scss
@@ -16,19 +16,17 @@ * */ -@import '../../../../scss/sp/sp-dialog.scss'; - -.divider { - margin-top: 10px; - margin-bottom: 10px; -} - -.static-property-panel { +.ep-settings-section { padding-left: 10px; margin-bottom: 10px; margin-top: 10px; + margin-right: 5px; } -.static-property-panel-border { +.ep-settings-section-border { border-left:5px solid gray; } + +.description { + font-size: 10px; +}
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.ts b/ui/src/app/connect/dialog/edit-event-property/components/ep-settings-section/ep-settings-section.component.ts similarity index 72% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.ts copy to ui/src/app/connect/dialog/edit-event-property/components/ep-settings-section/ep-settings-section.component.ts index 4e64c25..7700e3e 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.ts +++ b/ui/src/app/connect/dialog/edit-event-property/components/ep-settings-section/ep-settings-section.component.ts
@@ -16,23 +16,24 @@ * */ + import { Component, Input, OnInit } from '@angular/core'; -import { Notification } from '@streampipes/platform-services'; @Component({ - selector: 'sp-error-message', - templateUrl: './error-message.component.html', - styleUrls: ['./error-message.component.scss'] + selector: 'sp-ep-settings-section', + templateUrl: './ep-settings-section.component.html', + styleUrls: ['./ep-settings-section.component.scss'] }) -export class ErrorMessageComponent implements OnInit { +export class SpEpSettingsSectionComponent implements OnInit { - @Input() errorMessages: Notification[]; + @Input() + sectionTitle: string; - showErrorMessage = false; - - constructor() { } + @Input() + sectionDescription: string; ngOnInit(): void { } + }
diff --git a/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.html b/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.html index a67a461..132efac 100644 --- a/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.html +++ b/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.html
@@ -16,83 +16,103 @@ ~ --> -<h2 mat-dialog-title>Edit field {{property.runtimeName}}</h2> -<mat-dialog-content> - <form #propertyForm="ngForm"> - <div fxLayout="row" fxLayoutAlign="start"> - <div class="form-group" fxFlexAlign="center"> - <mat-form-field class="example-full-width" style="margin-right: 10px" color="accent"> - <input matInput placeholder="Label" name="label" id="label" [(ngModel)]="cachedProperty.label"> - </mat-form-field> - </div> - <div attr.id="input-runtime-name-{{cachedProperty.label}}" class="form-group" fxFlexAlign="center"> - <mat-form-field class="example-full-width" color="accent"> - <input matInput - placeholder="RuntimeName" - name="runtimename" - id="runtimename" - data-cy="connect-edit-field-runtime-name" - [(ngModel)]="cachedProperty.runtimeName"> - </mat-form-field> - </div> +<div class="sp-dialog-container"> + <div class="sp-dialog-content p-15"> + <div fxFlex="100" + fxLayout="column"> + <form #propertyForm="ngForm" + fxLayout="column"> + <div fxLayout="column" + fxLayoutAlign="start" + fxFlex="100"> + <div class="general-options-panel" + fxLayout="column" + fxFlex="100"> + <span class="general-options-header">Basics</span> + <sp-ep-settings-section sectionTitle="Field label" + sectionDescription="A label for better readability"> + <mat-form-field class="w-100" + color="accent"> + <input matInput + placeholder="Label" + name="label" + id="label" + [(ngModel)]="cachedProperty.label"> + </mat-form-field> + </sp-ep-settings-section> + <sp-ep-settings-section sectionTitle="Field description" + sectionDescription="A description for better readability"> + <mat-form-field class="full-width" + color="accent"> + <textarea matInput + name="description" + placeholder="Description" + id="description" + [(ngModel)]="cachedProperty.description" cols="20" rows="2"> + </textarea> + </mat-form-field> + </sp-ep-settings-section> + </div> + + + <sp-edit-schema-transformation [cachedProperty]="cachedProperty" + [isTimestampProperty]="isTimestampProperty" + [isNestedProperty]="isEventPropertyNested" + [isListProperty]="isEventPropertyList" + [isPrimitiveProperty]="isEventPropertyPrimitive" + *ngIf="!isEventPropertyNested" + (dataTypeChanged)="handleDataTypeChange($event)" + (timestampSemanticsChanged)="handleTimestampChange($event)" + #schemaTransformationComponent> + + </sp-edit-schema-transformation> + + <sp-edit-value-transformation [cachedProperty]="cachedProperty" + *ngIf="isEventPropertyPrimitive" + [isTimestampProperty]="isTimestampProperty" + [isNumericProperty]="isNumericProperty" + [isNestedProperty]="isEventPropertyNested" + [isListProperty]="isEventPropertyList" + [isPrimitiveProperty]="isEventPropertyPrimitive" + #valueTransformationComponent> + </sp-edit-value-transformation> + + <sp-edit-unit-transformation *ngIf="!isTimestampProperty && isEventPropertyPrimitive" + [cachedProperty]="cachedProperty" + [isTimestampProperty]="isTimestampProperty" + [isNumericProperty]="isNumericProperty" + [isPrimitiveProperty]="isEventPropertyPrimitive" + #unitTransformationComponent> + </sp-edit-unit-transformation> + + + </div> + + + </form> + + <!-- <sp-edit-event-property-primitive--> + <!-- *ngIf="isEventPropertyPrimitive"--> + <!-- [isTimestampProperty]="isTimestampProperty"--> + <!-- [cachedProperty]="cachedProperty"--> + <!-- (isNumericDataType)="isNumericDataType($event)">--> + <!-- </sp-edit-event-property-primitive>--> + <!-- <sp-edit-event-property-list--> + <!-- *ngIf="isEventPropertyList"--> + <!-- [cachedProperty]="cachedProperty">--> + <!-- </sp-edit-event-property-list>--> + </div> </div> - - <div class="form-group"> - <mat-form-field class="doubleWidth" color="accent"> - <textarea matInput name="description" placeholder="Description" id="description" - [(ngModel)]="cachedProperty.description" cols="20" rows="2"></textarea> - </mat-form-field> - </div> - - <sp-edit-correction-value - *ngIf="isNumericProperty && !isTimestampProperty" - [cachedProperty]="cachedProperty" - (correctionValueChanged)="enableSaveBtn($event)"> - </sp-edit-correction-value> - - <div class="form-group"> - <mat-form-field class="doubleWidth" color="accent"> - <input matInput placeholder="Semantic Type" class="dmainProperty" name="domainproperty" id="domainproperty" - [(ngModel)]="cachedProperty.domainProperties[0]" - [matAutocomplete]="st" - [formControl]="domainPropertyControl"> - <mat-autocomplete #st="matAutocomplete" [panelWidth]="'300px'"> - <mat-option *ngFor="let semanticType of semanticTypes | async" [value]="semanticType" style="font-size: 10pt;"> - {{semanticType}} - </mat-option> - </mat-autocomplete> - </mat-form-field> - <div *ngIf="!isEventPropertyNested"> - <mat-checkbox name="timestampCheckbox" - (change)="editTimestampDomainProperty($event.checked)" - [checked]="isTimestampProperty" - color="accent" - data-cy="sp-mark-as-timestamp"> - Mark as timestamp - </mat-checkbox> - </div> - </div> - </form> - - <sp-edit-event-property-primitive - *ngIf="isEventPropertyPrimitive" - [isTimestampProperty]="isTimestampProperty" - [cachedProperty]="cachedProperty" - (isNumericDataType)="isNumericDataType($event)"> - </sp-edit-event-property-primitive> - <sp-edit-event-property-list - *ngIf="isEventPropertyList" - [cachedProperty]="cachedProperty"> - </sp-edit-event-property-list> - -</mat-dialog-content> - -<mat-dialog-actions> - <button mat-button mat-raised-button class="mat-basic" mat-dialog-close>Close</button> - <button mat-button mat-raised-button color="accent" - [disabled]="isSaveBtnEnabled" - (click)="save(); + <mat-divider></mat-divider> + <div class="sp-dialog-actions"> + <button mat-button mat-raised-button color="accent" + [disabled]="isSaveBtnEnabled" + (click)="save(); isSaveBtnEnabled = false" - data-cy="sp-save-edit-property"> - Save</button> -</mat-dialog-actions> + style="margin-right: 10px;" + data-cy="sp-save-edit-property"> + Save + </button> + <button mat-button mat-raised-button class="mat-basic" (click)="dialogRef.close()">Close</button> + </div> +</div>
diff --git a/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.scss b/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.scss index 03fa4b4..85d8c6a 100644 --- a/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.scss +++ b/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.scss
@@ -16,6 +16,8 @@ * */ +@import '../../../../scss/sp/sp-dialog.scss'; + .doubleWidth { width: 370px !important; } @@ -24,3 +26,7 @@ justify-content: flex-end; } +.full-width { + width: 100%; +} +
diff --git a/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.ts b/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.ts index d7c7189..d3a3dc9 100644 --- a/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.ts +++ b/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.ts
@@ -16,20 +16,21 @@ * */ -import { Component, EventEmitter, Inject, OnInit, Output } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { - EventPropertyList, - EventPropertyNested, - EventPropertyPrimitive, - EventPropertyUnion, - SemanticTypesService + EventPropertyList, + EventPropertyNested, + EventPropertyPrimitive, + EventPropertyUnion, + SemanticTypesService } from '@streampipes/platform-services'; import { SemanticTypeUtilsService } from '../../../core-services/semantic-type/semantic-type-utils.service'; import { DataTypesService } from '../../services/data-type.service'; -import { Observable } from 'rxjs'; -import { debounceTime, distinctUntilChanged, startWith, switchMap } from 'rxjs/operators'; +import { DialogRef } from '@streampipes/shared-ui'; +import { EditSchemaTransformationComponent } from './components/edit-schema-transformation/edit-schema-transformation.component'; +import { EditValueTransformationComponent } from './components/edit-value-transformation/edit-value-transformation.component'; +import { EditUnitTransformationComponent } from './components/edit-unit-transformation/edit-unit-transformation.component'; @Component({ selector: 'sp-edit-event-property', @@ -38,13 +39,16 @@ }) export class EditEventPropertyComponent implements OnInit { - soTimestamp = 'http://schema.org/DateTime'; + @Input() property: EventPropertyUnion; + @Input() isEditable: boolean; @Output() propertyChange = new EventEmitter<EventPropertyUnion>(); + schemaTransformationComponent: EditSchemaTransformationComponent; + valueTransformationComponent: EditValueTransformationComponent; + unitTransformationComponent: EditUnitTransformationComponent; + cachedProperty: any; - property: any; - isEditable: boolean; isTimestampProperty = false; isEventPropertyPrimitive: boolean; @@ -53,15 +57,11 @@ isNumericProperty: boolean; isSaveBtnEnabled: boolean; - semanticTypes: Observable<string[]>; - private propertyForm: FormGroup; - domainPropertyControl = new FormControl(); private runtimeDataTypes; - constructor(@Inject(MAT_DIALOG_DATA) public data: any, - private dialogRef: MatDialogRef<EditEventPropertyComponent>, + constructor(public dialogRef: DialogRef<EditEventPropertyComponent>, private formBuilder: FormBuilder, private dataTypeService: DataTypesService, private semanticTypeUtilsService: SemanticTypeUtilsService, @@ -69,8 +69,6 @@ } ngOnInit(): void { - this.property = this.data.property; - this.isEditable = this.data.isEditable; this.cachedProperty = this.copyEp(this.property); this.runtimeDataTypes = this.dataTypeService.getDataTypes(); this.isTimestampProperty = this.semanticTypeUtilsService.isTimestamp(this.cachedProperty); @@ -80,15 +78,7 @@ this.isNumericProperty = this.semanticTypeUtilsService.isNumeric(this.cachedProperty) || this.dataTypeService.isNumeric(this.cachedProperty.runtimeType); this.createForm(); - this.semanticTypes = this.domainPropertyControl.valueChanges - .pipe( - startWith(''), - debounceTime(400), - distinctUntilChanged(), - switchMap(val => { - return val ? this.semanticTypesService.getSemanticTypes(val) : []; - }) - ); + } copyEp(ep: EventPropertyUnion) { @@ -131,19 +121,6 @@ return (this.property.elementId.startsWith('http://eventProperty.de/staticValue/')); } - editTimestampDomainProperty(checked: boolean) { - if (checked) { - this.isTimestampProperty = true; - this.cachedProperty.domainProperties = [this.soTimestamp]; - this.cachedProperty.propertyScope = 'HEADER_PROPERTY'; - this.cachedProperty.runtimeType = 'http://www.w3.org/2001/XMLSchema#long'; - } else { - this.cachedProperty.domainProperties = []; - this.cachedProperty.propertyScope = 'MEASUREMENT_PROPERTY'; - this.isTimestampProperty = false; - } - } - save(): void { this.property.label = this.cachedProperty.label; this.property.description = this.cachedProperty.description; @@ -176,7 +153,7 @@ (this.property as any).correctionValue = (this.cachedProperty as any).correctionValue; (this.property as any).operator = (this.cachedProperty as any).operator; } - this.dialogRef.close({ data: this.property }); + this.dialogRef.close({data: this.property}); } enableSaveBtn($event: boolean) { @@ -191,4 +168,24 @@ } this.isNumericProperty = $event; } + + handleDataTypeChange(changed: boolean) { + this.isNumericProperty = this.dataTypeService.isNumeric(this.cachedProperty.runtimeType); + } + + handleTimestampChange(isTimestamp: boolean) { + this.isTimestampProperty = isTimestamp; + } + + @ViewChild('schemaTransformationComponent') set schemaTransformation(comp: EditSchemaTransformationComponent) { + this.schemaTransformationComponent = comp; + } + + @ViewChild('unitTransformationComponent') set unitTransformation(comp: EditUnitTransformationComponent) { + this.unitTransformationComponent = comp; + } + + @ViewChild('valueTransformationComponent') set valueTransformation(comp: EditValueTransformationComponent) { + this.valueTransformationComponent = comp; + } }
diff --git a/ui/src/app/connect/filter/adapter-filter.pipe.ts b/ui/src/app/connect/filter/adapter-filter.pipe.ts new file mode 100644 index 0000000..8691a93 --- /dev/null +++ b/ui/src/app/connect/filter/adapter-filter.pipe.ts
@@ -0,0 +1,81 @@ +/* + * 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, Pipe, PipeTransform } from '@angular/core'; +import { AdapterDescriptionUnion } from '@streampipes/platform-services'; +import { AdapterFilterSettingsModel } from '../model/adapter-filter-settings.model'; +import { ConnectService } from '../services/connect.service'; + +@Pipe({ name: 'adapterFilter' }) +@Injectable({ providedIn: 'root' }) +export class AdapterFilterPipe implements PipeTransform { + + constructor(private connectService: ConnectService) { + } + + transform(adapterDescriptions: AdapterDescriptionUnion[], + activeFilters: AdapterFilterSettingsModel): AdapterDescriptionUnion[] { + if (!activeFilters) { + return adapterDescriptions; + } else { + return adapterDescriptions.filter(a => this.meetsFilterCondition(a, activeFilters)); + } + } + + private meetsFilterCondition(adapterDescription: AdapterDescriptionUnion, + activeFilters: AdapterFilterSettingsModel): boolean { + return this.meetsFilterTypeCondition(adapterDescription, activeFilters.selectedType) && + this.meetsFilterCategoryCondition(adapterDescription, activeFilters.selectedCategory) && + this.meetsFilterTextCondition(adapterDescription, activeFilters.textFilter); + } + + private meetsFilterTypeCondition(adapterDescription: AdapterDescriptionUnion, + selectedType: string): boolean { + if (selectedType === 'All types') { + return true; + } else if (selectedType === 'Data Set') { + return this.connectService.isDataSetDescription(adapterDescription); + } else if (selectedType === 'Data Stream') { + return !this.connectService.isDataSetDescription(adapterDescription); + } + } + + private meetsFilterCategoryCondition(adapterDescription: AdapterDescriptionUnion, + selectedCategory: string): boolean { + if (selectedCategory === 'All') { + return true; + } else { + return adapterDescription.category.indexOf(selectedCategory) !== -1; + } + } + + private meetsFilterTextCondition(adapterDescription: AdapterDescriptionUnion, + filterTerm: string): boolean { + if (filterTerm === undefined || filterTerm === '') { + return true; + } else { + if (adapterDescription.name == null) { + return true; + } else { + adapterDescription.name.replace(' ', '_'); + return adapterDescription.name.toLowerCase().includes(filterTerm.toLowerCase()) || + adapterDescription.description.toLowerCase().includes(filterTerm.toLowerCase()); + } + } + } +}
diff --git a/ui/src/app/connect/filter/filter.pipe.ts b/ui/src/app/connect/filter/filter.pipe.ts deleted file mode 100644 index b7f663f..0000000 --- a/ui/src/app/connect/filter/filter.pipe.ts +++ /dev/null
@@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Pipe, PipeTransform } from '@angular/core'; -import { AdapterDescriptionUnion } from '@streampipes/platform-services'; - -@Pipe({ - name: 'filter' -}) - -export class FilterPipe implements PipeTransform { - - transform(adapterDescriptions: AdapterDescriptionUnion[], filterTerm?: any): any { - // check if search filterTerm is undefined - if (filterTerm === undefined || !adapterDescriptions) { return adapterDescriptions; } - return adapterDescriptions.filter(adapterDescription => { - if (adapterDescription.name == null) { - return true; - } else { - adapterDescription.name.replace(' ', '_'); - return adapterDescription.name.toLowerCase().includes(filterTerm.toLowerCase()) || - adapterDescription.description.toLowerCase().includes(filterTerm.toLowerCase()); - } - }); - } -}
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/connect/filter/json-pretty-print.pipe.ts similarity index 70% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/connect/filter/json-pretty-print.pipe.ts index 58ba04b..5383916 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/connect/filter/json-pretty-print.pipe.ts
@@ -16,3 +16,18 @@ * */ +import { Injectable, Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'jsonpretty' +}) +@Injectable({providedIn: 'root'}) +export class JsonPrettyPrintPipe implements PipeTransform { + + transform(json) { + return JSON.stringify(json, undefined, 4) + .replace(/ /g, ' ') + .replace(/\n/g, '<br/>'); + } + +}
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/connect/model/adapter-filter-settings.model.ts similarity index 86% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/connect/model/adapter-filter-settings.model.ts index 58ba04b..3b30586 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/connect/model/adapter-filter-settings.model.ts
@@ -16,3 +16,8 @@ * */ +export interface AdapterFilterSettingsModel { + textFilter: string; + selectedType: string; + selectedCategory: string; +}
diff --git a/ui/src/app/connect/services/adapter-template.service.ts b/ui/src/app/connect/services/adapter-template.service.ts new file mode 100644 index 0000000..d7c0815 --- /dev/null +++ b/ui/src/app/connect/services/adapter-template.service.ts
@@ -0,0 +1,45 @@ +/* + * 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 { SpAdapterTemplateDialogComponent } from '../dialog/adapter-template/adapter-template-dialog.component'; +import { DialogService, PanelType } from '@streampipes/shared-ui'; +import { AdapterDescriptionUnion } from '@streampipes/platform-services'; +import { StaticPropertyUnion } from '../../../../projects/streampipes/platform-services/src/lib/model/gen/streampipes-model'; + +@Injectable({providedIn: 'root'}) +export class AdapterTemplateService { + + constructor(private dialogService: DialogService) { + + } + + getDialog(configs: StaticPropertyUnion[], + appId: string) { + return this.dialogService.open(SpAdapterTemplateDialogComponent, { + panelType: PanelType.SLIDE_IN_PANEL, + title: 'Create configuration template', + width: '50vw', + data: { + 'configs': configs, + 'appId': appId + } + }); + } + +}
diff --git a/ui/src/app/connect/services/connect.service.ts b/ui/src/app/connect/services/connect.service.ts index 1e4b73d..740cc43 100644 --- a/ui/src/app/connect/services/connect.service.ts +++ b/ui/src/app/connect/services/connect.service.ts
@@ -25,6 +25,7 @@ SpecificAdapterSetDescription, SpecificAdapterStreamDescription } from '@streampipes/platform-services'; +import { AdapterDescriptionUnion } from '../../../../projects/streampipes/platform-services/src/lib/model/gen/streampipes-model'; @Injectable() export class ConnectService { @@ -67,5 +68,25 @@ } } + cloneAdapterDescription(toClone: AdapterDescriptionUnion): AdapterDescriptionUnion { + let result: AdapterDescriptionUnion; + + if (this.isGenericDescription(toClone)) { + if (toClone instanceof GenericAdapterStreamDescription) { + result = GenericAdapterStreamDescription.fromData(toClone, new GenericAdapterStreamDescription()); + } else if (toClone instanceof GenericAdapterSetDescription) { + result = GenericAdapterSetDescription.fromData(toClone, new GenericAdapterSetDescription()); + } + } else { + if (toClone instanceof SpecificAdapterStreamDescription) { + result = SpecificAdapterStreamDescription.fromData(toClone, new SpecificAdapterStreamDescription()); + } else if (toClone instanceof SpecificAdapterSetDescription) { + result = SpecificAdapterSetDescription.fromData(toClone, new SpecificAdapterSetDescription()); + } + } + + return result; + } + }
diff --git a/ui/src/app/connect/services/rest.service.ts b/ui/src/app/connect/services/rest.service.ts index 5d33cdc..17459d5 100644 --- a/ui/src/app/connect/services/rest.service.ts +++ b/ui/src/app/connect/services/rest.service.ts
@@ -23,16 +23,20 @@ import { from, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { UnitDescription } from '../model/UnitDescription'; -import { AdapterDescription, FormatDescription, GuessSchema, Message, SpDataStream, PlatformServicesCommons } from '@streampipes/platform-services'; +import { + AdapterDescription, FormatDescription, GuessSchema, Message, SpDataStream, PlatformServicesCommons, + AdapterEventPreview, + GuessTypeInfo +} from '@streampipes/platform-services'; import { AuthService } from '../../services/auth.service'; @Injectable() export class RestService { constructor( - private http: HttpClient, - private platformServicesCommons: PlatformServicesCommons, - private authService: AuthService) { + private http: HttpClient, + private platformServicesCommons: PlatformServicesCommons, + private authService: AuthService) { } get connectPath() { @@ -66,7 +70,11 @@ .pipe(map(response => { return GuessSchema.fromData(response as GuessSchema); })); + } + getAdapterEventPreview(adapterEventPreview: AdapterEventPreview): Observable<Record<string, GuessTypeInfo>> { + return this.http.post(`${this.connectPath}/master/guess/schema/preview`, adapterEventPreview) + .pipe(map(response => response as Record<string, GuessTypeInfo>)); } getSourceDetails(sourceElementId): Observable<SpDataStream> { @@ -78,7 +86,7 @@ getRuntimeInfo(sourceDescription): Observable<any> { return this.http.post(`${this.platformServicesCommons.apiBasePath}/pipeline-element/runtime`, sourceDescription, { - headers: { ignoreLoadingBar: '' } + headers: {ignoreLoadingBar: ''} }); }
diff --git a/ui/src/app/connect/services/transformation-rule.service.ts b/ui/src/app/connect/services/transformation-rule.service.ts index 8781956..4786696 100644 --- a/ui/src/app/connect/services/transformation-rule.service.ts +++ b/ui/src/app/connect/services/transformation-rule.service.ts
@@ -30,6 +30,7 @@ EventSchema, MoveRuleDescription, RenameRuleDescription, + ChangeDatatypeTransformationRuleDescription, TimestampTranfsformationRuleDescription, TransformationRuleDescriptionUnion, UnitTransformRuleDescription @@ -82,33 +83,16 @@ } // Scale - transformationRuleDescription = transformationRuleDescription.concat(this.getCorrectionValueRules( - this.newEventSchema.eventProperties, this.oldEventSchema, this.newEventSchema)); + transformationRuleDescription = transformationRuleDescription + .concat(this.getCorrectionValueRules(this.newEventSchema.eventProperties, this.oldEventSchema, this.newEventSchema)) + .concat(this.getRenameRules(this.newEventSchema.eventProperties, this.oldEventSchema, this.newEventSchema)) + .concat(this.getCreateNestedRules(this.newEventSchema.eventProperties, this.oldEventSchema, this.newEventSchema)) + .concat(this.getMoveRules(this.newEventSchema.eventProperties, this.oldEventSchema, this.newEventSchema)) + .concat(this.getDeleteRules(this.newEventSchema.eventProperties, this.oldEventSchema, this.newEventSchema)) + .concat(this.getUnitTransformRules(this.newEventSchema.eventProperties, this.oldEventSchema, this.newEventSchema)) + .concat(this.getTimestampTransformRules(this.newEventSchema.eventProperties, this.oldEventSchema, this.newEventSchema)) + .concat(this.getDatatypeTransformRules(this.newEventSchema.eventProperties, this.oldEventSchema, this.newEventSchema)); - // Rename - transformationRuleDescription = transformationRuleDescription.concat(this.getRenameRules( - this.newEventSchema.eventProperties, this.oldEventSchema, this.newEventSchema)); - - - // Create Nested - transformationRuleDescription = transformationRuleDescription.concat(this.getCreateNestedRules( - this.newEventSchema.eventProperties, this.oldEventSchema, this.newEventSchema)); - - // Move - transformationRuleDescription = transformationRuleDescription.concat(this.getMoveRules( - this.newEventSchema.eventProperties, this.oldEventSchema, this.newEventSchema)); - - // Delete - transformationRuleDescription = transformationRuleDescription.concat(this.getDeleteRules( - this.newEventSchema.eventProperties, this.oldEventSchema, this.newEventSchema)); - - // Unit - transformationRuleDescription = transformationRuleDescription.concat(this.getUnitTransformRules( - this.newEventSchema.eventProperties, this.oldEventSchema, this.newEventSchema)); - - // Timestmap - transformationRuleDescription = transformationRuleDescription.concat(this.getTimestampTransformRules( - this.newEventSchema.eventProperties, this.oldEventSchema, this.newEventSchema)); return transformationRuleDescription; } @@ -454,6 +438,40 @@ return property.domainProperties.some(dp => dp === 'http://schema.org/DateTime'); } + private getDatatypeTransformRules(eventProperties: EventPropertyUnion[], + oldEventSchema: EventSchema, + newEventSchema: EventSchema): ChangeDatatypeTransformationRuleDescription[] { + + let result: ChangeDatatypeTransformationRuleDescription[] = []; + + eventProperties.forEach(ep => { + if (ep instanceof EventPropertyPrimitive) { + const eventPropertyPrimitive = ep as EventPropertyPrimitive; + const newRuntimeType = ep.runtimeType; + const keyNew = this.getCompleteRuntimeNameKey(newEventSchema.eventProperties, eventPropertyPrimitive.elementId); + const oldProperty = this.getEventProperty(oldEventSchema.eventProperties, ep.elementId); + if (oldProperty) { + const oldRuntimeType = (oldProperty as EventPropertyPrimitive).runtimeType; + if (newRuntimeType !== oldRuntimeType) { + const rule: ChangeDatatypeTransformationRuleDescription = new ChangeDatatypeTransformationRuleDescription(); + rule['@class'] = 'org.apache.streampipes.model.connect.rules.value.ChangeDatatypeTransformationRuleDescription'; + rule.runtimeKey = keyNew; + rule.originalDatatypeXsd = oldRuntimeType; + rule.targetDatatypeXsd = newRuntimeType; + + result.push(rule); + } + } + + } else if (ep instanceof EventPropertyNested) { + const nestedResults = this.getDatatypeTransformRules((ep as EventPropertyNested).eventProperties, oldEventSchema, newEventSchema); + result = result.concat(nestedResults); + } + }); + + return result; + } + private getCorrectionValueRules(eventProperties: EventPropertyUnion[], oldEventSchema: EventSchema, newEventSchema: EventSchema) {
diff --git a/ui/src/app/core-model/base/UserErrorMessage.ts b/ui/src/app/core-model/base/UserErrorMessage.ts index 85322e0..2fc7f5c 100644 --- a/ui/src/app/core-model/base/UserErrorMessage.ts +++ b/ui/src/app/core-model/base/UserErrorMessage.ts
@@ -19,9 +19,11 @@ export class UserErrorMessage { public title: string; public content: string; + public level: string; - constructor(title: string, content: string) { + constructor(title: string, content: string, level = 'error') { this.title = title; this.content = content; + this.level = level; } }
diff --git a/ui/src/app/core-services/template/PipelineInvocationBuilder.ts b/ui/src/app/core-services/template/PipelineInvocationBuilder.ts index 57c094a..cec4cf0 100644 --- a/ui/src/app/core-services/template/PipelineInvocationBuilder.ts +++ b/ui/src/app/core-services/template/PipelineInvocationBuilder.ts
@@ -41,7 +41,7 @@ public setFreeTextStaticProperty(name: string, value: string) { this.pipelineTemplateInvocation.staticProperties.forEach(property => { - if (property instanceof FreeTextStaticProperty && 'domId2' + name === property.internalName) { + if (property instanceof FreeTextStaticProperty && 'jsplumb_domId2' + name === property.internalName) { property.value = value; } }); @@ -51,7 +51,7 @@ public setMappingPropertyUnary(name: string, value: string) { this.pipelineTemplateInvocation.staticProperties.forEach(property => { - if (property instanceof MappingPropertyUnary && 'domId2' + name === property.internalName) { + if (property instanceof MappingPropertyUnary && 'jsplumb_domId2' + name === property.internalName) { property.selectedProperty = value; } });
diff --git a/ui/src/app/core-ui/core-ui.module.ts b/ui/src/app/core-ui/core-ui.module.ts index 22c3f48..89f0163 100644 --- a/ui/src/app/core-ui/core-ui.module.ts +++ b/ui/src/app/core-ui/core-ui.module.ts
@@ -82,6 +82,10 @@ import { PlatformServicesModule } from '@streampipes/platform-services'; import { ImageBarPreviewComponent } from './image/components/image-bar/image-bar-preview/image-bar-preview.component'; import { SharedUiModule } from '@streampipes/shared-ui'; +import { PipelineElementTemplateConfigComponent } from './pipeline-element-template-config/pipeline-element-template-config.component'; +import { PipelineElementTemplatePipe } from './pipeline-element-template-config/pipeline-element-template.pipe'; +import { DataDownloadDialogComponent } from './data-download-dialog/data-download-dialog.component'; +import { OwlDateTimeModule, OwlNativeDateTimeModule } from '@danielmoncada/angular-datetime-picker'; @NgModule({ imports: [ @@ -104,6 +108,8 @@ MatSlideToggleModule, MatChipsModule, MatTreeModule, + OwlDateTimeModule, + OwlNativeDateTimeModule, PlatformServicesModule, PortalModule, SharedUiModule, @@ -113,6 +119,7 @@ ], declarations: [ ConfigureLabelsComponent, + DataDownloadDialogComponent, DisplayRecommendedPipe, ImageBarPreviewComponent, ImageComponent, @@ -123,6 +130,8 @@ ImageAnnotationsComponent, ImageViewerComponent, ObjectPermissionDialogComponent, + PipelineElementTemplateConfigComponent, + PipelineElementTemplatePipe, SplitSectionComponent, StaticAnyInput, StaticPropertyComponent, @@ -159,8 +168,10 @@ ], exports: [ ConfigureLabelsComponent, + DataDownloadDialogComponent, ImageComponent, ImageLabelingComponent, + PipelineElementTemplateConfigComponent, SelectLabelComponent, StaticAnyInput, StaticPropertyComponent,
diff --git a/ui/src/app/core-ui/data-download-dialog/data-download-dialog.component.html b/ui/src/app/core-ui/data-download-dialog/data-download-dialog.component.html new file mode 100644 index 0000000..4c8675a --- /dev/null +++ b/ui/src/app/core-ui/data-download-dialog/data-download-dialog.component.html
@@ -0,0 +1,114 @@ +<!-- + ~ 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"> + <mat-horizontal-stepper #stepper> + <mat-step> + <ng-template matStepLabel>Select Data</ng-template> + <div class="mt-10"> + <mat-radio-group class="sp-radio-group" [(ngModel)]="selectedData"> + <mat-radio-button value="visible" class="sp-radio-button" *ngIf="dataConfig"> + Currently configured query + </mat-radio-button> + <div fxLayout="column" fxLayoutAlign="start start" class="ml-35 mb-10" *ngIf="selectedData === 'visible' && dataConfig && dataConfig.sourceConfigs.length > 1"> + <h5>Select source (only one source can be exported in a single file)</h5> + <mat-radio-group class="sp-radio-group" [(ngModel)]="selectedQueryIndex" fxLayout="column"> + <mat-radio-button [value]="i" *ngFor="let sourceConfig of dataConfig.sourceConfigs; let i = index" class="p-5"> + {{sourceConfig.measureName}} + </mat-radio-button> + </mat-radio-group> + </div> + <mat-radio-button value="all" class="sp-radio-button"> + All data in database + </mat-radio-button> + <mat-radio-button value="customInterval" class="sp-radio-button"> + All data in custom time interval + </mat-radio-button> + </mat-radio-group> + <div fxLayout="row" fxLayoutAlign="start center" class="ml-35"> + <mat-form-field class="form-field-date"> + <input matInput [owlDateTime]="dt1" [owlDateTimeTrigger]="dt1" + [(ngModel)]="dateRange" [selectMode]="'range'" + [disabled]="selectedData !== 'customInterval'"> + <mat-icon matSuffix [owlDateTimeTrigger]="dt1" + *ngIf="selectedData === 'customInterval'">event + </mat-icon> + <mat-icon matSuffix class="event-color" *ngIf="selectedData !== 'customInterval'"> + event + </mat-icon> + <owl-date-time #dt1></owl-date-time> + </mat-form-field> + </div> + </div> + </mat-step> + + + <mat-step> + <ng-template matStepLabel>Select Format</ng-template> + <div> + <h5>Download Format</h5> + <mat-radio-group class="sp-radio-group" [(ngModel)]="downloadFormat"> + <mat-radio-button value="json" class="sp-radio-button"> + JSON + </mat-radio-button> + <mat-radio-button value="csv" class="sp-radio-button"> + CSV + </mat-radio-button> + </mat-radio-group> + </div> + <div *ngIf="downloadFormat === 'csv'" class="mt-10"> + <h5>Delimiter</h5> + <mat-radio-group [(ngModel)]="delimiter" class="sp-radio-group"> + <mat-radio-button value="comma" class="sp-radio-button"> ,</mat-radio-button> + <mat-radio-button value="semicolon" class="sp-radio-button"> ;</mat-radio-button> + </mat-radio-group> + </div> + </mat-step> + + + <mat-step> + <ng-template matStepLabel>Download</ng-template> + <div fxFlex="100" fxLayout="column" fxLayoutAlign="center center" *ngIf="!downloadFinish" class="mt-35"> + <mat-spinner [diameter]="30" color="accent"></mat-spinner> + <label *ngIf="downloadedMBs !== undefined">{{downloadedMBs | number : '1.0-2' }} Mb</label> + <button mat-button warn color="warn" (click)="cancelDownload()">Cancel</button> + </div> + <div fxLayout="column" fxLayoutAlign="space-around center" *ngIf="downloadFinish"> + <mat-icon class="icon-check">check</mat-icon> + <h5>Download successful</h5> + </div> + </mat-step> + </mat-horizontal-stepper> + + </div> + </div> + + <mat-divider></mat-divider> + <div class="sp-dialog-actions actions-align-right"> + <button mat-button mat-raised-button class="mat-basic" style="margin-right: 10px;" (click)="exitDialog()">Close</button> + <button mat-button mat-raised-button class="mat-basic" style="margin-right: 10px;" *ngIf="stepper.selectedIndex == 1" (click)="previousStep()">Previous</button> + <button mat-button mat-raised-button *ngIf="stepper.selectedIndex < 1" color="accent" (click)="nextStep()"> + Next + </button> + <button mat-button mat-raised-button *ngIf="stepper.selectedIndex == 1" color="accent" (click)="downloadData()"> + Download + </button> + </div> +</div>
diff --git a/ui/src/app/data-explorer/components/datadownloadDialog/dataDownload.dialog.css b/ui/src/app/core-ui/data-download-dialog/data-download-dialog.component.scss similarity index 93% rename from ui/src/app/data-explorer/components/datadownloadDialog/dataDownload.dialog.css rename to ui/src/app/core-ui/data-download-dialog/data-download-dialog.component.scss index 0ff348e..1a799af 100644 --- a/ui/src/app/data-explorer/components/datadownloadDialog/dataDownload.dialog.css +++ b/ui/src/app/core-ui/data-download-dialog/data-download-dialog.component.scss
@@ -16,12 +16,14 @@ * */ -example-radio-group { +@import 'src/scss/sp/sp-dialog'; + +.sp-radio-group { display: flex; flex-direction: column; margin: 15px 0; } -.example-radio-button { +.sp-radio-button { margin: 5px; width: 100%; } @@ -59,6 +61,10 @@ margin-left: 35px; } +.mt-35 { + margin-top: 35px; +} + .form-field-date { top: -10px; width: 270px;
diff --git a/ui/src/app/core-ui/data-download-dialog/data-download-dialog.component.ts b/ui/src/app/core-ui/data-download-dialog/data-download-dialog.component.ts new file mode 100644 index 0000000..b68aadd --- /dev/null +++ b/ui/src/app/core-ui/data-download-dialog/data-download-dialog.component.ts
@@ -0,0 +1,234 @@ +/* + * 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 { HttpEventType } from '@angular/common/http'; +import { Component, Input, OnInit, ViewChild } from '@angular/core'; +import { MatStepper } from '@angular/material/stepper'; +import { + DataExplorerDataConfig, + DatalakeQueryParameters, + DatalakeRestService, + DataViewQueryGeneratorService, + DateRange +} from '@streampipes/platform-services'; +import { DialogRef } from '@streampipes/shared-ui'; + + +@Component({ + selector: 'sp-data-download-dialog', + templateUrl: 'data-download-dialog.component.html', + styleUrls: ['./data-download-dialog.component.scss'] +}) +// tslint:disable-next-line:component-class-suffix +export class DataDownloadDialogComponent implements OnInit { + + /** + * Provide either measureName without additional configuration + * or dataConfig to allow selection of multiple sources + */ + @Input() measureName: string; + @Input() dataConfig: DataExplorerDataConfig; + + @Input() date: DateRange; + + downloadFormat = 'csv'; + delimiter = 'comma'; + selectedData = 'visible'; + downloadFinish = false; + downloadedMBs: number = undefined; + selectedQueryIndex = 0; + + @ViewChild('stepper', {static: true}) stepper: MatStepper; + + downloadHttpRequestSubscribtion; + + dateRange: Date [] = []; // [0] start, [1] end + + + constructor(public dialogRef: DialogRef<DataDownloadDialogComponent>, + public datalakeRestService: DatalakeRestService, + private dataViewQueryService: DataViewQueryGeneratorService) { + } + + ngOnInit() { + if (!this.date) { + const endDate = new Date(); + endDate.setDate(endDate.getDate() - 5); + this.date = {startDate: new Date(), endDate}; + } + this.dateRange[0] = this.date.startDate; + this.dateRange[1] = this.date.endDate; + + if (!this.dataConfig) { + this.selectedData = 'all'; + } + } + + downloadData() { + const index = !this.dataConfig ? + this.measureName : this.dataConfig.sourceConfigs[this.selectedQueryIndex].measureName; + this.nextStep(); + const startTime = this.date.startDate.getTime(); + const endTime = this.date.endDate.getTime(); + const startDateString = this.getDateString(this.date.startDate); + const endDateString = this.getDateString(this.date.endDate); + switch (this.selectedData) { + case 'all': + this.performRequest(this.datalakeRestService.downloadRawData( + index, + this.downloadFormat, + this.delimiter), '', ''); + break; + case 'customInterval': + this.performRequest(this.datalakeRestService.downloadRawData( + index, + this.downloadFormat, + this.delimiter, + startTime, + endTime), startDateString, + endDateString); + break; + case 'visible': + this.performRequest( + this.datalakeRestService + .downloadQueriedData( + index, + this.downloadFormat, + this.delimiter, + this.generateQueryRequest(startTime, endTime) + ), + startDateString, + endDateString + ); + + } + } + + generateQueryRequest(startTime: number, + endTime: number): DatalakeQueryParameters { + return this.dataViewQueryService + .generateQuery(startTime, endTime, this.dataConfig.sourceConfigs[this.selectedQueryIndex]); + } + + performRequest(request, startDate, endDate) { + this.downloadHttpRequestSubscribtion = request.subscribe(event => { + // progress + if (event.type === HttpEventType.DownloadProgress) { + this.downloadedMBs = event.loaded / 1024 / 1014; + } + + // finished + if (event.type === HttpEventType.Response) { + this.createFile(event.body, this.downloadFormat, this.measureName, startDate, endDate); + this.downloadFinish = true; + } + }); + } + + convertData(data, format, xAxesKey, yAxesKeys) { + const indexXKey = data.headers.findIndex(headerName => headerName === xAxesKey); + const indicesYKeys = []; + yAxesKeys.forEach(key => { + indicesYKeys.push(data.headers.findIndex(headerName => headerName === key)); + }); + + if (format === 'json') { + const resultJson = []; + + + data.rows.forEach(row => { + const tmp = {'time': new Date(row[indexXKey]).getTime()}; + indicesYKeys.forEach(index => { + if (row[index] !== undefined) { + tmp[data.headers[index]] = row[index]; + } + }); + resultJson.push(tmp); + }); + + return JSON.stringify(resultJson); + } else { + // CSV + let resultCsv = ''; + + // header + resultCsv += xAxesKey; + yAxesKeys.forEach(key => { + resultCsv += ';'; + resultCsv += key; + }); + + + // content + data.rows.forEach(row => { + resultCsv += '\n'; + resultCsv += new Date(row[indexXKey]).getTime(); + indicesYKeys.forEach(index => { + resultCsv += ';'; + if (row[index] !== undefined) { + resultCsv += row[index]; + } + }); + }); + + return resultCsv; + } + } + + createFile(data, format, fileName, startDate, endDate) { + const a = document.createElement('a'); + document.body.appendChild(a); + a.style.display = 'display: none'; + + let name = 'sp_' + startDate + '_' + fileName + '.' + this.downloadFormat; + name = name.replace('__', '_'); + + const url = window.URL.createObjectURL(new Blob([String(data)], {type: 'data:text/' + format + ';charset=utf-8'})); + a.href = url; + a.download = name; + a.click(); + window.URL.revokeObjectURL(url); + } + + cancelDownload() { + try { + this.downloadHttpRequestSubscribtion.unsubscribe(); + } finally { + this.exitDialog(); + } + } + + + exitDialog(): void { + this.dialogRef.close(); + } + + nextStep() { + this.stepper.next(); + } + + previousStep() { + this.stepper.previous(); + } + + getDateString(date: Date): string { + return date.toLocaleDateString() + 'T' + date.toLocaleTimeString().replace(':', '.') + .replace(':', '.'); + } + +}
diff --git a/ui/src/app/core-ui/pipeline-element-template-config/pipeline-element-template-config.component.html b/ui/src/app/core-ui/pipeline-element-template-config/pipeline-element-template-config.component.html new file mode 100644 index 0000000..712119d --- /dev/null +++ b/ui/src/app/core-ui/pipeline-element-template-config/pipeline-element-template-config.component.html
@@ -0,0 +1,73 @@ +<!-- + ~ 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="p-15"> + <div fxFlex="100" fxLayout="column"> + <h4>Basics</h4> + <mat-form-field fxFlex color="accent"> + <mat-label>Template name</mat-label> + <input [(ngModel)]="template.templateName" matInput name="templateName" class="sp" required/> + </mat-form-field> + <mat-form-field fxFlex color="accent"> + <mat-label>Template description</mat-label> + <input [(ngModel)]="template.templateDescription" matInput name="templateDescription" class="sp" + required/> + </mat-form-field> + <!-- <mat-checkbox class="sp" color="accent">Make available as pipeline element</mat-checkbox>--> + <mat-divider class="divider"></mat-divider> + <h4>Configuration</h4> + <mat-hint style="margin-bottom: 10px;">(dynamic options cannot be saved and are hidden)</mat-hint> + <div fxLayout="column" *ngFor="let config of staticProperties | pipelineElementTemplatePipe" + class="static-property-panel static-property-panel-border"> + <div fxLayout="row"> + <div fxFlex="50"> + {{config.label}} + </div> + <div fxFlex="50"> + <div fxLayout="column"> + <mat-checkbox [checked]="templateConfigs.has(config.internalName)" + (change)="handleSelection(config)" name="store" class="sp" color="accent">Store + as template + </mat-checkbox> + <!-- <mat-checkbox *ngIf="templateConfigs.has(config.internalName)"--> + <!-- (click)="toggleViewPermission(config)" name="displayed"--> + <!-- class="sp" color="primary">Users can view--> + <!-- </mat-checkbox>--> + <!-- <mat-checkbox *ngIf="templateConfigs.has(config.internalName)"--> + <!-- (click)="toggleEditPermission(config)" name="editable"--> + <!-- class="sp" color="primary">Users can modify--> + <!-- </mat-checkbox>--> + </div> + </div> + </div> + + </div> + <mat-divider class="divider"></mat-divider> + <h4>Existing templates</h4> + <div fxLayout="column" *ngFor="let template of existingTemplates" class="static-property-panel static-property-panel-border"> + <div fxFlex="100" fxLayout="row"> + <div fxFlex fxLayoutAlign="start center">{{template.templateName}}</div> + <div fxLayoutAlign="end center"> + <button mat-icon-button color="accent" (click)="deleteTemplate(template._id)"><mat-icon>delete</mat-icon></button> + </div> + </div> + </div> + <mat-hint style="margin-bottom: 10px;" *ngIf="existingTemplates.length === 0">(no templates available)</mat-hint> + + </div> +</div>
diff --git a/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.scss b/ui/src/app/core-ui/pipeline-element-template-config/pipeline-element-template-config.component.scss similarity index 95% rename from ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.scss rename to ui/src/app/core-ui/pipeline-element-template-config/pipeline-element-template-config.component.scss index 2c1a70e..c232acd 100644 --- a/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.scss +++ b/ui/src/app/core-ui/pipeline-element-template-config/pipeline-element-template-config.component.scss
@@ -16,7 +16,7 @@ * */ -@import '../../../../scss/sp/sp-dialog.scss'; +@import 'src/scss/sp/sp-dialog'; .divider { margin-top: 10px;
diff --git a/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.ts b/ui/src/app/core-ui/pipeline-element-template-config/pipeline-element-template-config.component.ts similarity index 76% rename from ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.ts rename to ui/src/app/core-ui/pipeline-element-template-config/pipeline-element-template-config.component.ts index a9e3064..e8a7f78 100644 --- a/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.ts +++ b/ui/src/app/core-ui/pipeline-element-template-config/pipeline-element-template-config.component.ts
@@ -17,10 +17,10 @@ */ import { Component, Input, OnInit } from '@angular/core'; -import { InvocablePipelineElementUnion } from '../../model/editor.model'; import { + PipelineElementTemplateService, PipelineElementTemplate, - StaticPropertyUnion + StaticPropertyUnion, } from '@streampipes/platform-services'; import { PipelineElementTemplateGenerator } from './pipeline-element-template-generator'; @@ -32,22 +32,38 @@ export class PipelineElementTemplateConfigComponent implements OnInit { @Input() - cachedPipelineElement: InvocablePipelineElementUnion; - - @Input() template: PipelineElementTemplate; @Input() templateConfigs: Map<string, any>; + @Input() + appId: string; + + @Input() + staticProperties: StaticPropertyUnion[]; + + existingTemplates: PipelineElementTemplate[]; + + constructor(private pipelineElementTemplateService: PipelineElementTemplateService) { + + } + ngOnInit(): void { - this.template.basePipelineElementAppId = this.cachedPipelineElement.appId; - this.cachedPipelineElement.staticProperties.forEach(sp => { + this.loadTemplates(); + this.template.basePipelineElementAppId = this.appId; + this.staticProperties.forEach(sp => { this.templateConfigs.set(sp.internalName, this.makeTemplateValue(sp)); }); } + loadTemplates() { + this.pipelineElementTemplateService.getPipelineElementTemplates(this.appId).subscribe(templates => { + this.existingTemplates = templates; + }); + } + handleSelection(sp: StaticPropertyUnion) { if (this.templateConfigs.has(sp.internalName)) { this.templateConfigs.delete(sp.internalName); @@ -76,4 +92,9 @@ this.templateConfigs.set(sp.internalName, config); } + deleteTemplate(templateId: string) { + this.pipelineElementTemplateService + .deletePipelineElementTemplate(templateId).subscribe(result => this.loadTemplates()); + } + }
diff --git a/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-generator.ts b/ui/src/app/core-ui/pipeline-element-template-config/pipeline-element-template-generator.ts similarity index 92% rename from ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-generator.ts rename to ui/src/app/core-ui/pipeline-element-template-config/pipeline-element-template-generator.ts index 72366e3..4d7c830 100644 --- a/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-generator.ts +++ b/ui/src/app/core-ui/pipeline-element-template-config/pipeline-element-template-generator.ts
@@ -27,7 +27,8 @@ SecretStaticProperty, StaticPropertyAlternative, StaticPropertyAlternatives, StaticPropertyGroup, - StaticPropertyUnion + StaticPropertyUnion, + SlideToggleStaticProperty } from '@streampipes/platform-services'; export class PipelineElementTemplateGenerator { @@ -49,6 +50,8 @@ return this.sp.options.filter(o => o.selected).map(o => o.name); } else if (this.sp instanceof CodeInputStaticProperty) { return this.sp.value; + } else if (this.sp instanceof SlideToggleStaticProperty) { + return this.sp.selected; } else if (this.sp instanceof CollectionStaticProperty) { return { members: this.addListEntry(this.sp.members) @@ -60,9 +63,10 @@ alternatives: this.addNestedEntry(this.sp.alternatives) }; } else if (this.sp instanceof StaticPropertyAlternative) { + const sp = this.sp.staticProperty ? this.addNestedEntry([this.sp.staticProperty]) : {}; return { selected: this.sp.selected, - staticProperty: this.addNestedEntry([this.sp.staticProperty]) + staticProperty: sp }; } else if (this.sp instanceof StaticPropertyGroup) { return { staticProperties: this.addNestedEntry(this.sp.staticProperties)};
diff --git a/ui/src/app/core-ui/pipeline-element-template-config/pipeline-element-template.pipe.ts b/ui/src/app/core-ui/pipeline-element-template-config/pipeline-element-template.pipe.ts new file mode 100644 index 0000000..f44b8aa --- /dev/null +++ b/ui/src/app/core-ui/pipeline-element-template-config/pipeline-element-template.pipe.ts
@@ -0,0 +1,37 @@ +/* + * 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, Pipe, PipeTransform } from '@angular/core'; +import { + RuntimeResolvableAnyStaticProperty, RuntimeResolvableOneOfStaticProperty, RuntimeResolvableTreeInputStaticProperty, + StaticPropertyUnion +} from '@streampipes/platform-services'; + +@Pipe({name: 'pipelineElementTemplatePipe'}) +@Injectable({providedIn: 'root'}) +export class PipelineElementTemplatePipe implements PipeTransform { + + transform(properties: StaticPropertyUnion[]): StaticPropertyUnion[] { + + return properties.filter(p => ( + !(p instanceof RuntimeResolvableAnyStaticProperty) && + !(p instanceof RuntimeResolvableOneOfStaticProperty && + !(p instanceof RuntimeResolvableTreeInputStaticProperty)))); + } + +}
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 6e3b6e4..19c514a 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
@@ -24,8 +24,8 @@ <mat-radio-button [value]="false">Upload new file</mat-radio-button> </mat-radio-group> </div> - <div *ngIf="chooseExistingFileControl.value && filesLoaded" > - <mat-form-field> + <div *ngIf="chooseExistingFileControl.value && filesLoaded" class="mt-10"> + <mat-form-field color="accent" class="w-100"> <input type="text" placeholder="Select file" formControlName="{{fieldName}}" @@ -34,7 +34,7 @@ <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-autocomplete #auto="matAutocomplete" (optionSelected)="selectOption($event.option.value)" [displayWith]="displayFn" style="width: 50%;"> <mat-option *ngFor="let fileMetadata of fileMetadata" [value]="fileMetadata"> {{fileMetadata.originalFilename}} </mat-option>
diff --git a/ui/src/app/core-ui/static-properties/static-free-input/static-free-input.component.ts b/ui/src/app/core-ui/static-properties/static-free-input/static-free-input.component.ts index 15eff2f..fd3bb56 100644 --- a/ui/src/app/core-ui/static-properties/static-free-input/static-free-input.component.ts +++ b/ui/src/app/core-ui/static-properties/static-free-input/static-free-input.component.ts
@@ -38,10 +38,10 @@ quillModules: any = { toolbar: [['bold', 'italic', 'underline', 'strike'], - [{ 'header': 1 }, { 'header': 2 }], - [{ 'size': ['small', false, 'large', 'huge'] }], - [{ 'header': [1, 2, 3, 4, 5, 6, false] }], - [{ 'color': [] }, { 'background': [] }] + [{'header': 1}, {'header': 2}], + [{'size': ['small', false, 'large', 'huge']}], + [{'header': [1, 2, 3, 4, 5, 6, false]}], + [{'color': []}, {'background': []}] ] }; @@ -50,7 +50,7 @@ ] }; - @ViewChild('textEditor', { static: false }) + @ViewChild('textEditor', {static: false}) quillEditorComponent: QuillEditorComponent; constructor(public staticPropertyUtil: StaticPropertyUtilService, @@ -62,6 +62,7 @@ ngOnInit() { this.addValidator(this.staticProperty.value, this.collectValidators()); this.enableValidators(); + this.emitUpdate(); } collectValidators() { @@ -83,7 +84,9 @@ } emitUpdate() { - const valid = (this.staticProperty.value !== undefined && this.staticProperty.value !== ''); + const valid = (this.staticProperty.value !== undefined && + this.staticProperty.value !== '' && + this.staticProperty.value !== null); this.updateEmitter.emit(new ConfigurationInfo(this.staticProperty.internalName, valid)); }
diff --git a/ui/src/app/core-ui/static-properties/static-property.component.html b/ui/src/app/core-ui/static-properties/static-property.component.html index 308ce51..c7d8967 100644 --- a/ui/src/app/core-ui/static-properties/static-property.component.html +++ b/ui/src/app/core-ui/static-properties/static-property.component.html
@@ -68,6 +68,7 @@ [staticProperties]="staticProperties" [eventSchemas]="eventSchemas" [pipelineElement]="pipelineElement" + [parentForm]="parentForm" [completedStaticProperty]="completedStaticProperty" [adapterId]="adapterId"> </app-static-runtime-resolvable-any-input> @@ -77,6 +78,7 @@ [pipelineElement]="pipelineElement" [eventSchemas]="eventSchemas" [staticProperty]="staticProperty" + [parentForm]="parentForm" [staticProperties]="staticProperties" [adapterId]="adapterId"></app-static-runtime-resolvable-oneof-input>
diff --git a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.html b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.html index 211cce1..9e287ba 100644 --- a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.html +++ b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.html
@@ -32,7 +32,7 @@ {{option.name}} </mat-checkbox> </div> - <div fxLayout="column" *ngIf="!showOptions && !loading"> + <div fxLayout="column" *ngIf="!showOptions && !loading" class="mt-10"> <span>(waiting for input)</span> </div> <div fxLayout="column" *ngIf="loading">
diff --git a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.ts b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.ts index b24bc7a..c1589be 100644 --- a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.ts +++ b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.ts
@@ -53,4 +53,7 @@ return staticProperty as RuntimeResolvableAnyStaticProperty; } + afterErrorReceived() { + } + }
diff --git a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-input/base-runtime-resolvable-input.ts b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-input/base-runtime-resolvable-input.ts index 229beba..b2f33e3 100644 --- a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-input/base-runtime-resolvable-input.ts +++ b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-input/base-runtime-resolvable-input.ts
@@ -30,6 +30,7 @@ import { Observable } from 'rxjs'; import { Directive, Input, OnChanges, SimpleChanges } from '@angular/core'; import { ConfigurationInfo } from '../../../connect/model/ConfigurationInfo'; +import { StreamPipesErrorMessage } from '../../../../../projects/streampipes/platform-services/src/lib/model/gen/streampipes-model'; @Directive() // tslint:disable-next-line:directive-class-suffix @@ -43,6 +44,8 @@ showOptions = false; loading = false; + error = false; + errorMessage: StreamPipesErrorMessage; dependentStaticProperties: any = new Map(); constructor(private runtimeResolvableService: RuntimeResolvableService) { @@ -70,6 +73,8 @@ this.showOptions = false; this.loading = true; + this.error = false; + this.errorMessage = undefined; const observable: Observable<RuntimeOptionsResponse> = this.adapterId ? this.runtimeResolvableService.fetchRemoteOptionsForAdapter(resolvableOptionsParameterRequest, this.adapterId) : this.runtimeResolvableService.fetchRemoteOptionsForPipelineElement(resolvableOptionsParameterRequest); @@ -80,6 +85,12 @@ } this.loading = false; this.showOptions = true; + }, errorMessage => { + this.loading = false; + this.showOptions = true; + this.error = true; + this.errorMessage = errorMessage.error as StreamPipesErrorMessage; + this.afterErrorReceived(); }); } @@ -107,4 +118,6 @@ abstract afterOptionsLoaded(staticProperty: T); + abstract afterErrorReceived(); + }
diff --git a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-oneof-input/static-runtime-resolvable-oneof-input.component.html b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-oneof-input/static-runtime-resolvable-oneof-input.component.html index e58f8ad..3f1ff10 100644 --- a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-oneof-input/static-runtime-resolvable-oneof-input.component.html +++ b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-oneof-input/static-runtime-resolvable-oneof-input.component.html
@@ -16,7 +16,7 @@ ~ --> -<div id="formWrapper" fxFlex="100" fxLayout="column"> +<div [formGroup]="parentForm" id="formWrapper" fxFlex="100" fxLayout="column"> <div> <button mat-button mat-raised-button color="accent" class="small-button" data-cy="sp-reload" @@ -26,7 +26,10 @@ <span>Reload</span> </button> </div> - <div *ngIf="!staticProperty.horizontalRendering" fxLayout="column"> + <div fxLayout="column" *ngIf="error" class="mt-10"> + <sp-exception-message [message]="errorMessage"></sp-exception-message> + </div> + <div *ngIf="!loading" fxLayout="column"> <div fxFlex fxLayout="row"> <div fxLayout="column" *ngIf="showOptions || staticProperty.options" style="margin-left: 10px"> <mat-radio-button *ngFor="let option of staticProperty.options" @@ -38,7 +41,7 @@ </label> </mat-radio-button> </div> - <div fxLayout="column" *ngIf="!showOptions && !loading"> + <div fxLayout="column" *ngIf="!showOptions && !loading" class="mt-10"> <span>(waiting for input)</span> </div> <div fxLayout="column" *ngIf="loading"> @@ -49,21 +52,4 @@ </div> </div> </div> - - <div *ngIf="staticProperty.horizontalRendering"> - <mat-form-field style="width: 100%"> - <mat-label>{{staticProperty.label}}</mat-label> - <span matPrefix *ngIf="loading"><mat-spinner style="top:5px" [diameter]="20"></mat-spinner></span> - <mat-select> - <mat-option *ngFor="let option of staticProperty.options" [value]="option.elementId" - (click)="select(option.elementId)"> - <label style="font-weight: normal"> - {{option.name}} - </label> - </mat-option> - </mat-select> - <mat-hint>{{staticProperty.description}}</mat-hint> - </mat-form-field> - </div> - </div>
diff --git a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-oneof-input/static-runtime-resolvable-oneof-input.component.ts b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-oneof-input/static-runtime-resolvable-oneof-input.component.ts index a6c12b1..f5b973c 100644 --- a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-oneof-input/static-runtime-resolvable-oneof-input.component.ts +++ b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-oneof-input/static-runtime-resolvable-oneof-input.component.ts
@@ -20,6 +20,7 @@ import { RuntimeResolvableOneOfStaticProperty, StaticPropertyUnion } from '@streampipes/platform-services'; import { RuntimeResolvableService } from '../static-runtime-resolvable-input/runtime-resolvable.service'; import { BaseRuntimeResolvableSelectionInput } from '../static-runtime-resolvable-input/base-runtime-resolvable-selection-input'; +import { FormControl } from '@angular/forms'; @Component({ selector: 'app-static-runtime-resolvable-oneof-input', @@ -35,6 +36,8 @@ ngOnInit() { super.onInit(); + this.parentForm.addControl(this.staticProperty.internalName, new FormControl(this.staticProperty.options, [])); + this.performValidation(); } afterOptionsLoaded(staticProperty: RuntimeResolvableOneOfStaticProperty) { @@ -49,9 +52,24 @@ option.selected = false; } this.staticProperty.options.find(option => option.elementId === id).selected = true; + this.performValidation(); } parse(staticProperty: StaticPropertyUnion): RuntimeResolvableOneOfStaticProperty { return staticProperty as RuntimeResolvableOneOfStaticProperty; } + + afterErrorReceived() { + this.staticProperty.options = []; + this.performValidation(); + } + + performValidation() { + let error = {error: true}; + if (this.staticProperty.options && this.staticProperty.options.find(o => o.selected) !== undefined) { + error = undefined; + } + console.log(error); + this.parentForm.controls[this.staticProperty.internalName].setErrors(error); + } }
diff --git a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input.component.html b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input.component.html index 753c76a..49e036d 100644 --- a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input.component.html +++ b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input.component.html
@@ -20,10 +20,18 @@ <div> <button mat-button mat-raised-button color="accent" class="small-button" (click)="loadOptionsFromRestApi()" - style="margin-right:10px;margin-left:10px;" [disabled]="!showOptions"> + style="margin-right:10px;" [disabled]="!showOptions"> <span>Reload</span> </button> </div> + <div fxLayout="column" *ngIf="loading" class="mt-10"> + <mat-spinner color="accent" + [mode]="'indeterminate'" + [diameter]="20"></mat-spinner> + </div> + <div fxLayout="column" *ngIf="error" class="mt-10"> + <sp-exception-message [message]="errorMessage"></sp-exception-message> + </div> <mat-tree [dataSource]="dataSource" [treeControl]="treeControl" class="sp-tree"> <mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle> <mat-checkbox color="accent"
diff --git a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input.component.ts b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input.component.ts index 3be9378..cb2fa18 100644 --- a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input.component.ts +++ b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input.component.ts
@@ -26,6 +26,7 @@ import { RuntimeResolvableService } from '../static-runtime-resolvable-input/runtime-resolvable.service'; import { NestedTreeControl } from '@angular/cdk/tree'; import { MatTreeNestedDataSource } from '@angular/material/tree'; +import { AbstractControl, FormControl, ValidationErrors, ValidatorFn } from '@angular/forms'; @Component({ selector: 'sp-runtime-resolvable-tree-input', @@ -55,6 +56,7 @@ this.showOptions = true; } super.onInit(); + this.parentForm.addControl(this.staticProperty.internalName, new FormControl(this.staticProperty.nodes, [])); } parse(staticProperty: StaticPropertyUnion): RuntimeResolvableTreeInputStaticProperty { @@ -64,10 +66,12 @@ afterOptionsLoaded(staticProperty: RuntimeResolvableTreeInputStaticProperty) { this.staticProperty.nodes = staticProperty.nodes; this.dataSource.data = this.staticProperty.nodes; + this.performValidation(); } toggleNodeSelection(node: TreeInputNode) { node.selected = !node.selected; + this.performValidation(); } toggleAllNodeSelection(node: any) { @@ -75,6 +79,7 @@ const newState = !node.selected; node.selected = newState; descendants.forEach(d => d.selected = newState); + this.performValidation(); } descendantsAllSelected(node: TreeInputNode) { @@ -93,4 +98,30 @@ return result && !this.descendantsAllSelected(node); } + performValidation() { + let error = {error: true}; + if (this.anyNodeSelected()) { + error = undefined; + } + this.parentForm.controls[this.staticProperty.internalName].setErrors(error); + } + + anyNodeSelected(): boolean { + return this.dataSource.data.find(d => this.anySelected(d)) !== undefined; + } + + anySelected(node: TreeInputNode): boolean { + if (node.selected) { + return true; + } else { + return node.children.find(n => this.anySelected(n)) !== undefined; + } + } + + afterErrorReceived() { + this.staticProperty.nodes = []; + this.dataSource.data = []; + this.performValidation(); + } + }
diff --git a/ui/src/app/core-ui/static-properties/static-secret-input/static-secret-input.component.html b/ui/src/app/core-ui/static-properties/static-secret-input/static-secret-input.component.html index 54f9ac5..4206ab8 100644 --- a/ui/src/app/core-ui/static-properties/static-secret-input/static-secret-input.component.html +++ b/ui/src/app/core-ui/static-properties/static-secret-input/static-secret-input.component.html
@@ -18,7 +18,7 @@ <div [formGroup]="parentForm" id="formWrapper" fxFlex="100" fxLayout="column"> <div fxFlex="100" fxLayout="row"> - <mat-form-field fxFlex> + <mat-form-field fxFlex color="accent"> <input type="password" fxFlex formControlName="{{fieldName}}" @@ -34,4 +34,4 @@ </mat-error> </mat-form-field> </div> -</div> \ No newline at end of file +</div>
diff --git a/ui/src/app/core/components/breadcrumb/breadcrumb.component.html b/ui/src/app/core/components/breadcrumb/breadcrumb.component.html new file mode 100644 index 0000000..c605f1f --- /dev/null +++ b/ui/src/app/core/components/breadcrumb/breadcrumb.component.html
@@ -0,0 +1,30 @@ +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~ + --> + +<div fxLayout="column" fxFlex="100" class="breadcrumb-outer" fxLayoutAlign="center start"> + <div fxLayout="row" fxLayoutAlign="start center"> + <div [ngClass]="currentNavItems.length > 0 ? 'bc-item' : 'mat-hint'" fxLayout="row" fxLayoutAlign="start center" (click)="navigateTo([''])"> + <mat-icon fxLayoutAlign="start center" class="divider">home</mat-icon> + <div> Home</div> + </div> + <div *ngFor="let bcItem of currentNavItems" fxLayout="row" fxLayoutAlign="start center"> + <mat-icon fxLayoutAlign="start center" class="divider mat-hint">arrow_right</mat-icon> + <div [ngClass]="bcItem.link ? 'bc-item' : 'mat-hint'" (click)="navigateTo(bcItem.link)">{{bcItem.label}}</div> + </div> + </div> +</div>
diff --git a/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.scss b/ui/src/app/core/components/breadcrumb/breadcrumb.component.scss similarity index 76% copy from ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.scss copy to ui/src/app/core/components/breadcrumb/breadcrumb.component.scss index 2c1a70e..d3b603e 100644 --- a/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.scss +++ b/ui/src/app/core/components/breadcrumb/breadcrumb.component.scss
@@ -16,19 +16,21 @@ * */ -@import '../../../../scss/sp/sp-dialog.scss'; +.breadcrumb-outer { + margin: 10px 10px 0 10px; + max-height: 20px; + height: 20px; + font-size: 10pt; + color: var(--color-accent); +} .divider { - margin-top: 10px; - margin-bottom: 10px; + font-size: 10pt; + width: 10pt; + height: 10pt; } -.static-property-panel { - padding-left: 10px; - margin-bottom: 10px; - margin-top: 10px; -} - -.static-property-panel-border { - border-left:5px solid gray; +.bc-item:hover { + color: var(--color-primary); + cursor: pointer; }
diff --git a/ui/src/app/core/components/breadcrumb/breadcrumb.component.ts b/ui/src/app/core/components/breadcrumb/breadcrumb.component.ts new file mode 100644 index 0000000..17c8488 --- /dev/null +++ b/ui/src/app/core/components/breadcrumb/breadcrumb.component.ts
@@ -0,0 +1,49 @@ +/* + * 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 { SpBreadcrumbItem, SpBreadcrumbService } from '@streampipes/shared-ui'; +import { Router } from '@angular/router'; + +@Component({ + selector: 'sp-breadcrumb', + templateUrl: './breadcrumb.component.html', + styleUrls: ['./breadcrumb.component.scss'] +}) +export class SpBreadcrumbComponent implements OnInit { + + currentNavItems: SpBreadcrumbItem[] = []; + + constructor(private breadcrumbService: SpBreadcrumbService, + private router: Router) { + + } + + ngOnInit(): void { + this.breadcrumbService.currentNavHierarchy$.subscribe(currentNavItems => { + this.currentNavItems = currentNavItems; + }); + } + + navigateTo(target: string[]) { + this.router.navigate(target); + } + + + +}
diff --git a/ui/src/app/core/components/feedback/feedback.component.html b/ui/src/app/core/components/feedback/feedback.component.html deleted file mode 100644 index 781c749..0000000 --- a/ui/src/app/core/components/feedback/feedback.component.html +++ /dev/null
@@ -1,64 +0,0 @@ -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one or more - ~ contributor license agreements. See the NOTICE file distributed with - ~ this work for additional information regarding copyright ownership. - ~ The ASF licenses this file to You under the Apache License, Version 2.0 - ~ (the "License"); you may not use this file except in compliance with - ~ the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - ~ - --> - -<div class="feedback-container" (click) = "$event.stopPropagation()"> - <div fxLayout="column" fxFlex="100" *ngIf="!sendingFeedback"> - <div fxLayout="column" fxFlex="50" fxLayoutAlign="start center"> - <div class="feedback-title">We welcome your feedback!</div> - </div> - <div fxLayout="column" fxFlex="40" fxLayoutAlign="start center" style="margin-bottom:20px;"> - <div fxFlex="100" class="feedback-explainer"> - <span>Your feedback helps us to improve {{appConstants.APP_NAME}}.<br/></span> - <span>Features you'd like to see, bugs you've found or things you like - tell us what you think!</span> - </div> - </div> - <div fxLayout="column" fxFlex="40" fxLayoutAlign="start center" style="margin-bottom:20px;"> - <mat-form-field class="feedback-width-100 feedback-font-size-small" color="accent"> - <label>Your feedback</label> - <textarea matInput [(ngModel)]="feedback.feedbackText" maxlength="500" rows="5"></textarea> - </mat-form-field> - </div> - <div fxLayout="column" fxFlex="40" fxLayoutAlign="end center"> - <div fxLayout="row" fxLayoutAlign="end end"> - <button mat-button mat-raised-button class="mat-basic" (click)="closeDialog()" style="margin-right:10px;"> - Close - </button> - <button mat-button mat-raised-button color="accent" type="submit" - (click)="sendMail()"> - Send Mail - </button> - </div> - </div> - </div> - <div fxFlex="100" fxLayout="column" *ngIf="sendingFeedback" class="feedback-height-100"> - <div *ngIf="!sendingFeedbackFinished" class="feedback-height-100"> - <div fxLayout="column" fxLayoutAlign="center center" fxFlex="100" fxLayoutFill> - <mat-spinner [mode]="'indeterminate'" [diameter]="96"></mat-spinner> - <div class="feedback-status">Submitting feedback...</div> - </div> - </div> - <div *ngIf="sendingFeedbackFinished" fxFlex="100" class="feedback-height-100"> - <div fxLayout="column" fxLayoutAlign="center center" fxFlex="100" fxLayoutFill> - <div class="feedback-status">Thanks!</div> - <button mat-button mat-raised-button class="mat-basic" (click)="closeDialog()"> - Close - </button> - </div> - </div> - </div> -</div>
diff --git a/ui/src/app/core/components/feedback/feedback.component.ts b/ui/src/app/core/components/feedback/feedback.component.ts deleted file mode 100644 index e27e46a..0000000 --- a/ui/src/app/core/components/feedback/feedback.component.ts +++ /dev/null
@@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Component, EventEmitter, OnInit, Output } from '@angular/core'; -import { AppConstants } from '../../../services/app.constants'; - -@Component({ - selector: 'feedback', - templateUrl: './feedback.component.html', -}) -export class FeedbackComponent implements OnInit { - - @Output() - closeFeedbackEmitter: EventEmitter<void> = new EventEmitter<void>(); - - feedback: any = {}; - - sendingFeedback = false; - sendingFeedbackFinished = false; - - // deactivate direct feedback for Apache transition - feedbackUrl = ''; - debugFeedbackUrl = ''; - - targetEmail: string; - - constructor(public appConstants: AppConstants) { - this.targetEmail = appConstants.EMAIL; - } - - ngOnInit() { - this.sendingFeedback = false; - this.sendingFeedbackFinished = false; - } - - closeDialog() { - this.closeFeedbackEmitter.emit(); - this.sendingFeedback = false; - this.sendingFeedbackFinished = false; - } - - sendMail() { - this.sendingFeedback = true; - window.open('mailto:' + this.targetEmail + '?subject=' + '[USER-FEEDBACK]' + '&body=' + this.feedback.feedbackText, '_self'); - this.sendingFeedbackFinished = true; - } -}
diff --git a/ui/src/app/core/components/iconbar/iconbar.component.html b/ui/src/app/core/components/iconbar/iconbar.component.html index a04b784..4cd727d 100644 --- a/ui/src/app/core/components/iconbar/iconbar.component.html +++ b/ui/src/app/core/components/iconbar/iconbar.component.html
@@ -28,19 +28,7 @@ </button> </div> </div> - <div [ngClass]="'notifications' === activePage ? 'sp-navbar-item-selected' : 'sp-navbar-item'" - style="padding-top:5px;padding-bottom:5px;" *ngIf="notificationsVisible"> - <button mat-button mat-icon-button class="md-icon-button button-margin-iconbar iconbar-size" - (click)="go('notifications')" - matTooltip="Notifications" matTooltipPosition="right"> - <mat-icon [matBadge]="unreadNotificationCount" - [matBadgeHidden]="unreadNotificationCount == 0" - [ngClass]="'notifications' === activePage ?'sp-navbar-icon-selected' : 'sp-navbar-icon'" - data-cy="navigation-icon">chat - </mat-icon> - </button> - </div> <mat-divider style="border-top-color:var(--color-navigation-text);"></mat-divider> <div *ngFor="let item of admin" > <div [ngClass]="item.link === activePage ? 'sp-navbar-item-selected' : 'sp-navbar-item'" @@ -48,7 +36,7 @@ *ngIf="item.visible"> <button mat-button mat-icon-button class="md-icon-button button-margin-iconbar iconbar-size" (click)="go(item.link)" - matTooltip="{{item.title}}" > + matTooltip="{{item.title}}" matTooltipPosition="right" > <mat-icon [ngClass]="item.link === activePage ?'sp-navbar-icon-selected' : 'sp-navbar-icon'" data-cy="navigation-icon">{{item.icon}}</mat-icon>
diff --git a/ui/src/app/core/components/iconbar/iconbar.component.ts b/ui/src/app/core/components/iconbar/iconbar.component.ts index c775ce9..9d7aeea 100644 --- a/ui/src/app/core/components/iconbar/iconbar.component.ts +++ b/ui/src/app/core/components/iconbar/iconbar.component.ts
@@ -21,41 +21,29 @@ import { Router } from '@angular/router'; import { NotificationCountService } from '../../../services/notification-count-service'; import { AuthService } from '../../../services/auth.service'; -import { Subscription, timer } from "rxjs"; -import { exhaustMap, mergeMap } from "rxjs/operators"; -import { RestApi } from "../../../services/rest-api.service"; +import { Subscription, timer } from 'rxjs'; +import { exhaustMap } from 'rxjs/operators'; +import { RestApi } from '../../../services/rest-api.service'; +import { AppConstants } from '../../../services/app.constants'; @Component({ selector: 'iconbar', templateUrl: './iconbar.component.html', styleUrls: ['./iconbar.component.scss'] }) -export class IconbarComponent extends BaseNavigationComponent implements OnInit, OnDestroy { +export class IconbarComponent extends BaseNavigationComponent implements OnInit { - unreadNotificationCount = 0; - unreadNotificationsSubscription: Subscription; constructor(router: Router, authService: AuthService, public notificationCountService: NotificationCountService, - private restApi: RestApi) { - super(authService, router); + private restApi: RestApi, + appConstants: AppConstants) { + super(authService, router, appConstants); } ngOnInit(): void { super.onInit(); - this.unreadNotificationsSubscription = timer(0, 10000).pipe( - exhaustMap(() => this.restApi.getUnreadNotificationsCount())) - .subscribe(response => { - this.notificationCountService.unreadNotificationCount$.next(response.count); - }); - this.notificationCountService.unreadNotificationCount$.subscribe(count => { - this.unreadNotificationCount = count; - }); - } - - ngOnDestroy() { - this.unreadNotificationsSubscription.unsubscribe(); } }
diff --git a/ui/src/app/core/components/streampipes/streampipes.component.html b/ui/src/app/core/components/streampipes/streampipes.component.html index 168f6e2..7ff132b 100644 --- a/ui/src/app/core/components/streampipes/streampipes.component.html +++ b/ui/src/app/core/components/streampipes/streampipes.component.html
@@ -25,6 +25,7 @@ <iconbar></iconbar> </div> <div style="width: 100%; height: 100%; overflow-y: auto;" class="base"> + <sp-breadcrumb></sp-breadcrumb> <router-outlet></router-outlet> </div> </div>
diff --git a/ui/src/app/core/components/toolbar/toolbar.component.html b/ui/src/app/core/components/toolbar/toolbar.component.html index 6ee8046..2767609 100644 --- a/ui/src/app/core/components/toolbar/toolbar.component.html +++ b/ui/src/app/core/components/toolbar/toolbar.component.html
@@ -18,39 +18,33 @@ <mat-toolbar class="md-primary md-hue-2 top-nav toolbar-bg"> <div class="md-toolbar-tools sp-toolbar"> - <div fxFlex="60" fxLayout fxLayoutAlign="start center"> + <div fxFlex="100" fxLayout fxLayoutAlign="start center"> <div class="md-toolbar-tools" style="height:40px;max-height:40px;" fxFlex fxLayout="row" fxLayoutAlign="start center"> <div style="padding:5px;border-radius:0px;margin-right:15px;position:relative;left:20px;"> - <img alt="icon" src="../../../../assets/img/sp/logo-navigation.png" style="height:30px;"> - </div> - <div style="margin-left:30px;"> - <span class="active-page">{{activePageName}}</span> + <img alt="icon" src="../../../../assets/img/sp/logo-navigation.png" style="max-height:30px;max-width: 250px;"> </div> </div> - </div> - <span fxFlex></span> - <div fxFlex="40" fxLayout fxLayoutAlign="end center" *ngIf="authenticated" style="height:100%;"> - <div fxLayoutAlign="start center" *ngIf="versionInfo && versionInfo.backendVersion"> - <span class="version-info-text">v{{versionInfo.backendVersion}}</span> - </div> + <div fxFlex fxLayout fxLayoutAlign="end center" *ngIf="authenticated" style="height:100%;"> <!-- uncomment this to quickly investigate layout issues between dark and light mode --> <!-- <div>--> <!-- <mat-slide-toggle color="accent" [formControl]="appearanceControl">Dark Mode</mat-slide-toggle>--> <!-- </div>--> - <div style="height:100%;"> - <div [ngClass]="feedbackOpen.menuOpen ? 'sp-navbar-item-selected' : 'sp-navbar-item'" fxLayout fxLayoutAlign="center center" style="height: 100%;"> - <button mat-button mat-icon-button - [matMenuTriggerFor]="feedbackMenu" - #feedbackOpen="matMenuTrigger" - matTooltip="Feedback" matTooltipPosition="below" - [ngClass]="feedbackOpen.menuOpen ? 'sp-icon-button-no-hover' : 'sp-icon-button'" style="min-width:0px;" fxLayout fxLayoutAlign="center center"> - <i [ngClass]="feedbackOpen.menuOpen ? 'sp-navbar-icon-selected' : 'sp-navbar-icon'" class="material-icons">feedback</i> - </button> - </div> + <div [ngClass]="'notifications' === activePage ? 'sp-navbar-item-selected' : 'sp-navbar-item'" + *ngIf="notificationsVisible" class="h-100"> + <button mat-button mat-icon-button class="md-icon-button button-margin-iconbar iconbar-size" + (click)="go('notifications')" + fxLayout fxLayoutAlign="center center" + matTooltip="Notifications" matTooltipPosition="below"> + <mat-icon [matBadge]="unreadNotificationCount" + matBadgeColor="accent" + matBadgePosition="below after" + [matBadgeHidden]="unreadNotificationCount == 0" + [ngClass]="'notifications' === activePage ?'sp-navbar-icon-selected' : 'sp-navbar-icon'" + data-cy="navigation-icon">chat + + </mat-icon> + </button> </div> - <mat-menu #feedbackMenu="matMenu" style="max-width: none;" class="feedback-menu-content"> - <feedback (closeFeedbackEmitter)="closeFeedbackWindow()"></feedback> - </mat-menu> <div style="height:100%;"> <div [ngClass]="accountMenuOpen.menuOpen ? 'sp-navbar-item-selected' : 'sp-navbar-item'" fxLayout fxLayoutAlign="center center" style="height: 100%;"> <button mat-button mat-icon-button @@ -91,5 +85,6 @@ </button> </mat-menu> </div> + </div> </div> </mat-toolbar>
diff --git a/ui/src/app/core/components/toolbar/toolbar.component.ts b/ui/src/app/core/components/toolbar/toolbar.component.ts index ee52a28..d476b91 100644 --- a/ui/src/app/core/components/toolbar/toolbar.component.ts +++ b/ui/src/app/core/components/toolbar/toolbar.component.ts
@@ -16,7 +16,7 @@ * */ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { BaseNavigationComponent } from '../base-navigation.component'; import { Router } from '@angular/router'; import { RestApi } from '../../../services/rest-api.service'; @@ -24,35 +24,50 @@ import { FormControl } from '@angular/forms'; import { OverlayContainer } from '@angular/cdk/overlay'; import { ProfileService } from '../../../profile/profile.service'; -import { VersionInfo } from '../../../info/versions/service/version-info.model'; import { AuthService } from '../../../services/auth.service'; +import { AppConstants } from '../../../services/app.constants'; +import { Subscription, timer } from 'rxjs'; +import { exhaustMap } from 'rxjs/operators'; +import { NotificationCountService } from '../../../services/notification-count-service'; @Component({ selector: 'toolbar', templateUrl: './toolbar.component.html', styleUrls: ['./toolbar.component.scss'] }) -export class ToolbarComponent extends BaseNavigationComponent implements OnInit { +export class ToolbarComponent extends BaseNavigationComponent implements OnInit, OnDestroy { @ViewChild('feedbackOpen') feedbackOpen: MatMenuTrigger; @ViewChild('accountMenuOpen') accountMenuOpen: MatMenuTrigger; userEmail; - versionInfo: VersionInfo; darkMode: boolean; appearanceControl: FormControl; + unreadNotificationCount = 0; + unreadNotificationsSubscription: Subscription; + constructor(router: Router, private profileService: ProfileService, private restApi: RestApi, private overlay: OverlayContainer, - authService: AuthService) { - super(authService, router); + authService: AuthService, + appConstants: AppConstants, + public notificationCountService: NotificationCountService) { + super(authService, router, appConstants); } ngOnInit(): void { - this.getVersion(); + this.unreadNotificationsSubscription = timer(0, 10000).pipe( + exhaustMap(() => this.restApi.getUnreadNotificationsCount())) + .subscribe(response => { + this.notificationCountService.unreadNotificationCount$.next(response.count); + }); + + this.notificationCountService.unreadNotificationCount$.subscribe(count => { + this.unreadNotificationCount = count; + }); this.authService.user$.subscribe(user => { this.userEmail = user.displayName; this.profileService.getUserProfile(user.username).subscribe(userInfo => { @@ -79,11 +94,6 @@ } } - closeFeedbackWindow() { - // this.feedbackOpen = false; - this.feedbackOpen.closeMenu(); - } - openDocumentation() { window.open('https://streampipes.apache.org/docs', '_blank'); } @@ -103,10 +113,8 @@ this.router.navigate(['login']); } - getVersion() { - this.restApi.getVersionInfo().subscribe((response) => { - this.versionInfo = response as VersionInfo; - }); + ngOnDestroy() { + this.unreadNotificationsSubscription.unsubscribe(); } }
diff --git a/ui/src/app/core/core.module.ts b/ui/src/app/core/core.module.ts index 956182f..84ee547 100644 --- a/ui/src/app/core/core.module.ts +++ b/ui/src/app/core/core.module.ts
@@ -22,7 +22,6 @@ import { FlexLayoutModule } from '@angular/flex-layout'; import { CommonModule } from '@angular/common'; import { StreampipesComponent } from './components/streampipes/streampipes.component'; -import { FeedbackComponent } from './components/feedback/feedback.component'; import { MatButtonModule } from '@angular/material/button'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatInputModule } from '@angular/material/input'; @@ -37,34 +36,37 @@ import { MatMenuModule } from '@angular/material/menu'; import { MatBadgeModule } from '@angular/material/badge'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; +import { SpBreadcrumbComponent } from './components/breadcrumb/breadcrumb.component'; +import { SharedUiModule } from '@streampipes/shared-ui'; @NgModule({ - imports: [ - CommonModule, - FlexLayoutModule, - MatGridListModule, - MatDividerModule, - MatListModule, - MatIconModule, - MatMenuModule, - MatBadgeModule, - MatButtonModule, - MatTooltipModule, - MatProgressSpinnerModule, - MatInputModule, - MatToolbarModule, - FormsModule, - RouterModule, - MatSlideToggleModule, - ReactiveFormsModule - ], - declarations: [ - StreampipesComponent, - FeedbackComponent, - IconbarComponent, - ToolbarComponent - ], - providers: [] + imports: [ + CommonModule, + FlexLayoutModule, + MatGridListModule, + MatDividerModule, + MatListModule, + MatIconModule, + MatMenuModule, + MatBadgeModule, + MatButtonModule, + MatTooltipModule, + MatProgressSpinnerModule, + MatInputModule, + MatToolbarModule, + FormsModule, + RouterModule, + MatSlideToggleModule, + ReactiveFormsModule, + SharedUiModule + ], + declarations: [ + SpBreadcrumbComponent, + StreampipesComponent, + IconbarComponent, + ToolbarComponent + ], + providers: [] }) export class CoreModule { }
diff --git a/ui/src/app/dashboard/components/grid/dashboard-grid.component.html b/ui/src/app/dashboard/components/grid/dashboard-grid.component.html index d0d3795..de987ce 100644 --- a/ui/src/app/dashboard/components/grid/dashboard-grid.component.html +++ b/ui/src/app/dashboard/components/grid/dashboard-grid.component.html
@@ -16,18 +16,21 @@ ~ --> -<div *ngIf="dashboard.displayHeader" class="text-center"> +<div *ngIf="dashboard && dashboard.displayHeader" class="text-center"> <h2>{{dashboard.name}}</h2> <h3>{{dashboard.description}}</h3> </div> <gridster [options]="options" [ngClass]="editMode ? 'edit' : ''"> <ng-container *ngFor="let item of dashboard.widgets;let i=index"> <gridster-item [item]="item" #gridsterItemComponent> - <dashboard-widget (updateCallback)="propagateItemUpdate($event)" + <dashboard-widget (updateCallback)="propagateItemUpdate($event)" #dashboardWidgetComponent (deleteCallback)="propagateItemRemoval($event)" [widget]="item" [editMode]="editMode" + [allMeasurements]="allMeasurements" + [globalRefresh]="dashboard.dashboardGeneralSettings.globalRefresh" [headerVisible]="headerVisible" + [gridsterItemComponent]="gridsterItemComponent" [itemWidth]="gridsterItemComponent.width" [itemHeight]="gridsterItemComponent.height" ></dashboard-widget>
diff --git a/ui/src/app/dashboard/components/grid/dashboard-grid.component.ts b/ui/src/app/dashboard/components/grid/dashboard-grid.component.ts index c31211d..443aa49 100644 --- a/ui/src/app/dashboard/components/grid/dashboard-grid.component.ts +++ b/ui/src/app/dashboard/components/grid/dashboard-grid.component.ts
@@ -17,80 +17,145 @@ */ import { - Component, - EventEmitter, - Input, - OnChanges, - OnInit, - Output, - QueryList, - SimpleChanges, - ViewChildren + AfterContentInit, + Component, + EventEmitter, + Input, + OnChanges, OnDestroy, + OnInit, + Output, + QueryList, + SimpleChanges, + ViewChildren } from '@angular/core'; -import { Dashboard, DashboardConfig, DashboardItem, DashboardWidgetModel } from '@streampipes/platform-services'; +import { + Dashboard, + DashboardConfig, + DashboardItem, + DashboardWidgetModel, DataLakeMeasure, + DatalakeRestService, SpQueryResult +} from '@streampipes/platform-services'; import { ResizeService } from '../../services/resize.service'; import { GridsterItemComponent, GridType } from 'angular-gridster2'; +import { GridsterInfo } from "../../models/gridster-info.model"; +import { DashboardWidgetComponent } from '../widget/dashboard-widget.component'; +import { exhaustMap } from 'rxjs/operators'; +import { Observable, of, Subscription, timer } from 'rxjs'; @Component({ - selector: 'dashboard-grid', - templateUrl: './dashboard-grid.component.html', - styleUrls: ['./dashboard-grid.component.css'] + selector: 'dashboard-grid', + templateUrl: './dashboard-grid.component.html', + styleUrls: ['./dashboard-grid.component.css'] }) -export class DashboardGridComponent implements OnInit, OnChanges { +export class DashboardGridComponent implements OnInit, OnChanges, AfterContentInit, OnDestroy { - @Input() editMode: boolean; - @Input() headerVisible: boolean; - @Input() dashboard: Dashboard; + @Input() editMode: boolean; + @Input() headerVisible: boolean; + @Input() dashboard: Dashboard; + @Input() allMeasurements: DataLakeMeasure[]; - @Output() deleteCallback: EventEmitter<DashboardItem> = new EventEmitter<DashboardItem>(); - @Output() updateCallback: EventEmitter<DashboardWidgetModel> = new EventEmitter<DashboardWidgetModel>(); + @Output() deleteCallback: EventEmitter<DashboardItem> = new EventEmitter<DashboardItem>(); + @Output() updateCallback: EventEmitter<DashboardWidgetModel> = new EventEmitter<DashboardWidgetModel>(); - options: DashboardConfig; - loaded = false; + options: DashboardConfig; + loaded = false; - @ViewChildren(GridsterItemComponent) gridsterItemComponents: QueryList<GridsterItemComponent>; + subscription: Subscription; - constructor(private resizeService: ResizeService) { + @ViewChildren(GridsterItemComponent) gridsterItemComponents: QueryList<GridsterItemComponent>; + @ViewChildren(DashboardWidgetComponent) dashboardWidgetComponents: QueryList<DashboardWidgetComponent>; + constructor(private resizeService: ResizeService, + private datalakeRestService: DatalakeRestService) { + + } + + ngOnInit(): void { + this.options = { + disablePushOnDrag: true, + draggable: {enabled: this.editMode}, + gridType: GridType.VerticalFixed, + minCols: 12, + maxCols: 12, + minRows: 4, + fixedRowHeight: 50, + fixedColWidth: 50, + margin: 5, + resizable: {enabled: this.editMode}, + displayGrid: this.editMode ? 'always' : 'none', + itemResizeCallback: ((item, itemComponent) => { + this.resizeService.notify({ + gridsterItem: item, + gridsterItemComponent: itemComponent + } as GridsterInfo); + }), + itemInitCallback: ((item, itemComponent) => { + this.resizeService.notify({ + gridsterItem: item, + gridsterItemComponent: itemComponent + } as GridsterInfo); + //window.dispatchEvent(new Event('resize')); + }) + }; + } + + ngOnDestroy() { + if (this.subscription) { + this.subscription.unsubscribe(); } + } - ngOnInit(): void { - this.options = { - disablePushOnDrag: true, - draggable: { enabled: this.editMode }, - gridType: GridType.VerticalFixed, - minCols: 12, - maxCols: 12, - minRows: 4, - fixedRowHeight: 50, - fixedColWidth: 50, - margin: 5, - resizable: { enabled: this.editMode }, - displayGrid: this.editMode ? 'always' : 'none', - itemResizeCallback: ((item, itemComponent) => { - this.resizeService.notify({id: item.id, width: itemComponent.width, height: itemComponent.height}); - }), - itemInitCallback: ((item, itemComponent) => { - this.resizeService.notify({id: item.id, width: itemComponent.width, height: itemComponent.height}); - }) - }; + ngOnChanges(changes: SimpleChanges): void { + if (changes['editMode'] && this.options) { + this.options.draggable.enabled = this.editMode; + this.options.resizable.enabled = this.editMode; + this.options.displayGrid = this.editMode ? 'always' : 'none'; + this.options.api.optionsChanged(); } + } - ngOnChanges(changes: SimpleChanges): void { - if (changes['editMode'] && this.options) { - this.options.draggable.enabled = this.editMode; - this.options.resizable.enabled = this.editMode; - this.options.displayGrid = this.editMode ? 'always' : 'none'; - this.options.api.optionsChanged(); + propagateItemRemoval(widget: DashboardItem) { + this.deleteCallback.emit(widget); + } + + propagateItemUpdate(dashboardWidget: DashboardWidgetModel) { + this.updateCallback.emit(dashboardWidget); + } + + ngAfterContentInit(): void { + if (this.dashboard.dashboardGeneralSettings.globalRefresh) { + this.checkWidgetsReady(); + } + } + + checkWidgetsReady() { + if (this.dashboardWidgetComponents) { + this.createQuerySubscription(); + } else { + setTimeout(() => this.checkWidgetsReady(), 1000); + } + } + + createQuerySubscription() { + this.subscription = timer(0, this.dashboard.dashboardGeneralSettings.refreshIntervalInSeconds * 1000) + .pipe(exhaustMap(() => this.makeQueryObservable())) + .subscribe(res => { + if (res.length > 0) { + this.dashboardWidgetComponents.forEach((widget, index) => { + const widgetId = widget.getWidgetId(); + const queryResult = res.find(r => r.forId === widgetId); + if (queryResult) { + widget.processQueryResponse(queryResult); + } + }); } - } + }); + } - propagateItemRemoval(widget: DashboardItem) { - this.deleteCallback.emit(widget); - } - - propagateItemUpdate(dashboardWidget: DashboardWidgetModel) { - this.updateCallback.emit(dashboardWidget); - } - + makeQueryObservable(): Observable<SpQueryResult[]> { + const queries = this.dashboardWidgetComponents + .map(dw => dw.getWidgetQuery()) + .filter(query => query !== undefined); + return this.datalakeRestService.performMultiQuery(queries); + } }
diff --git a/ui/src/app/dashboard/components/overview/dashboard-overview.component.css b/ui/src/app/dashboard/components/overview/dashboard-overview.component.css index 121e838..8bd5722 100644 --- a/ui/src/app/dashboard/components/overview/dashboard-overview.component.css +++ b/ui/src/app/dashboard/components/overview/dashboard-overview.component.css
@@ -36,3 +36,10 @@ display: inline; margin-right: 10px; } + +.mat-row:nth-child(even) { + background-color: var(--color-bg-1); +} +.mat-row:nth-child(odd) { + background-color: var(--color-bg-2); +}
diff --git a/ui/src/app/dashboard/components/overview/dashboard-overview.component.html b/ui/src/app/dashboard/components/overview/dashboard-overview.component.html index d557cd9..054a420 100644 --- a/ui/src/app/dashboard/components/overview/dashboard-overview.component.html +++ b/ui/src/app/dashboard/components/overview/dashboard-overview.component.html
@@ -16,91 +16,98 @@ ~ --> -<div fxFlex="100" fxLayout="column"> - <div fxFlex="100" fxLayout="column"> - <div fxLayout="row" class="fixed-height options-bar sp-tab-bg"> - <div class="options-bar-item pl-10" fxLayoutAlign="start center" fxLayout="row"> - <button mat-button - mat-raised-button - color="accent" - (click)="openNewDashboardDialog()" - *ngIf="hasDashboardWritePrivileges" - data-cy="new-dashboard-btn"> - <i class="material-icons">add</i> - <span> New dashboard</span> - </button> - </div> - </div> +<sp-basic-view [showBackLink]="false" [padding]="true"> + + <div nav fxFlex="100" fxLayoutAlign="start center" fxLayout="row" class="pl-10"> + <button mat-button mat-raised-button color="accent" + data-cy="new-dashboard-btn" + (click)="openNewDashboardDialog()" + *ngIf="hasDashboardWritePrivileges"> + <i class="material-icons">add</i> + <span>New Dashboard</span> + </button> </div> - <div fxFlex="100" fxLayout="row wrap" fxLayoutAlign="start stretch" class="m-20"> - <div fxFlex="100" class="assemblyOptions sp-blue-bg p-5"> - <div fxLayout="row" fxLayoutAlign="start center" fxFlex="100"> - <h4>My dashboards</h4> - <span fxFlex></span> - </div> - </div> - <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" class="sp-blue-border"> - <table fxFlex="95" mat-table [dataSource]="dataSource" multiTemplateDataRows> + <div fxFlex="100" fxLayout="column"> + <sp-basic-header-title-component title="My Dashboards"></sp-basic-header-title-component> + <div fxFlex="100" fxLayout="row" fxLayoutAlign="center start"> + <sp-basic-inner-panel [showTitle]="false" innerPadding="0" outerMargin="0" fxFlex="90" [hideToolbar]="true"> + <div fxFlex="100" fxLayout="column" class="w-100" *ngIf="dashboards.length > 0"> - <ng-container matColumnDef="name"> - <th fxFlex="60" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Dashboard</th> - <td fxFlex="60" fxLayoutAlign="start center" mat-cell *matCellDef="let element"> - {{element.name}}<br/> - {{element.description}} - </td> - </ng-container> + <table fxFlex="95" mat-table [dataSource]="dataSource" multiTemplateDataRows> - <ng-container matColumnDef="actions"> - <th fxFlex="40" fxLayoutAlign="center center" mat-header-cell *matHeaderCellDef> Actions</th> - <td fxFlex="40" fxLayoutAlign="start center" mat-cell *matCellDef="let element"> - <div fxLayout="row" fxFlex="100"> + <ng-container matColumnDef="name"> + <th fxFlex="60" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Dashboard + </th> + <td fxFlex="60" fxLayoutAlign="start center" mat-cell *matCellDef="let element"> + {{element.name}}<br/> + {{element.description}} + </td> + </ng-container> + + <ng-container matColumnDef="actions"> + <th fxFlex="40" fxLayoutAlign="center center" mat-header-cell *matHeaderCellDef> Actions + </th> + <td fxFlex="40" fxLayoutAlign="start center" mat-cell *matCellDef="let element"> + <div fxLayout="row" fxFlex="100"> <span fxFlex fxFlexOrder="1" fxLayout="row" fxLayoutAlign="center center"> <button mat-button mat-icon-button color="accent" - (click)="showDashboard(element, false)" + (click)="showDashboard(element)" [attr.data-cy]="'show-dashboard-' + element.name"> <i class="material-icons">visibility</i> </button> </span> - <span fxFlex fxFlexOrder="2" fxLayout="row" fxLayoutAlign="center center"> + <span fxFlex fxFlexOrder="2" fxLayout="row" fxLayoutAlign="center center"> <button mat-button mat-icon-button color="accent" (click)="openExternalDashboard(element)"> <i class="material-icons">open_in_new</i> </button> </span> - <span fxFlex fxFlexOrder="3" fxLayout="row" fxLayoutAlign="center center" *ngIf="hasDashboardWritePrivileges"> + <span fxFlex fxFlexOrder="3" fxLayout="row" fxLayoutAlign="center center" + *ngIf="hasDashboardWritePrivileges"> <button mat-button mat-icon-button color="accent" (click)="openEditDashboardDialog(element)"> <i class="material-icons">settings</i> </button> </span> - <span fxFlex fxFlexOrder="4" fxLayout="row" fxLayoutAlign="center center" *ngIf="hasDashboardWritePrivileges"> + <span fxFlex fxFlexOrder="4" fxLayout="row" fxLayoutAlign="center center" + *ngIf="hasDashboardWritePrivileges"> <button mat-button mat-icon-button color="accent" - (click)="showDashboard(element, true)" + (click)="editDashboard(element)" [attr.data-cy]="'edit-dashboard-' + element.name"> <i class="material-icons">edit</i> </button> </span> - <span fxFlex fxFlexOrder="5" fxLayout="row" fxLayoutAlign="center center" *ngIf="isAdmin"> + <span fxFlex fxFlexOrder="5" fxLayout="row" fxLayoutAlign="center center" + *ngIf="isAdmin"> <button mat-button mat-icon-button color="accent" (click)="showPermissionsDialog(element)"> <i class="material-icons">share</i> </button> </span> - <span fxFlex fxFlexOrder="6" fxLayout="row" fxLayoutAlign="center center" *ngIf="hasDashboardDeletePrivileges"> + <span fxFlex fxFlexOrder="6" fxLayout="row" fxLayoutAlign="center center" + *ngIf="hasDashboardDeletePrivileges"> <button mat-button mat-icon-button color="accent" (click)="openDeleteDashboardDialog(element)"> <i class="material-icons">delete</i> </button> </span> - </div> - </td> - </ng-container> + </div> + </td> + </ng-container> - <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> - <tr mat-row *matRowDef="let element; columns: displayedColumns;"> - </tr> - </table> + <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> + <tr mat-row *matRowDef="let element; columns: displayedColumns;"> + </tr> + </table> + </div> + <div fxFlex="100" + fxLayout="column" + fxLayoutAlign="center center" + *ngIf="dashboards.length == 0"> + <h5>(no dashboards available)</h5> + </div> + </sp-basic-inner-panel> </div> </div> -</div> +</sp-basic-view>
diff --git a/ui/src/app/dashboard/components/overview/dashboard-overview.component.ts b/ui/src/app/dashboard/components/overview/dashboard-overview.component.ts index 86387fc..3d41f70 100644 --- a/ui/src/app/dashboard/components/overview/dashboard-overview.component.ts +++ b/ui/src/app/dashboard/components/overview/dashboard-overview.component.ts
@@ -16,19 +16,19 @@ * */ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { Dashboard } from '@streampipes/platform-services'; +import { Component, OnInit } from '@angular/core'; +import { Dashboard, DashboardService } from '@streampipes/platform-services'; import { MatTableDataSource } from '@angular/material/table'; import { MatDialog } from '@angular/material/dialog'; -import { DashboardService } from '../../services/dashboard.service'; import { EditDashboardDialogComponent } from '../../dialogs/edit-dashboard/edit-dashboard-dialog.component'; -import { Tuple2 } from '../../../core-model/base/Tuple2'; import { Router } from '@angular/router'; import { ObjectPermissionDialogComponent } from '../../../core-ui/object-permission-dialog/object-permission-dialog.component'; -import { PanelType, DialogService } from '@streampipes/shared-ui'; +import { DialogService, PanelType, SpBreadcrumbService } from '@streampipes/shared-ui'; import { UserRole } from '../../../_enums/user-role.enum'; import { AuthService } from '../../../services/auth.service'; import { UserPrivilege } from '../../../_enums/user-privilege.enum'; +import { SpDashboardRoutes } from '../../dashboard.routes'; +import { zip } from 'rxjs'; @Component({ selector: 'dashboard-overview', @@ -37,9 +37,7 @@ }) export class DashboardOverviewComponent implements OnInit { - @Input() dashboards: Dashboard[]; - @Output() reloadDashboardsEmitter = new EventEmitter<void>(); - @Output() selectDashboardEmitter = new EventEmitter<Tuple2<Dashboard, boolean>>(); + dashboards: Dashboard[] = []; dataSource = new MatTableDataSource<Dashboard>(); displayedColumns: string[] = []; @@ -52,11 +50,13 @@ public dialog: MatDialog, private router: Router, private dialogService: DialogService, - private authService: AuthService) { + private authService: AuthService, + private breadcrumbService: SpBreadcrumbService) { } ngOnInit(): void { + this.breadcrumbService.updateBreadcrumb(this.breadcrumbService.getRootLink(SpDashboardRoutes.BASE)); this.authService.user$.subscribe(user => { this.isAdmin = user.roles.indexOf(UserRole.ROLE_ADMIN) > -1; this.hasDashboardWritePrivileges = this.authService.hasRole(UserPrivilege.PRIVILEGE_WRITE_DASHBOARD); @@ -64,12 +64,20 @@ this.displayedColumns = ['name', 'actions']; }); - this.dataSource.data = this.dashboards; + this.getDashboards(); + } + + getDashboards() { + this.dashboardService.getDashboards().subscribe(data => { + this.dashboards = data.sort((a, b) => a.name.localeCompare(b.name)); + this.dataSource.data = this.dashboards; + }); } openNewDashboardDialog() { const dashboard = {} as Dashboard; dashboard.widgets = []; + dashboard.dashboardGeneralSettings = {}; this.openDashboardModificationDialog(true, dashboard); } @@ -86,7 +94,7 @@ }); dialogRef.afterClosed().subscribe(result => { - this.reloadDashboardsEmitter.emit(); + this.getDashboards(); }); } @@ -96,16 +104,18 @@ openDeleteDashboardDialog(dashboard: Dashboard) { // TODO add confirm dialog - this.dashboardService.deleteDashboard(dashboard).subscribe(result => { - this.reloadDashboardsEmitter.emit(); + const widgetsToDelete = dashboard.widgets.map(widget => this.dashboardService.deleteWidget(widget.id)); + zip(...widgetsToDelete, this.dashboardService.deleteDashboard(dashboard)).subscribe(result => { + this.getDashboards(); }); } - showDashboard(dashboard: Dashboard, openInEditMode: boolean) { - const data: Tuple2<Dashboard, boolean> = {} as Tuple2<Dashboard, boolean>; - data.a = dashboard; - data.b = openInEditMode; - this.selectDashboardEmitter.emit(data); + showDashboard(dashboard: Dashboard): void { + this.router.navigate(['dashboard', dashboard._id]); + } + + editDashboard(dashboard: Dashboard): void { + this.router.navigate(['dashboard', dashboard._id], {queryParams: {action: 'edit'}}); } openExternalDashboard(dashboard: Dashboard) { @@ -128,7 +138,7 @@ dialogRef.afterClosed().subscribe(refresh => { if (refresh) { - this.reloadDashboardsEmitter.emit(); + this.getDashboards(); } }); }
diff --git a/ui/src/app/dashboard/components/panel/dashboard-panel.component.html b/ui/src/app/dashboard/components/panel/dashboard-panel.component.html index 9f1fe82..1e368cf 100644 --- a/ui/src/app/dashboard/components/panel/dashboard-panel.component.html +++ b/ui/src/app/dashboard/components/panel/dashboard-panel.component.html
@@ -15,9 +15,11 @@ ~ limitations under the License. ~ --> -<div fxFlex="100" fxLayout="column"> - <div fxLayout="row" class="fixed-height options-bar sp-tab-bg" *ngIf="editMode"> - <div class="options-bar-item pl-10" fxLayoutAlign="start center" fxLayout="row"> + +<sp-basic-view [showBackLink]="true" [padding]="false" [backLinkTarget]="['dashboard']"> + + <div nav fxFlex="100" fxLayoutAlign="start center" fxLayout="row" class="pl-10"> + <div fxLayout="row" fxFlex="100" *ngIf="editMode" fxLayoutAlign="start center"> <button mat-button mat-raised-button color="accent" @@ -43,9 +45,7 @@ <i class="material-icons">add</i> <span> Add visualization</span> </button> - </div> - <span fxFlex></span> - <div class="options-bar-item" fxLayoutAlign="start center" fxLayout="row" > + <span fxFlex></span> <mat-slide-toggle color="accent" [(ngModel)]="headerVisible"> @@ -53,11 +53,13 @@ </mat-slide-toggle> </div> </div> - - <dashboard-grid [editMode]="editMode" [dashboard]="dashboard" - [headerVisible]="headerVisible" - (updateCallback)="updateAndQueueItemForDeletion($event)" - (deleteCallback)="removeAndQueueItemForDeletion($event)" - class="h-100 dashboard-grid"></dashboard-grid> -</div> - + <div fxFlex="100" fxLayout="column"> + <dashboard-grid [editMode]="editMode" [dashboard]="dashboard" + [headerVisible]="headerVisible" + [allMeasurements]="allMeasurements" + (updateCallback)="updateAndQueueItemForDeletion($event)" + (deleteCallback)="removeAndQueueItemForDeletion($event)" + *ngIf="dashboard && allMeasurements" + class="h-100 dashboard-grid"></dashboard-grid> + </div> +</sp-basic-view>
diff --git a/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts b/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts index 4ca676d..11d0cfb 100644 --- a/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts +++ b/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts
@@ -16,13 +16,25 @@ * */ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { Dashboard, ClientDashboardItem, DashboardWidgetModel } from '@streampipes/platform-services'; -import { forkJoin, Observable, Subscription } from 'rxjs'; +import { Component, EventEmitter, OnInit, Output } from '@angular/core'; +import { + ClientDashboardItem, + Dashboard, + DashboardService, + DashboardWidgetModel, DataLakeMeasure, + DatalakeRestService +} from '@streampipes/platform-services'; +import { forkJoin, Observable, of, Subscription } from 'rxjs'; import { AddVisualizationDialogComponent } from '../../dialogs/add-widget/add-visualization-dialog.component'; -import { DashboardService } from '../../services/dashboard.service'; import { RefreshDashboardService } from '../../services/refresh-dashboard.service'; -import { PanelType, DialogService } from '@streampipes/shared-ui'; +import { ConfirmDialogComponent, DialogService, PanelType, SpBreadcrumbService } from '@streampipes/shared-ui'; +import { ActivatedRoute, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; +import { UserPrivilege } from '../../../_enums/user-privilege.enum'; +import { AuthService } from '../../../services/auth.service'; +import { SpDashboardRoutes } from '../../dashboard.routes'; +import { map } from 'rxjs/operators'; +import { MatDialog } from '@angular/material/dialog'; + @Component({ selector: 'dashboard-panel', templateUrl: './dashboard-panel.component.html', @@ -30,8 +42,8 @@ }) export class DashboardPanelComponent implements OnInit { - @Input() dashboard: Dashboard; - @Input('editMode') editMode: boolean; + dashboard: Dashboard; + editMode: boolean; @Output('editModeChange') editModeChange: EventEmitter<boolean> = new EventEmitter(); public items: ClientDashboardItem[]; @@ -40,16 +52,49 @@ widgetIdsToRemove: string[] = []; widgetsToUpdate: Map<string, DashboardWidgetModel> = new Map<string, DashboardWidgetModel>(); + allMeasurements: DataLakeMeasure[]; headerVisible = true; constructor(private dashboardService: DashboardService, + private datalakeRestService: DatalakeRestService, private dialogService: DialogService, - private refreshDashboardService: RefreshDashboardService) { + private dialog: MatDialog, + private refreshDashboardService: RefreshDashboardService, + private route: ActivatedRoute, + private authService: AuthService, + private breadcrumbService: SpBreadcrumbService) { } public ngOnInit() { + const params = this.route.snapshot.params; + const queryParams = this.route.snapshot.queryParams; + this.authService.user$.subscribe(user => { + const hasDashboardWritePrivileges = this.authService.hasRole( + UserPrivilege.PRIVILEGE_WRITE_DASHBOARD + ); + if (queryParams.action === 'edit' && hasDashboardWritePrivileges) { + this.editMode = true; + } + }); + + this.getDashboard(params.id); + this.getAllMeasurements(); + + } + + getDashboard(dashboardId: string): void { + this.dashboardService.getDashboard(dashboardId).subscribe(dashboard => { + if (dashboard) { + this.dashboard = dashboard; + this.breadcrumbService.updateBreadcrumb(this.breadcrumbService.makeRoute([SpDashboardRoutes.BASE], this.dashboard.name)); + } + }); + } + + getAllMeasurements(): void { + this.datalakeRestService.getAllMeasurementSeries().subscribe(res => this.allMeasurements = res); } addWidget(): void { @@ -93,8 +138,8 @@ } closeEditModeAndReloadDashboard() { - this.editModeChange.emit(!(this.editMode)); - this.refreshDashboardService.notify(this.dashboard._id); + this.editMode = !this.editMode; + this.getDashboard(this.dashboard._id); } prepareWidgetUpdates(): Observable<any>[] { @@ -125,4 +170,28 @@ this.dashboardService.deleteWidget(widgetId).subscribe(); }); } + + confirmLeaveDashboard(route: ActivatedRouteSnapshot, + state: RouterStateSnapshot): Observable<boolean> { + if (this.editMode) { + const dialogRef = this.dialog.open(ConfirmDialogComponent, { + width: '500px', + data: { + 'title': 'Save changes?', + 'subtitle': 'Update all changes to dashboard widgets or discard current changes.', + 'cancelTitle': 'Discard changes', + 'okTitle': 'Update', + 'confirmAndCancel': true + }, + }); + return dialogRef.afterClosed().pipe(map(shouldUpdate => { + if (shouldUpdate) { + this.updateDashboardAndCloseEditMode(); + } + return true; + })); + } else { + return of(true); + } + } }
diff --git a/ui/src/app/dashboard/components/standalone/standalone-dashboard.component.html b/ui/src/app/dashboard/components/standalone/standalone-dashboard.component.html index a5e7832..1103c2b 100644 --- a/ui/src/app/dashboard/components/standalone/standalone-dashboard.component.html +++ b/ui/src/app/dashboard/components/standalone/standalone-dashboard.component.html
@@ -17,5 +17,5 @@ <div fxFlex="100" class="panel"> <dashboard-grid [editMode]="false" [dashboard]="dashboard" class="h-100" *ngIf="dashboardReady"></dashboard-grid> - <img src="/assets/img/favicon/apple-touch-icon-76x76.png" class="icon-overlay"> -</div> \ No newline at end of file + <img src="/assets/img/favicon/favicon-96x96.png" class="icon-overlay"> +</div>
diff --git a/ui/src/app/dashboard/components/standalone/standalone-dashboard.component.ts b/ui/src/app/dashboard/components/standalone/standalone-dashboard.component.ts index ca41c44..03b3d1f 100644 --- a/ui/src/app/dashboard/components/standalone/standalone-dashboard.component.ts +++ b/ui/src/app/dashboard/components/standalone/standalone-dashboard.component.ts
@@ -16,8 +16,7 @@ */ import { Component, OnInit } from '@angular/core'; -import { Dashboard } from '@streampipes/platform-services'; -import { DashboardService } from '../../services/dashboard.service'; +import { Dashboard, DashboardService } from '@streampipes/platform-services'; import { ActivatedRoute } from '@angular/router'; @Component({ @@ -37,7 +36,6 @@ this.activatedRoute.params.subscribe(params => { if (params['dashboardId']) { const dashboardId = params['dashboardId']; - console.log(dashboardId); this.dashboardService.getDashboard(dashboardId).subscribe(dashboard => { this.dashboard = dashboard; this.dashboardReady = true;
diff --git a/ui/src/app/dashboard/components/widget/dashboard-widget.component.html b/ui/src/app/dashboard/components/widget/dashboard-widget.component.html index 1c4e872..d7a4ec7 100644 --- a/ui/src/app/dashboard/components/widget/dashboard-widget.component.html +++ b/ui/src/app/dashboard/components/widget/dashboard-widget.component.html
@@ -51,100 +51,128 @@ </div> <div *ngIf="widgetLoaded && pipelineRunning" class="h-100"> <div *ngIf="configuredWidget.widgetType === 'number'" class="h-100 p-0"> - <number-widget [itemWidth]="itemWidth" + <number-widget [itemWidth]="itemWidth" #activeWidget [itemHeight]="itemHeight" [editMode]="editMode" + [globalRefresh]="globalRefresh" + [gridsterItemComponent]="gridsterItemComponent" [widgetConfig]="configuredWidget" [widgetDataConfig]="widgetDataConfig" class="h-100"></number-widget> </div> <div *ngIf="configuredWidget.widgetType === 'line'" class="h-100 p-0"> - <line-widget [itemWidth]="itemWidth" + <line-widget [itemWidth]="itemWidth" #activeWidget [itemHeight]="itemHeight" [editMode]="editMode" + [globalRefresh]="globalRefresh" + [gridsterItemComponent]="gridsterItemComponent" [widgetConfig]="configuredWidget" [widgetDataConfig]="widgetDataConfig" class="h-100"></line-widget> </div> <div *ngIf="configuredWidget.widgetType === 'area'" class="h-100 p-0"> - <area-widget [itemWidth]="itemWidth" + <area-widget [itemWidth]="itemWidth" #activeWidget [itemHeight]="itemHeight" [editMode]="editMode" + [globalRefresh]="globalRefresh" + [gridsterItemComponent]="gridsterItemComponent" [widgetConfig]="configuredWidget" [widgetDataConfig]="widgetDataConfig" class="h-100"></area-widget> </div> <div *ngIf="configuredWidget.widgetType === 'table'" class="h-100 p-0"> - <table-widget [itemWidth]="itemWidth" + <table-widget [itemWidth]="itemWidth" #activeWidget [itemHeight]="itemHeight" [editMode]="editMode" + [globalRefresh]="globalRefresh" + [gridsterItemComponent]="gridsterItemComponent" [widgetConfig]="configuredWidget" [widgetDataConfig]="widgetDataConfig" class="h-100"></table-widget> </div> <div *ngIf="configuredWidget.widgetType === 'gauge'" class="h-100 p-0"> - <gauge-widget [itemWidth]="itemWidth" + <gauge-widget [itemWidth]="itemWidth" #activeWidget [itemHeight]="itemHeight" [editMode]="editMode" + [globalRefresh]="globalRefresh" + [gridsterItemComponent]="gridsterItemComponent" [widgetConfig]="configuredWidget" [widgetDataConfig]="widgetDataConfig" class="h-100"></gauge-widget> </div> <div *ngIf="configuredWidget.widgetType === 'image'" class="h-100 p-0"> - <image-widget [itemWidth]="itemWidth" + <image-widget [itemWidth]="itemWidth" #activeWidget [itemHeight]="itemHeight" [editMode]="editMode" + [globalRefresh]="globalRefresh" + [gridsterItemComponent]="gridsterItemComponent" [widgetConfig]="configuredWidget" [widgetDataConfig]="widgetDataConfig" class="h-100"></image-widget> </div> <div *ngIf="configuredWidget.widgetType === 'map'" class="h-100 p-0"> - <map-widget [itemWidth]="itemWidth" + <map-widget [itemWidth]="itemWidth" #activeWidget [itemHeight]="itemHeight" [editMode]="editMode" + [globalRefresh]="globalRefresh" + [gridsterItemComponent]="gridsterItemComponent" [widgetConfig]="configuredWidget" [widgetDataConfig]="widgetDataConfig" class="h-100"></map-widget> </div> <div *ngIf="configuredWidget.widgetType === 'raw'" class="h-100 p-0"> - <raw-widget [itemWidth]="itemWidth" + <raw-widget [itemWidth]="itemWidth" #activeWidget [itemHeight]="itemHeight" [editMode]="editMode" + [globalRefresh]="globalRefresh" + [gridsterItemComponent]="gridsterItemComponent" [widgetConfig]="configuredWidget" [widgetDataConfig]="widgetDataConfig" class="h-100"></raw-widget> </div> <div *ngIf="configuredWidget.widgetType === 'html'" class="h-100 p-0"> - <html-widget [itemWidth]="itemWidth" + <html-widget [itemWidth]="itemWidth" #activeWidget [itemHeight]="itemHeight" [editMode]="editMode" + [globalRefresh]="globalRefresh" + [gridsterItemComponent]="gridsterItemComponent" [widgetConfig]="configuredWidget" [widgetDataConfig]="widgetDataConfig" class="h-100"></html-widget> </div> <div *ngIf="configuredWidget.widgetType === 'trafficlight'" class="h-100 p-0"> - <traffic-light-widget [itemWidth]="itemWidth" + <traffic-light-widget [itemWidth]="itemWidth" #activeWidget [itemHeight]="itemHeight" [editMode]="editMode" + [globalRefresh]="globalRefresh" + [gridsterItemComponent]="gridsterItemComponent" [widgetConfig]="configuredWidget" [widgetDataConfig]="widgetDataConfig" class="h-100"></traffic-light-widget> </div> <div *ngIf="configuredWidget.widgetType === 'wordcloud'" class="h-100 p-0"> - <wordcloud-widget [itemWidth]="itemWidth" + <wordcloud-widget [itemWidth]="itemWidth" #activeWidget [itemHeight]="itemHeight" [editMode]="editMode" + [globalRefresh]="globalRefresh" + [gridsterItemComponent]="gridsterItemComponent" [widgetConfig]="configuredWidget" [widgetDataConfig]="widgetDataConfig" class="h-100"></wordcloud-widget> </div> <div *ngIf="configuredWidget.widgetType === 'status'" class="h-100 p-0"> - <status-widget [itemWidth]="itemWidth" + <status-widget [itemWidth]="itemWidth" #activeWidget [itemHeight]="itemHeight" [editMode]="editMode" + [globalRefresh]="globalRefresh" + [gridsterItemComponent]="gridsterItemComponent" [widgetConfig]="configuredWidget" [widgetDataConfig]="widgetDataConfig" class="h-100"></status-widget> </div> <div *ngIf="configuredWidget.widgetType === 'bar-race'" class="h-100 p-0"> - <bar-race-widget [itemWidth]="itemWidth" + <bar-race-widget [itemWidth]="itemWidth" #activeWidget [itemHeight]="itemHeight" [editMode]="editMode" + [globalRefresh]="globalRefresh" + [gridsterItemComponent]="gridsterItemComponent" [widgetConfig]="configuredWidget" [widgetDataConfig]="widgetDataConfig" class="h-100"></bar-race-widget> </div> <div *ngIf="configuredWidget.widgetType === 'stacked-line-chart'" class="h-100 p-0"> - <stacked-line-chart-widget [itemWidth]="itemWidth" + <stacked-line-chart-widget [itemWidth]="itemWidth" #activeWidget [itemHeight]="itemHeight" [editMode]="editMode" + [globalRefresh]="globalRefresh" + [gridsterItemComponent]="gridsterItemComponent" [widgetConfig]="configuredWidget" [widgetDataConfig]="widgetDataConfig" class="h-100"></stacked-line-chart-widget>
diff --git a/ui/src/app/dashboard/components/widget/dashboard-widget.component.ts b/ui/src/app/dashboard/components/widget/dashboard-widget.component.ts index 35213ac..85b12ec 100644 --- a/ui/src/app/dashboard/components/widget/dashboard-widget.component.ts +++ b/ui/src/app/dashboard/components/widget/dashboard-widget.component.ts
@@ -16,21 +16,36 @@ * */ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { DashboardService } from '../../services/dashboard.service'; +import { + Component, + EventEmitter, + Input, + OnInit, + Output, + QueryList, ViewChild, + ViewChildren, + ViewContainerRef +} from '@angular/core'; import { AddVisualizationDialogComponent } from '../../dialogs/add-widget/add-visualization-dialog.component'; import { DashboardItem, + DashboardService, DashboardWidgetModel, - DataLakeMeasure, DatalakeRestService, + DataLakeMeasure, DatalakeQueryParameters, + DatalakeRestService, DataViewDataExplorerService, Pipeline, - PipelineService + PipelineService, SpQueryResult } from '@streampipes/platform-services'; import { DialogService, PanelType } from '@streampipes/shared-ui'; import { EditModeService } from '../../services/edit-mode.service'; import { ReloadPipelineService } from '../../services/reload-pipeline.service'; import { zip } from 'rxjs'; +import { GridsterItemComponent } from 'angular-gridster2'; +import { ResizeService } from '../../services/resize.service'; +import { GridsterInfo } from '../../models/gridster-info.model'; +import { BaseDataExplorerWidgetDirective } from '../../../data-explorer/components/widgets/base/base-data-explorer-widget.directive'; +import { BaseStreamPipesWidget } from '../widgets/base/base-widget'; @Component({ selector: 'dashboard-widget', @@ -44,6 +59,9 @@ @Input() headerVisible = false; @Input() itemWidth: number; @Input() itemHeight: number; + @Input() gridsterItemComponent: GridsterItemComponent; + @Input() globalRefresh: boolean; + @Input() allMeasurements: DataLakeMeasure[]; @Output() deleteCallback: EventEmitter<DashboardItem> = new EventEmitter<DashboardItem>(); @Output() updateCallback: EventEmitter<DashboardWidgetModel> = new EventEmitter<DashboardWidgetModel>(); @@ -56,13 +74,16 @@ pipelineRunning = false; widgetNotAvailable = false; + _activeWidget: BaseStreamPipesWidget; + constructor(private dashboardService: DashboardService, private dialogService: DialogService, private pipelineService: PipelineService, private editModeService: EditModeService, private reloadPipelineService: ReloadPipelineService, private dataExplorerService: DataViewDataExplorerService, - private dataLakeRestService: DatalakeRestService) { + private dataLakeRestService: DatalakeRestService, + private resizeService: ResizeService) { } ngOnInit(): void { @@ -80,22 +101,28 @@ } loadVisualizablePipeline() { - zip(this.dataExplorerService.getPersistedDataStream(this.configuredWidget.pipelineId, this.configuredWidget.visualizationName), this.dataLakeRestService.getAllMeasurementSeries()) + zip(this.dataExplorerService.getPersistedDataStream(this.configuredWidget.pipelineId, this.configuredWidget.visualizationName)) .subscribe(res => { const vizPipeline = res[0]; - const measurement = res[1].find(m => m.measureName === vizPipeline.measureName); + const measurement = this.allMeasurements.find(m => m.measureName === vizPipeline.measureName); vizPipeline.eventSchema = measurement.eventSchema; - this.widgetDataConfig = vizPipeline; - this.dashboardService.getPipelineById(vizPipeline.pipelineId).subscribe(pipeline => { - this.pipeline = pipeline; - this.pipelineRunning = pipeline.running; - this.widgetNotAvailable = false; + this.widgetDataConfig = vizPipeline; + this.dashboardService.getPipelineById(vizPipeline.pipelineId).subscribe(pipeline => { + this.pipeline = pipeline; + this.pipelineRunning = pipeline.running; + this.widgetNotAvailable = false; + this.widgetLoaded = true; + setTimeout(() => { + this.resizeService.notify({ + gridsterItem: this.widget, + gridsterItemComponent: this.gridsterItemComponent + } as GridsterInfo); + }, 20); + }); + }, err => { this.widgetLoaded = true; + this.widgetNotAvailable = true; }); - }, err => { - this.widgetLoaded = true; - this.widgetNotAvailable = true; - }); } removeWidget() { @@ -105,11 +132,11 @@ startPipeline() { if (!this.pipelineRunning) { this.pipelineService - .startPipeline(this.pipeline._id) - .subscribe(status => { - // this.loadWidget(); - this.reloadPipelineService.reloadPipelineSubject.next(); - }); + .startPipeline(this.pipeline._id) + .subscribe(status => { + // this.loadWidget(); + this.reloadPipelineService.reloadPipelineSubject.next(); + }); } } @@ -139,4 +166,25 @@ } }); } + + @ViewChild('activeWidget') + set activeWidget(activeWidget: BaseStreamPipesWidget) { + this._activeWidget = activeWidget; + } + + getWidgetQuery(): DatalakeQueryParameters { + if (this._activeWidget) { + return this._activeWidget.buildQuery(true); + } else { + return undefined; + } + } + + processQueryResponse(res: SpQueryResult) { + this._activeWidget.processQueryResult(res); + } + + getWidgetId(): string { + return this.widget.id; + } }
diff --git a/ui/src/app/dashboard/components/widgets/area/area-widget.component.ts b/ui/src/app/dashboard/components/widgets/area/area-widget.component.ts index 1e7ea9d..5331ea6 100644 --- a/ui/src/app/dashboard/components/widgets/area/area-widget.component.ts +++ b/ui/src/app/dashboard/components/widgets/area/area-widget.component.ts
@@ -39,5 +39,4 @@ ngOnDestroy(): void { super.ngOnDestroy(); } - }
diff --git a/ui/src/app/dashboard/components/widgets/bar-race/bar-race-widget.component.html b/ui/src/app/dashboard/components/widgets/bar-race/bar-race-widget.component.html index d4cf255..59b7f59 100644 --- a/ui/src/app/dashboard/components/widgets/bar-race/bar-race-widget.component.html +++ b/ui/src/app/dashboard/components/widgets/bar-race/bar-race-widget.component.html
@@ -20,9 +20,9 @@ <div class="title-panel mt-20" *ngIf="hasTitlePanelSettings"> {{selectedTitle}} </div> - <div class="value-panel"> - <div echarts [options]="chartOption" [ngStyle]="{'width': '100%', 'height': currentHeight}" - (chartInit)="onChartInit($event)" [merge]= "dynamicData" *ngIf="configReady"> + <div fxFlex [ngStyle]="{height: currentHeight + 'px'}" *ngIf="configReady"> + <div echarts [options]="chartOption" [ngStyle]="{'width': '100%', 'height': '100%'}" + (chartInit)="onChartInit($event)" [merge]= "dynamicData"> </div> </div> </div>
diff --git a/ui/src/app/dashboard/components/widgets/bar-race/bar-race-widget.component.scss b/ui/src/app/dashboard/components/widgets/bar-race/bar-race-widget.component.scss index 76e1caf..e374f5d 100644 --- a/ui/src/app/dashboard/components/widgets/bar-race/bar-race-widget.component.scss +++ b/ui/src/app/dashboard/components/widgets/bar-race/bar-race-widget.component.scss
@@ -30,15 +30,6 @@ font-size: 20px; } -.value-panel { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - align-content: center; - flex: 1; -} - .status-light { border-radius: 50%; float: left;
diff --git a/ui/src/app/dashboard/components/widgets/bar-race/bar-race-widget.component.ts b/ui/src/app/dashboard/components/widgets/bar-race/bar-race-widget.component.ts index 5bbcf60..fa91d9e 100644 --- a/ui/src/app/dashboard/components/widgets/bar-race/bar-race-widget.component.ts +++ b/ui/src/app/dashboard/components/widgets/bar-race/bar-race-widget.component.ts
@@ -46,10 +46,10 @@ chartOption = { grid: { + left: 100, top: 10, - bottom: 30, - left: 150, - right: 80 + right: 120, + bottom: 100 }, xAxis: { max: 'dataMax', @@ -165,4 +165,8 @@ protected getQueryLimit(extractor: StaticPropertyExtractor): number { return 1; } + + getFieldsToQuery(): string[] { + return [this.partitionField, this.valueField]; + } }
diff --git a/ui/src/app/dashboard/components/widgets/base/base-echarts-widget.ts b/ui/src/app/dashboard/components/widgets/base/base-echarts-widget.ts index ff37734..2d4e602 100644 --- a/ui/src/app/dashboard/components/widgets/base/base-echarts-widget.ts +++ b/ui/src/app/dashboard/components/widgets/base/base-echarts-widget.ts
@@ -41,18 +41,12 @@ this.currentWidth = width; this.currentHeight = height; this.configReady = true; - this.applySize(width, height); - } - - onChartInit(ec) { - this.eChartsInstance = ec; - this.applySize(this.currentWidth, this.currentHeight); - } - - applySize(width: number, height: number) { if (this.eChartsInstance) { this.eChartsInstance.resize({width, height}); } } + onChartInit(ec) { + this.eChartsInstance = ec; + } }
diff --git a/ui/src/app/dashboard/components/widgets/base/base-ngx-line-charts-widget.ts b/ui/src/app/dashboard/components/widgets/base/base-ngx-line-charts-widget.ts index 94fef22..64f984c 100644 --- a/ui/src/app/dashboard/components/widgets/base/base-ngx-line-charts-widget.ts +++ b/ui/src/app/dashboard/components/widgets/base/base-ngx-line-charts-widget.ts
@@ -63,11 +63,16 @@ } timestampTickFormatting(timestamp: any): string { + const padL = (nr, len = 2, chr = `0`) => `${nr}`.padStart(2, chr); const date = new Date(timestamp); - return date.getHours() + ':' + date.getMinutes().toString().substr(-2) + ':' + date.getSeconds().toString().substr(-2); + return date.getHours() + ':' + `${padL(date.getMinutes())}` + ':' + `${padL(date.getSeconds())}`; } protected getQueryLimit(extractor: StaticPropertyExtractor): number { return extractor.integerParameter(WidgetConfigBuilder.QUERY_LIMIT_KEY); } + + getFieldsToQuery(): string[] { + return [this.selectedNumberProperty]; + } }
diff --git a/ui/src/app/dashboard/components/widgets/base/base-widget.ts b/ui/src/app/dashboard/components/widgets/base/base-widget.ts index 33ee18a..9a801a4 100644 --- a/ui/src/app/dashboard/components/widgets/base/base-widget.ts +++ b/ui/src/app/dashboard/components/widgets/base/base-widget.ts
@@ -16,23 +16,24 @@ * */ -import { Directive, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { Directive, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core'; import { StaticPropertyExtractor } from '../../../sdk/extractor/static-property-extractor'; -import { BehaviorSubject, interval, Observable, Subscription } from 'rxjs'; +import { BehaviorSubject, interval, Observable, Subscription, timer } from 'rxjs'; import { WidgetConfigBuilder } from '../../../registry/widget-config-builder'; import { ResizeService } from '../../../services/resize.service'; -import { WidgetInfo } from '../../../models/gridster-info.model'; import { DashboardWidgetModel, DataLakeMeasure, - DatalakeQueryParameterBuilder, - DatalakeRestService, + DatalakeQueryParameterBuilder, DatalakeQueryParameters, + DatalakeRestService, EventPropertyPrimitive, EventPropertyUnion, FieldConfig, SpQueryResult } from '@streampipes/platform-services'; -import { map, switchMap } from 'rxjs/operators'; +import { exhaustMap, map, switchMap } from 'rxjs/operators'; +import { GridsterItemComponent } from 'angular-gridster2'; +import { query } from '@angular/animations'; @Directive() -export abstract class BaseStreamPipesWidget implements OnChanges { +export abstract class BaseStreamPipesWidget implements OnInit, OnChanges, OnDestroy { protected constructor(protected dataLakeService: DatalakeRestService, protected resizeService: ResizeService, @@ -45,9 +46,11 @@ @Input() widgetConfig: DashboardWidgetModel; @Input() widgetDataConfig: DataLakeMeasure; + @Input() gridsterItemComponent: GridsterItemComponent; @Input() itemWidth: number; @Input() itemHeight: number; @Input() editMode: boolean; + @Input() globalRefresh: boolean; subscription: Subscription; intervalSubject: BehaviorSubject<number>; @@ -67,22 +70,31 @@ refreshIntervalInSeconds = 5; queryLimit = 1; + resizeSub: Subscription; + ngOnInit(): void { - this.prepareConfigExtraction(); - this.resizeService.resizeSubject.subscribe(info => { - this.onResize(info); + const widthOffset = 0; + const heightOffset = 0; + this.resizeSub = this.resizeService.resizeSubject.subscribe(info => { + if (info.gridsterItem.id === this.widgetConfig._id) { + this.onSizeChanged(this.computeCurrentWidth(this.gridsterItemComponent.width - widthOffset), + this.computeCurrentHeight(this.gridsterItemComponent.height - heightOffset)); + } }); - this.fireQuery().subscribe(result => this.processQueryResult(result)); + this.prepareConfigExtraction(); - this.intervalSubject = new BehaviorSubject<number>(this.refreshIntervalInSeconds); - this.subscription = this.intervalSubject.pipe( - switchMap(val => interval(val * 1000))) - .subscribe(() => { - this.fireQuery().subscribe(result => { + if (!(this.globalRefresh)) { + this.fireQuery().subscribe(result => this.processQueryResult(result)); + + this.intervalSubject = new BehaviorSubject<number>(this.refreshIntervalInSeconds); + this.subscription = this.intervalSubject.pipe( + switchMap(val => interval(val * 1000))) + .pipe(exhaustMap(() => this.fireQuery())) + .subscribe((result) => { this.processQueryResult(result); }); - }); + } } prepareConfigExtraction() { @@ -112,7 +124,13 @@ } ngOnDestroy(): void { - this.subscription.unsubscribe(); + if (this.subscription) { + this.subscription.unsubscribe(); + this.intervalSubject.unsubscribe(); + } + if (this.resizeSub) { + this.resizeSub.unsubscribe(); + } } computeCurrentWidth(width: number): number { @@ -149,15 +167,6 @@ } } - onResize(info: WidgetInfo) { - if (info.id === this.widgetConfig._id) { - setTimeout(() => { - this.onSizeChanged(this.computeCurrentWidth(info.width), - this.computeCurrentHeight(info.height)); - }, 100); - } - } - fireQuery(): Observable<SpQueryResult> { return this.dataLakeService .getData(this.widgetDataConfig.measureName, this.buildQuery(), true) @@ -181,8 +190,47 @@ } } - buildQuery() { + public buildQuery(includeMeasure = false): DatalakeQueryParameters { const queryBuilder = DatalakeQueryParameterBuilder.create(); - return queryBuilder.withLimit(this.queryLimit).withOrdering('DESC').build(); + const columns = this.getFieldsToQuery(); + if (columns) { + if (this.hasOnlyDimensionFields(this.widgetDataConfig.eventSchema.eventProperties, columns)) { + const firstMeasurementField = this.getAnyMeasurementField(this.widgetDataConfig.eventSchema.eventProperties); + columns.push(firstMeasurementField); + } + const fields: FieldConfig[] = columns.map(f => { + return {runtimeName: f, selected: false, numeric: false}; + }); + queryBuilder.withColumnFilter(fields, false); + } + + const queryParams = queryBuilder + .withLimit(this.queryLimit) + .withOrdering('DESC') + .build(); + + if (includeMeasure) { + queryParams.measureName = this.widgetDataConfig.measureName; + queryParams.forId = this.widgetConfig._id; + } + + return queryParams; } + + getAnyMeasurementField(eventProperties: EventPropertyUnion[]): string { + return eventProperties + .filter(ep => ep instanceof EventPropertyPrimitive) + .find(ep => ep.propertyScope === 'MEASUREMENT_PROPERTY').runtimeName; + } + + hasOnlyDimensionFields(eventProperties: EventPropertyUnion[], + columns: string[]): boolean { + return columns + .map(column => eventProperties + .find(ep => ep.runtimeName === column)) + .filter(ep => ep instanceof EventPropertyPrimitive) + .every(ep => (ep as EventPropertyPrimitive).propertyScope === 'DIMENSION_PROPERTY'); + } + + abstract getFieldsToQuery(): string[]; }
diff --git a/ui/src/app/dashboard/components/widgets/gauge/gauge-widget.component.ts b/ui/src/app/dashboard/components/widgets/gauge/gauge-widget.component.ts index f1993ed..14d351b 100644 --- a/ui/src/app/dashboard/components/widgets/gauge/gauge-widget.component.ts +++ b/ui/src/app/dashboard/components/widgets/gauge/gauge-widget.component.ts
@@ -68,4 +68,8 @@ return 1; } + getFieldsToQuery(): string[] { + return [this.selectedProperty]; + } + }
diff --git a/ui/src/app/dashboard/components/widgets/html/html-widget.component.ts b/ui/src/app/dashboard/components/widgets/html/html-widget.component.ts index bce9eff..6e4f759 100644 --- a/ui/src/app/dashboard/components/widgets/html/html-widget.component.ts +++ b/ui/src/app/dashboard/components/widgets/html/html-widget.component.ts
@@ -66,4 +66,8 @@ return 1; } + getFieldsToQuery(): string[] { + return [this.selectedHtmlField]; + } + }
diff --git a/ui/src/app/dashboard/components/widgets/image/image-widget.component.ts b/ui/src/app/dashboard/components/widgets/image/image-widget.component.ts index f2129ad..9423732 100644 --- a/ui/src/app/dashboard/components/widgets/image/image-widget.component.ts +++ b/ui/src/app/dashboard/components/widgets/image/image-widget.component.ts
@@ -74,4 +74,8 @@ return 1; } + getFieldsToQuery(): string[] { + return [this.selectedProperty]; + } + }
diff --git a/ui/src/app/dashboard/components/widgets/map/map-widget.component.ts b/ui/src/app/dashboard/components/widgets/map/map-widget.component.ts index 37fc542..ee0f7e8 100644 --- a/ui/src/app/dashboard/components/widgets/map/map-widget.component.ts +++ b/ui/src/app/dashboard/components/widgets/map/map-widget.component.ts
@@ -83,6 +83,10 @@ this.centerMap = extractor.selectedSingleValue(MapConfig.CENTER_MAP_KEY) === 'Center'; } + getFieldsToQuery(): string[] { + return [this.selectedLatitudeField, this.selectedLongitudeField, ...this.idsToDisplay]; + } + markerImage(selectedMarker: string): string { return selectedMarker === 'Default' ? 'assets/img/marker-icon.png' : 'assets/img/pe_icons/car.png'; }
diff --git a/ui/src/app/dashboard/components/widgets/number/number-widget.component.ts b/ui/src/app/dashboard/components/widgets/number/number-widget.component.ts index 1c36326..a05edab 100644 --- a/ui/src/app/dashboard/components/widgets/number/number-widget.component.ts +++ b/ui/src/app/dashboard/components/widgets/number/number-widget.component.ts
@@ -21,8 +21,7 @@ import { StaticPropertyExtractor } from '../../../sdk/extractor/static-property-extractor'; import { NumberConfig } from './number-config'; import { ResizeService } from '../../../services/resize.service'; -import { DashboardService } from '../../../services/dashboard.service'; -import { DatalakeRestService, EventPropertyPrimitive } from '@streampipes/platform-services'; +import { DashboardService, DatalakeRestService, EventPropertyPrimitive } from '@streampipes/platform-services'; @Component({ selector: 'number-widget', @@ -66,7 +65,7 @@ protected onEvent(events: any[]) { let value = events[0][this.selectedProperty]; - if (!isNaN(value)) { + if (typeof value === 'number') { value = value.toFixed(2); } this.item = value; @@ -79,4 +78,8 @@ return 1; } + getFieldsToQuery(): string[] { + return [this.selectedProperty]; + } + }
diff --git a/ui/src/app/dashboard/components/widgets/raw/raw-widget.component.ts b/ui/src/app/dashboard/components/widgets/raw/raw-widget.component.ts index d4f6708..d7e6288 100644 --- a/ui/src/app/dashboard/components/widgets/raw/raw-widget.component.ts +++ b/ui/src/app/dashboard/components/widgets/raw/raw-widget.component.ts
@@ -65,4 +65,8 @@ return extractor.integerParameter(WidgetConfigBuilder.QUERY_LIMIT_KEY); } + getFieldsToQuery(): string[] { + return undefined; + } + }
diff --git a/ui/src/app/dashboard/components/widgets/stacked-line-chart/stacked-line-chart-widget.component.html b/ui/src/app/dashboard/components/widgets/stacked-line-chart/stacked-line-chart-widget.component.html index d4cf255..59b7f59 100644 --- a/ui/src/app/dashboard/components/widgets/stacked-line-chart/stacked-line-chart-widget.component.html +++ b/ui/src/app/dashboard/components/widgets/stacked-line-chart/stacked-line-chart-widget.component.html
@@ -20,9 +20,9 @@ <div class="title-panel mt-20" *ngIf="hasTitlePanelSettings"> {{selectedTitle}} </div> - <div class="value-panel"> - <div echarts [options]="chartOption" [ngStyle]="{'width': '100%', 'height': currentHeight}" - (chartInit)="onChartInit($event)" [merge]= "dynamicData" *ngIf="configReady"> + <div fxFlex [ngStyle]="{height: currentHeight + 'px'}" *ngIf="configReady"> + <div echarts [options]="chartOption" [ngStyle]="{'width': '100%', 'height': '100%'}" + (chartInit)="onChartInit($event)" [merge]= "dynamicData"> </div> </div> </div>
diff --git a/ui/src/app/dashboard/components/widgets/stacked-line-chart/stacked-line-chart-widget.component.scss b/ui/src/app/dashboard/components/widgets/stacked-line-chart/stacked-line-chart-widget.component.scss index 76e1caf..e374f5d 100644 --- a/ui/src/app/dashboard/components/widgets/stacked-line-chart/stacked-line-chart-widget.component.scss +++ b/ui/src/app/dashboard/components/widgets/stacked-line-chart/stacked-line-chart-widget.component.scss
@@ -30,15 +30,6 @@ font-size: 20px; } -.value-panel { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - align-content: center; - flex: 1; -} - .status-light { border-radius: 50%; float: left;
diff --git a/ui/src/app/dashboard/components/widgets/stacked-line-chart/stacked-line-chart-widget.component.ts b/ui/src/app/dashboard/components/widgets/stacked-line-chart/stacked-line-chart-widget.component.ts index d7cd1da..3bf42bc 100644 --- a/ui/src/app/dashboard/components/widgets/stacked-line-chart/stacked-line-chart-widget.component.ts +++ b/ui/src/app/dashboard/components/widgets/stacked-line-chart/stacked-line-chart-widget.component.ts
@@ -24,7 +24,7 @@ import { EChartsOption } from 'echarts'; import { DatalakeRestService } from '@streampipes/platform-services'; import { BaseNgxLineChartsStreamPipesWidget } from '../base/base-ngx-line-charts-widget'; -import { WidgetConfigBuilder } from "../../../registry/widget-config-builder"; +import { WidgetConfigBuilder } from '../../../registry/widget-config-builder'; @Component({ @@ -39,6 +39,12 @@ timestampField: string; chartOption = { + grid: { + left: 50, + top: 10, + right: 50, + bottom: 100 + }, tooltip: { trigger: 'axis', formatter (params) { @@ -71,11 +77,12 @@ } }, series: [], - animationDuration: 500 + animationDuration: 300 }; constructor(dataLakeService: DatalakeRestService, resizeService: ResizeService) { super(dataLakeService, resizeService); + this.configReady = true; } protected extractConfig(extractor: StaticPropertyExtractor) { @@ -84,38 +91,38 @@ this.chartOption.yAxis.axisLabel.textStyle.color = this.selectedPrimaryTextColor; } - protected onEvent(event: any) { + getFieldsToQuery(): string[] { + return this.valueFields; + } + + protected onEvent(events: any) { this.dynamicData = this.chartOption; - const timestamp = event[BaseNgxLineChartsStreamPipesWidget.TIMESTAMP_KEY]; + this.dynamicData.series = []; + this.valueFields.forEach(field => { - if (this.dynamicData.series.some(d => d.name === field)) { - const date = new Date(timestamp); - this.dynamicData.series.find(d => d.name === field).data.push( - {'name': date.toString(), value: [timestamp, event[field]]} - ); - if (this.dynamicData.series.find(d => d.name === field).data.length > 5) { - this.dynamicData.series.find(d => d.name === field).data.shift(); - } - } else { - this.dynamicData.series.push(this.makeNewSeries(field, timestamp, event[field])); - } + const series = this.makeNewSeries(field); + series.data = events.map(event => { + const timestamp = event[BaseNgxLineChartsStreamPipesWidget.TIMESTAMP_KEY]; + return { + 'name': timestamp.toString(), + value: [timestamp, event[field]] + }; + }); + this.dynamicData.series.push(series); }); if (this.eChartsInstance) { this.eChartsInstance.setOption(this.dynamicData as EChartsOption); } + } - makeNewSeries(seriesName, timestamp, value) { - const date = new Date(timestamp); + makeNewSeries(seriesName: string): any { return { type: 'line', smooth: true, name: seriesName, - data: [{ - 'name': date.toString(), - value: [timestamp, value] - }], + data: [], }; }
diff --git a/ui/src/app/dashboard/components/widgets/status/status-widget.component.ts b/ui/src/app/dashboard/components/widgets/status/status-widget.component.ts index 6d08ddf..c8658c8 100644 --- a/ui/src/app/dashboard/components/widgets/status/status-widget.component.ts +++ b/ui/src/app/dashboard/components/widgets/status/status-widget.component.ts
@@ -72,4 +72,8 @@ return 1; } + getFieldsToQuery(): string[] { + return undefined; + } + }
diff --git a/ui/src/app/dashboard/components/widgets/table/table-widget.component.ts b/ui/src/app/dashboard/components/widgets/table/table-widget.component.ts index d291899..65360b0 100644 --- a/ui/src/app/dashboard/components/widgets/table/table-widget.component.ts +++ b/ui/src/app/dashboard/components/widgets/table/table-widget.component.ts
@@ -34,6 +34,7 @@ export class TableWidgetComponent extends BaseStreamPipesWidget implements OnInit, OnDestroy { selectedProperties: string[]; + fields: string[]; displayedColumns: string[] = []; dataSource = new MatTableDataSource(); @@ -61,9 +62,14 @@ extractConfig(extractor: StaticPropertyExtractor) { this.selectedProperties = extractor.mappingPropertyValues(TableConfig.SELECTED_PROPERTIES_KEYS); + this.fields = extractor.mappingPropertyValues(TableConfig.SELECTED_PROPERTIES_KEYS); this.selectedProperties.push(BaseStreamPipesWidget.TIMESTAMP_KEY); } + getFieldsToQuery(): string[] { + return this.fields; + } + protected onEvent(events: any[]) { this.dataSource.data = events.map(ev => this.createTableObject(ev)).reverse(); this.dataSource.data = [...this.dataSource.data];
diff --git a/ui/src/app/dashboard/components/widgets/trafficlight/traffic-light-widget.component.ts b/ui/src/app/dashboard/components/widgets/trafficlight/traffic-light-widget.component.ts index 8681357..c008362 100644 --- a/ui/src/app/dashboard/components/widgets/trafficlight/traffic-light-widget.component.ts +++ b/ui/src/app/dashboard/components/widgets/trafficlight/traffic-light-widget.component.ts
@@ -80,6 +80,9 @@ this.selectedLimitGreaterThan = extractor.selectedSingleValue(TrafficLightConfig.CRITICAL_VALUE_LIMIT) === 'Upper Limit'; } + getFieldsToQuery(): string[] { + return [this.selectedFieldToObserve]; + } protected onEvent(events: any[]) { const item = events[0][this.selectedFieldToObserve];
diff --git a/ui/src/app/dashboard/components/widgets/wordcloud/wordcloud-widget.component.ts b/ui/src/app/dashboard/components/widgets/wordcloud/wordcloud-widget.component.ts index 0a08634..aa8a237 100644 --- a/ui/src/app/dashboard/components/widgets/wordcloud/wordcloud-widget.component.ts +++ b/ui/src/app/dashboard/components/widgets/wordcloud/wordcloud-widget.component.ts
@@ -106,6 +106,10 @@ this.windowSize = extractor.integerParameter(WordCloudConfig.WINDOW_SIZE_KEY); } + getFieldsToQuery(): string[] { + return [this.countProperty, this.nameProperty]; + } + protected onEvent(event: any) { const value = event[this.countProperty]; const name = event[this.nameProperty];
diff --git a/ui/src/app/dashboard/dashboard.can-deactivate.guard.ts b/ui/src/app/dashboard/dashboard.can-deactivate.guard.ts new file mode 100644 index 0000000..b720de5 --- /dev/null +++ b/ui/src/app/dashboard/dashboard.can-deactivate.guard.ts
@@ -0,0 +1,35 @@ +/* + * 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 { ActivatedRouteSnapshot, CanDeactivate, RouterStateSnapshot } from '@angular/router'; +import { Observable } from 'rxjs'; +import { DashboardPanelComponent } from './components/panel/dashboard-panel.component'; + +@Injectable({providedIn: 'root'}) +export class DashboardPanelCanDeactivateGuard implements CanDeactivate<DashboardPanelComponent> { + + canDeactivate( + component: DashboardPanelComponent, + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): Observable<boolean> | boolean { + + return component.confirmLeaveDashboard(route, state); + } +}
diff --git a/ui/src/app/dashboard/dashboard.component.css b/ui/src/app/dashboard/dashboard.component.css deleted file mode 100644 index 8e7687a..0000000 --- a/ui/src/app/dashboard/dashboard.component.css +++ /dev/null
@@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -.mr-20 { - margin-right:20px; -} - -.dashboard-panel { - height: 100%; - flex-direction: column; - box-sizing: border-box; - display: flex; - flex: 1 1 100%; - overflow-y: auto; -} \ No newline at end of file
diff --git a/ui/src/app/dashboard/dashboard.component.html b/ui/src/app/dashboard/dashboard.component.html deleted file mode 100644 index 7cb4e9c..0000000 --- a/ui/src/app/dashboard/dashboard.component.html +++ /dev/null
@@ -1,51 +0,0 @@ -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one or more - ~ contributor license agreements. See the NOTICE file distributed with - ~ this work for additional information regarding copyright ownership. - ~ The ASF licenses this file to You under the Apache License, Version 2.0 - ~ (the "License"); you may not use this file except in compliance with - ~ the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - ~ - --> - -<div fxLayout="column" class="page-container"> - <div fxLayout="row" class="p-0 sp-tab-bg"> - <div fxFlex="100" class="page-container-nav"> - <div fxFlex="100" fxLayout="row"> - <div fxFlex fxLayoutAlign="start center"> - <mat-tab-group [selectedIndex]="selectedIndex" (selectedIndexChange)="selectDashboard($event)" color="accent"> - <mat-tab label="Start"></mat-tab> - <mat-tab *ngFor="let dashboard of dashboards" label="{{dashboard.name}}"></mat-tab> - </mat-tab-group> - </div> - <div fxFlex fxLayoutAlign="end center" class="mr-20"> - <button mat-button mat-icon-button color="accent" - *ngIf="selectedIndex > 0 && hasDashboardWritePrivileges" (click)="toggleEditMode()" [disabled]="editMode"> - <i class="material-icons">edit</i> - </button> - </div> - </div> - </div> - </div> - - <div class="fixed-height" fxLayout="column" fxFlex="100" *ngIf="dashboardsLoaded"> - <dashboard-overview (selectDashboardEmitter)="openDashboard($event)" - (reloadDashboardsEmitter)="getDashboards()" - [dashboards]="dashboards" - *ngIf="!dashboardTabSelected"> - - </dashboard-overview> - <dashboard-panel fxLayout="column" [(editMode)]="editMode" [dashboard]="selectedDashboard" - class="dashboard-panel" *ngIf="dashboardTabSelected"> - - </dashboard-panel> - </div> -</div>
diff --git a/ui/src/app/dashboard/dashboard.component.ts b/ui/src/app/dashboard/dashboard.component.ts deleted file mode 100644 index a8d11f4..0000000 --- a/ui/src/app/dashboard/dashboard.component.ts +++ /dev/null
@@ -1,101 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Component, OnInit } from '@angular/core'; -import { Dashboard } from '@streampipes/platform-services'; -import { DashboardService } from './services/dashboard.service'; -import { RefreshDashboardService } from './services/refresh-dashboard.service'; -import { Tuple2 } from '../core-model/base/Tuple2'; -import { EditModeService } from './services/edit-mode.service'; -import { ActivatedRoute } from '@angular/router'; -import { AuthService } from '../services/auth.service'; -import { UserPrivilege } from '../_enums/user-privilege.enum'; - -@Component({ - selector: 'dashboard', - templateUrl: './dashboard.component.html', - styleUrls: ['./dashboard.component.css'] -}) -export class DashboardComponent implements OnInit { - - selectedDashboard: Dashboard; - selectedIndex = 0; - dashboardsLoaded = false; - dashboardTabSelected = false; - - editMode = false; - - dashboards: Dashboard[]; - hasDashboardWritePrivileges = false; - - routeParams: any; - - constructor(private dashboardService: DashboardService, - private refreshDashboardService: RefreshDashboardService, - private editModeService: EditModeService, - private route: ActivatedRoute, - private authService: AuthService) {} - - ngOnInit() { - this.hasDashboardWritePrivileges = this.authService.hasRole(UserPrivilege.PRIVILEGE_WRITE_DASHBOARD); - this.route.queryParams.subscribe(params => { - this.getDashboards(params['dashboardId']); - }); - this.refreshDashboardService.refreshSubject.subscribe(currentDashboardId => { - this.getDashboards(currentDashboardId); - }); - this.editModeService.editModeSubject.subscribe(editMode => { - this.editMode = editMode; - }); - - } - - openDashboard(data: Tuple2<Dashboard, boolean>) { - const index = this.dashboards.indexOf(data.a); - this.editMode = data.b; - this.selectDashboard((index + 1)); - } - - selectDashboard(index: number) { - this.selectedIndex = index; - if (index === 0) { - this.dashboardTabSelected = false; - } else { - this.dashboardTabSelected = true; - this.selectedDashboard = this.dashboards[(index - 1)]; - } - } - - protected getDashboards(currentDashboardId?: string) { - this.dashboardsLoaded = false; - this.dashboardService.getDashboards().subscribe(data => { - this.dashboards = data.sort((a, b) => a.name.localeCompare(b.name)); - if (currentDashboardId) { - const currentDashboard = this.dashboards.find(d => d._id === currentDashboardId); - this.selectDashboard(this.dashboards.indexOf(currentDashboard) + 1); - } else { - this.selectedIndex = 0; - } - this.dashboardsLoaded = true; - }); - } - - toggleEditMode() { - this.editMode = ! (this.editMode); - } -}
diff --git a/ui/src/app/dashboard/dashboard.module.ts b/ui/src/app/dashboard/dashboard.module.ts index 3072ee1..a736ce9 100644 --- a/ui/src/app/dashboard/dashboard.module.ts +++ b/ui/src/app/dashboard/dashboard.module.ts
@@ -20,7 +20,6 @@ import { CommonModule } from '@angular/common'; import { FlexLayoutModule } from '@angular/flex-layout'; import { GridsterModule } from 'angular-gridster2'; -import { DashboardComponent } from './dashboard.component'; import { DashboardPanelComponent } from './components/panel/dashboard-panel.component'; import { MatTabsModule } from '@angular/material/tabs'; import { DashboardWidgetComponent } from './components/widget/dashboard-widget.component'; @@ -29,7 +28,6 @@ import { ColorPickerModule } from 'ngx-color-picker'; import { AddVisualizationDialogComponent } from './dialogs/add-widget/add-visualization-dialog.component'; import { MatGridListModule } from '@angular/material/grid-list'; -import { DashboardService } from './services/dashboard.service'; import { NumberWidgetComponent } from './components/widgets/number/number-widget.component'; import { DashboardOverviewComponent } from './components/overview/dashboard-overview.component'; import { EditDashboardDialogComponent } from './dialogs/edit-dashboard/edit-dashboard-dialog.component'; @@ -60,69 +58,89 @@ import { ReloadPipelineService } from './services/reload-pipeline.service'; import { PlatformServicesModule } from '@streampipes/platform-services'; import { CustomMaterialModule } from '../CustomMaterial/custom-material.module'; -import { ServicesModule } from "../services/services.module"; +import { ServicesModule } from '../services/services.module'; +import { RouterModule } from '@angular/router'; +import { SharedUiModule } from '@streampipes/shared-ui'; +import { DataExplorerPanelCanDeactivateGuard } from '../data-explorer/data-explorer-panel.can-deactivate.guard'; +import { DashboardPanelCanDeactivateGuard } from './dashboard.can-deactivate.guard'; @NgModule({ - imports: [ - NgxEchartsModule.forRoot({ - /** - * This will import all modules from echarts. - * If you only need custom modules, - * please refer to [Custom Build] section. - */ - echarts: () => import('echarts'), - }), - CommonModule, - CoreUiModule, - MatTabsModule, - GridsterModule, - FlexLayoutModule, - CustomMaterialModule, - FormsModule, - ColorPickerModule, - MatGridListModule, - NgxChartsModule, - CdkTableModule, - LeafletModule, - PlatformServicesModule, - ServicesModule - ], - declarations: [ - BarRaceWidgetComponent, - DashboardComponent, - DashboardGridComponent, - DashboardOverviewComponent, - DashboardPanelComponent, - DashboardWidgetComponent, - AddVisualizationDialogComponent, - EditDashboardDialogComponent, - AreaWidgetComponent, - LineWidgetComponent, - NumberWidgetComponent, - TableWidgetComponent, - GaugeWidgetComponent, - ImageWidgetComponent, - MapWidgetComponent, - RawWidgetComponent, - StackedLineChartWidgetComponent, - HtmlWidgetComponent, - StatusWidgetComponent, - TrafficLightWidgetComponent, - WordcloudWidgetComponent, - StandaloneDashboardComponent - ], - providers: [ - DashboardService, - EditModeService, - ReloadPipelineService, - ResizeService, - RefreshDashboardService, - SemanticTypeUtilsService - ], - exports: [ - DashboardComponent, - DashboardWidgetComponent - ] + imports: [ + NgxEchartsModule.forRoot({ + /** + * This will import all modules from echarts. + * If you only need custom modules, + * please refer to [Custom Build] section. + */ + echarts: () => import('echarts'), + }), + CommonModule, + CoreUiModule, + MatTabsModule, + GridsterModule, + FlexLayoutModule, + CustomMaterialModule, + FormsModule, + ColorPickerModule, + MatGridListModule, + NgxChartsModule, + CdkTableModule, + LeafletModule, + PlatformServicesModule, + ServicesModule, + SharedUiModule, + RouterModule.forChild([ + { + path: 'dashboard', + children: [ + { + path: '', + component: DashboardOverviewComponent + }, + { + path: ':id', + component: DashboardPanelComponent, + canDeactivate: [DashboardPanelCanDeactivateGuard] + } + ] + } + ]), + SharedUiModule, + ], + declarations: [ + BarRaceWidgetComponent, + DashboardGridComponent, + DashboardOverviewComponent, + DashboardPanelComponent, + DashboardWidgetComponent, + AddVisualizationDialogComponent, + EditDashboardDialogComponent, + AreaWidgetComponent, + LineWidgetComponent, + NumberWidgetComponent, + TableWidgetComponent, + GaugeWidgetComponent, + ImageWidgetComponent, + MapWidgetComponent, + RawWidgetComponent, + StackedLineChartWidgetComponent, + HtmlWidgetComponent, + StatusWidgetComponent, + TrafficLightWidgetComponent, + WordcloudWidgetComponent, + StandaloneDashboardComponent + ], + providers: [ + EditModeService, + ReloadPipelineService, + ResizeService, + RefreshDashboardService, + SemanticTypeUtilsService + ], + exports: [ + DashboardWidgetComponent, + StandaloneDashboardComponent + ] }) export class DashboardModule {
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/dashboard/dashboard.routes.ts similarity index 81% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/dashboard/dashboard.routes.ts index 58ba04b..57da4a1 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/dashboard/dashboard.routes.ts
@@ -16,3 +16,10 @@ * */ +import { SpBreadcrumbItem, } from '@streampipes/shared-ui'; + +export class SpDashboardRoutes { + + static BASE: SpBreadcrumbItem = {label: 'Dashboards', link: ['dashboard']}; + +}
diff --git a/ui/src/app/dashboard/dialogs/add-widget/add-visualization-dialog.component.html b/ui/src/app/dashboard/dialogs/add-widget/add-visualization-dialog.component.html index 45c650a..5142e8c 100644 --- a/ui/src/app/dashboard/dialogs/add-widget/add-visualization-dialog.component.html +++ b/ui/src/app/dashboard/dialogs/add-widget/add-visualization-dialog.component.html
@@ -26,7 +26,7 @@ <mat-list-item *ngFor="let pipeline of visualizablePipelines" (click)="selectPipeline(pipeline)" class="list-item" - [attr.data-cy]="'dashboard-visualize-pipeline-' + pipeline.pipelineName"> + [attr.data-cy]="'dashboard-visualize-pipeline-' + pipeline.pipelineName.replaceAll(' ', '_')"> <div mat-list-avatar class="pipeline-avatar sp-accent-bg">{{iconText(pipeline.measureName)}} </div>
diff --git a/ui/src/app/dashboard/dialogs/add-widget/add-visualization-dialog.component.ts b/ui/src/app/dashboard/dialogs/add-widget/add-visualization-dialog.component.ts index 2b65f47..538408d 100644 --- a/ui/src/app/dashboard/dialogs/add-widget/add-visualization-dialog.component.ts +++ b/ui/src/app/dashboard/dialogs/add-widget/add-visualization-dialog.component.ts
@@ -21,9 +21,9 @@ import { WidgetConfigBuilder } from '../../registry/widget-config-builder'; import { WidgetRegistry } from '../../registry/widget-registry'; import { MappingPropertyGenerator } from '../../sdk/matching/mapping-property-generator'; -import { DashboardService } from '../../services/dashboard.service'; import { Dashboard, + DashboardService, DashboardWidgetModel, DashboardWidgetSettings, DataLakeMeasure, DatalakeRestService,
diff --git a/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.html b/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.html index a653ab0..d45e60a 100644 --- a/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.html +++ b/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.html
@@ -33,7 +33,18 @@ </mat-form-field> <mat-checkbox [(ngModel)]="dashboard.displayHeader">Show name and description in dashboard </mat-checkbox> + <div fxLayout="column" class="mt-10"> + <mat-checkbox [(ngModel)]="dashboard.dashboardGeneralSettings.globalRefresh"> + Use same update frequency for all widgets (will override widget-specific intervals) + </mat-checkbox> + <mat-form-field class="full-width mt-10" + color="accent" + *ngIf="dashboard.dashboardGeneralSettings.globalRefresh"> + <mat-label>Refresh interval (seconds)</mat-label> + <input matInput [(ngModel)]="dashboard.dashboardGeneralSettings.refreshIntervalInSeconds"> + </mat-form-field> + </div> </div> </div> </div>
diff --git a/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.ts b/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.ts index 26be5b4..a9461f0 100644 --- a/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.ts +++ b/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.ts
@@ -17,8 +17,7 @@ */ import { Component, Input } from '@angular/core'; -import { DashboardService } from '../../services/dashboard.service'; -import { Dashboard } from '@streampipes/platform-services'; +import { Dashboard, DashboardService } from '@streampipes/platform-services'; import { DialogRef } from '@streampipes/shared-ui'; @Component({
diff --git a/ui/src/app/dashboard/services/resize.service.ts b/ui/src/app/dashboard/services/resize.service.ts index 129f7c2..32101c3 100644 --- a/ui/src/app/dashboard/services/resize.service.ts +++ b/ui/src/app/dashboard/services/resize.service.ts
@@ -18,14 +18,14 @@ import { Subject } from 'rxjs'; import { Injectable } from '@angular/core'; -import { WidgetInfo } from '../models/gridster-info.model'; +import { GridsterInfo } from '../models/gridster-info.model'; @Injectable() export class ResizeService { - public resizeSubject: Subject<WidgetInfo> = new Subject<WidgetInfo>(); + public resizeSubject: Subject<GridsterInfo> = new Subject<GridsterInfo>(); - public notify(info: WidgetInfo): void { + public notify(info: GridsterInfo): void { this.resizeSubject.next(info); } }
diff --git a/ui/src/app/data-explorer/components/datadownloadDialog/dataDownload.dialog.html b/ui/src/app/data-explorer/components/datadownloadDialog/dataDownload.dialog.html deleted file mode 100644 index 8334031..0000000 --- a/ui/src/app/data-explorer/components/datadownloadDialog/dataDownload.dialog.html +++ /dev/null
@@ -1,100 +0,0 @@ -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one or more - ~ contributor license agreements. See the NOTICE file distributed with - ~ this work for additional information regarding copyright ownership. - ~ The ASF licenses this file to You under the Apache License, Version 2.0 - ~ (the "License"); you may not use this file except in compliance with - ~ the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - ~ - --> - -<mat-toolbar> - <div class="md-toolbar-tools"> - <h2>Download Data</h2> - <span fxFlex></span> - <button mat-icon-button (click)="exitDialog()"> - <i class="material-icons">close</i> - </button> - </div> -</mat-toolbar> - -<div mat-dialog-content class="md-dialog-content"> - - - <mat-horizontal-stepper #stepper> - <mat-step> - <ng-template matStepLabel>Select Data</ng-template> - <div> - <mat-radio-group class="example-radio-group" [(ngModel)]="selectedData"> -<!-- <mat-radio-button value="visible" class="example-radio-button">--> -<!-- Visible data in charts--> -<!-- </mat-radio-button>--> - <mat-radio-button value="all" class="example-radio-button"> - All data in database - </mat-radio-button> - <mat-radio-button value="customInterval" class="example-radio-button"> - All data in custom time interval - </mat-radio-button> - </mat-radio-group> - <div fxLayout="row" fxLayoutAlign="start center" class="ml-35"> - <mat-form-field class="form-field-date"> - <input matInput [owlDateTime]="dt1" [owlDateTimeTrigger]="dt1" - [(ngModel)]="dateRange" [selectMode]="'range'" [disabled]="selectedData !== 'customInterval'"> - <mat-icon matSuffix [owlDateTimeTrigger]="dt1" *ngIf="selectedData === 'customInterval'">event</mat-icon> - <mat-icon matSuffix class="event-color" *ngIf="selectedData !== 'customInterval'">event</mat-icon> - <owl-date-time #dt1></owl-date-time> - </mat-form-field> - </div> - </div> - </mat-step> - - - - <mat-step> - <ng-template matStepLabel>Select Format</ng-template> - <div> - <mat-radio-group class="example-radio-group" [(ngModel)]="downloadFormat"> - <mat-radio-button value="json" class="example-radio-button"> - JSON - </mat-radio-button> - <mat-radio-button value="csv" class="example-radio-button"> - CSV - </mat-radio-button> - </mat-radio-group> - </div> - </mat-step> - - - - - - <mat-step> - <ng-template matStepLabel>Download</ng-template> - <div div fxLayout="column" fxLayoutAlign="space-around center" *ngIf="!downloadFinish"> - <mat-spinner></mat-spinner> - <label *ngIf="downloadedMBs !== undefined">{{downloadedMBs | number : '1.0-2' }} Mb</label> - <button mat-button warn color="warn" (click)="cancelDownload()">Cancel</button> - </div> - <div div fxLayout="column" fxLayoutAlign="space-around center" *ngIf="downloadFinish"> - <mat-icon class="icon-check">check</mat-icon> - </div> - </mat-step> - </mat-horizontal-stepper> - -</div> - -<mat-divider></mat-divider> -<div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center"> - <button mat-button *ngIf="stepper.selectedIndex == 1" color="primary" (click)="previousStep()">Previous</button> - <button mat-button mat-raised-button *ngIf="stepper.selectedIndex < 1" color="primary" (click)="nextStep()">Next</button> - <button mat-button mat-raised-button *ngIf="stepper.selectedIndex == 1" color="accent" (click)="downloadData()">Download</button> - <button mat-button mat-raised-button *ngIf="downloadFinish" color="primary" (click)="exitDialog()">Close</button> -</div>
diff --git a/ui/src/app/data-explorer/components/datadownloadDialog/dataDownload.dialog.ts b/ui/src/app/data-explorer/components/datadownloadDialog/dataDownload.dialog.ts deleted file mode 100644 index 794fbf9..0000000 --- a/ui/src/app/data-explorer/components/datadownloadDialog/dataDownload.dialog.ts +++ /dev/null
@@ -1,174 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { HttpEventType } from '@angular/common/http'; -import { Component, Inject, ViewChild } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { MatStepper } from '@angular/material/stepper'; -import { DatalakeRestService } from '@streampipes/platform-services'; - - -@Component({ - selector: 'sp-data-download-dialog', - templateUrl: 'dataDownload.dialog.html', - styleUrls: ['./dataDownload.dialog.css'] -}) -// tslint:disable-next-line:component-class-suffix -export class DataDownloadDialog { - - - downloadFormat = 'csv'; - selectedData = 'visible'; - downloadFinish = false; - downloadedMBs: number = undefined; - - @ViewChild('stepper', { static: true }) stepper: MatStepper; - - downloadHttpRequestSubscribtion; - - dateRange: Date [] = []; // [0] start, [1] end - - - constructor(public dialogRef: MatDialogRef<DataDownloadDialog>, - @Inject(MAT_DIALOG_DATA) public data, - public datalakeRestService: DatalakeRestService) { - this.dateRange[0] = new Date(); - this.dateRange[1] = new Date(this.dateRange[0].getTime() + 60000 * 60 * 24); - } - - downloadData() { - this.nextStep(); - switch (this.selectedData) { - case 'all': - this.performRequest(this.data.downloadRawData(this.data.index, this.downloadFormat), '', ''); - break; - case 'customInterval': - this.performRequest(this.datalakeRestService.downloadQueriedData(this.data.index, this.downloadFormat, - this.dateRange[0].getTime(), this.dateRange[1].getTime()), this.getDateString(this.dateRange[0]), - this.getDateString(this.dateRange[1])); - - } - } - - performRequest(request, startDate, endDate) { - this.downloadHttpRequestSubscribtion = request.subscribe(event => { - // progress - if (event.type === HttpEventType.DownloadProgress) { - this.downloadedMBs = event.loaded / 1024 / 1014; - } - - // finished - if (event.type === HttpEventType.Response) { - this.createFile(event.body, this.downloadFormat, this.data.index, startDate, endDate); - this.downloadFinish = true; - } - }); - } - - convertData(data, format, xAxesKey, yAxesKeys) { - const indexXKey = data.headers.findIndex(headerName => headerName === xAxesKey); - const indicesYKeys = []; - yAxesKeys.forEach(key => { - indicesYKeys.push(data.headers.findIndex(headerName => headerName === key)); - }); - - if (format === 'json') { - const resultJson = []; - - - data.rows.forEach(row => { - const tmp = {'time': new Date(row[indexXKey]).getTime()}; - indicesYKeys.forEach(index => { - if (row[index] !== undefined) { - tmp[data.headers[index]] = row[index]; - } - }); - resultJson.push(tmp); - }); - - return JSON.stringify(resultJson); - } else { - // CSV - let resultCsv = ''; - - // header - resultCsv += xAxesKey; - yAxesKeys.forEach(key => { - resultCsv += ';'; - resultCsv += key; - }); - - - // content - data.rows.forEach(row => { - resultCsv += '\n'; - resultCsv += new Date(row[indexXKey]).getTime(); - indicesYKeys.forEach(index => { - resultCsv += ';'; - if (row[index] !== undefined) { - resultCsv += row[index]; - } - }); - }); - - return resultCsv; - } - } - - createFile(data, format, fileName, startDate, endDate) { - const a = document.createElement('a'); - document.body.appendChild(a); - a.style.display = 'display: none'; - - let name = 'sp_' + startDate + '_' + fileName + '.' + this.downloadFormat; - name = name.replace('__', '_'); - - const url = window.URL.createObjectURL(new Blob([String(data)], { type: 'data:text/' + format + ';charset=utf-8' })); - a.href = url; - a.download = name; - a.click(); - window.URL.revokeObjectURL(url); - } - - cancelDownload() { - try { - this.downloadHttpRequestSubscribtion.unsubscribe(); - } finally { - this.exitDialog(); - } - } - - - exitDialog(): void { - this.dialogRef.close(); - } - - nextStep() { - this.stepper.next(); - } - - previousStep() { - this.stepper.previous(); - } - - getDateString(date: Date) { - return date.toLocaleDateString() + 'T' + date.toLocaleTimeString().replace(':', '.') - .replace(':', '.'); - } - -}
diff --git a/ui/src/app/data-explorer/components/designer-panel/data-explorer-designer-panel.component.html b/ui/src/app/data-explorer/components/designer-panel/data-explorer-designer-panel.component.html index 8866e18..af0e26f 100644 --- a/ui/src/app/data-explorer/components/designer-panel/data-explorer-designer-panel.component.html +++ b/ui/src/app/data-explorer/components/designer-panel/data-explorer-designer-panel.component.html
@@ -39,7 +39,8 @@ <div fxFlex fxLayout="column" class="designer-panel-config"> <div *ngIf="selectedIndex == 0"> - <sp-data-explorer-widget-data-settings [(dataLakeMeasure)]="dataLakeMeasure" + <sp-data-explorer-widget-data-settings #dataSettingsPanel + [(dataLakeMeasure)]="dataLakeMeasure" [dataConfig]="currentlyConfiguredWidget.dataConfig" [newWidgetMode]="newWidgetMode" [widgetId]="currentlyConfiguredWidget._id" @@ -64,6 +65,7 @@ *ngIf="newWidgetMode"> <button mat-button mat-raised-button color="accent" data-cy="data-explorer-select-data-set-next-btn" + [disabled]="selectedIndex === 0 && (!(currentlyConfiguredWidget.dataConfig.sourceConfigs) || currentlyConfiguredWidget.dataConfig.sourceConfigs.length === 0 || currentlyConfiguredWidget.dataConfig.sourceConfigs[0].measureName === '')" *ngIf="newWidgetMode && selectedIndex == 0" (click)="selectedIndex = 1"> Next
diff --git a/ui/src/app/data-explorer/components/designer-panel/data-explorer-designer-panel.component.ts b/ui/src/app/data-explorer/components/designer-panel/data-explorer-designer-panel.component.ts index 94af4fa..ec7b7e0 100644 --- a/ui/src/app/data-explorer/components/designer-panel/data-explorer-designer-panel.component.ts +++ b/ui/src/app/data-explorer/components/designer-panel/data-explorer-designer-panel.component.ts
@@ -16,9 +16,10 @@ * */ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; import { DataExplorerWidgetModel, DataLakeMeasure } from '@streampipes/platform-services'; import { Tuple2 } from '../../../core-model/base/Tuple2'; +import { DataExplorerWidgetDataSettingsComponent } from './data-settings/data-explorer-widget-data-settings.component'; @Component({ selector: 'sp-data-explorer-designer-panel', @@ -38,6 +39,8 @@ selectedIndex = 0; + dataSettingsPanel: DataExplorerWidgetDataSettingsComponent; + ngOnInit(): void { } @@ -51,15 +54,23 @@ // Set default name to the measure name if (this.currentlyConfiguredWidget.dataConfig.sourceConfigs.length > 0) { this.currentlyConfiguredWidget.baseAppearanceConfig.widgetTitle = - this.currentlyConfiguredWidget.dataConfig.sourceConfigs[0].measureName; + this.currentlyConfiguredWidget.dataConfig.sourceConfigs[0].measureName + + ' - ' + + this.currentlyConfiguredWidget.widgetType; } this.addWidgetEmitter.emit({ a: this.dataLakeMeasure, b: this.currentlyConfiguredWidget }); } - modifyWidgetMode(widget: DataExplorerWidgetModel, newWidgetMode: boolean) { + modifyWidgetMode(widget: DataExplorerWidgetModel, + newWidgetMode: boolean) { this.currentlyConfiguredWidget = widget; this.newWidgetMode = newWidgetMode; + if (this.dataSettingsPanel) { + setTimeout(() => { + this.dataSettingsPanel.checkSourceTypes(); + }); + } } closeDesignerPanel() { @@ -70,4 +81,9 @@ this.selectedIndex = 0; this.newWidgetMode = true; } + + @ViewChild('dataSettingsPanel') + public set content(dataSettingsPanel: DataExplorerWidgetDataSettingsComponent) { + this.dataSettingsPanel = dataSettingsPanel; + } }
diff --git a/ui/src/app/data-explorer/components/designer-panel/data-settings/data-explorer-widget-data-settings.component.html b/ui/src/app/data-explorer/components/designer-panel/data-settings/data-explorer-widget-data-settings.component.html index dee6ba4..c276798 100644 --- a/ui/src/app/data-explorer/components/designer-panel/data-settings/data-explorer-widget-data-settings.component.html +++ b/ui/src/app/data-explorer/components/designer-panel/data-settings/data-explorer-widget-data-settings.component.html
@@ -48,16 +48,16 @@ <mat-radio-group class="selection-radio-group" [(ngModel)]="sourceConfig.sourceType"> - <mat-radio-button class="selection-radio-button" [value]="'pipeline'">Pipeline + <mat-radio-button class="selection-radio-button" [value]="'pipeline'" [disabled]="availablePipelines.length === 0">Pipeline </mat-radio-button> <mat-radio-button class="selection-radio-button" [value]="'measurement'">Measurement </mat-radio-button> </mat-radio-group> </div> <mat-form-field color="accent" fxFlex="100" *ngIf="sourceConfig.sourceType == 'pipeline'"> - <mat-label>Data Explorer Sinks</mat-label> + <mat-label>Select data explorer sink</mat-label> <mat-select [(value)]="sourceConfig.measureName" - (selectionChange)="updateMeasure(sourceConfig, $event)" + (selectionChange)="updateMeasure(sourceConfig, $event.value)" data-cy="data-explorer-select-data-set"> <mat-option *ngFor="let pipeline of availablePipelines" [value]="pipeline.measureName"> @@ -66,9 +66,9 @@ </mat-select> </mat-form-field> <mat-form-field color="accent" fxFlex="100" *ngIf="sourceConfig.sourceType == 'measurement'"> - <mat-label>Data Lake Measurements</mat-label> + <mat-label>Select measurement</mat-label> <mat-select [(value)]="sourceConfig.measureName" - (selectionChange)="updateMeasure(sourceConfig, $event)"> + (selectionChange)="updateMeasure(sourceConfig, $event.value)"> <mat-option [value]="measurement.measureName" *ngFor="let measurement of availableMeasurements"> <span class="pipeline-name">{{ measurement.measureName }}</span> @@ -124,7 +124,8 @@ </div> <div fxLayout="column" fxFlex="100" class="data-explorer-options-panel" *ngIf="sourceConfig.queryType && sourceConfig.measure"> - <sp-field-selection-panel #fieldSelectionPanel [sourceConfig]="sourceConfig" + <sp-field-selection-panel #fieldSelectionPanel + [sourceConfig]="sourceConfig" [widgetId]="widgetId"></sp-field-selection-panel> </div> <div fxLayout="column" fxFlex="100" class="data-explorer-options-panel" @@ -134,7 +135,8 @@ </div> <div fxLayout="column" fxFlex="100" class="data-explorer-options-panel" *ngIf="sourceConfig.queryType && sourceConfig.measure"> - <sp-group-selection-panel [sourceConfig]="sourceConfig" + <sp-group-selection-panel #groupSelectionPanel + [sourceConfig]="sourceConfig" [widgetId]="widgetId"></sp-group-selection-panel> </div> </div>
diff --git a/ui/src/app/data-explorer/components/designer-panel/data-settings/data-explorer-widget-data-settings.component.ts b/ui/src/app/data-explorer/components/designer-panel/data-settings/data-explorer-widget-data-settings.component.ts index 6bb4c6b..7768df9 100644 --- a/ui/src/app/data-explorer/components/designer-panel/data-settings/data-explorer-widget-data-settings.component.ts +++ b/ui/src/app/data-explorer/components/designer-panel/data-settings/data-explorer-widget-data-settings.component.ts
@@ -30,6 +30,7 @@ import { zip } from 'rxjs'; import { WidgetConfigurationService } from '../../../services/widget-configuration.service'; import { FieldSelectionPanelComponent } from './field-selection-panel/field-selection-panel.component'; +import { GroupSelectionPanelComponent } from './group-selection-panel/group-selection-panel.component'; @Component({ selector: 'sp-data-explorer-widget-data-settings', @@ -51,8 +52,12 @@ @ViewChild('fieldSelectionPanel') fieldSelectionPanel: FieldSelectionPanelComponent; - availablePipelines: DataLakeMeasure[]; - availableMeasurements: DataLakeMeasure[]; + @ViewChild('groupSelectionPanel') + groupSelectionPanel: GroupSelectionPanelComponent; + + + availablePipelines: DataLakeMeasure[] = []; + availableMeasurements: DataLakeMeasure[] = []; step = 0; @@ -79,22 +84,55 @@ p.eventSchema = measurement.eventSchema; }); - if (!this.dataConfig.sourceConfigs) { - this.addDataSource(); + if (!(this.dataConfig.sourceConfigs)) { + const defaultConfigs = this.findDefaultConfig(); + this.addDataSource(defaultConfigs.measureName, defaultConfigs.sourceType); + if (defaultConfigs.measureName !== undefined) { + this.updateMeasure(this.dataConfig.sourceConfigs[0], defaultConfigs.measureName); + } + } else { + this.checkSourceTypes(); } }); } - updateMeasure(sourceConfig: SourceConfig, event: MatSelectChange) { - sourceConfig.measure = this.findMeasure(event.value); + checkSourceTypes() { + this.dataConfig.sourceConfigs.forEach(sourceConfig => { + if (sourceConfig.sourceType === 'pipeline' && !this.existsPipelineWithMeasure(sourceConfig.measureName)) { + sourceConfig.sourceType = 'measurement'; + } + }); + } + + existsPipelineWithMeasure(measureName: string) { + return this.availablePipelines.find(pipeline => pipeline.measureName === measureName) !== undefined; + } + + findDefaultConfig(): { measureName: string, sourceType: 'pipeline' | 'measurement' } { + if (this.availablePipelines.length > 0) { + return { measureName: this.availablePipelines[0].measureName, sourceType: 'pipeline'}; + } else if (this.availableMeasurements.length > 0) { + return { measureName: this.availableMeasurements[0].measureName, sourceType: 'measurement'}; + } else { + return { measureName: undefined, sourceType: undefined }; + } + } + + updateMeasure(sourceConfig: SourceConfig, measureName: string) { + sourceConfig.measure = this.findMeasure(measureName); sourceConfig.queryConfig.fields = []; if (this.fieldSelectionPanel) { this.fieldSelectionPanel.applyDefaultFields(); } + sourceConfig.queryConfig.groupBy = []; + if (this.groupSelectionPanel) { + this.groupSelectionPanel.applyDefaultFields(); + } + } - findMeasure(measureName) { + findMeasure(measureName: string) { return this.availablePipelines.find(pipeline => pipeline.measureName === measureName) || this.availableMeasurements.find(m => m.measureName === measureName); } @@ -108,16 +146,18 @@ this.triggerDataRefresh(); } - addDataSource() { + addDataSource(measureName = '', + sourceType: 'pipeline' | 'measurement' = 'pipeline') { if (!this.dataConfig.sourceConfigs) { this.dataConfig.sourceConfigs = []; } - this.dataConfig.sourceConfigs.push(this.makeSourceConfig()); + this.dataConfig.sourceConfigs.push(this.makeSourceConfig(measureName, sourceType)); } - makeSourceConfig(): SourceConfig { + makeSourceConfig(measureName = '', + sourceType: 'pipeline' | 'measurement' = 'pipeline'): SourceConfig { return { - measureName: '', + measureName, queryConfig: { selectedFilters: [], limit: 100, @@ -126,7 +166,7 @@ aggregationValue: 1 }, queryType: 'raw', - sourceType: 'pipeline' + sourceType }; }
diff --git a/ui/src/app/data-explorer/components/designer-panel/data-settings/field-selection-panel/field-selection-panel.component.ts b/ui/src/app/data-explorer/components/designer-panel/data-settings/field-selection-panel/field-selection-panel.component.ts index 62bb904..75ecc2f 100644 --- a/ui/src/app/data-explorer/components/designer-panel/data-settings/field-selection-panel/field-selection-panel.component.ts +++ b/ui/src/app/data-explorer/components/designer-panel/data-settings/field-selection-panel/field-selection-panel.component.ts
@@ -28,6 +28,8 @@ }) export class FieldSelectionPanelComponent implements OnInit { + MAX_INITIAL_FIELDS = 3; + @Input() sourceConfig: SourceConfig; @Input() widgetId: string; @@ -49,6 +51,7 @@ applyDefaultFields() { if (this.sourceConfig.queryConfig.fields.length === 0) { this.addAllFields(); + this.selectInitialFields(); } else { const oldFields = this.sourceConfig.queryConfig.fields; this.sourceConfig.queryConfig.fields = []; @@ -60,8 +63,17 @@ this.sourceConfig.measure.eventSchema.eventProperties.forEach(property => { // this ensures that dimension properties are not aggregated, this is not possible with the influxdb, See [STREAMPIPES-524] if (this.sourceConfig.queryType === 'raw' || property.propertyScope !== 'DIMENSION_PROPERTY') { - const isSelected = checkFields.some(v => v.runtimeName === property.runtimeName); - this.addField(property, isSelected); + const fieldConfig = checkFields.find(field => field.runtimeName === property.runtimeName); + const isSelected = fieldConfig && fieldConfig.selected; + this.addField(property, isSelected, fieldConfig); + } + }); + } + + selectInitialFields() { + this.sourceConfig.queryConfig.fields.forEach((field, index) => { + if (index < this.MAX_INITIAL_FIELDS) { + field.selected = true; } }); } @@ -79,12 +91,12 @@ this.widgetConfigService.notify({widgetId: this.widgetId, refreshData: true, refreshView: true}); } - addField(property: EventPropertyUnion, isSelected = false) { + addField(property: EventPropertyUnion, isSelected = false, fieldConfig: FieldConfig) { const selection: FieldConfig = { runtimeName: property.runtimeName, selected: isSelected, numeric: this.fieldProvider.isNumber(property)}; - selection.aggregations = [this.findDefaultAggregation(property)]; + selection.aggregations = fieldConfig && fieldConfig.aggregations ? fieldConfig.aggregations : [this.findDefaultAggregation(property)]; this.sourceConfig.queryConfig.fields.push(selection); }
diff --git a/ui/src/app/data-explorer/components/designer-panel/data-settings/group-selection-panel/group-selection-panel.component.ts b/ui/src/app/data-explorer/components/designer-panel/data-settings/group-selection-panel/group-selection-panel.component.ts index 91ef564..e8f0641 100644 --- a/ui/src/app/data-explorer/components/designer-panel/data-settings/group-selection-panel/group-selection-panel.component.ts +++ b/ui/src/app/data-explorer/components/designer-panel/data-settings/group-selection-panel/group-selection-panel.component.ts
@@ -36,7 +36,9 @@ } ngOnInit() { - if (this.sourceConfig.queryConfig.groupBy === undefined) { + const groupByFields = this.sourceConfig.queryConfig.groupBy; + + if (groupByFields === undefined || groupByFields.length === 0) { this.applyDefaultFields(); } }
diff --git a/ui/src/app/data-explorer/components/grid/data-explorer-dashboard-grid.component.ts b/ui/src/app/data-explorer/components/grid/data-explorer-dashboard-grid.component.ts deleted file mode 100644 index 45ee85d..0000000 --- a/ui/src/app/data-explorer/components/grid/data-explorer-dashboard-grid.component.ts +++ /dev/null
@@ -1,182 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { - Component, - EventEmitter, - Input, - OnChanges, - OnInit, - Output, - QueryList, - SimpleChanges, - ViewChildren -} from '@angular/core'; -import { GridsterItemComponent, GridType } from 'angular-gridster2'; -import { GridsterInfo } from '../../../dashboard/models/gridster-info.model'; -import { IDataViewDashboardConfig } from '../../models/dataview-dashboard.model'; -import { ResizeService } from '../../services/resize.service'; -import { - DataViewDataExplorerService, - Dashboard, - DataExplorerWidgetModel, - DataLakeMeasure, - TimeSettings -} from '@streampipes/platform-services'; - -@Component({ - selector: 'sp-data-explorer-dashboard-grid', - templateUrl: './data-explorer-dashboard-grid.component.html', - styleUrls: ['./data-explorer-dashboard-grid.component.scss'] -}) -export class DataExplorerDashboardGridComponent implements OnInit, OnChanges { - - @Input() - editMode: boolean; - - _dashboard: Dashboard; - - configuredWidgets: Map<string, DataExplorerWidgetModel> = new Map<string, DataExplorerWidgetModel>(); - dataLakeMeasures: Map<string, DataLakeMeasure> = new Map<string, DataLakeMeasure>(); - - /** - * This is the date range (start, end) to view the data and is set in data-explorer.ts - */ - @Input() - timeSettings: TimeSettings; - - @Output() deleteCallback: EventEmitter<DataExplorerWidgetModel> = new EventEmitter<DataExplorerWidgetModel>(); - @Output() updateCallback: EventEmitter<DataExplorerWidgetModel> = new EventEmitter<DataExplorerWidgetModel>(); - @Output() configureWidgetCallback: EventEmitter<DataExplorerWidgetModel> = new EventEmitter<DataExplorerWidgetModel>(); - @Output() startEditModeEmitter: EventEmitter<DataExplorerWidgetModel> = new EventEmitter<DataExplorerWidgetModel>(); - - options: IDataViewDashboardConfig; - loaded = false; - - @Input() - currentlyConfiguredWidgetId: string; - - @ViewChildren(GridsterItemComponent) gridsterItemComponents: QueryList<GridsterItemComponent>; - - constructor(private resizeService: ResizeService, - private dataViewDataExplorerService: DataViewDataExplorerService) { - - } - - ngOnInit(): void { - this.options = { - disablePushOnDrag: true, - draggable: {enabled: this.editMode}, - gridType: GridType.VerticalFixed, - minCols: 8, - maxCols: 8, - minRows: 4, - fixedRowHeight: 100, - fixedColWidth: 100, - margin: 5, - displayGrid: this.editMode ? 'always' : 'none', - resizable: {enabled: this.editMode}, - itemResizeCallback: ((item, itemComponent) => { - this.resizeService.notify({ - gridsterItem: item, - gridsterItemComponent: itemComponent - } as GridsterInfo); - }), - itemInitCallback: ((item, itemComponent) => { - this.resizeService.notify({ - gridsterItem: item, - gridsterItemComponent: itemComponent - } as GridsterInfo); - window.dispatchEvent(new Event('resize')); - }) - }; - } - - @Input() set dashboard(dashboard: Dashboard) { - this._dashboard = dashboard; - this.loadWidgetConfigs(); - } - - get dashboard() { - return this._dashboard; - } - - loadWidgetConfigs() { - this.dashboard.widgets.forEach(widget => { - this.loadWidgetConfig(widget.id); - }); - - } - - loadWidgetConfig(widgetId: string, setCurrentlyConfigured?: boolean) { - this.dataViewDataExplorerService.getWidget(widgetId).subscribe(response => { - this.configuredWidgets.set(widgetId, response); - this.dataLakeMeasures.set(widgetId, response.dataConfig.sourceConfigs[0].measure); - if (setCurrentlyConfigured) { - this.propagateWidgetSelection(this.configuredWidgets.get(widgetId)); - } - }); - } - - ngOnChanges(changes: SimpleChanges): void { - if (changes['editMode'] && this.options) { - this.options.draggable.enabled = this.editMode; - this.options.resizable.enabled = this.editMode; - this.options.displayGrid = this.editMode ? 'always' : 'none'; - this.options.api.optionsChanged(); - } - } - - propagateItemRemoval(widget: DataExplorerWidgetModel) { - this.deleteCallback.emit(widget); - } - - propagateItemUpdate(dashboardWidget: DataExplorerWidgetModel) { - this.updateCallback.emit(dashboardWidget); - } - - propagateWidgetSelection(configuredWidget: DataExplorerWidgetModel) { - this.configureWidgetCallback.emit(configuredWidget); - if (configuredWidget) { - this.currentlyConfiguredWidgetId = configuredWidget._id; - } else { - this.currentlyConfiguredWidgetId = undefined; - } - this.options.api.optionsChanged(); - } - - toggleGrid() { - this.options.displayGrid = this.options.displayGrid === 'none' ? 'always' : 'none'; - this.options.api.optionsChanged(); - } - - updateAllWidgets() { - this.configuredWidgets.forEach((value, key) => { - this.dataViewDataExplorerService.updateWidget(value).subscribe(response => { - value._rev = response._rev; - this.currentlyConfiguredWidgetId = undefined; - }); - }); - } - - startEditMode(value: DataExplorerWidgetModel) { - this.startEditModeEmitter.emit(value); - this.currentlyConfiguredWidgetId = value._id; - } - -}
diff --git a/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.html b/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.html index 67d255d..b7e869a 100644 --- a/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.html +++ b/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.html
@@ -17,79 +17,91 @@ --> -<div fxFlex="100" fxLayout="column"> - <div fxFlex="100" fxLayout="column"> - <div fxLayout="row" class="fixed-height options-bar page-container-nav sp-tab-bg"> - <div fxLayoutAlign="start center" fxLayout="row" class="pl-10"> - <button mat-button mat-raised-button color="accent" - data-cy="open-new-data-view-dialog" - (click)="openNewDataViewDialog()" class="mr-10" *ngIf="hasDataExplorerWritePrivileges"> - <i class="material-icons">add</i> - <span>New Data View</span> - </button> - </div> - </div> +<sp-basic-view [showBackLink]="false" [padding]="true"> + + <div nav fxFlex="100" fxLayoutAlign="start center" fxLayout="row" class="pl-10"> + <button mat-button mat-raised-button color="accent" + data-cy="open-new-data-view-dialog" + (click)="openNewDataViewDialog()" class="mr-10" *ngIf="hasDataExplorerWritePrivileges"> + <i class="material-icons">add</i> + <span>New Data View</span> + </button> + </div> - <div *ngIf="!editLabels" fxFlex="100" fxLayout="row wrap" fxLayoutAlign="start stretch" class="m-20"> - <div fxFlex="100" class="assemblyOptions sp-blue-bg p-5"> - <div fxLayout="row" fxLayoutAlign="start center" fxFlex="100"> - <h4>My Data Views</h4> - <span fxFlex></span> - </div> - </div> - <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" class="sp-blue-border"> - <div fxFlex="100" fxLayout="column" class="w-100 p-2"> - <table mat-table [dataSource]="dataSource" multiTemplateDataRows> + <div fxFlex="100" fxLayout="column"> + <sp-basic-header-title-component title="My Data Views"></sp-basic-header-title-component> + <div fxFlex="100" fxLayout="row" fxLayoutAlign="center start"> + <sp-basic-inner-panel [showTitle]="false" innerPadding="0" outerMargin="0" fxFlex="90" [hideToolbar]="true"> + <div fxFlex="100" fxLayout="column" class="w-100" *ngIf="dashboards.length > 0"> + <table mat-table [dataSource]="dataSource" multiTemplateDataRows> - <ng-container matColumnDef="name"> - <th fxFlex="60" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Data View</th> - <td fxFlex="60" fxLayoutAlign="start center" mat-cell *matCellDef="let element"> - {{element.name}}<br/> - {{element.description}} - </td> - </ng-container> + <ng-container matColumnDef="name"> + <th fxFlex="60" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Data View + </th> + <td fxFlex="60" fxLayoutAlign="start center" mat-cell *matCellDef="let element"> + {{element.name}}<br/> + {{element.description}} + </td> + </ng-container> - <ng-container matColumnDef="actions"> - <th fxFlex="40" fxLayoutAlign="center center" mat-header-cell *matHeaderCellDef> Actions</th> - <td fxFlex="40" fxLayoutAlign="start center" mat-cell *matCellDef="let element"> - <div fxLayout="row" fxFlex="100"> + <ng-container matColumnDef="actions"> + <th fxFlex="40" fxLayoutAlign="center center" mat-header-cell *matHeaderCellDef> Actions + </th> + <td fxFlex="40" fxLayoutAlign="start center" mat-cell *matCellDef="let element"> + <div fxLayout="row" fxFlex="100"> <span fxFlex fxFlexOrder="1" fxLayout="row" fxLayoutAlign="center center"> - <button mat-button mat-icon-button color="accent" - (click)="showDashboard(element, false)"> + <button mat-button mat-icon-button color="accent" matTooltip="Show data view" + (click)="showDashboard(element)"> <i class="material-icons">visibility</i> </button> </span> - <span fxFlex fxFlexOrder="2" fxLayout="row" fxLayoutAlign="center center" *ngIf="hasDataExplorerWritePrivileges"> - <button mat-button mat-icon-button color="accent" + <span fxFlex fxFlexOrder="2" fxLayout="row" fxLayoutAlign="center center" + *ngIf="hasDataExplorerWritePrivileges"> + <button mat-button mat-icon-button color="accent" matTooltip="Edit data view" [attr.data-cy]="'edit-dashboard-' + element.name" - (click)="showDashboard(element, true)"> + (click)="editDashboard(element)"> <i class="material-icons">edit</i> </button> </span> - <span fxFlex fxFlexOrder="3" fxLayout="row" fxLayoutAlign="center center" *ngIf="isAdmin"> - <button mat-button mat-icon-button color="accent" + <span fxFlex fxFlexOrder="3" fxLayout="row" fxLayoutAlign="center center" + *ngIf="hasDataExplorerWritePrivileges"> + <button mat-button mat-icon-button color="accent" matTooltip="Edit data view settings" + (click)="openEditDataViewDialog(element)"> + <i class="material-icons">settings</i> + </button> + </span> + <span fxFlex fxFlexOrder="4" fxLayout="row" fxLayoutAlign="center center" + *ngIf="isAdmin"> + <button mat-button mat-icon-button color="accent" matTooltip="Manage permissions" (click)="showPermissionsDialog(element)"> <i class="material-icons">share</i> </button> </span> - <span fxFlex fxFlexOrder="4" fxLayout="row" fxLayoutAlign="center center" *ngIf="hasDataExplorerDeletePrivileges"> - <button mat-button mat-icon-button color="accent" + <span fxFlex fxFlexOrder="5" fxLayout="row" fxLayoutAlign="center center" + *ngIf="hasDataExplorerDeletePrivileges"> + <button mat-button mat-icon-button color="accent" matTooltip="Delete data view" [attr.data-cy]="'delete-dashboard-' + element.name" (click)="openDeleteDashboardDialog(element)"> <i class="material-icons">delete</i> </button> </span> - </div> - </td> - </ng-container> + </div> + </td> + </ng-container> - <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> - <tr mat-row *matRowDef="let element; columns: displayedColumns;"> - </tr> - </table> - </div> + <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> + <tr mat-row *matRowDef="let element; columns: displayedColumns;"> + </tr> + </table> + </div> + <div fxFlex="100" + fxLayout="column" + fxLayoutAlign="center center" + *ngIf="dashboards.length == 0"> + <h5>(no data views available)</h5> + </div> + </sp-basic-inner-panel> </div> </div> - <sp-configure-labels *ngIf="editLabels"></sp-configure-labels> -</div> +</sp-basic-view>
diff --git a/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.scss b/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.scss index 25b8b8b..6e728cc 100644 --- a/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.scss +++ b/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.scss
@@ -25,10 +25,10 @@ } .mat-row:nth-child(even) { - background-color: var(--color-bg-2); + background-color: var(--color-bg-1); } .mat-row:nth-child(odd) { - background-color: var(--color-bg-3); + background-color: var(--color-bg-2); } .w-100 {
diff --git a/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.ts b/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.ts index d35d4ad..1e645d9 100644 --- a/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.ts +++ b/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.ts
@@ -16,66 +16,80 @@ * */ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { MatTableDataSource } from '@angular/material/table'; import { DataExplorerEditDataViewDialogComponent } from '../../dialogs/edit-dashboard/data-explorer-edit-data-view-dialog.component'; -import { DataViewDataExplorerService, Dashboard } from '@streampipes/platform-services'; -import { Tuple2 } from '../../../core-model/base/Tuple2'; -import { DialogService, PanelType } from '@streampipes/shared-ui'; +import { Dashboard, DataViewDataExplorerService } from '@streampipes/platform-services'; +import { DialogService, PanelType, SpBreadcrumbService } from '@streampipes/shared-ui'; import { ObjectPermissionDialogComponent } from '../../../core-ui/object-permission-dialog/object-permission-dialog.component'; import { UserRole } from '../../../_enums/user-role.enum'; import { AuthService } from '../../../services/auth.service'; import { UserPrivilege } from '../../../_enums/user-privilege.enum'; +import { Router } from '@angular/router'; +import { SpDataExplorerRoutes } from '../../data-explorer.routes'; +import { Subscription } from 'rxjs'; @Component({ selector: 'sp-data-explorer-dashboard-overview', templateUrl: './data-explorer-dashboard-overview.component.html', styleUrls: ['./data-explorer-dashboard-overview.component.scss'] }) -export class DataExplorerDashboardOverviewComponent implements OnInit { +export class DataExplorerDashboardOverviewComponent implements OnInit, OnDestroy { - @Input() dataViewDashboards: Dashboard[]; - @Output() reloadDashboardsEmitter = new EventEmitter<void>(); - @Output() selectDashboardEmitter = new EventEmitter<Tuple2<Dashboard, boolean>>(); dataSource = new MatTableDataSource<Dashboard>(); displayedColumns: string[] = []; + dashboards: Dashboard[] = []; - editLabels: boolean; isAdmin = false; hasDataExplorerWritePrivileges = false; hasDataExplorerDeletePrivileges = false; - constructor(private dashboardService: DataViewDataExplorerService, + authSubscription: Subscription; + + constructor(private dataViewService: DataViewDataExplorerService, + private dashboardService: DataViewDataExplorerService, public dialogService: DialogService, - private authService: AuthService) { + private authService: AuthService, + private router: Router, + private breadcrumbService: SpBreadcrumbService) { } ngOnInit(): void { - this.authService.user$.subscribe(user => { + this.breadcrumbService.updateBreadcrumb(this.breadcrumbService.getRootLink(SpDataExplorerRoutes.BASE)); + this.authSubscription = this.authService.user$.subscribe(user => { this.hasDataExplorerWritePrivileges = this.authService.hasRole(UserPrivilege.PRIVILEGE_WRITE_DATA_EXPLORER_VIEW); this.hasDataExplorerDeletePrivileges = this.authService.hasRole(UserPrivilege.PRIVILEGE_DELETE_DATA_EXPLORER_VIEW); this.isAdmin = user.roles.indexOf(UserRole.ROLE_ADMIN) > -1; this.displayedColumns = ['name', 'actions']; - }); - this.dataSource.data = this.dataViewDashboards; - this.editLabels = false; + + this.getDashboards(); + } + + ngOnDestroy() { + if (this.authSubscription) { + this.authSubscription.unsubscribe(); + } + } + + getDashboards() { + this.dataViewService.getDataViews().subscribe(data => { + this.dashboards = data.sort((a, b) => a.name.localeCompare(b.name)); + this.dataSource.data = this.dashboards; + }); } openNewDataViewDialog() { const dataViewDashboard: Dashboard = {}; + dataViewDashboard.dashboardGeneralSettings = {}; dataViewDashboard.widgets = []; this.openDataViewModificationDialog(true, dataViewDashboard); } - openEditLabelView() { - this.editLabels = true; - } - openDataViewModificationDialog(createMode: boolean, dashboard: Dashboard) { const dialogRef = this.dialogService.open(DataExplorerEditDataViewDialogComponent, { panelType: PanelType.STANDARD_PANEL, @@ -88,7 +102,7 @@ }); dialogRef.afterClosed().subscribe(result => { - this.reloadDashboardsEmitter.emit(); + this.getDashboards(); }); } @@ -106,7 +120,7 @@ dialogRef.afterClosed().subscribe(refresh => { if (refresh) { - this.reloadDashboardsEmitter.emit(); + this.getDashboards(); } }); } @@ -116,14 +130,17 @@ } openDeleteDashboardDialog(dashboard: Dashboard) { - // TODO add confirm dialog - this.dashboardService.deleteDashboard(dashboard).subscribe(result => { - this.reloadDashboardsEmitter.emit(); + this.dashboardService.deleteDashboard(dashboard).subscribe(() => { + this.getDashboards(); }); } - showDashboard(dashboard: Dashboard, editMode: boolean) { - const dashboardSettings: Tuple2<Dashboard, boolean> = { a: dashboard, b: editMode }; - this.selectDashboardEmitter.emit(dashboardSettings); + showDashboard(dashboard: Dashboard) { + this.router.navigate(['dataexplorer/', dashboard._id]); } + + editDashboard(dashboard: Dashboard) { + this.router.navigate(['dataexplorer/', dashboard._id], {queryParams: {action: 'edit'}}); + } + }
diff --git a/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.css b/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.css index 3236d72..3cbc82c 100644 --- a/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.css +++ b/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.css
@@ -16,6 +16,19 @@ * */ +.fixed-height { + height: 50px; +} + +.data-explorer-options { + padding:0px; +} + +.data-explorer-options-item { + display: inline; + margin-right: 10px; +} + .m-20 { margin: 20px; }
diff --git a/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.html b/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.html index b2c976f..d2108e6 100644 --- a/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.html +++ b/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.html
@@ -16,74 +16,162 @@ ~ --> -<div class="fixed-height data-explorer-options sp-tab-bg page-container-nav" fxLayout="row" *ngIf="(editMode || timeRangeVisible)"> - <div class="data-explorer-options-item pl-10" fxLayoutAlign="start center" fxLayout="row" *ngIf="editMode"> - <button mat-button - mat-raised-button - color="accent" - matTooltip="Save" - class="edit-menu-btn" - [matTooltipPosition]="'above'" - (click)="persistDashboardChanges()" - data-cy="save-data-explorer-widget-btn"> - <mat-icon>save</mat-icon> <span>Save</span> - </button> - <button mat-button - mat-raised-button - class="mat-basic mr-10 edit-menu-btn" - (click)="discardChanges()"> - <i class="material-icons">clear</i> - <span> Discard</span> - </button> - <button mat-button - mat-raised-button - color="accent" - class="edit-menu-btn" - (click)="createWidget()" - [disabled]="!editMode" - data-cy="add-new-widget"> - <i class="material-icons">add</i> - <span> Add Widget</span> - </button> - </div> - <div class="data-explorer-options-item" fxLayoutAlign="end center" fxFlex fxLayout="row"> - <sp-time-range-selector (dateRangeEmitter)="updateDateRange($event)" [dateRange]="timeSettings"> - </sp-time-range-selector> - </div> -</div> - -<div fxFlex="100" fxLayout="column"> - <mat-drawer-container class="designer-panel-container h-100 dashboard-grid"> - <mat-drawer #designerDrawer - [opened]="showDesignerPanel" - (opened)="triggerResize()" - (closed)="triggerResize()" - mode="side" - position="end" - class="designer-panel"> - <div fxLayout="column" fxFlex="100"> - <sp-data-explorer-designer-panel #designerPanel - [currentlyConfiguredWidget]="currentlyConfiguredWidget" - [dataLakeMeasure]="dataLakeMeasure" - [newWidgetMode]="newWidgetMode" - (addWidgetEmitter)="addWidget($event)" - (closeDesignerPanelEmitter)="closeDesignerPanel()" - fxFlex="100"> - </sp-data-explorer-designer-panel> +<div fxLayout="column" class="page-container"> + <div fxLayout="column" fxFlex="100" *ngIf="dashboardLoaded"> + <div class="fixed-height data-explorer-options sp-tab-bg page-container-nav" fxLayout="row"> + <div class="data-explorer-options-item pl-10" + fxLayout="row" + fxLayoutAlign="start center" + style="border-right: 2px solid var(--color-bg-2)"> + <button mat-button + mat-icon-button + color="accent" + matTooltip="Back" + (click)="goBackToOverview()" + class="edit-menu-btn" + data-cy="save-data-explorer-go-back-to-overview"> + <mat-icon>arrow_back</mat-icon> + </button> </div> - </mat-drawer> - <mat-drawer-content class="h-100 dashboard-grid"> - <sp-data-explorer-dashboard-grid - #dashboardGrid - [editMode]="editMode" - [dashboard]="dashboard" - [timeSettings]="timeSettings" - [currentlyConfiguredWidgetId]="currentlyConfiguredWidgetId" - (configureWidgetCallback)="updateCurrentlyConfiguredWidget($event)" - (updateCallback)="updateAndQueueItemForDeletion($event)" - (deleteCallback)="removeAndQueueItemForDeletion($event)" - (startEditModeEmitter)="startEditMode($event)" - class="h-100 dashboard-grid"></sp-data-explorer-dashboard-grid> - </mat-drawer-content> - </mat-drawer-container> + <div class="data-explorer-options-item" fxLayoutAlign="start center" fxLayout="row" *ngIf="editMode"> + <button mat-button mat-icon-button + color="accent" + matTooltip="Save" + class="edit-menu-btn" + (click)="persistDashboardChanges()" + data-cy="save-data-explorer-widget-btn"> + <mat-icon>save</mat-icon> + </button> + <button mat-button + mat-icon-button + color="accent" + matTooltip="Discard" + class="mat-basic mr-10 edit-menu-btn" + (click)="discardChanges()"> + <i class="material-icons">undo</i> + </button> + <button mat-button + mat-icon-button + matTooltip="Add widget" + color="accent" + class="edit-menu-btn" (click)="createWidget()" + [disabled]="!editMode" data-cy="add-new-widget"> + <i class="material-icons">add</i> + </button> + </div> + <div class="data-explorer-options-item" fxLayoutAlign="start center" fxLayout="row"> + <button mat-icon-button + [matMenuTriggerFor]="menu" + aria-label="View mode" + matTooltip="View mode"> + <mat-icon>{{viewMode === 'grid' ? 'grid_view' : 'web_asset'}}</mat-icon> + </button> + <mat-menu #menu="matMenu"> + <button mat-menu-item (click)="viewMode = 'grid'"> + <mat-icon>grid_view</mat-icon> + <span>Grid</span> + </button> + <button mat-menu-item (click)="viewMode = 'slide'"> + <mat-icon>web_asset</mat-icon> + <span>Slides</span> + </button> + </mat-menu> + </div> + <div class="data-explorer-options-item" style="margin-right: 0" fxLayoutAlign="end center" fxFlex + fxLayout="row"> + <sp-time-range-selector *ngIf="(editMode || timeRangeVisible)" + (dateRangeEmitter)="updateDateRange($event)" [dateRange]="timeSettings"> + </sp-time-range-selector> + + <button mat-icon-button [matMenuTriggerFor]="optMenu" aria-label="Options" + data-cy="options-data-explorer"> + <mat-icon>more_vert</mat-icon> + </button> + <mat-menu #optMenu="matMenu"> + <button mat-menu-item + (click)="triggerEditMode()" + *ngIf="!editMode && hasDataExplorerWritePrivileges" + data-cy="options-edit-dashboard"> + <mat-icon>edit</mat-icon> + <span>Edit dashboard</span> + </button> + <button mat-menu-item + (click)="timeRangeVisible = true" + *ngIf="!editMode && !timeRangeVisible"> + <mat-icon>alarm_on</mat-icon> + <span>Show time range selector</span> + </button> + <button mat-menu-item (click)="timeRangeVisible = false" *ngIf="!editMode && timeRangeVisible"> + <mat-icon>alarm_off</mat-icon> + <span>Hide time range selector</span> + </button> + <button mat-menu-item *ngIf="hasDataExplorerDeletePrivileges" + (click)="deleteDashboard(dashboard)"> + <mat-icon>clear</mat-icon> + <span>Delete dashboard</span> + </button> + </mat-menu> + </div> + + </div> + + <div fxFlex="100" fxLayout="column"> + <mat-drawer-container class="designer-panel-container h-100 dashboard-grid"> + <mat-drawer #designerDrawer + [opened]="showDesignerPanel" + (opened)="triggerResize()" + (closed)="triggerResize()" + mode="side" + position="end" + class="designer-panel"> + <div fxLayout="column" fxFlex="100"> + <sp-data-explorer-designer-panel #designerPanel + [currentlyConfiguredWidget]="currentlyConfiguredWidget" + [dataLakeMeasure]="dataLakeMeasure" + [newWidgetMode]="newWidgetMode" + (addWidgetEmitter)="addWidget($event)" + (closeDesignerPanelEmitter)="closeDesignerPanel()" + fxFlex="100"> + </sp-data-explorer-designer-panel> + </div> + </mat-drawer> + <mat-drawer-content class="h-100 dashboard-grid"> + <div *ngIf="showEditingHelpInfo" fxFlex="100" fxLayout="column" fxLayoutAlign="center center"> + <h4>This data view is empty and doesn't contain any widgets.</h4> + <button mat-button + mat-raised-button + color="accent" + *ngIf="hasDataExplorerWritePrivileges" + (click)="triggerEditMode()"> + <mat-icon>add</mat-icon> + Add widget + </button> + </div> + <sp-data-explorer-dashboard-grid #dashboardGrid + *ngIf="!showEditingHelpInfo && viewMode === 'grid'" + [editMode]="editMode" + [dashboard]="dashboard" + [timeSettings]="timeSettings" + [currentlyConfiguredWidgetId]="currentlyConfiguredWidgetId" + (configureWidgetCallback)="updateCurrentlyConfiguredWidget($event)" + (updateCallback)="updateAndQueueItemForDeletion($event)" + (deleteCallback)="removeAndQueueItemForDeletion($event)" + (startEditModeEmitter)="startEditMode($event)" + class="h-100 dashboard-grid"> + </sp-data-explorer-dashboard-grid> + <sp-data-explorer-dashboard-slide-view class="h-100 dashboard-grid" #dashboardSlide + [editMode]="editMode" + [dashboard]="dashboard" + [timeSettings]="timeSettings" + [currentlyConfiguredWidgetId]="currentlyConfiguredWidgetId" + (configureWidgetCallback)="updateCurrentlyConfiguredWidget($event)" + (updateCallback)="updateAndQueueItemForDeletion($event)" + (deleteCallback)="removeAndQueueItemForDeletion($event)" + (startEditModeEmitter)="startEditMode($event)" + *ngIf="!showEditingHelpInfo && viewMode === 'slide'"> + </sp-data-explorer-dashboard-slide-view> + </mat-drawer-content> + </mat-drawer-container> + </div> + </div> </div>
diff --git a/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.ts b/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.ts index 3e214d9..f03b006 100644 --- a/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.ts +++ b/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.ts
@@ -16,47 +16,65 @@ * */ -import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; -import { MatDialog } from '@angular/material/dialog'; -import { Observable, zip } from 'rxjs'; -import { RefreshDashboardService } from '../../services/refresh-dashboard.service'; -import { DataExplorerDashboardGridComponent } from '../grid/data-explorer-dashboard-grid.component'; +import { Component, EventEmitter, OnDestroy, OnInit, Output, ViewChild, } from '@angular/core'; +import { Observable, of, Subscription, zip } from 'rxjs'; +import { DataExplorerDashboardGridComponent } from '../widget-view/grid-view/data-explorer-dashboard-grid.component'; import { MatDrawer } from '@angular/material/sidenav'; import { Tuple2 } from '../../../core-model/base/Tuple2'; import { + ClientDashboardItem, Dashboard, - TimeSettings, DataExplorerWidgetModel, DataLakeMeasure, - ClientDashboardItem, - DataViewDataExplorerService + DataViewDataExplorerService, + TimeSettings, } from '@streampipes/platform-services'; import { DataExplorerDesignerPanelComponent } from '../designer-panel/data-explorer-designer-panel.component'; import { TimeSelectionService } from '../../services/time-selection.service'; +import { AuthService } from '../../../services/auth.service'; +import { UserPrivilege } from '../../../_enums/user-privilege.enum'; +import { ActivatedRoute, ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; +import { DataExplorerDashboardSlideViewComponent } from '../widget-view/slide-view/data-explorer-dashboard-slide-view.component'; +import { ConfirmDialogComponent, SpBreadcrumbService } from '@streampipes/shared-ui'; +import { MatDialog } from '@angular/material/dialog'; +import { map } from 'rxjs/operators'; +import { SpDataExplorerRoutes } from '../../data-explorer.routes'; @Component({ selector: 'sp-data-explorer-dashboard-panel', templateUrl: './data-explorer-dashboard-panel.component.html', - styleUrls: ['./data-explorer-dashboard-panel.component.css'] + styleUrls: ['./data-explorer-dashboard-panel.component.css'], }) -export class DataExplorerDashboardPanelComponent implements OnInit { - - @Input() dashboard: Dashboard; +export class DataExplorerDashboardPanelComponent implements OnInit, OnDestroy { + dashboardLoaded = false; + dashboard: Dashboard; /** * This is the date range (start, end) to view the data and is set in data-explorer.ts */ - @Input() timeSettings: TimeSettings; - @Input() editMode: boolean; - @Input() timeRangeVisible: boolean; + timeSettings: TimeSettings; + viewMode = 'grid'; - @Output() editModeChange: EventEmitter<boolean> = new EventEmitter(); + editMode = false; + timeRangeVisible = true; - @Output() resetDashboardChanges: EventEmitter<boolean> = new EventEmitter(); + @Output() + editModeChange: EventEmitter<boolean> = new EventEmitter(); - @ViewChild('dashboardGrid') dashboardGrid: DataExplorerDashboardGridComponent; - @ViewChild('designerDrawer') designerDrawer: MatDrawer; - @ViewChild('designerPanel') designerPanel: DataExplorerDesignerPanelComponent; + @ViewChild('dashboardGrid') + dashboardGrid: DataExplorerDashboardGridComponent; + + @ViewChild('dashboardSlide') + dashboardSlide: DataExplorerDashboardSlideViewComponent; + + @ViewChild('designerDrawer') + designerDrawer: MatDrawer; + + @ViewChild('designerPanel') + designerPanel: DataExplorerDesignerPanelComponent; + + hasDataExplorerWritePrivileges = false; + hasDataExplorerDeletePrivileges = false; public items: Dashboard[]; @@ -69,25 +87,65 @@ dataLakeMeasure: DataLakeMeasure; showDesignerPanel = false; + showEditingHelpInfo = false; - constructor(private dataViewDataExplorerService: DataViewDataExplorerService, - public dialog: MatDialog, - private refreshDashboardService: RefreshDashboardService, - private timeSelectionService: TimeSelectionService) { + authSubscription: Subscription; + + constructor( + private dataViewDataExplorerService: DataViewDataExplorerService, + private dialog: MatDialog, + private timeSelectionService: TimeSelectionService, + private authService: AuthService, + private dashboardService: DataViewDataExplorerService, + private route: ActivatedRoute, + private dataViewService: DataViewDataExplorerService, + private router: Router, + private breadcrumbService: SpBreadcrumbService) { } public ngOnInit() { + + const params = this.route.snapshot.params; + const queryParams = this.route.snapshot.queryParams; + + const startTime = params.startTime; + const endTime = params.endTime; + + this.getDashboard(params.id, startTime, endTime); + + + this.authSubscription = this.authService.user$.subscribe(user => { + this.hasDataExplorerWritePrivileges = this.authService.hasRole( + UserPrivilege.PRIVILEGE_WRITE_DATA_EXPLORER_VIEW + ); + this.hasDataExplorerDeletePrivileges = this.authService.hasRole( + UserPrivilege.PRIVILEGE_DELETE_DATA_EXPLORER_VIEW + ); + if (queryParams.action === 'edit' && this.hasDataExplorerWritePrivileges) { + this.editMode = true; + } + }); + } + + ngOnDestroy() { + if (this.authSubscription) { + this.authSubscription.unsubscribe(); + } } triggerResize() { window.dispatchEvent(new Event('resize')); } - addWidget(widgetConfig: Tuple2<DataLakeMeasure, DataExplorerWidgetModel>): void { + addWidget( + widgetConfig: Tuple2<DataLakeMeasure, DataExplorerWidgetModel> + ): void { this.dataLakeMeasure = widgetConfig.a; - this.dataViewDataExplorerService.saveWidget(widgetConfig.b).subscribe(response => { - this.addWidgetToDashboard(response); - }); + this.dataViewDataExplorerService + .saveWidget(widgetConfig.b) + .subscribe((response) => { + this.addWidgetToDashboard(response); + }); } addWidgetToDashboard(widget: DataExplorerWidgetModel) { @@ -99,37 +157,54 @@ dashboardItem.x = 0; dashboardItem.y = 0; this.dashboard.widgets.push(dashboardItem); - this.dashboardGrid.loadWidgetConfig(widget._id, true); + if (this.viewMode === 'grid') { + this.dashboardGrid.loadWidgetConfig(widget._id, true); + } else { + this.dashboardSlide.loadWidgetConfig(widget._id, true); + } } persistDashboardChanges() { - this.dataViewDataExplorerService.updateDashboard(this.dashboard).subscribe(result => { - this.dashboard._rev = result._rev; - if (this.widgetIdsToRemove.length > 0) { - const observables = this.deleteWidgets(); - zip(...observables).subscribe(() => { - this.widgetIdsToRemove.forEach(id => { - this.dashboardGrid.configuredWidgets.delete(id); + this.dataViewDataExplorerService + .updateDashboard(this.dashboard) + .subscribe((result) => { + this.dashboard._rev = result._rev; + if (this.widgetIdsToRemove.length > 0) { + const observables = this.deleteWidgets(); + zip(...observables).subscribe(() => { + this.widgetIdsToRemove.forEach((id) => { + if (this.viewMode === 'grid') { + this.dashboardGrid.configuredWidgets.delete(id); + } else { + this.dashboardSlide.configuredWidgets.delete(id); + } + }); + + this.afterDashboardChange(); }); - + } else { this.afterDashboardChange(); - }); - } else { - this.afterDashboardChange(); - } + } + }); - }); + this.editMode = false; } afterDashboardChange() { - this.dashboardGrid.updateAllWidgets(); + if (this.viewMode === 'grid') { + this.dashboardGrid.updateAllWidgets(); + } else { + this.dashboardSlide.updateAllWidgets(); + } this.editModeChange.emit(false); this.closeDesignerPanel(); } startEditMode(widgetModel: DataExplorerWidgetModel) { + this.editMode = true; this.editModeChange.emit(true); this.updateCurrentlyConfiguredWidget(widgetModel); + this.showEditingHelpInfo = false; } prepareWidgetUpdates(): Observable<any>[] { @@ -142,7 +217,9 @@ } removeAndQueueItemForDeletion(widget: DataExplorerWidgetModel) { - const index = this.dashboard.widgets.findIndex(item => item.id === widget._id); + const index = this.dashboard.widgets.findIndex( + (item) => item.id === widget._id + ); this.dashboard.widgets.splice(index, 1); this.widgetIdsToRemove.push(widget._id); if (this.currentlyConfiguredWidget._id === widget._id) { @@ -155,7 +232,7 @@ } deleteWidgets(): Observable<any>[] { - return this.widgetIdsToRemove.map(widgetId => { + return this.widgetIdsToRemove.map((widgetId) => { return this.dataViewDataExplorerService.deleteWidget(widgetId); }); } @@ -180,26 +257,37 @@ } else { this.showDesignerPanel = false; } - } discardChanges() { - this.resetDashboardChanges.emit(true); + this.editMode = false; + } + + triggerEditMode() { + this.showEditingHelpInfo = false; + this.editMode = true; + this.editModeChange.emit(true); + this.createWidget(); } createWidget() { this.dataLakeMeasure = new DataLakeMeasure(); this.currentlyConfiguredWidget = new DataExplorerWidgetModel(); - this.currentlyConfiguredWidget['@class'] = 'org.apache.streampipes.model.datalake.DataExplorerWidgetModel'; + this.currentlyConfiguredWidget['@class'] = + 'org.apache.streampipes.model.datalake.DataExplorerWidgetModel'; this.currentlyConfiguredWidget.baseAppearanceConfig = {}; - this.currentlyConfiguredWidget.baseAppearanceConfig.widgetTitle = 'New Widget'; + this.currentlyConfiguredWidget.baseAppearanceConfig.widgetTitle = + 'New Widget'; this.currentlyConfiguredWidget.dataConfig = {}; - this.currentlyConfiguredWidget.baseAppearanceConfig.backgroundColor = '#FFFFFF'; + this.currentlyConfiguredWidget.baseAppearanceConfig.backgroundColor = + '#FFFFFF'; this.currentlyConfiguredWidget.baseAppearanceConfig.textColor = '#3e3e3e'; this.newWidgetMode = true; this.showDesignerPanel = true; this.newWidgetMode = true; - this.designerPanel.resetIndex(); + if (this.designerPanel) { + this.designerPanel.resetIndex(); + } } closeDesignerPanel() { @@ -208,4 +296,62 @@ this.dataLakeMeasure = undefined; this.currentlyConfiguredWidgetId = undefined; } + + deleteDashboard(dashboard: Dashboard) { + this.dashboardService.deleteDashboard(dashboard).subscribe((result) => { + this.goBackToOverview(); + }); + } + + getDashboard(dashboardId: string, + startTime: number, + endTime: number) { + this.dataViewService.getDataViews().subscribe((data) => { + this.dashboard = data.filter( + (dashboard) => dashboard._id === dashboardId + )[0]; + this.breadcrumbService.updateBreadcrumb(this.breadcrumbService.makeRoute([SpDataExplorerRoutes.BASE], this.dashboard.name)); + this.viewMode = this.dashboard.dashboardGeneralSettings.defaultViewMode || 'grid'; + this.timeSettings = (startTime && endTime) ? this.overrideTime(+startTime, +endTime) : this.dashboard.dashboardTimeSettings; + if (this.dashboard.widgets.length === 0 && this.editMode) { + this.triggerEditMode(); + } else if (this.dashboard.widgets.length === 0 && !(this.editMode)) { + this.showEditingHelpInfo = true; + } + this.dashboardLoaded = true; + }); + } + + overrideTime(startTime: number, + endTime: number): TimeSettings { + return {startTime, endTime, dynamicSelection: -1}; + } + + goBackToOverview() { + this.router.navigate(['dataexplorer']); + } + + confirmLeaveDashboard(route: ActivatedRouteSnapshot, + state: RouterStateSnapshot): Observable<boolean> { + if (this.editMode) { + const dialogRef = this.dialog.open(ConfirmDialogComponent, { + width: '500px', + data: { + 'title': 'Save changes?', + 'subtitle': 'Update all changes to dashboard widgets or discard current changes.', + 'cancelTitle': 'Discard changes', + 'okTitle': 'Update', + 'confirmAndCancel': true + }, + }); + return dialogRef.afterClosed().pipe(map(shouldUpdate => { + if (shouldUpdate) { + this.persistDashboardChanges(); + } + return true; + })); + } else { + return of(true); + } + } }
diff --git a/ui/src/app/data-explorer/components/time-selector/timeRangeSelector.component.html b/ui/src/app/data-explorer/components/time-selector/timeRangeSelector.component.html index 492a18d..a7feeac 100644 --- a/ui/src/app/data-explorer/components/time-selector/timeRangeSelector.component.html +++ b/ui/src/app/data-explorer/components/time-selector/timeRangeSelector.component.html
@@ -22,7 +22,7 @@ *ngFor="let item of possibleTimeButtons" [color]="selectedTimeButton.value === item.value ? 'accent' : ''" [attr.data-cy]="item.value.replace(' ', '_')" - class="button-margin smaller-button-font-size" + [ngClass]="'button-margin smaller-button-font-size'" (click)="this.setCurrentDateRange(item)">{{item.value}}</button> </div> <div class="time-wrapper" fxFlex fxLayoutAlign="center center">
diff --git a/ui/src/app/data-explorer/components/time-selector/timeRangeSelector.component.scss b/ui/src/app/data-explorer/components/time-selector/timeRangeSelector.component.scss index 4768cb9..eeb2dd6 100644 --- a/ui/src/app/data-explorer/components/time-selector/timeRangeSelector.component.scss +++ b/ui/src/app/data-explorer/components/time-selector/timeRangeSelector.component.scss
@@ -31,14 +31,14 @@ } .button-margin { - border-radius: 0; - padding-left: 4px; - padding-right:4px; - border-right: 1px solid #cccccc; + border-radius: 0 !important; + padding-left: 4px !important; + padding-right:4px !important; + border-right: 1px solid #cccccc !important; } .button-margin:last-of-type { - border-right: 0; + border-right: 0 !important; } .time-range-wrapper {
diff --git a/ui/src/app/data-explorer/components/time-selector/timeRangeSelector.component.ts b/ui/src/app/data-explorer/components/time-selector/timeRangeSelector.component.ts index 3891683..da92eb2 100644 --- a/ui/src/app/data-explorer/components/time-selector/timeRangeSelector.component.ts +++ b/ui/src/app/data-explorer/components/time-selector/timeRangeSelector.component.ts
@@ -54,6 +54,9 @@ this.setCurrentDateRange(this.possibleTimeButtons[0]); } else if (this.dateRange.dynamicSelection !== -1) { this.setCurrentDateRange(this.possibleTimeButtons.find(tb => tb.offset === this.dateRange.dynamicSelection)); + } else { + this.startDate = new Date(this._dateRange.startTime); + this.endDate = new Date(this._dateRange.endTime); } }
diff --git a/ui/src/app/data-explorer/components/widget-view/abstract-widget-view.directive.ts b/ui/src/app/data-explorer/components/widget-view/abstract-widget-view.directive.ts new file mode 100644 index 0000000..a05811b --- /dev/null +++ b/ui/src/app/data-explorer/components/widget-view/abstract-widget-view.directive.ts
@@ -0,0 +1,153 @@ +/* + * 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 { Directive, EventEmitter, Input, Output } from '@angular/core'; +import { + Dashboard, + DataExplorerWidgetModel, + DataLakeMeasure, + DataViewDataExplorerService, + TimeSettings +} from '@streampipes/platform-services'; +import { ResizeService } from '../../services/resize.service'; +import { zip } from 'rxjs'; + +@Directive() +export abstract class AbstractWidgetViewDirective { + + _dashboard: Dashboard; + + @Input() + editMode: boolean; + + @Input() + currentlyConfiguredWidgetId: string; + + configuredWidgets: Map<string, DataExplorerWidgetModel> = new Map<string, DataExplorerWidgetModel>(); + dataLakeMeasures: Map<string, DataLakeMeasure> = new Map<string, DataLakeMeasure>(); + + widgetsAvailable = false; + widgetsVisible = true; + + /** + * This is the date range (start, end) to view the data and is set in data-explorer.ts + */ + @Input() + timeSettings: TimeSettings; + + @Output() deleteCallback: EventEmitter<DataExplorerWidgetModel> = new EventEmitter<DataExplorerWidgetModel>(); + @Output() updateCallback: EventEmitter<DataExplorerWidgetModel> = new EventEmitter<DataExplorerWidgetModel>(); + @Output() configureWidgetCallback: EventEmitter<DataExplorerWidgetModel> = new EventEmitter<DataExplorerWidgetModel>(); + @Output() startEditModeEmitter: EventEmitter<DataExplorerWidgetModel> = new EventEmitter<DataExplorerWidgetModel>(); + + + constructor(protected resizeService: ResizeService, + protected dataViewDataExplorerService: DataViewDataExplorerService) { + + } + + updateAllWidgets() { + this.configuredWidgets.forEach((value, key) => { + this.dataViewDataExplorerService.updateWidget(value).subscribe(response => { + value._rev = response._rev; + this.currentlyConfiguredWidgetId = undefined; + }); + }); + } + + startEditMode(value: DataExplorerWidgetModel) { + this.startEditModeEmitter.emit(value); + this.currentlyConfiguredWidgetId = value._id; + } + + @Input() set dashboard(dashboard: Dashboard) { + this._dashboard = dashboard; + this.loadWidgetConfigs(); + } + + get dashboard() { + return this._dashboard; + } + + loadWidgetConfigs() { + const observables = this.dashboard.widgets.map(w => this.dataViewDataExplorerService.getWidget(w.id)); + zip(...observables).subscribe(results => { + results.forEach(r => { + this.processWidget(r); + this.onWidgetsAvailable(); + this.widgetsAvailable = true; + if (this.dashboard.widgets.length > 0 && this.editMode) { + this.startEditModeEmitter.emit(this.configuredWidgets.get(this.dashboard.widgets[0].id)); + } + }); + }); + } + + loadWidgetConfig(widgetId: string, setCurrentlyConfigured?: boolean) { + if (!this.isGridView()) { + this.widgetsVisible = false; + } + this.dataViewDataExplorerService.getWidget(widgetId).subscribe(response => { + this.processWidget(response); + if (setCurrentlyConfigured) { + this.propagateWidgetSelection(this.configuredWidgets.get(widgetId)); + if (!this.isGridView()) { + this.selectNewWidget(widgetId); + } + } + if (!this.isGridView()) { + this.widgetsVisible = true; + } + this.widgetsAvailable = true; + }); + } + + processWidget(widget: DataExplorerWidgetModel) { + this.configuredWidgets.set(widget._id, widget); + this.dataLakeMeasures.set(widget._id, widget.dataConfig.sourceConfigs[0].measure); + } + + propagateItemRemoval(widget: DataExplorerWidgetModel) { + this.deleteCallback.emit(widget); + } + + propagateItemUpdate(dashboardWidget: DataExplorerWidgetModel) { + this.updateCallback.emit(dashboardWidget); + } + + propagateWidgetSelection(configuredWidget: DataExplorerWidgetModel) { + this.configureWidgetCallback.emit(configuredWidget); + if (configuredWidget) { + this.currentlyConfiguredWidgetId = configuredWidget._id; + } else { + this.currentlyConfiguredWidgetId = undefined; + } + this.onOptionsChanged(); + } + + abstract onOptionsChanged(): void; + + abstract onWidgetsAvailable(): void; + + abstract isGridView(): boolean; + + abstract selectNewWidget(widgetId): void; + + + +}
diff --git a/ui/src/app/data-explorer/components/grid/data-explorer-dashboard-grid.component.html b/ui/src/app/data-explorer/components/widget-view/grid-view/data-explorer-dashboard-grid.component.html similarity index 89% rename from ui/src/app/data-explorer/components/grid/data-explorer-dashboard-grid.component.html rename to ui/src/app/data-explorer/components/widget-view/grid-view/data-explorer-dashboard-grid.component.html index 31fea68..5afe663 100644 --- a/ui/src/app/data-explorer/components/grid/data-explorer-dashboard-grid.component.html +++ b/ui/src/app/data-explorer/components/widget-view/grid-view/data-explorer-dashboard-grid.component.html
@@ -24,6 +24,7 @@ <ng-container *ngFor="let item of dashboard.widgets;let i=index"> <gridster-item [item]="item" #gridsterItemComponent class="shadow"> <sp-data-explorer-dashboard-widget + [ngStyle]="{height: gridsterItemComponent.height -13 + 'px'}" [timeSettings]="timeSettings" (updateCallback)="propagateItemUpdate($event)" (deleteCallback)="propagateItemRemoval($event)" @@ -34,8 +35,9 @@ [dataLakeMeasure]="dataLakeMeasures.get(item.id)" [currentlyConfiguredWidgetId]="currentlyConfiguredWidgetId" [editMode]="editMode" + [gridMode]="true" [gridsterItemComponent]="gridsterItemComponent" - *ngIf="configuredWidgets.has(item.id) && dataLakeMeasures.has(item.id)"></sp-data-explorer-dashboard-widget> + *ngIf="widgetsAvailable && configuredWidgets.has(item.id)"></sp-data-explorer-dashboard-widget> </gridster-item> </ng-container> </gridster>
diff --git a/ui/src/app/data-explorer/components/grid/data-explorer-dashboard-grid.component.scss b/ui/src/app/data-explorer/components/widget-view/grid-view/data-explorer-dashboard-grid.component.scss similarity index 100% rename from ui/src/app/data-explorer/components/grid/data-explorer-dashboard-grid.component.scss rename to ui/src/app/data-explorer/components/widget-view/grid-view/data-explorer-dashboard-grid.component.scss
diff --git a/ui/src/app/data-explorer/components/widget-view/grid-view/data-explorer-dashboard-grid.component.ts b/ui/src/app/data-explorer/components/widget-view/grid-view/data-explorer-dashboard-grid.component.ts new file mode 100644 index 0000000..ccd179c --- /dev/null +++ b/ui/src/app/data-explorer/components/widget-view/grid-view/data-explorer-dashboard-grid.component.ts
@@ -0,0 +1,101 @@ +/* + * 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, OnChanges, OnInit, QueryList, SimpleChanges, ViewChildren } from '@angular/core'; +import { GridsterItemComponent, GridType } from 'angular-gridster2'; +import { GridsterInfo } from '../../../../dashboard/models/gridster-info.model'; +import { IDataViewDashboardConfig } from '../../../models/dataview-dashboard.model'; +import { ResizeService } from '../../../services/resize.service'; +import { DataViewDataExplorerService } from '@streampipes/platform-services'; +import { AbstractWidgetViewDirective } from '../abstract-widget-view.directive'; + +@Component({ + selector: 'sp-data-explorer-dashboard-grid', + templateUrl: './data-explorer-dashboard-grid.component.html', + styleUrls: ['./data-explorer-dashboard-grid.component.scss'] +}) +export class DataExplorerDashboardGridComponent extends AbstractWidgetViewDirective implements OnInit, OnChanges { + + options: IDataViewDashboardConfig; + loaded = false; + + @ViewChildren(GridsterItemComponent) gridsterItemComponents: QueryList<GridsterItemComponent>; + + constructor(protected resizeService: ResizeService, + protected dataViewDataExplorerService: DataViewDataExplorerService) { + super(resizeService, dataViewDataExplorerService); + } + + ngOnInit(): void { + this.options = { + disablePushOnDrag: true, + draggable: {enabled: this.editMode}, + gridType: GridType.VerticalFixed, + minCols: 8, + maxCols: 8, + minRows: 4, + fixedRowHeight: 100, + fixedColWidth: 100, + margin: 5, + displayGrid: this.editMode ? 'always' : 'none', + resizable: {enabled: this.editMode}, + itemResizeCallback: ((item, itemComponent) => { + this.resizeService.notify({ + gridsterItem: item, + gridsterItemComponent: itemComponent + } as GridsterInfo); + }), + itemInitCallback: ((item, itemComponent) => { + this.resizeService.notify({ + gridsterItem: item, + gridsterItemComponent: itemComponent + } as GridsterInfo); + window.dispatchEvent(new Event('resize')); + }) + }; + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes['editMode'] && this.options) { + this.options.draggable.enabled = this.editMode; + this.options.resizable.enabled = this.editMode; + this.options.displayGrid = this.editMode ? 'always' : 'none'; + this.options.api.optionsChanged(); + } + } + + toggleGrid() { + this.options.displayGrid = this.options.displayGrid === 'none' ? 'always' : 'none'; + this.options.api.optionsChanged(); + } + + onOptionsChanged() { + this.options.api.optionsChanged(); + } + + onWidgetsAvailable(): void { + } + + isGridView(): boolean { + return true; + } + + selectNewWidget(widgetId): void { + } + +}
diff --git a/ui/src/app/data-explorer/components/widget-view/slide-view/data-explorer-dashboard-slide-view.component.html b/ui/src/app/data-explorer/components/widget-view/slide-view/data-explorer-dashboard-slide-view.component.html new file mode 100644 index 0000000..df87da3 --- /dev/null +++ b/ui/src/app/data-explorer/components/widget-view/slide-view/data-explorer-dashboard-slide-view.component.html
@@ -0,0 +1,55 @@ +<!-- + ~ 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" style="overflow-y:hidden"> + <div class="h-100" fxLayout="row" fxFlex="100"> + <div fxFlex="200px" + fxLayout="column" + class="selection-box" *ngIf="widgetsAvailable && currentWidget"> + <div *ngFor="let item of dashboard.widgets; let i = index" + [ngClass]="item.id === currentWidget._id ? 'viz-preview viz-preview-selected' : 'viz-preview'" + fxLayoutAlign="center center" + (click)="selectWidget(i, item.id)"> + <div fxFlex="100" + fxLayout="column" + fxLayoutAlign="center center"> + <span class="slide-view-title" *ngIf="widgetsVisible">{{configuredWidgets.get(item.id).baseAppearanceConfig.widgetTitle}}</span> + </div> + </div> + </div> + <div fxFlex="100"> + <div class="h-100 w-100 mw-100" id="slideViewOuter" fxFlex="100"> + <sp-data-explorer-dashboard-widget + [ngStyle]="{height: gridsterItemComponent.height -15 + 'px'}" + [timeSettings]="timeSettings" + (updateCallback)="propagateItemUpdate($event)" + (deleteCallback)="propagateItemRemoval($event)" + (configureWidgetCallback)="propagateWidgetSelection($event)" + (startEditModeEmitter)="startEditMode($event)" + [dashboardItem]="currentDashboardItem" + [configuredWidget]="currentWidget" + [dataLakeMeasure]="currentMeasure" + [currentlyConfiguredWidgetId]="currentlyConfiguredWidgetId" + [editMode]="editMode" + [gridMode]="false" + [gridsterItemComponent]="gridsterItemComponent" + *ngIf="widgetsAvailable && displayWidget && currentWidget && widgetsVisible"></sp-data-explorer-dashboard-widget> + </div> + </div> + </div> +</div>
diff --git a/ui/src/app/connect/components/format-item-json/format-item-json.component.scss b/ui/src/app/data-explorer/components/widget-view/slide-view/data-explorer-dashboard-slide-view.component.scss similarity index 66% copy from ui/src/app/connect/components/format-item-json/format-item-json.component.scss copy to ui/src/app/data-explorer/components/widget-view/slide-view/data-explorer-dashboard-slide-view.component.scss index 30123c0..8203bd3 100644 --- a/ui/src/app/connect/components/format-item-json/format-item-json.component.scss +++ b/ui/src/app/data-explorer/components/widget-view/slide-view/data-explorer-dashboard-slide-view.component.scss
@@ -16,32 +16,33 @@ * */ - -.format-label { - line-height:50px; - margin: auto; - text-align: center; - font-weight: bold; - font-size: 1.3em; -} - -.format-box { - min-height: 50px; - box-shadow: 1px 1px 2px #555; - border: 1px solid gray; +.viz-preview { + height: 100px; + min-height: 100px; + border: 1px solid var(--color-bg-2); cursor: pointer; - padding: 10px; - opacity: 0.7; - margin: 10px; - background: #ffffff; + margin: 5px 10px; + padding: 5px; } -.format-box:hover { - opacity: 1; +.viz-preview-selected { + border: 3px solid var(--color-accent); } -.selectedItem { - opacity: 1; - background-color: grey; +.selection-box { + overflow-y: auto; + overflow-x: hidden; + margin-bottom: 5px; + height: calc(100vh - 147px); + max-width: 100%; } +.slide-view-title { + text-align: center; + font-size: 10pt; +} + +.mw-100 { + max-width: 100%; + overflow-x: hidden; +}
diff --git a/ui/src/app/data-explorer/components/widget-view/slide-view/data-explorer-dashboard-slide-view.component.ts b/ui/src/app/data-explorer/components/widget-view/slide-view/data-explorer-dashboard-slide-view.component.ts new file mode 100644 index 0000000..e272c70 --- /dev/null +++ b/ui/src/app/data-explorer/components/widget-view/slide-view/data-explorer-dashboard-slide-view.component.ts
@@ -0,0 +1,112 @@ +/* + * 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 { AfterViewInit, Component, ElementRef, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core'; +import { AbstractWidgetViewDirective } from '../abstract-widget-view.directive'; +import { ResizeService } from '../../../services/resize.service'; +import { + DashboardItem, + DataExplorerWidgetModel, + DataLakeMeasure, + DataViewDataExplorerService +} from '@streampipes/platform-services'; + +@Component({ + selector: 'sp-data-explorer-dashboard-slide-view', + templateUrl: './data-explorer-dashboard-slide-view.component.html', + styleUrls: ['./data-explorer-dashboard-slide-view.component.scss'] +}) +export class DataExplorerDashboardSlideViewComponent extends AbstractWidgetViewDirective implements OnInit, AfterViewInit, OnChanges { + + selectedWidgetIndex = 0; + + gridsterItemComponent: any = {width: 100, height: 100}; + previewGridsterItemComponent: any = {width: 200, height: 100}; + + currentWidget: DataExplorerWidgetModel; + currentMeasure: DataLakeMeasure; + currentDashboardItem: DashboardItem; + + displayWidget = false; + + @ViewChild('slideViewOuter') slideViewOuter: ElementRef; + + constructor(protected resizeService: ResizeService, + protected dataViewDataExplorerService: DataViewDataExplorerService) { + super(resizeService, dataViewDataExplorerService); + } + + ngOnChanges(changes: SimpleChanges): void { + } + + ngOnInit(): void { + } + + + onOptionsChanged(): void { + } + + selectWidget(index: number, + widgetId: string): void { + this.displayWidget = false; + setTimeout(() => { + this.selectedWidgetIndex = index; + this.currentWidget = this.configuredWidgets.get(widgetId); + this.currentMeasure = this.dataLakeMeasures.get(widgetId); + this.currentDashboardItem = this.dashboard.widgets[index] as unknown as DashboardItem; + this.currentlyConfiguredWidgetId = widgetId; + + // Opens the design panel for the current widget when in edit mode + if (this.editMode) { + this.startEditModeEmitter.emit(this.currentWidget); + } + + this.displayWidget = true; + }); + + } + + ngAfterViewInit(): void { + const obs = new ResizeObserver(entries => { + entries.forEach(entry => { + const cr = entry.contentRect; + this.gridsterItemComponent.width = cr.width; + this.gridsterItemComponent.height = cr.height; + this.resizeService.notify({ + gridsterItem: this.dashboard.widgets[this.selectedWidgetIndex], + gridsterItemComponent: this.gridsterItemComponent + }); + }); + }); + obs.observe(document.getElementById('slideViewOuter')); + + } + + onWidgetsAvailable(): void { + this.selectWidget(0, this.dashboard.widgets[0].id); + } + + isGridView(): boolean { + return false; + } + + selectNewWidget(widgetId): void { + this.selectWidget(this.dashboard.widgets.length - 1, widgetId); + } + +}
diff --git a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.html b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.html index f6c3d61..8c4b4b5 100644 --- a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.html +++ b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.html
@@ -16,73 +16,83 @@ ~ --> -<div class="h-100 shadow"> - <div class="box" - [ngStyle]='{background: configuredWidget.baseAppearanceConfig.backgroundColor, +<div class="h-100"> + <div class="box" + [ngStyle]="{background: configuredWidget.baseAppearanceConfig.backgroundColor, color: configuredWidget.baseAppearanceConfig.textColor, - border: currentlyConfiguredWidgetId === configuredWidget._id ? "2px solid var(--color-accent)" : "2px solid " + configuredWidget.baseAppearanceConfig.backgroundColor}' - [attr.data-cy]="'widget-' + configuredWidget.baseAppearanceConfig.widgetTitle"> - <div class="widget-header h-40"> - <div fxFlex="100" fxLayout="row" fxLayoutAlign="start center" class="widget-header-text"> - {{ configuredWidget.baseAppearanceConfig.widgetTitle }} - </div> - <div fxFlex="100" fxLayout="row" fxLayoutAlign="end center"> - <div class="time-counter" - *ngIf="editMode" - [ngStyle]="{background: configuredWidget.baseAppearanceConfig.textColor, color: configuredWidget.baseAppearanceConfig.backgroundColor}"> - {{loadingTime}}s - </div> - <button mat-button - mat-icon-button - [matMenuTriggerFor]="menu" - aria-label="More options" - matTooltip="More options" - *ngIf="!editMode" - [attr.data-cy]="'more-options-' + configuredWidget.baseAppearanceConfig.widgetTitle"> - <mat-icon>more_vert</mat-icon> - </button> - <mat-menu #menu="matMenu"> - <button mat-menu-item - (click)="downloadDataAsFile()"> - <mat-icon>get_app</mat-icon> - <span>Download data</span> - </button> - <button mat-menu-item - (click)="startEditMode()" - *ngIf="hasDataExplorerWritePrivileges" - [attr.data-cy]="'start-edit-' + configuredWidget.baseAppearanceConfig.widgetTitle"> - <mat-icon>edit</mat-icon> - <span>Edit Widget</span> - </button> - </mat-menu> - <button mat-button - mat-icon-button - *ngIf="editMode" - (click)="downloadDataAsFile()"> - <mat-icon>get_app</mat-icon> - </button> - <button mat-button - mat-icon-button - [class.mat-raised-button]="currentlyConfiguredWidgetId === configuredWidget._id" - (click)="triggerWidgetEditMode()" - *ngIf="editMode" - [color]="currentlyConfiguredWidgetId === configuredWidget._id ? 'accent' : ''" - matTooltip="Edit widget" - [attr.data-cy]="'edit-' + configuredWidget.baseAppearanceConfig.widgetTitle"> - <mat-icon>edit</mat-icon> - </button> - <button mat-button - mat-icon-button - (click)="removeWidget()" - matTooltip="Delete widget" - *ngIf="editMode && hasDataExplorerDeletePrivileges" - [attr.data-cy]="'remove-' + configuredWidget.baseAppearanceConfig.widgetTitle"> - <mat-icon>clear</mat-icon> - </button> - </div> + height: (gridsterItemComponent.height - 13) + 'px', + border: editMode && currentlyConfiguredWidgetId === configuredWidget._id ? '4px solid var(--color-accent)' : '2px solid ' + configuredWidget.baseAppearanceConfig.backgroundColor}" + [attr.data-cy]="'widget-' + configuredWidget.baseAppearanceConfig.widgetTitle"> + <div class="widget-header h-40" *ngIf="!previewMode"> + <div fxFlex="100" fxLayout="row" fxLayoutAlign="start center" class="widget-header-text"> + {{ configuredWidget.baseAppearanceConfig.widgetTitle }} + </div> + <div fxFlex="100" fxLayout="row" fxLayoutAlign="end center"> + <mat-spinner [diameter]="20" color="primary" class="mr-10" *ngIf="timerActive"> + </mat-spinner> + <div class="time-counter" + *ngIf="editMode" + [ngStyle]="{background: configuredWidget.baseAppearanceConfig.textColor, color: configuredWidget.baseAppearanceConfig.backgroundColor}"> + {{loadingTime}}s </div> - <div class="widget-content p-0 gridster-item-content ml-0 mr-0 h-100"> - <ng-template widgetHost class="h-100 p-0"></ng-template> - </div> + <button mat-button + mat-icon-button + [matMenuTriggerFor]="menu" + aria-label="More options" + matTooltip="More options" + *ngIf="!editMode" + [attr.data-cy]="'more-options-' + configuredWidget.baseAppearanceConfig.widgetTitle"> + <mat-icon>more_vert</mat-icon> + </button> + <mat-menu #menu="matMenu"> + <button mat-menu-item + (click)="downloadDataAsFile()"> + <mat-icon>get_app</mat-icon> + <span>Download data</span> + </button> + <button mat-menu-item + (click)="startEditMode()" + *ngIf="hasDataExplorerWritePrivileges" + [attr.data-cy]="'start-edit-' + configuredWidget.baseAppearanceConfig.widgetTitle"> + <mat-icon>edit</mat-icon> + <span>Edit Widget</span> + </button> + </mat-menu> + <button mat-button + mat-icon-button + *ngIf="editMode" + (click)="downloadDataAsFile()"> + <mat-icon>get_app</mat-icon> + </button> + <button mat-button + mat-icon-button + [class.mat-raised-button]="currentlyConfiguredWidgetId === configuredWidget._id" + (click)="triggerWidgetEditMode()" + *ngIf="editMode" + [color]="currentlyConfiguredWidgetId === configuredWidget._id ? 'accent' : ''" + matTooltip="Edit widget" + [attr.data-cy]="'edit-' + configuredWidget.baseAppearanceConfig.widgetTitle"> + <mat-icon>edit</mat-icon> + </button> + <button mat-button + mat-icon-button + (click)="removeWidget()" + matTooltip="Delete widget" + *ngIf="editMode && hasDataExplorerDeletePrivileges" + [attr.data-cy]="'remove-' + configuredWidget.baseAppearanceConfig.widgetTitle"> + <mat-icon>clear</mat-icon> + </button> + </div> </div> + <div class="widget-content p-0 gridster-item-content ml-0 mr-0 h-100 mw-100"> + <ng-template widgetHost class="h-100 p-0"></ng-template> + <div fxFlex="100" + fxLayout="column" + fxLayoutAlign="center center" + *ngIf="errorMessage"> + <sp-exception-message [message]="errorMessage" + [showDetails]="true"></sp-exception-message> + </div> + </div> + </div> </div>
diff --git a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.scss b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.scss index 7dfcbef..79be76d 100644 --- a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.scss +++ b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.scss
@@ -46,6 +46,7 @@ display: flex; flex-flow: column; height: 100%; + padding-top: 5px; } .box .row.content { @@ -91,3 +92,12 @@ text-align: center; } +.h-0 { + height: 0px; +} + +.mw-100 { + max-width: 100%; + width: 100%; + overflow-x: hidden; +}
diff --git a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.ts b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.ts index 7163672..16dd074 100644 --- a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.ts +++ b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.ts
@@ -21,22 +21,22 @@ ComponentFactoryResolver, EventEmitter, Input, + OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; -import { MatDialog } from '@angular/material/dialog'; import { GridsterItemComponent } from 'angular-gridster2'; import { - DateRange, + DashboardItem, DataExplorerDataConfig, DataExplorerWidgetModel, DataLakeMeasure, DataViewDataExplorerService, - DashboardItem, + DateRange, TimeSettings } from '@streampipes/platform-services'; -import { DataDownloadDialog } from '../datadownloadDialog/dataDownload.dialog'; -import { interval } from 'rxjs'; +import { DataDownloadDialogComponent } from '../../../core-ui/data-download-dialog/data-download-dialog.component'; +import { interval, Subscription } from 'rxjs'; import { takeWhile } from 'rxjs/operators'; import { DataExplorerWidgetRegistry } from '../../registry/data-explorer-widget-registry'; import { WidgetDirective } from './widget.directive'; @@ -44,13 +44,15 @@ import { WidgetTypeService } from '../../services/widget-type.service'; import { AuthService } from '../../../services/auth.service'; import { UserPrivilege } from '../../../_enums/user-privilege.enum'; +import { DialogService, PanelType } from '@streampipes/shared-ui'; +import { StreamPipesErrorMessage } from '../../../../../projects/streampipes/platform-services/src/lib/model/gen/streampipes-model'; @Component({ selector: 'sp-data-explorer-dashboard-widget', templateUrl: './data-explorer-dashboard-widget.component.html', styleUrls: ['./data-explorer-dashboard-widget.component.scss'] }) -export class DataExplorerDashboardWidgetComponent implements OnInit { +export class DataExplorerDashboardWidgetComponent implements OnInit, OnDestroy { @Input() dashboardItem: DashboardItem; @@ -70,6 +72,12 @@ @Input() currentlyConfiguredWidgetId: string; + @Input() + previewMode = false; + + @Input() + gridMode = true; + /** * This is the date range (start, end) to view the data and is set in data-explorer.ts */ @@ -92,23 +100,29 @@ hasDataExplorerWritePrivileges = false; hasDataExplorerDeletePrivileges = false; + authSubscription: Subscription; + widgetTypeChangedSubscription: Subscription; + intervalSubscription: Subscription; + + errorMessage: StreamPipesErrorMessage; + @ViewChild(WidgetDirective, {static: true}) widgetHost!: WidgetDirective; constructor(private dataViewDataExplorerService: DataViewDataExplorerService, - private dialog: MatDialog, + private dialogService: DialogService, private componentFactoryResolver: ComponentFactoryResolver, private widgetTypeService: WidgetTypeService, private authService: AuthService) { } ngOnInit(): void { - this.authService.user$.subscribe(user => { + this.authSubscription = this.authService.user$.subscribe(user => { this.hasDataExplorerWritePrivileges = this.authService.hasRole(UserPrivilege.PRIVILEGE_WRITE_DATA_EXPLORER_VIEW); this.hasDataExplorerDeletePrivileges = this.authService.hasRole(UserPrivilege.PRIVILEGE_DELETE_DATA_EXPLORER_VIEW); }); this.widgetLoaded = true; this.title = this.dataLakeMeasure.measureName; - this.widgetTypeService.widgetTypeChangeSubject.subscribe(typeChange => { + this.widgetTypeChangedSubscription = this.widgetTypeService.widgetTypeChangeSubject.subscribe(typeChange => { if (typeChange.widgetId === this.configuredWidget._id) { this.chooseWidget(typeChange.newWidgetTypeId); } @@ -116,6 +130,15 @@ this.chooseWidget(this.configuredWidget.widgetType); } + ngOnDestroy() { + if (this.authSubscription) { + this.authSubscription.unsubscribe(); + } + if (this.widgetTypeChangedSubscription) { + this.widgetTypeChangedSubscription.unsubscribe(); + } + } + chooseWidget(widgetTypeId: string) { const widgets = DataExplorerWidgetRegistry.getAvailableWidgetTemplates(); const widgetToDisplay = widgets.find(widget => widget.id === widgetTypeId); @@ -136,12 +159,16 @@ componentRef.instance.editMode = this.editMode; componentRef.instance.dataViewDashboardItem = this.dashboardItem; componentRef.instance.dataExplorerWidget = this.configuredWidget; + componentRef.instance.previewMode = this.previewMode; + componentRef.instance.gridMode = this.gridMode; const removeSub = componentRef.instance.removeWidgetCallback.subscribe(ev => this.removeWidget()); const timerSub = componentRef.instance.timerCallback.subscribe(ev => this.handleTimer(ev)); + const errorSub = componentRef.instance.errorCallback.subscribe(ev => this.errorMessage = ev); componentRef.onDestroy(destroy => { removeSub.unsubscribe(); timerSub.unsubscribe(); + errorSub.unsubscribe(); }); } @@ -150,13 +177,14 @@ } downloadDataAsFile() { - this.dialog.open(DataDownloadDialog, { - width: '600px', + this.dialogService.open(DataDownloadDialogComponent, { + panelType: PanelType.SLIDE_IN_PANEL, + title: 'Download data', + width: '50vw', data: { - index: this.dataLakeMeasure.measureName, - date: DateRange.fromTimeSettings(this.timeSettings) - }, - panelClass: 'custom-dialog-container' + 'date': DateRange.fromTimeSettings(this.timeSettings), + 'dataConfig': this.configuredWidget.dataConfig as DataExplorerDataConfig + } }); } @@ -174,7 +202,7 @@ startLoadingTimer() { this.timerActive = true; - interval( 10 ) + this.intervalSubscription = interval( 10 ) .pipe(takeWhile(() => this.timerActive)) .subscribe(value => { this.loadingTime = (value * 10 / 1000); @@ -183,9 +211,11 @@ stopLoadingTimer() { this.timerActive = false; + this.intervalSubscription.unsubscribe(); } handleTimer(start: boolean) { start ? this.startLoadingTimer() : this.stopLoadingTimer(); } + }
diff --git a/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts b/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts index a77a09d..151b503 100644 --- a/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts +++ b/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts
@@ -20,20 +20,23 @@ import { GridsterItem, GridsterItemComponent } from 'angular-gridster2'; import { WidgetConfigurationService } from '../../../services/widget-configuration.service'; import { + DashboardItem, DataExplorerDataConfig, DataExplorerField, - DataViewQueryGeneratorService, DataExplorerWidgetModel, - SpQueryResult, - DashboardItem, DatalakeRestService, - TimeSettings } from '@streampipes/platform-services'; + DataViewQueryGeneratorService, + SpQueryResult, + StreamPipesErrorMessage, + TimeSettings +} from '@streampipes/platform-services'; import { ResizeService } from '../../../services/resize.service'; import { FieldProvider } from '../../../models/dataview-dashboard.model'; -import { Observable, Subscription, zip } from 'rxjs'; +import { Observable, Subject, Subscription, zip } from 'rxjs'; import { DataExplorerFieldProviderService } from '../../../services/data-explorer-field-provider-service'; import { BaseWidgetData } from './data-explorer-widget-data'; import { TimeSelectionService } from '../../../services/time-selection.service'; +import { catchError, switchMap } from 'rxjs/operators'; @Directive() export abstract class BaseDataExplorerWidgetDirective<T extends DataExplorerWidgetModel> implements BaseWidgetData<T>, OnInit, OnDestroy { @@ -46,12 +49,21 @@ @Output() timerCallback: EventEmitter<boolean> = new EventEmitter(); + @Output() + errorCallback: EventEmitter<StreamPipesErrorMessage> = new EventEmitter<StreamPipesErrorMessage>(); + @Input() gridsterItem: GridsterItem; @Input() gridsterItemComponent: GridsterItemComponent; @Input() editMode: boolean; @Input() timeSettings: TimeSettings; + @Input() + previewMode = false; + + @Input() + gridMode = true; + @Input() dataViewDashboardItem: DashboardItem; @Input() dataExplorerWidget: T; @@ -71,6 +83,8 @@ resizeSub: Subscription; timeSelectionSub: Subscription; + requestQueue$: Subject<Observable<SpQueryResult>[]> = new Subject<Observable<SpQueryResult>[]>(); + constructor(protected dataLakeRestService: DatalakeRestService, protected widgetConfigurationService: WidgetConfigurationService, protected resizeService: ResizeService, @@ -80,9 +94,28 @@ } ngOnInit(): void { + const heightOffset = this.gridMode ? 70 : 65; + const widthOffset = this.gridMode ? 10 : 10; this.showData = true; const sourceConfigs = this.dataExplorerWidget.dataConfig.sourceConfigs; this.fieldProvider = this.fieldService.generateFieldLists(sourceConfigs); + + this.requestQueue$ + .pipe(switchMap((observables) => { + this.errorCallback.emit(undefined); + return zip(...observables).pipe(catchError((err) => { + this.timerCallback.emit(false); + this.errorCallback.emit(err.error); + return []; + })); + })) + .subscribe(results => { + results.forEach((result, index) => result.sourceIndex = index); + this.validateReceivedData(results); + this.refreshView(); + this.timerCallback.emit(false); + }); + this.widgetConfigurationSub = this.widgetConfigurationService.configurationChangedSubject.subscribe(refreshMessage => { if (refreshMessage.widgetId === this.dataExplorerWidget._id) { if (refreshMessage.refreshData) { @@ -99,23 +132,28 @@ } } }); - this.resizeSub = this.resizeService.resizeSubject.subscribe(info => { - if (info.gridsterItem.id === this.dataExplorerWidget._id) { - this.onResize(this.gridsterItemComponent.width, this.gridsterItemComponent.height - 40); - } - }); + if (!this.previewMode) { + this.resizeSub = this.resizeService.resizeSubject.subscribe(info => { + if (info.gridsterItem.id === this.dataExplorerWidget._id) { + this.onResize(this.gridsterItemComponent.width - widthOffset, this.gridsterItemComponent.height - heightOffset); + } + }); + } this.timeSelectionSub = this.timeSelectionService.timeSelectionChangeSubject.subscribe(ts => { this.timeSettings = ts; this.updateData(); }); this.updateData(); - this.onResize(this.gridsterItemComponent.width, this.gridsterItemComponent.height - 40); + this.onResize(this.gridsterItemComponent.width - widthOffset, this.gridsterItemComponent.height - heightOffset); } ngOnDestroy(): void { this.widgetConfigurationSub.unsubscribe(); - this.resizeSub.unsubscribe(); + if (this.resizeSub) { + this.resizeSub.unsubscribe(); + } this.timeSelectionSub.unsubscribe(); + this.requestQueue$.unsubscribe(); } public removeWidget() { @@ -140,35 +178,27 @@ } private loadData(includeTooMuchEventsParameter: boolean) { - let observables: Observable<SpQueryResult>[]; - if (includeTooMuchEventsParameter && !this.dataExplorerWidget.dataConfig.ignoreTooMuchDataWarning) { observables = this - .dataViewQueryGeneratorService - .generateObservables( - this.timeSettings.startTime, - this.timeSettings.endTime, - this.dataExplorerWidget.dataConfig as DataExplorerDataConfig, - BaseDataExplorerWidgetDirective.TOO_MUCH_DATA_PARAMETER - ); + .dataViewQueryGeneratorService + .generateObservables( + this.timeSettings.startTime, + this.timeSettings.endTime, + this.dataExplorerWidget.dataConfig as DataExplorerDataConfig, + BaseDataExplorerWidgetDirective.TOO_MUCH_DATA_PARAMETER + ); } else { observables = this - .dataViewQueryGeneratorService - .generateObservables( - this.timeSettings.startTime, - this.timeSettings.endTime, - this.dataExplorerWidget.dataConfig as DataExplorerDataConfig); + .dataViewQueryGeneratorService + .generateObservables( + this.timeSettings.startTime, + this.timeSettings.endTime, + this.dataExplorerWidget.dataConfig as DataExplorerDataConfig); } this.timerCallback.emit(true); - zip(...observables).subscribe(results => { - results.forEach((result, index) => result.sourceIndex = index); - this.validateReceivedData(results); - // this.onDataReceived(results); - this.refreshView(); - this.timerCallback.emit(false); - }); + this.requestQueue$.next(observables); } validateReceivedData(spQueryResults: SpQueryResult[]) {
diff --git a/ui/src/app/data-explorer/components/widgets/base/data-explorer-widget-data.ts b/ui/src/app/data-explorer/components/widgets/base/data-explorer-widget-data.ts index b6927b1..1a75781 100644 --- a/ui/src/app/data-explorer/components/widgets/base/data-explorer-widget-data.ts +++ b/ui/src/app/data-explorer/components/widgets/base/data-explorer-widget-data.ts
@@ -18,11 +18,16 @@ import { EventEmitter } from '@angular/core'; import { GridsterItem, GridsterItemComponent } from 'angular-gridster2'; -import { DataExplorerWidgetModel, DashboardItem, TimeSettings } from '@streampipes/platform-services'; +import { + DashboardItem, + DataExplorerWidgetModel, + StreamPipesErrorMessage, + TimeSettings } from '@streampipes/platform-services'; export interface BaseWidgetData<T extends DataExplorerWidgetModel> { removeWidgetCallback: EventEmitter<boolean>; timerCallback: EventEmitter<boolean>; + errorCallback: EventEmitter<StreamPipesErrorMessage>; gridsterItem: GridsterItem; gridsterItemComponent: GridsterItemComponent; @@ -32,4 +37,6 @@ dataViewDashboardItem: DashboardItem; dataExplorerWidget: T; + previewMode: boolean; + gridMode: boolean; }
diff --git a/ui/src/app/data-explorer/components/widgets/correlation-chart/correlation-chart-widget.component.html b/ui/src/app/data-explorer/components/widgets/correlation-chart/correlation-chart-widget.component.html index cd0e477..1f7c8ae 100644 --- a/ui/src/app/data-explorer/components/widgets/correlation-chart/correlation-chart-widget.component.html +++ b/ui/src/app/data-explorer/components/widgets/correlation-chart/correlation-chart-widget.component.html
@@ -19,14 +19,17 @@ <div fxLayout="column" fxFlex="100" [ngStyle]="{background: dataExplorerWidget.baseAppearanceConfig.backgroundColor, color: dataExplorerWidget.baseAppearanceConfig.textColor}"> - <sp-load-data-spinner *ngIf="showIsLoadingData" class="h-100"></sp-load-data-spinner> - - <sp-no-data-in-date-range *ngIf="showNoDataInDateRange" [viewDateRange]="timeSettings"></sp-no-data-in-date-range> + <sp-no-data-in-date-range + *ngIf="showNoDataInDateRange" + [viewDateRange]="timeSettings" + class="h-100"> + </sp-no-data-in-date-range> <sp-too-much-data [amountOfEvents]="amountOfTooMuchEvents" (loadDataWithTooManyEventsEmitter)="loadDataWithTooManyEvents()" - *ngIf="showTooMuchData"></sp-too-much-data> + *ngIf="showTooMuchData" class="h-100"> + </sp-too-much-data> <plotly-plot *ngIf="showData"
diff --git a/ui/src/app/data-explorer/components/widgets/correlation-chart/correlation-chart-widget.component.ts b/ui/src/app/data-explorer/components/widgets/correlation-chart/correlation-chart-widget.component.ts index 7ee788b..3de451f 100644 --- a/ui/src/app/data-explorer/components/widgets/correlation-chart/correlation-chart-widget.component.ts +++ b/ui/src/app/data-explorer/components/widgets/correlation-chart/correlation-chart-widget.component.ts
@@ -20,6 +20,7 @@ import { BaseDataExplorerWidgetDirective } from '../base/base-data-explorer-widget.directive'; import { CorrelationChartWidgetModel } from './model/correlation-chart-widget.model'; import { DataExplorerField, SpQueryResult } from '@streampipes/platform-services'; +import { ColorUtils } from '../utils/color-utils'; @Component({ selector: 'sp-data-explorer-correlation-chart-widget', @@ -37,12 +38,18 @@ graph = { layout: { grid: {rows: this.rowNo, columns: this.fixedColNo, pattern: 'independent'}, + margin: { + t: 35, + b: 35 + }, xaxis: { + automargin: true, title: { text: '' } }, yaxis: { + automargin: true, title: { text: '' } @@ -66,17 +73,6 @@ this.updateAppearance(); } - lightenColor(color: string, percent: number) { - const num = parseInt(color.replace('#', ''), 16); - const amt = Math.round(2.55 * percent); - const R = (num >> 16) + amt; - const B = (num >> 8 & 0x00FF) + amt; - const G = (num & 0x0000FF) + amt; - const result = '#' + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + - (B < 255 ? B < 1 ? 0 : B : 255) * 0x100 + (G < 255 ? G < 1 ? 0 : G : 255)).toString(16).slice(1); - return result; - } - prepareData(result: SpQueryResult[]) { const xIndex = this.getColumnIndex(this.dataExplorerWidget.visualizationConfig.firstField, result[0]); @@ -174,7 +170,7 @@ colCount += 1; } - colorVal = this.lightenColor(colorVal, 11.); + colorVal = ColorUtils.lightenColor(colorVal, 11.); }); }
diff --git a/ui/src/app/data-explorer/components/widgets/distribution-chart/config/distribution-chart-widget-config.component.html b/ui/src/app/data-explorer/components/widgets/distribution-chart/config/distribution-chart-widget-config.component.html index b0d367d..2f51faa 100644 --- a/ui/src/app/data-explorer/components/widgets/distribution-chart/config/distribution-chart-widget-config.component.html +++ b/ui/src/app/data-explorer/components/widgets/distribution-chart/config/distribution-chart-widget-config.component.html
@@ -31,7 +31,7 @@ </mat-form-field> <h5>Field</h5> - <sp-select-property [availableProperties]="fieldProvider.allFields" + <sp-select-property [availableProperties]="currentlyConfiguredWidget.visualizationConfig.displayType === 'heatmap' ? fieldProvider.numericFields : fieldProvider.allFields" [selectedProperty]="currentlyConfiguredWidget.visualizationConfig.selectedProperty" (changeSelectedProperty)="setSelectedProperty($event)"> </sp-select-property>
diff --git a/ui/src/app/data-explorer/components/widgets/distribution-chart/config/distribution-chart-widget-config.component.ts b/ui/src/app/data-explorer/components/widgets/distribution-chart/config/distribution-chart-widget-config.component.ts index 7e645c2..18f935a 100644 --- a/ui/src/app/data-explorer/components/widgets/distribution-chart/config/distribution-chart-widget-config.component.ts +++ b/ui/src/app/data-explorer/components/widgets/distribution-chart/config/distribution-chart-widget-config.component.ts
@@ -41,6 +41,9 @@ updateDisplayType(selectedType: string) { this.currentlyConfiguredWidget.visualizationConfig.displayType = selectedType; + if (this.fieldProvider.numericFields.find(field => field === this.currentlyConfiguredWidget.visualizationConfig.selectedProperty) === undefined) { + this.currentlyConfiguredWidget.visualizationConfig.selectedProperty = this.fieldProvider.numericFields[0]; + } this.triggerDataRefresh(); }
diff --git a/ui/src/app/data-explorer/components/widgets/distribution-chart/distribution-chart-widget.component.html b/ui/src/app/data-explorer/components/widgets/distribution-chart/distribution-chart-widget.component.html index ce9d36e..df75b8c 100644 --- a/ui/src/app/data-explorer/components/widgets/distribution-chart/distribution-chart-widget.component.html +++ b/ui/src/app/data-explorer/components/widgets/distribution-chart/distribution-chart-widget.component.html
@@ -19,14 +19,16 @@ <div fxLayout="column" fxFlex="100" [ngStyle]="{background: dataExplorerWidget.baseAppearanceConfig.backgroundColor, color: dataExplorerWidget.baseAppearanceConfig.textColor}"> - <sp-load-data-spinner *ngIf="showIsLoadingData" class="h-100"></sp-load-data-spinner> - - <sp-no-data-in-date-range *ngIf="showNoDataInDateRange" [viewDateRange]="timeSettings"></sp-no-data-in-date-range> + <sp-no-data-in-date-range + *ngIf="showNoDataInDateRange" + [viewDateRange]="timeSettings" + class="h-100"> + </sp-no-data-in-date-range> <sp-too-much-data [amountOfEvents]="amountOfTooMuchEvents" (loadDataWithTooManyEventsEmitter)="loadDataWithTooManyEvents()" - *ngIf="showTooMuchData"></sp-too-much-data> + *ngIf="showTooMuchData" class="h-100"></sp-too-much-data> <plotly-plot *ngIf="showData && !(dataExplorerWidget.visualizationConfig.displayType === 'heatmap')" [divId]="dataExplorerWidget._id"
diff --git a/ui/src/app/data-explorer/components/widgets/distribution-chart/value-heatmap/value-heatmap.component.ts b/ui/src/app/data-explorer/components/widgets/distribution-chart/value-heatmap/value-heatmap.component.ts index 450f99d..5559ac2 100644 --- a/ui/src/app/data-explorer/components/widgets/distribution-chart/value-heatmap/value-heatmap.component.ts +++ b/ui/src/app/data-explorer/components/widgets/distribution-chart/value-heatmap/value-heatmap.component.ts
@@ -18,9 +18,9 @@ import { Component, Input, OnInit } from '@angular/core'; import { EChartsOption } from 'echarts'; -import { ECharts } from "echarts/core"; -import { DataExplorerWidgetModel, SpQueryResult } from "../../../../../../../dist/streampipes/platform-services"; -import { DistributionChartWidgetModel } from "../model/distribution-chart-widget.model"; +import { ECharts } from 'echarts/core'; +import { SpQueryResult } from '@streampipes/platform-services'; +import { DistributionChartWidgetModel } from '../model/distribution-chart-widget.model'; @Component({ selector: 'sp-data-explorer-value-heatmap-widget',
diff --git a/ui/src/app/data-explorer/components/widgets/heatmap/heatmap-widget.component.html b/ui/src/app/data-explorer/components/widgets/heatmap/heatmap-widget.component.html index 24a404a..e953542 100644 --- a/ui/src/app/data-explorer/components/widgets/heatmap/heatmap-widget.component.html +++ b/ui/src/app/data-explorer/components/widgets/heatmap/heatmap-widget.component.html
@@ -18,14 +18,18 @@ <div fxFlex="100" fxLayoutAlign="center center" fxLayout="column" class="main-panel"> - <sp-load-data-spinner *ngIf="showIsLoadingData" class="h-100"></sp-load-data-spinner> - - <sp-no-data-in-date-range *ngIf="showNoDataInDateRange" [viewDateRange]="timeSettings"></sp-no-data-in-date-range> + <sp-no-data-in-date-range + *ngIf="showNoDataInDateRange" + [viewDateRange]="timeSettings" + class="h-100"> + </sp-no-data-in-date-range> <sp-too-much-data [amountOfEvents]="amountOfTooMuchEvents" (loadDataWithTooManyEventsEmitter)="loadDataWithTooManyEvents()" - *ngIf="showTooMuchData"></sp-too-much-data> + *ngIf="showTooMuchData" + class="h-100"> + </sp-too-much-data> <div class="value-panel"> <div echarts [options]="option"
diff --git a/ui/src/app/data-explorer/components/widgets/image/config/image-widget-config.component.ts b/ui/src/app/data-explorer/components/widgets/image/config/image-widget-config.component.ts index 19f55ef..ae971d4 100644 --- a/ui/src/app/data-explorer/components/widgets/image/config/image-widget-config.component.ts +++ b/ui/src/app/data-explorer/components/widgets/image/config/image-widget-config.component.ts
@@ -20,7 +20,7 @@ import { BaseWidgetConfig } from '../../base/base-widget-config'; import { ImageWidgetModel, ImageWidgetVisConfig } from '../model/image-widget.model'; import { WidgetType } from '../../../../registry/data-explorer-widgets'; -import { DataExplorerField } from "../../../../../../../dist/streampipes/platform-services"; +import { DataExplorerField } from '@streampipes/platform-services'; @Component({ selector: 'sp-data-explorer-image-widget-config',
diff --git a/ui/src/app/data-explorer/components/widgets/image/image-widget.component.html b/ui/src/app/data-explorer/components/widgets/image/image-widget.component.html index 1577277..a2bd9ec 100644 --- a/ui/src/app/data-explorer/components/widgets/image/image-widget.component.html +++ b/ui/src/app/data-explorer/components/widgets/image/image-widget.component.html
@@ -19,8 +19,6 @@ <div fxFlex="100" fxLayoutAlign="center center" fxLayout="column" class="main-panel"> - <sp-load-data-spinner *ngIf="showIsLoadingData" class="h-100"></sp-load-data-spinner> - <sp-no-data-in-date-range *ngIf="showNoDataInDateRange" [viewDateRange]="timeSettings"></sp-no-data-in-date-range>
diff --git a/ui/src/app/data-explorer/components/widgets/indicator/indicator-chart-widget.component.html b/ui/src/app/data-explorer/components/widgets/indicator/indicator-chart-widget.component.html index 074d1fa..1dbe8da 100644 --- a/ui/src/app/data-explorer/components/widgets/indicator/indicator-chart-widget.component.html +++ b/ui/src/app/data-explorer/components/widgets/indicator/indicator-chart-widget.component.html
@@ -19,14 +19,16 @@ <div fxLayout="column" fxFlex="100" [ngStyle]="{background: dataExplorerWidget.baseAppearanceConfig.backgroundColor, color: dataExplorerWidget.baseAppearanceConfig.textColor}"> - <sp-load-data-spinner *ngIf="showIsLoadingData" class="h-100"></sp-load-data-spinner> - - <sp-no-data-in-date-range *ngIf="showNoDataInDateRange" [viewDateRange]="timeSettings"></sp-no-data-in-date-range> + <sp-no-data-in-date-range + *ngIf="showNoDataInDateRange" + [viewDateRange]="timeSettings" + class="h-100"> + </sp-no-data-in-date-range> <sp-too-much-data [amountOfEvents]="amountOfTooMuchEvents" (loadDataWithTooManyEventsEmitter)="loadDataWithTooManyEvents()" - *ngIf="showTooMuchData"></sp-too-much-data> + *ngIf="showTooMuchData" class="h-100"></sp-too-much-data> <plotly-plot *ngIf="showData" [divId]="dataExplorerWidget._id"
diff --git a/ui/src/app/data-explorer/components/widgets/map/map-widget.component.html b/ui/src/app/data-explorer/components/widgets/map/map-widget.component.html index fdacf07..38fd24a 100644 --- a/ui/src/app/data-explorer/components/widgets/map/map-widget.component.html +++ b/ui/src/app/data-explorer/components/widgets/map/map-widget.component.html
@@ -18,14 +18,15 @@ <div fxFlex="100" fxLayoutAlign="center center" fxLayout="column" class="main-panel"> - <sp-load-data-spinner *ngIf="showIsLoadingData" class="h-100"></sp-load-data-spinner> - - <sp-no-data-in-date-range *ngIf="showNoDataInDateRange" [viewDateRange]="timeSettings"></sp-no-data-in-date-range> + <sp-no-data-in-date-range + *ngIf="showNoDataInDateRange" + [viewDateRange]="timeSettings" class="h-100"> + </sp-no-data-in-date-range> <sp-too-much-data [amountOfEvents]="amountOfTooMuchEvents" (loadDataWithTooManyEventsEmitter)="loadDataWithTooManyEvents()" - *ngIf="showTooMuchData"></sp-too-much-data> + *ngIf="showTooMuchData" class="h-100"></sp-too-much-data> <div *ngIf="showData"> <div [ngStyle]="{'width': mapWidth + 'px', 'height': mapHeight + 'px'}"
diff --git a/ui/src/app/data-explorer/components/widgets/table/table-widget.component.html b/ui/src/app/data-explorer/components/widgets/table/table-widget.component.html index 5102e53..a1b2a9e 100644 --- a/ui/src/app/data-explorer/components/widgets/table/table-widget.component.html +++ b/ui/src/app/data-explorer/components/widgets/table/table-widget.component.html
@@ -19,15 +19,18 @@ <div fxLayout="column" fxFlex="100" [ngStyle]="{background: dataExplorerWidget.baseAppearanceConfig.backgroundColor, color: dataExplorerWidget.baseAppearanceConfig.textColor}"> - <sp-load-data-spinner *ngIf="showIsLoadingData" class="h-100"></sp-load-data-spinner> - - <sp-no-data-in-date-range *ngIf="showNoDataInDateRange" [viewDateRange]="timeSettings"></sp-no-data-in-date-range> + <sp-no-data-in-date-range + *ngIf="showNoDataInDateRange" + [viewDateRange]="timeSettings" + class="h-100"> + </sp-no-data-in-date-range> <sp-too-much-data [amountOfEvents]="amountOfTooMuchEvents" (loadDataWithTooManyEventsEmitter)="loadDataWithTooManyEvents()" *ngIf="showTooMuchData" - ></sp-too-much-data> + class="h-100"> + </sp-too-much-data> <div class="table-container"> <table
diff --git a/ui/src/app/data-explorer/components/widgets/time-series-chart/config/time-series-chart-widget-config.component.ts b/ui/src/app/data-explorer/components/widgets/time-series-chart/config/time-series-chart-widget-config.component.ts index 73e7e2d..f359700 100644 --- a/ui/src/app/data-explorer/components/widgets/time-series-chart/config/time-series-chart-widget-config.component.ts +++ b/ui/src/app/data-explorer/components/widgets/time-series-chart/config/time-series-chart-widget-config.component.ts
@@ -37,14 +37,56 @@ super(widgetConfigurationService, fieldService); } - presetColors: string[] = ['#39B54A', '#1B1464', '#f44336', '#4CAF50', '#FFEB3B', '#FFFFFF', '#000000']; - + presetColors: string[] = [ + '#39B54A', + '#1B1464', + '#f44336', + '#FFEB3B', + '#000000', + '#433BFF', + '#FF00E4', + '#FD8B00', + '#FD8B00', + '#00FFD5', + '#581845', + '#767676', + '#4300BF', + '#6699D4', + '#D466A1' + ]; + ngOnInit(): void { super.onInit(); } setSelectedProperties(selectedColumns: DataExplorerField[]) { this.currentlyConfiguredWidget.visualizationConfig.selectedTimeSeriesChartProperties = selectedColumns; + + const numericPlusBooleanFields = this.fieldProvider.numericFields.concat(this.fieldProvider.booleanFields); + + const currentColors = this.currentlyConfiguredWidget.visualizationConfig.chosenColor; + const currentNames = this.currentlyConfiguredWidget.visualizationConfig.displayName; + const currentTypes = this.currentlyConfiguredWidget.visualizationConfig.displayType; + const currentAxis = this.currentlyConfiguredWidget.visualizationConfig.chosenAxis; + + const lenBefore = Object.keys(currentAxis).length + + numericPlusBooleanFields.map((field, index) => { + const name = field.fullDbName + field.sourceIndex + if (!(name in currentColors)) { + console.log("choosing color " + lenBefore+index + " " + this.presetColors[lenBefore+index]); + currentColors[name] = this.presetColors[lenBefore+index]; + currentNames[name] = field.fullDbName; + currentTypes[name] = 'lines'; + currentAxis[name] = 'left'; + } + }); + + this.currentlyConfiguredWidget.visualizationConfig.chosenColor = currentColors; + this.currentlyConfiguredWidget.visualizationConfig.displayName = currentNames; + this.currentlyConfiguredWidget.visualizationConfig.displayType = currentTypes; + this.currentlyConfiguredWidget.visualizationConfig.chosenAxis = currentAxis + // this.currentlyConfiguredWidget.dataConfig.yKeys = this.getRuntimeNames(selectedColumns); this.triggerDataRefresh(); } @@ -82,6 +124,7 @@ const axes = {}; numericPlusBooleanFields.map((field, index) => { + console.log("field full db name " + field.fullDbName) colors[field.fullDbName + field.sourceIndex] = this.presetColors[index]; names[field.fullDbName + field.sourceIndex] = field.fullDbName; dTypes[field.fullDbName + field.sourceIndex] = 'lines';
diff --git a/ui/src/app/data-explorer/components/widgets/time-series-chart/time-series-chart-widget.component.html b/ui/src/app/data-explorer/components/widgets/time-series-chart/time-series-chart-widget.component.html index 7a5a7e9..ac729ca 100644 --- a/ui/src/app/data-explorer/components/widgets/time-series-chart/time-series-chart-widget.component.html +++ b/ui/src/app/data-explorer/components/widgets/time-series-chart/time-series-chart-widget.component.html
@@ -18,14 +18,17 @@ <div fxLayout="column" fxFlex="100" [ngStyle]="{background: dataExplorerWidget.baseAppearanceConfig.backgroundColor, color: dataExplorerWidget.baseAppearanceConfig.textColor}"> - <sp-load-data-spinner *ngIf="showIsLoadingData" class="h-100"></sp-load-data-spinner> - - <sp-no-data-in-date-range *ngIf="showNoDataInDateRange" [viewDateRange]="timeSettings"></sp-no-data-in-date-range> + <sp-no-data-in-date-range + *ngIf="showNoDataInDateRange" + [viewDateRange]="timeSettings" + class="h-100"> + </sp-no-data-in-date-range> <sp-too-much-data [amountOfEvents]="amountOfTooMuchEvents" (loadDataWithTooManyEventsEmitter)="loadDataWithTooManyEvents()" - *ngIf="showTooMuchData"></sp-too-much-data> + *ngIf="showTooMuchData" class="h-100"> + </sp-too-much-data> <plotly-plot *ngIf="showData" [divId]="dataExplorerWidget._id"
diff --git a/ui/src/app/data-explorer/components/widgets/time-series-chart/time-series-chart-widget.component.ts b/ui/src/app/data-explorer/components/widgets/time-series-chart/time-series-chart-widget.component.ts index 9e851b4..b1f76f2 100644 --- a/ui/src/app/data-explorer/components/widgets/time-series-chart/time-series-chart-widget.component.ts +++ b/ui/src/app/data-explorer/components/widgets/time-series-chart/time-series-chart-widget.component.ts
@@ -20,6 +20,7 @@ import { BaseDataExplorerWidgetDirective } from '../base/base-data-explorer-widget.directive'; import { TimeSeriesChartWidgetModel } from './model/time-series-chart-widget.model'; import { DataExplorerField, SpQueryResult } from '@streampipes/platform-services'; +import { ColorUtils } from '../utils/color-utils'; @Component({ selector: 'sp-data-explorer-time-series-chart-widget', @@ -28,7 +29,23 @@ }) export class TimeSeriesChartWidgetComponent extends BaseDataExplorerWidgetDirective<TimeSeriesChartWidgetModel> implements OnInit { - presetColors: string[] = ['#39B54A', '#1B1464', '#f44336', '#4CAF50', '#FFEB3B', '#FFFFFF', '#000000']; + presetColors: string[] = [ + '#39B54A', + '#1B1464', + '#f44336', + '#FFEB3B', + '#000000', + '#433BFF', + '#FF00E4', + '#FD8B00', + '#FD8B00', + '#00FFD5', + '#581845', + '#767676', + '#4300BF', + '#6699D4', + '#D466A1' + ]; groupKeeper: {} = {}; @@ -59,11 +76,19 @@ plot_bgcolor: '#fff', paper_bgcolor: '#fff', yaxis: { - fixedrange: true + fixedrange: true, + automargin: true + }, + margin: { + t: 35, + b: 35 }, updatemenus: this.updatemenus, hovermode: 'x', + hoverlabel: { + namelength: 200 + }, showlegend: true, shapes: [], selectdirection: 'h', @@ -96,28 +121,20 @@ } ], direction: 'left', - pad: { 'r': 10, 't': 10 }, + pad: {'r': 10, 't': 10}, showactive: true, type: 'buttons', x: 0.0, xanchor: 'left', y: 1.3, yanchor: 'top', - font: { color: this.dataExplorerWidget.baseAppearanceConfig.textColor }, - bgcolor: this.dataExplorerWidget.baseAppearanceConfig.backgroundColor, + font: {color: this.dataExplorerWidget.baseAppearanceConfig.textColor}, + plot_bgcolor: this.dataExplorerWidget.baseAppearanceConfig.backgroundColor, + paper_bgcolor: this.dataExplorerWidget.baseAppearanceConfig.backgroundColor, bordercolor: '#000' }]; super.ngOnInit(); - this.resizeService.resizeSubject.subscribe(info => { - if (info.gridsterItem.id === this.gridsterItem.id) { - setTimeout(() => { - this.graph.layout.autosize = false; - (this.graph.layout as any).width = (info.gridsterItemComponent.width - this.offsetRightLineChart); - (this.graph.layout as any).height = (info.gridsterItemComponent.height - 80); - }, 100); - } - }); } transformData(data: SpQueryResult, @@ -157,7 +174,7 @@ Object.entries(group['tags']).forEach( ([key, val]) => { if (name in this.groupKeeper) { - if (this.groupKeeper[name].indexOf(val) === - 1) { + if (this.groupKeeper[name].indexOf(val) === -1) { this.groupKeeper[name].push(val); } } else { @@ -196,20 +213,6 @@ return Object.values(tmpLineChartTraces); } - lightenColor(color: string, percent: number) { - const num = parseInt(color.replace('#', ''), 16); - const amt = Math.round(2.55 * percent); - // tslint:disable-next-line:no-bitwise - const R = (num >> 16) + amt; - // tslint:disable-next-line:no-bitwise - const B = (num >> 8 & 0x00FF) + amt; - // tslint:disable-next-line:no-bitwise - const G = (num & 0x0000FF) + amt; - const result = '#' + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + - (B < 255 ? B < 1 ? 0 : B : 255) * 0x100 + (G < 255 ? G < 1 ? 0 : G : 255)).toString(16).slice(1); - return result; - } - setStartX(startX: string) { this.selectedStartX = startX; } @@ -234,12 +237,14 @@ spikedash: 'dash', spikecolor: '#666666', spikethickness: 2, + automargin: true, }; this.graph.layout.hovermode = 'x'; } else { this.graph.layout['xaxis'] = { type: 'date', + automargin: true, }; this.graph.layout.hovermode = ''; } @@ -276,7 +281,7 @@ index = pastGroups; if (this.data[index] !== undefined) { - this.data[index]['marker'] = { 'color': '' }; + this.data[index]['marker'] = {'color': ''}; if (!(name in this.dataExplorerWidget.visualizationConfig.chosenColor)) { this.dataExplorerWidget.visualizationConfig.chosenColor[name] = this.presetColors[index]; @@ -302,7 +307,7 @@ if (setType === 'bar') { visualizationOptions = barVisualizationOptions; } - if (setType === 'lines' || setType === 'lines+markers') { + if (setType === 'lines' || setType === 'lines+markers') { visualizationOptions = lineVisualizationOptions; } if (setType === 'symbol_markers') { @@ -320,7 +325,7 @@ if (visualizationTypePosition === (visualizationOptions.length - 1)) { dashType = visualizationOptions[0]; dashTypeKeeper[name] = dashType; - color = this.lightenColor(colorKeeper[name], 11.0); + color = ColorUtils.lightenColor(colorKeeper[name], 11.0); colorKeeper[name] = color; } else { dashType = visualizationOptions[visualizationTypePosition + 1]; @@ -344,16 +349,16 @@ if (setType === 'bar') { this.data[index].marker['pattern'] = { - 'shape' : dashType, - 'fillmode' : 'overlay', - 'fgcolor' : '#ffffff', - // 'size' : 3, + 'shape': dashType, + 'fillmode': 'overlay', + 'fgcolor': '#ffffff', + // 'size' : 3, }; } else { if (setType === 'lines' || setType === 'lines+markers') { this.data[index]['line'] = { - 'dash' : dashType, - 'width' : 3, + 'dash': dashType, + 'width': 3, }; } } @@ -391,10 +396,10 @@ if (setAxis === 'y2') { this.graph.layout['yaxis2'] = { - title: '', - overlaying: 'y', - side: 'right' - }; + title: '', + overlaying: 'y', + side: 'right' + }; } pastGroups += 1; @@ -409,9 +414,11 @@ } onResize(width: number, height: number) { - this.graph.layout.autosize = false; - (this.graph.layout as any).width = width; - (this.graph.layout as any).height = height; + setTimeout(() => { + this.graph.layout.autosize = false; + (this.graph.layout as any).width = width - this.offsetRightLineChart; + (this.graph.layout as any).height = height; + }, 10); } beforeDataFetched() { @@ -422,19 +429,19 @@ onDataReceived(spQueryResults: SpQueryResult[]) { this.data = []; - // this.setShownComponents(true, false, false, false); - this.groupKeeper = {}; + // this.setShownComponents(true, false, false, false); + this.groupKeeper = {}; - this.orderedSelectedProperties = []; + this.orderedSelectedProperties = []; - spQueryResults.map((spQueryResult, index) => { - const res = this.transformData(spQueryResult, spQueryResult.sourceIndex); - res.forEach(item => { - this.data = this.data.concat(item); - }); + spQueryResults.map((spQueryResult, index) => { + const res = this.transformData(spQueryResult, spQueryResult.sourceIndex); + res.forEach(item => { + this.data = this.data.concat(item); }); + }); - this.setShownComponents(false, true, false, false); + this.setShownComponents(false, true, false, false); }
diff --git a/ui/src/app/data-explorer/components/widgets/utils/aggregate-configuration/aggregate-configuration.component.ts b/ui/src/app/data-explorer/components/widgets/utils/aggregate-configuration/aggregate-configuration.component.ts index 918eec6..43fdf8c 100644 --- a/ui/src/app/data-explorer/components/widgets/utils/aggregate-configuration/aggregate-configuration.component.ts +++ b/ui/src/app/data-explorer/components/widgets/utils/aggregate-configuration/aggregate-configuration.component.ts
@@ -36,9 +36,7 @@ {value: 'm', label: 'Minute'}, {value: 'h', label: 'Hour'}, {value: 'd', label: 'Day'}, - {value: 'w', label: 'Week'}, - {value: 'month', label: 'Month'}, - {value: 'year', label: 'Year'} + {value: 'w', label: 'Week'} ]; constructor(private widgetConfigService: WidgetConfigurationService) {
diff --git a/ui/src/app/data-explorer/components/widgets/utils/color-utils.ts b/ui/src/app/data-explorer/components/widgets/utils/color-utils.ts new file mode 100644 index 0000000..30d39de --- /dev/null +++ b/ui/src/app/data-explorer/components/widgets/utils/color-utils.ts
@@ -0,0 +1,35 @@ +/* + * 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. + * + */ + +export class ColorUtils { + + static lightenColor(color: string, + percent: number): string { + const num = parseInt(color.replace('#', ''), 16); + const amt = Math.round(2.55 * percent); + // tslint:disable-next-line:no-bitwise + const R = (num >> 16) + amt; + // tslint:disable-next-line:no-bitwise + const B = (num >> 8 & 0x00FF) + amt; + // tslint:disable-next-line:no-bitwise + const G = (num & 0x0000FF) + amt; + const result = '#' + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + + (B < 255 ? B < 1 ? 0 : B : 255) * 0x100 + (G < 255 ? G < 1 ? 0 : G : 255)).toString(16).slice(1); + return result; + } +}
diff --git a/ui/src/app/data-explorer/components/widgets/utils/no-data/no-data-in-date-range.component.html b/ui/src/app/data-explorer/components/widgets/utils/no-data/no-data-in-date-range.component.html index c409e7e..6e31fd5 100644 --- a/ui/src/app/data-explorer/components/widgets/utils/no-data/no-data-in-date-range.component.html +++ b/ui/src/app/data-explorer/components/widgets/utils/no-data/no-data-in-date-range.component.html
@@ -16,12 +16,12 @@ ~ --> -<div fxLayout="column" fxLayoutAlign="space-around center" > +<div fxLayout="column" fxLayoutAlign="center center" fxFlex="100"> - <div fxLayout="row" fxLayoutAlign="center center" style="margin-top: 30px"> + <div fxLayout="row" fxLayoutAlign="center center"> <!-- TODO Icon --> </div> - <div fxLayout="column" fxLayoutAlign="center center" style="margin-top: 30px"> + <div fxLayout="column" fxLayoutAlign="center center" style="margin-top: 10px"> <div class="default-text">Found no data in selected time range</div> <div class="default-text date-range-text">{{viewDateRange.startTime | date:'MM/dd/yyyy HH:mm'}} - {{viewDateRange.endTime | date:'MM/dd/yyyy HH:mm'}}</div>
diff --git a/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.html b/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.html index d7f91c9..44b78a9 100644 --- a/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.html +++ b/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.html
@@ -38,7 +38,7 @@ [checked]="isSelected(field)" (change)="toggleFieldSelection(field)"> <b>{{field.runtimeName}}</b> - {{'(' + (field.aggregation ? field.aggregation + ', ' : '') + field.measure + ')'}} + {{'(' + (field.aggregation ? field.aggregation + ', ' : '') + field.measure + ' #' + (field.sourceIndex + 1).toString() + ')'}} </mat-checkbox> <div fxFlex fxLayoutAlign="end center"
diff --git a/ui/src/app/data-explorer/components/widgets/utils/select-property/select-property.component.html b/ui/src/app/data-explorer/components/widgets/utils/select-property/select-property.component.html index 05695f9..0d372b6 100644 --- a/ui/src/app/data-explorer/components/widgets/utils/select-property/select-property.component.html +++ b/ui/src/app/data-explorer/components/widgets/utils/select-property/select-property.component.html
@@ -21,7 +21,7 @@ <mat-select [ngModel]="selectedProperty" (selectionChange)="triggerSelectedProperty($event.value)" [compareWith]="compare"> <mat-option *ngFor="let column of availableProperties" [value]="column" style="background-color: #FFFFFF"> <b>{{column.runtimeName}}</b> - {{'(' +(column.aggregation ? column.aggregation + ', ': '') + column.measure +')'}} + {{'(' +(column.aggregation ? column.aggregation + ', ': '') + column.measure + ' #' + (column.sourceIndex + 1).toString() + ')'}} </mat-option> </mat-select> </mat-form-field>
diff --git a/ui/src/app/data-explorer/components/widgets/utils/too-much-data/too-much-data.component.html b/ui/src/app/data-explorer/components/widgets/utils/too-much-data/too-much-data.component.html index 9a9a43a..a30ba99 100644 --- a/ui/src/app/data-explorer/components/widgets/utils/too-much-data/too-much-data.component.html +++ b/ui/src/app/data-explorer/components/widgets/utils/too-much-data/too-much-data.component.html
@@ -15,13 +15,13 @@ ~ limitations under the License. ~ --> -<div fxLayout="column" fxLayoutAlign="space-around center" > +<div fxLayout="column" fxLayoutAlign="center center" fxFlex="100"> - <div fxLayout="row" fxLayoutAlign="center center" style="margin-top: 30px"> + <div fxLayout="row" fxLayoutAlign="center center"> <i class="material-icons" style="margin-top: 8px">warning</i> - <h2>Warning</h2> + <h2> Warning</h2> </div> - <div fxLayout="column" fxLayoutAlign="center center" style="margin-top: 30px"> + <div fxLayout="column" fxLayoutAlign="center center" style="margin-top: 10px"> <div class="default-text">This widget tries to load too much data (#Events: {{amountOfEvents}})</div> <div class="default-text date-range-text">Please change the widget settings or decrease the time range</div>
diff --git a/ui/src/app/data-explorer/data-explorer-panel.can-deactivate.guard.ts b/ui/src/app/data-explorer/data-explorer-panel.can-deactivate.guard.ts new file mode 100644 index 0000000..d998b07 --- /dev/null +++ b/ui/src/app/data-explorer/data-explorer-panel.can-deactivate.guard.ts
@@ -0,0 +1,35 @@ +/* + * 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 { DataExplorerDashboardPanelComponent } from './components/panel/data-explorer-dashboard-panel.component'; +import { ActivatedRouteSnapshot, CanDeactivate, RouterStateSnapshot } from '@angular/router'; +import { Observable } from 'rxjs'; + +@Injectable({providedIn: 'root'}) +export class DataExplorerPanelCanDeactivateGuard implements CanDeactivate<DataExplorerDashboardPanelComponent> { + + canDeactivate( + component: DataExplorerDashboardPanelComponent, + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): Observable<boolean> | boolean { + + return component.confirmLeaveDashboard(route, state); + } +}
diff --git a/ui/src/app/data-explorer/data-explorer.component.css b/ui/src/app/data-explorer/data-explorer.component.css deleted file mode 100644 index 4482be5..0000000 --- a/ui/src/app/data-explorer/data-explorer.component.css +++ /dev/null
@@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -.mr-20 { - margin-right:20px; -} - -.dashboard-panel { - height: 100%; - flex-direction: column; - box-sizing: border-box; - display: flex; - flex: 1 1 100%; - overflow-y: auto; -} - -.ribbon { - position: absolute; - right: 5px; top: 55px; - z-index: 1; - overflow: hidden; - width: 75px; height: 75px; - text-align: right; -} -.ribbon span { - font-weight: bold; - color: #FFF; - text-transform: uppercase; - text-align: center; - line-height: 20px; - transform: rotate(45deg); - -webkit-transform: rotate(45deg); - width: 100px; - display: block; - background: #f5b53f; - background: linear-gradient(#f5b53f 0%, #f5b53f 100%); - position: absolute; - top: 19px; right: -21px; -} -.ribbon span::before { - content: ""; - position: absolute; left: 0px; top: 100%; - z-index: -1; - border-left: 3px solid #f5b53f; - border-right: 3px solid transparent; - border-bottom: 3px solid transparent; - border-top: 3px solid #f5b53f; -} - -.ribbon span::after { - content: ""; - position: absolute; right: 0px; top: 100%; - z-index: -1; - border-left: 3px solid transparent; - border-right: 3px solid #f5b53f; - border-bottom: 3px solid transparent; - border-top: 3px solid #f5b53f; -} - -.fixed-height { - height: 50px; -} - -.data-explorer-options { - padding:0px; -} - -.data-explorer-options-item { - display: inline; - margin-right: 10px; -} - -.pl-10 { - padding-left: 10px; -}
diff --git a/ui/src/app/data-explorer/data-explorer.component.html b/ui/src/app/data-explorer/data-explorer.component.html deleted file mode 100644 index b4f8b0f..0000000 --- a/ui/src/app/data-explorer/data-explorer.component.html +++ /dev/null
@@ -1,86 +0,0 @@ -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one or more - ~ contributor license agreements. See the NOTICE file distributed with - ~ this work for additional information regarding copyright ownership. - ~ The ASF licenses this file to You under the Apache License, Version 2.0 - ~ (the "License"); you may not use this file except in compliance with - ~ the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - ~ - --> - -<div fxLayout="column" class="page-container"> - <div fxLayout="row" class="p-0 sp-bg-lightgray"> - <div fxFlex="100" class="page-container-nav"> - <div fxFlex="100" fxLayout="row"> - <div fxFlex fxLayoutAlign="start center"> - <mat-tab-group [selectedIndex]="selectedIndex" - (selectedIndexChange)="selectDashboardInTab($event)" - color="accent"> - <mat-tab data-cy="data-explorer-start-tab" - label="Start"></mat-tab> - <mat-tab *ngFor="let dataViewDashboard of dataViewDashboards" - label="{{dataViewDashboard.name}}"></mat-tab> - </mat-tab-group> - </div> - - <div fxFlex fxLayoutAlign="end center" *ngIf="selectedIndex > 0"> - <button mat-icon-button [matMenuTriggerFor]="menu" aria-label="Options" data-cy="options-data-explorer"> - <mat-icon>more_vert</mat-icon> - </button> - <mat-menu #menu="matMenu"> - <button mat-menu-item (click)="triggerEditMode()" - *ngIf="!editMode && hasDataExplorerWritePrivileges" - data-cy="options-edit-dashboard"> - <mat-icon>edit</mat-icon> - <span>Edit dashboard</span> - </button> - <button mat-menu-item (click)="getDashboards(selectedDataViewDashboard._id)"> - <mat-icon>refresh</mat-icon> - <span>Reload dashboard</span> - </button> - <button mat-menu-item (click)="timeRangeVisible = true" *ngIf="!editMode && !timeRangeVisible"> - <mat-icon>alarm_on</mat-icon> - <span>Show time range selector</span> - </button> - <button mat-menu-item (click)="timeRangeVisible = false" *ngIf="!editMode && timeRangeVisible"> - <mat-icon>alarm_off</mat-icon> - <span>Hide time range selector</span> - </button> - <button mat-menu-item *ngIf="hasDataExplorerDeletePrivileges" (click)="deleteDashboard(selectedDataViewDashboard)"> - <mat-icon>clear</mat-icon> - <span>Delete dashboard</span> - </button> - </mat-menu> - </div> - </div> - </div> - </div> - - - <div fxLayout="column" fxFlex="100" *ngIf="dashboardsLoaded"> - <sp-data-explorer-dashboard-overview (selectDashboardEmitter)="openDashboard($event)" - (reloadDashboardsEmitter)="getDashboards()" - [dataViewDashboards]="dataViewDashboards" - *ngIf="!dashboardTabSelected"> - - </sp-data-explorer-dashboard-overview> - <sp-data-explorer-dashboard-panel fxLayout="column" - #dashboardPanel - (resetDashboardChanges)="resetDashboardChanges()" - [(editMode)]="editMode" - [dashboard]="selectedDataViewDashboard" - [timeSettings]="selectedDataViewDashboard.dashboardTimeSettings" - [timeRangeVisible]="timeRangeVisible" - class="dashboard-panel" - *ngIf="dashboardTabSelected"> - </sp-data-explorer-dashboard-panel> - </div> -</div>
diff --git a/ui/src/app/data-explorer/data-explorer.component.ts b/ui/src/app/data-explorer/data-explorer.component.ts deleted file mode 100644 index 214e3db..0000000 --- a/ui/src/app/data-explorer/data-explorer.component.ts +++ /dev/null
@@ -1,148 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Component, OnInit, ViewChild } from '@angular/core'; -import { DataViewDataExplorerService, Dashboard } from '@streampipes/platform-services'; -import { RefreshDashboardService } from './services/refresh-dashboard.service'; -import { DataExplorerDashboardPanelComponent } from './components/panel/data-explorer-dashboard-panel.component'; -import { Tuple2 } from '../core-model/base/Tuple2'; -import { ActivatedRoute } from '@angular/router'; -import { AuthService } from '../services/auth.service'; -import { UserPrivilege } from '../_enums/user-privilege.enum'; - -@Component({ - selector: 'sp-data-explorer', - templateUrl: './data-explorer.component.html', - styleUrls: ['./data-explorer.component.css'] -}) -export class DataExplorerComponent implements OnInit { - - selectedDataViewDashboard: Dashboard; - selectedIndex = 0; - dashboardsLoaded = false; - dashboardTabSelected = false; - - timeRangeVisible = true; - - editMode = true; - dataViewDashboards: Dashboard[]; - - routeParams: any; - - hasDataExplorerWritePrivileges = false; - hasDataExplorerDeletePrivileges = false; - - @ViewChild('dashboardPanel') dashboardPanel: DataExplorerDashboardPanelComponent; - - constructor(private dataViewService: DataViewDataExplorerService, - private refreshDashboardService: RefreshDashboardService, - private route: ActivatedRoute, - private authService: AuthService, - private dashboardService: DataViewDataExplorerService) { - } - - - public ngOnInit() { - this.authService.user$.subscribe(user => { - this.hasDataExplorerWritePrivileges = this.authService.hasRole(UserPrivilege.PRIVILEGE_WRITE_DATA_EXPLORER_VIEW); - this.hasDataExplorerDeletePrivileges = this.authService.hasRole(UserPrivilege.PRIVILEGE_DELETE_DATA_EXPLORER_VIEW); - }); - this.route.queryParams.subscribe(params => { - this.routeParams = { startTime: params['startTime'], endTime: params['endTime'], dashboardId: params['dashboardId'] }; - this.getDashboards(); - }); - this.refreshDashboardService.refreshSubject.subscribe(currentDashboardId => { - this.getDashboards(currentDashboardId); - }); - - } - - openDashboard(dashboard: Tuple2<Dashboard, boolean>) { - const index = this.dataViewDashboards.indexOf(dashboard.a); - this.selectDashboard((index + 1), dashboard.b); - } - - selectDashboardInTab(index: number) { - if (index !== this.selectedIndex) { - this.selectDashboard(index); - } - } - - selectDashboard(index: number, editMode = false) { - this.selectedIndex = index; - this.editMode = editMode; - if (index === 0) { - this.dashboardTabSelected = false; - } else { - this.dashboardTabSelected = true; - this.applyTimeSettings(this.dataViewDashboards[(index - 1)]); - this.selectedDataViewDashboard = this.dataViewDashboards[(index - 1)]; - } - } - - applyTimeSettings(dashboard: Dashboard) { - if (this.routeParams.startTime && this.routeParams.endTime) { - dashboard.dashboardTimeSettings = { - startTime: this.routeParams.startTime * 1, - endTime: this.routeParams.endTime * 1, - dynamicSelection: -1 - }; - } else if (!dashboard.dashboardTimeSettings) { - const currentTime = new Date().getTime(); - dashboard.dashboardTimeSettings = { - startTime: currentTime - 100000 * 60000, - endTime: currentTime, - dynamicSelection: -1 - }; - } - } - - findAndSelectDashboard(dashboardId: string) { - const currentDashboard = this.dataViewDashboards.find(d => d._id === dashboardId); - this.selectDashboard(this.dataViewDashboards.indexOf(currentDashboard) + 1); - } - - getDashboards(currentDashboardId?: string) { - this.dashboardsLoaded = false; - this.dataViewService.getDataViews().subscribe(data => { - this.dataViewDashboards = data.sort((a, b) => a.name.localeCompare(b.name)); - if (currentDashboardId) { - this.findAndSelectDashboard(currentDashboardId); - } else if (this.routeParams.dashboardId) { - this.findAndSelectDashboard(this.routeParams.dashboardId); - } else { - this.selectedIndex = 0; - } - this.dashboardsLoaded = true; - }); - } - - triggerEditMode() { - this.editMode = true; - } - - deleteDashboard(dashboard: Dashboard) { - this.dashboardService.deleteDashboard(dashboard).subscribe(result => { - this.getDashboards(); - }); - } - - resetDashboardChanges() { - this.getDashboards(this.selectedDataViewDashboard._id); - } -}
diff --git a/ui/src/app/data-explorer/data-explorer.module.ts b/ui/src/app/data-explorer/data-explorer.module.ts index 79819b3..f0702a2 100644 --- a/ui/src/app/data-explorer/data-explorer.module.ts +++ b/ui/src/app/data-explorer/data-explorer.module.ts
@@ -50,8 +50,7 @@ } from '@streampipes/platform-services'; import { CoreUiModule } from '../core-ui/core-ui.module'; import { CustomMaterialModule } from '../CustomMaterial/custom-material.module'; -import { DataDownloadDialog } from './components/datadownloadDialog/dataDownload.dialog'; -import { DataExplorerDashboardGridComponent } from './components/grid/data-explorer-dashboard-grid.component'; +import { DataExplorerDashboardGridComponent } from './components/widget-view/grid-view/data-explorer-dashboard-grid.component'; import { DataExplorerDashboardOverviewComponent } from './components/overview/data-explorer-dashboard-overview.component'; import { DataExplorerDashboardPanelComponent } from './components/panel/data-explorer-dashboard-panel.component'; import { TimeRangeSelectorComponent } from './components/time-selector/timeRangeSelector.component'; @@ -64,7 +63,6 @@ import { NoDataInDateRangeComponent } from './components/widgets/utils/no-data/no-data-in-date-range.component'; import { SelectPropertiesComponent } from './components/widgets/utils/select-properties/select-properties.component'; import { SelectColorPropertiesComponent } from './components/widgets/utils/select-color-properties/select-color-properties.component'; -import { DataExplorerComponent } from './data-explorer.component'; import { DataExplorerEditDataViewDialogComponent } from './dialogs/edit-dashboard/data-explorer-edit-data-view-dialog.component'; import { RefreshDashboardService } from './services/refresh-dashboard.service'; import { ResizeService } from './services/resize.service'; @@ -100,6 +98,10 @@ import { NgxEchartsModule } from 'ngx-echarts'; import { TooMuchDataComponent } from './components/widgets/utils/too-much-data/too-much-data.component'; import { SpValueHeatmapComponent } from './components/widgets/distribution-chart/value-heatmap/value-heatmap.component'; +import { RouterModule } from '@angular/router'; +import { DataExplorerDashboardSlideViewComponent } from './components/widget-view/slide-view/data-explorer-dashboard-slide-view.component'; +import { SharedUiModule } from '@streampipes/shared-ui'; +import { DataExplorerPanelCanDeactivateGuard } from './data-explorer-panel.can-deactivate.guard'; export const MY_NATIVE_FORMATS = { fullPickerInput: { @@ -145,22 +147,39 @@ MatSlideToggleModule, MatChipsModule, PlatformServicesModule, + SharedUiModule, NgxEchartsModule.forRoot({ - /** - * This will import all modules from echarts. - * If you only need custom modules, - * please refer to [Custom Build] section. - */ echarts: () => import('echarts'), }), + RouterModule.forChild([ + { + path: 'dataexplorer', + children: [ + { + path: '', + component: DataExplorerDashboardOverviewComponent + }, + { + path: ':id', + component: DataExplorerDashboardPanelComponent, + canDeactivate: [DataExplorerPanelCanDeactivateGuard] + }, + { + path: ':id/:startTime/:endTime', + component: DataExplorerDashboardPanelComponent, + canDeactivate: [DataExplorerPanelCanDeactivateGuard] + } + ] + } + ]), + ], declarations: [ AggregateConfigurationComponent, - DataDownloadDialog, - DataExplorerComponent, DataExplorerDashboardGridComponent, DataExplorerDashboardOverviewComponent, DataExplorerDashboardPanelComponent, + DataExplorerDashboardSlideViewComponent, DataExplorerDashboardWidgetComponent, DataExplorerDesignerPanelComponent, DataExplorerEditDataViewDialogComponent, @@ -216,7 +235,6 @@ } ], exports: [ - DataExplorerComponent ] }) export class DataExplorerModule {
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.scss b/ui/src/app/data-explorer/data-explorer.routes.ts similarity index 81% copy from ui/src/app/pipeline-details/pipeline-details.component.scss copy to ui/src/app/data-explorer/data-explorer.routes.ts index a375af7..7c3df23 100644 --- a/ui/src/app/pipeline-details/pipeline-details.component.scss +++ b/ui/src/app/data-explorer/data-explorer.routes.ts
@@ -16,7 +16,10 @@ * */ -.md-padding { - padding: 10px; -} +import { SpBreadcrumbItem, } from '@streampipes/shared-ui'; +export class SpDataExplorerRoutes { + + static BASE: SpBreadcrumbItem = {label: 'Data Views', link: ['dataexplorer']}; + +}
diff --git a/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-data-view-dialog.component.html b/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-data-view-dialog.component.html index 20a5501..d64581e 100644 --- a/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-data-view-dialog.component.html +++ b/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-data-view-dialog.component.html
@@ -30,6 +30,16 @@ <mat-label>Description</mat-label> <input matInput [(ngModel)]="dashboard.description"> </mat-form-field> + <label>Default view mode</label> + <mat-radio-group + [(ngModel)]="dashboard.dashboardGeneralSettings.defaultViewMode"> + <mat-radio-button class="view-radio-button" [value]="'grid'"> + Grid View + </mat-radio-button> + <mat-radio-button class="view-radio-button" [value]="'slide'"> + Slide View + </mat-radio-button> + </mat-radio-group> <!--<mat-checkbox [(ngModel)]="dashboard.displayHeader">Show name and description in dashboard</mat-checkbox>--> </div>
diff --git a/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-data-view-dialog.component.scss b/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-data-view-dialog.component.scss index 2c22a1c..ff0c283 100644 --- a/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-data-view-dialog.component.scss +++ b/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-data-view-dialog.component.scss
@@ -30,3 +30,14 @@ .mr-10 { margin-right: 10px; } + +.view-radio-group { + display: flex; + flex-direction: column; + margin: 15px 0; + align-items: flex-start; +} + +.view-radio-button { + margin: 5px; +}
diff --git a/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-data-view-dialog.component.ts b/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-data-view-dialog.component.ts index 1af1ab8..8d5a3fc 100644 --- a/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-data-view-dialog.component.ts +++ b/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-data-view-dialog.component.ts
@@ -36,7 +36,9 @@ } ngOnInit() { - + if (!this.dashboard.dashboardGeneralSettings.defaultViewMode) { + this.dashboard.dashboardGeneralSettings.defaultViewMode = 'grid'; + } } onCancel(): void {
diff --git a/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.ts b/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.ts index 3be8ef4..edf8e0d 100644 --- a/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.ts +++ b/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.ts
@@ -34,7 +34,7 @@ import { ShepherdService } from '../../../services/tour/shepherd.service'; import { PipelineElementConfig, PipelineElementUnion } from '../../model/editor.model'; import { ObjectProvider } from '../../services/object-provider.service'; -import { DialogService, PanelType, ConfirmDialogComponent } from '@streampipes/shared-ui'; +import { ConfirmDialogComponent, DialogService, PanelType, SpBreadcrumbService } from '@streampipes/shared-ui'; import { SavePipelineComponent } from '../../dialog/save-pipeline/save-pipeline.component'; import { MatDialog } from '@angular/material/dialog'; import { EditorService } from '../../services/editor.service'; @@ -45,6 +45,8 @@ import { PipelineComponent } from '../pipeline/pipeline.component'; import { forkJoin } from 'rxjs'; import { PipelineElementDiscoveryComponent } from '../../dialog/pipeline-element-discovery/pipeline-element-discovery.component'; +import { SpPipelineRoutes } from '../../../pipelines/pipelines.routes'; +import { Router } from '@angular/router'; @Component({ @@ -106,7 +108,9 @@ private dialog: MatDialog, private ngZone: NgZone, private pipelineElementDraggedService: PipelineElementDraggedService, - private pipelineCanvasMetadataService: PipelineCanvasMetadataService) { + private pipelineCanvasMetadataService: PipelineCanvasMetadataService, + private breadcrumbService: SpBreadcrumbService, + private router: Router) { this.selectMode = true; this.currentZoomLevel = 1; @@ -249,6 +253,7 @@ pipelineRequest.subscribe(pipelineResp => { const pipeline = pipelineResp; this.currentPipelineName = pipeline.name; + this.breadcrumbService.updateBreadcrumb([SpPipelineRoutes.BASE, {label: pipeline.name}, {label: 'Modify'}]); this.currentPipelineDescription = pipeline.description; this.rawPipelineModel = this.jsplumbService.makeRawPipeline(pipeline, false); canvasRequest.subscribe(canvasResp => {
diff --git a/ui/src/app/editor/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.scss b/ui/src/app/editor/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.scss index 8ede964..be1bab1 100644 --- a/ui/src/app/editor/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.scss +++ b/ui/src/app/editor/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.scss
@@ -25,7 +25,7 @@ } .icon-stand { - max-height: calc(100vh - 118px); + max-height: calc(100vh - 148px); overflow-y: auto; background: var(--color-bg-1); margin-top: 5px; @@ -110,6 +110,7 @@ border-radius: 3px; font-size: small; background: var(--color-primary); + color: var(--color-accent); } .sort-option {
diff --git a/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.html b/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.html deleted file mode 100644 index 97cd141..0000000 --- a/ui/src/app/editor/components/pipeline-element-template-config/pipeline-element-template-config.component.html +++ /dev/null
@@ -1,60 +0,0 @@ -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one or more - ~ contributor license agreements. See the NOTICE file distributed with - ~ this work for additional information regarding copyright ownership. - ~ The ASF licenses this file to You under the Apache License, Version 2.0 - ~ (the "License"); you may not use this file except in compliance with - ~ the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - ~ - --> - -<div class="p-15"> - <div fxFlex="100" fxLayout="column"> - <h4>Basics</h4> - <mat-form-field fxFlex> - <mat-label>Template name</mat-label> - <input [(ngModel)]="template.templateName" matInput name="templateName" class="sp" required/> - </mat-form-field> - <mat-form-field fxFlex> - <mat-label>Template description</mat-label> - <input [(ngModel)]="template.templateDescription" matInput name="templateDescription" class="sp" - required/> - </mat-form-field> - <mat-checkbox class="sp" color="primary">Make available as pipeline element</mat-checkbox> - <mat-divider class="divider"></mat-divider> - <h4>Configuration</h4> - <div fxLayout="column" *ngFor="let config of cachedPipelineElement.staticProperties" - class="static-property-panel static-property-panel-border"> - <div fxLayout="row"> - <div fxFlex="50"> - {{config.label}} - </div> - <div fxFlex="50"> - <div fxLayout="column"> - <mat-checkbox [checked]="templateConfigs.has(config.internalName)" - (change)="handleSelection(config)" name="store" class="sp" color="primary">Store - as template - </mat-checkbox> -<!-- <mat-checkbox *ngIf="templateConfigs.has(config.internalName)"--> -<!-- (click)="toggleViewPermission(config)" name="displayed"--> -<!-- class="sp" color="primary">Users can view--> -<!-- </mat-checkbox>--> -<!-- <mat-checkbox *ngIf="templateConfigs.has(config.internalName)"--> -<!-- (click)="toggleEditPermission(config)" name="editable"--> -<!-- class="sp" color="primary">Users can modify--> -<!-- </mat-checkbox>--> - </div> - </div> - </div> - - </div> - </div> -</div>
diff --git a/ui/src/app/editor/components/pipeline/pipeline.component.ts b/ui/src/app/editor/components/pipeline/pipeline.component.ts index bcc2690..719eefa 100644 --- a/ui/src/app/editor/components/pipeline/pipeline.component.ts +++ b/ui/src/app/editor/components/pipeline/pipeline.component.ts
@@ -338,8 +338,9 @@ this.showCustomizeDialog(pe); } else { (pe.payload as InvocablePipelineElementUnion).configured = true; - this.pipelineStyleService.updatePeConfigurationStatus(pe, PipelineElementConfigurationStatus.INCOMPLETE); + this.pipelineStyleService.updatePeConfigurationStatus(pe, PipelineElementConfigurationStatus.OK); this.announceConfiguredElement(pe); + this.triggerPipelineCacheUpdate(); } } } else { @@ -408,11 +409,13 @@ isCustomOutput(pe) { let custom = false; - pe.payload.outputStrategies.forEach(strategy => { - if (strategy instanceof CustomOutputStrategy) { - custom = true; - } - }); + if (pe.payload instanceof DataProcessorInvocation) { + pe.payload.outputStrategies.forEach(strategy => { + if (strategy instanceof CustomOutputStrategy) { + custom = true; + } + }); + } return custom; }
diff --git a/ui/src/app/editor/dialog/customize/customize.component.html b/ui/src/app/editor/dialog/customize/customize.component.html index 78c8589..9e5e04f 100644 --- a/ui/src/app/editor/dialog/customize/customize.component.html +++ b/ui/src/app/editor/dialog/customize/customize.component.html
@@ -21,9 +21,10 @@ <div fxFlex="100" fxLayout="column"> <div style="border-bottom:1px solid #ccc;padding:10px;" fxLayout="row" class="sp-tab-bg"> <div fxFlex fxLayoutAlign="start center" *ngIf="availableTemplates && availableTemplates.length > 0"> - <mat-form-field class="form-field" floatLabel="never"> + <mat-form-field class="form-field" floatLabel="never" color="accent"> <mat-label>Use template</mat-label> - <mat-select (selectionChange)="loadTemplate($event)" [(value)]="selectedTemplate"> + <mat-select (selectionChange)="loadTemplate($event)" + [(value)]="selectedTemplate"> <mat-option>--</mat-option> <mat-option [value]="template" *ngFor="let template of availableTemplates"> {{template.templateName}} @@ -72,8 +73,8 @@ </div> </div> <div fxLayout="column" *ngIf="templateMode"> - <pipeline-element-template-config [cachedPipelineElement]="cachedPipelineElement" - [template]="template" [templateConfigs]="templateConfigs"> + <pipeline-element-template-config [staticProperties]="cachedPipelineElement.staticProperties" + [template]="template" [templateConfigs]="templateConfigs" [appId]="cachedPipelineElement.appId"> </pipeline-element-template-config> </div> </div>
diff --git a/ui/src/app/editor/dialog/customize/customize.component.ts b/ui/src/app/editor/dialog/customize/customize.component.ts index 1dfd772..f042ccf 100644 --- a/ui/src/app/editor/dialog/customize/customize.component.ts +++ b/ui/src/app/editor/dialog/customize/customize.component.ts
@@ -205,9 +205,6 @@ this.cachedPipelineElement = pe as InvocablePipelineElementUnion; }); } - } } - - }
diff --git a/ui/src/app/editor/editor.component.ts b/ui/src/app/editor/editor.component.ts index 76caa68..d4cf227 100644 --- a/ui/src/app/editor/editor.component.ts +++ b/ui/src/app/editor/editor.component.ts
@@ -20,7 +20,7 @@ import { EditorService } from './services/editor.service'; import { DataSourceDescription, PipelineElementService, SpDataStream } from '@streampipes/platform-services'; import { PipelineElementConfig, PipelineElementUnion } from './model/editor.model'; -import { PanelType, DialogService } from '@streampipes/shared-ui'; +import { DialogService, PanelType, SpBreadcrumbService } from '@streampipes/shared-ui'; import { WelcomeTourComponent } from './dialog/welcome-tour/welcome-tour.component'; import { MissingElementsForTutorialComponent } from './dialog/missing-elements-for-tutorial/missing-elements-for-tutorial.component'; import { ShepherdService } from '../services/tour/shepherd.service'; @@ -28,6 +28,7 @@ import { AuthService } from '../services/auth.service'; import { zip } from 'rxjs'; import { AppConstants } from '../services/app.constants'; +import { SpPipelineRoutes } from '../pipelines/pipelines.routes'; @Component({ selector: 'editor', @@ -56,13 +57,16 @@ private dialogService: DialogService, private shepherdService: ShepherdService, private activatedRoute: ActivatedRoute, - private appConstants: AppConstants) { + private appConstants: AppConstants, + private breadcrumbService: SpBreadcrumbService) { } ngOnInit() { - this.activatedRoute.queryParams.subscribe(params => { - if (params['pipeline']) { - this.currentModifiedPipelineId = params['pipeline']; + this.activatedRoute.params.subscribe(params => { + if (params.pipelineId) { + this.currentModifiedPipelineId = params.pipelineId; + } else { + this.breadcrumbService.updateBreadcrumb([SpPipelineRoutes.BASE, {label: 'New Pipeline'}]); } }); zip(this.pipelineElementService.getDataStreams(),
diff --git a/ui/src/app/editor/editor.module.ts b/ui/src/app/editor/editor.module.ts index 266b0fd..284ce1f 100644 --- a/ui/src/app/editor/editor.module.ts +++ b/ui/src/app/editor/editor.module.ts
@@ -29,13 +29,8 @@ import { PipelineElementIconStandComponent } from './components/pipeline-element-icon-stand/pipeline-element-icon-stand.component'; import { PipelineAssemblyComponent } from './components/pipeline-assembly/pipeline-assembly.component'; import { PipelineElementComponent } from './components/pipeline-element/pipeline-element.component'; -import { PipelinePositioningService } from './services/pipeline-positioning.service'; -import { JsplumbService } from './services/jsplumb.service'; -import { JsplumbConfigService } from './services/jsplumb-config.service'; import { PipelineEditorService } from './services/pipeline-editor.service'; -import { PipelineValidationService } from './services/pipeline-validation.service'; import { PipelineComponent } from './components/pipeline/pipeline.component'; -import { ObjectProvider } from './services/object-provider.service'; import { PipelineElementOptionsComponent } from './components/pipeline-element-options/pipeline-element-options.component'; import { PipelineElementRecommendationService } from './services/pipeline-element-recommendation.service'; import { CustomizeComponent } from './dialog/customize/customize.component'; @@ -57,20 +52,16 @@ import { PropertySelectionComponent } from './components/output-strategy/property-selection/property-selection.component'; import { UserDefinedOutputStrategyComponent } from './components/output-strategy/user-defined-output/user-defined-output.component'; import { ConnectModule } from '../connect/connect.module'; -import { PipelineElementTemplateConfigComponent } from './components/pipeline-element-template-config/pipeline-element-template-config.component'; import { EnabledPipelineElementFilter } from './filter/enabled-pipeline-element.filter'; import { PipelineElementDraggedService } from './services/pipeline-element-dragged.service'; import { PipelineCanvasScrollingService } from './services/pipeline-canvas-scrolling.service'; -import { JsplumbEndpointService } from './services/jsplumb-endpoint.service'; -import { JsplumbFactoryService } from './services/jsplumb-factory.service'; import { PipelineElementPreviewComponent } from './components/pipeline-element-preview/pipeline-element-preview.component'; import { PipelineElementDiscoveryComponent } from './dialog/pipeline-element-discovery/pipeline-element-discovery.component'; -import { PipelineStyleService } from './services/pipeline-style.service'; import { PlatformServicesModule } from '@streampipes/platform-services'; import { PipelineElementIconStandRowComponent } from './components/pipeline-element-icon-stand-row/pipeline-element-icon-stand-row.component'; import { PipelineElementTypeFilterPipe } from './services/pipeline-element-type-filter.pipe'; -import { PipelineElementNameFilterPipe } from "./services/pipeline-element-name-filter.pipe"; -import { PipelineElementGroupFilterPipe } from "./services/pipeline-element-group-filter.pipe"; +import { PipelineElementNameFilterPipe } from './services/pipeline-element-name-filter.pipe'; +import { PipelineElementGroupFilterPipe } from './services/pipeline-element-group-filter.pipe'; @NgModule({ @@ -113,7 +104,6 @@ PipelineElementOptionsComponent, PipelineElementPreviewComponent, PipelineElementRecommendationComponent, - PipelineElementTemplateConfigComponent, PipelineElementTypeFilterPipe, PipelineComponent, PropertySelectionComponent, @@ -122,20 +112,7 @@ WelcomeTourComponent ], providers: [ - EditorService, SemanticTypeUtilsService, - JsplumbFactoryService, - JsplumbEndpointService, - JsplumbService, - JsplumbConfigService, - ObjectProvider, - PipelineCanvasScrollingService, - PipelineElementDraggedService, - PipelineEditorService, - PipelinePositioningService, - PipelineStyleService, - PipelineValidationService, - PipelineElementRecommendationService, SafeCss, ], exports: [
diff --git a/ui/src/app/editor/services/editor.service.ts b/ui/src/app/editor/services/editor.service.ts index fcde9ad..99c19e3 100644 --- a/ui/src/app/editor/services/editor.service.ts +++ b/ui/src/app/editor/services/editor.service.ts
@@ -37,7 +37,7 @@ import { HelpComponent } from '../dialog/help/help.component'; import { map } from 'rxjs/operators'; -@Injectable() +@Injectable({providedIn: 'root'}) export class EditorService { private pipelineElementConfigured = new Subject<string>();
diff --git a/ui/src/app/editor/services/jsplumb-config.service.ts b/ui/src/app/editor/services/jsplumb-config.service.ts index f43742b..76d0f38 100644 --- a/ui/src/app/editor/services/jsplumb-config.service.ts +++ b/ui/src/app/editor/services/jsplumb-config.service.ts
@@ -22,7 +22,7 @@ import { EndpointTypeDescriptor } from '@jsplumb/core'; import { ArrowOverlayOptions } from '@jsplumb/common'; -@Injectable() +@Injectable({providedIn: 'root'}) export class JsplumbConfigService { constructor() {
diff --git a/ui/src/app/editor/services/jsplumb-endpoint.service.ts b/ui/src/app/editor/services/jsplumb-endpoint.service.ts index fc554e4..e9786dd 100644 --- a/ui/src/app/editor/services/jsplumb-endpoint.service.ts +++ b/ui/src/app/editor/services/jsplumb-endpoint.service.ts
@@ -19,7 +19,7 @@ import { Injectable } from '@angular/core'; import { JsplumbConfigService } from './jsplumb-config.service'; -@Injectable() +@Injectable({providedIn: 'root'}) export class JsplumbEndpointService { constructor(private jsplumbConfigService: JsplumbConfigService) {
diff --git a/ui/src/app/editor/services/jsplumb-factory.service.ts b/ui/src/app/editor/services/jsplumb-factory.service.ts index a0f98c9..a895e72 100644 --- a/ui/src/app/editor/services/jsplumb-factory.service.ts +++ b/ui/src/app/editor/services/jsplumb-factory.service.ts
@@ -23,7 +23,7 @@ import { PipelineElementDraggedService } from './pipeline-element-dragged.service'; import { JsplumbConfigService } from './jsplumb-config.service'; -@Injectable() +@Injectable({providedIn: 'root'}) export class JsplumbFactoryService { pipelineEditorInstance: BrowserJsPlumbInstance;
diff --git a/ui/src/app/editor/services/jsplumb.service.ts b/ui/src/app/editor/services/jsplumb.service.ts index efb4390..127d608 100644 --- a/ui/src/app/editor/services/jsplumb.service.ts +++ b/ui/src/app/editor/services/jsplumb.service.ts
@@ -38,7 +38,7 @@ import { JsplumbFactoryService } from './jsplumb-factory.service'; import { EditorService } from './editor.service'; -@Injectable() +@Injectable({providedIn: 'root'}) export class JsplumbService { idCounter = 0; @@ -98,7 +98,8 @@ pipelineElementConfig.payload, true, false); - }, 100); + this.getBridge(false).repaintEverything(); + }, 10); } }
diff --git a/ui/src/app/editor/services/object-provider.service.ts b/ui/src/app/editor/services/object-provider.service.ts index 9a60865..95375ed 100644 --- a/ui/src/app/editor/services/object-provider.service.ts +++ b/ui/src/app/editor/services/object-provider.service.ts
@@ -23,7 +23,7 @@ import { EditorService } from './editor.service'; import { JsplumbFactoryService } from './jsplumb-factory.service'; -@Injectable() +@Injectable({providedIn: 'root'}) export class ObjectProvider { constructor(private restApi: RestApi,
diff --git a/ui/src/app/editor/services/pipeline-canvas-scrolling.service.ts b/ui/src/app/editor/services/pipeline-canvas-scrolling.service.ts index 5be904d..764b1f7 100644 --- a/ui/src/app/editor/services/pipeline-canvas-scrolling.service.ts +++ b/ui/src/app/editor/services/pipeline-canvas-scrolling.service.ts
@@ -19,7 +19,7 @@ import { Injectable } from '@angular/core'; import { Subject } from 'rxjs'; -@Injectable() +@Injectable({providedIn: 'root'}) export class PipelineCanvasScrollingService { public canvasScrollXSubject: Subject<number> = new Subject<number>();
diff --git a/ui/src/app/editor/services/pipeline-editor.service.ts b/ui/src/app/editor/services/pipeline-editor.service.ts index 1057188..2e3dfeb 100644 --- a/ui/src/app/editor/services/pipeline-editor.service.ts +++ b/ui/src/app/editor/services/pipeline-editor.service.ts
@@ -18,7 +18,7 @@ import { Injectable } from '@angular/core'; -@Injectable() +@Injectable({providedIn: 'root'}) export class PipelineEditorService { constructor() {
diff --git a/ui/src/app/editor/services/pipeline-element-dragged.service.ts b/ui/src/app/editor/services/pipeline-element-dragged.service.ts index 16ae51e..c5c2bc5 100644 --- a/ui/src/app/editor/services/pipeline-element-dragged.service.ts +++ b/ui/src/app/editor/services/pipeline-element-dragged.service.ts
@@ -20,7 +20,7 @@ import { Subject } from 'rxjs'; import { PipelineElementPosition } from '../model/editor.model'; -@Injectable() +@Injectable({providedIn: 'root'}) export class PipelineElementDraggedService { public pipelineElementMovedSubject: Subject<PipelineElementPosition> = new Subject<PipelineElementPosition>();
diff --git a/ui/src/app/editor/services/pipeline-element-recommendation.service.ts b/ui/src/app/editor/services/pipeline-element-recommendation.service.ts index 129c159..ae676f9 100644 --- a/ui/src/app/editor/services/pipeline-element-recommendation.service.ts +++ b/ui/src/app/editor/services/pipeline-element-recommendation.service.ts
@@ -24,7 +24,7 @@ SpDataStream } from '@streampipes/platform-services'; -@Injectable() +@Injectable({providedIn: 'root'}) export class PipelineElementRecommendationService { constructor() {
diff --git a/ui/src/app/editor/services/pipeline-positioning.service.ts b/ui/src/app/editor/services/pipeline-positioning.service.ts index 2293d0b..1f8b281 100644 --- a/ui/src/app/editor/services/pipeline-positioning.service.ts +++ b/ui/src/app/editor/services/pipeline-positioning.service.ts
@@ -33,7 +33,7 @@ import { ObjectProvider } from './object-provider.service'; import { Connection } from '@jsplumb/core'; -@Injectable() +@Injectable({providedIn: 'root'}) export class PipelinePositioningService { constructor(private jsplumbService: JsplumbService,
diff --git a/ui/src/app/editor/services/pipeline-style.service.ts b/ui/src/app/editor/services/pipeline-style.service.ts index 42a14f3..9d6dabe 100644 --- a/ui/src/app/editor/services/pipeline-style.service.ts +++ b/ui/src/app/editor/services/pipeline-style.service.ts
@@ -23,7 +23,7 @@ import { JsplumbFactoryService } from './jsplumb-factory.service'; import { PipelineElementConfig, PipelineElementConfigurationStatus } from '../model/editor.model'; -@Injectable() +@Injectable({providedIn: 'root'}) export class PipelineStyleService { constructor(private jsPlumbConfigService: JsplumbConfigService,
diff --git a/ui/src/app/editor/services/pipeline-validation.service.ts b/ui/src/app/editor/services/pipeline-validation.service.ts index 779b83e..e3607fa 100644 --- a/ui/src/app/editor/services/pipeline-validation.service.ts +++ b/ui/src/app/editor/services/pipeline-validation.service.ts
@@ -25,7 +25,7 @@ import { UserErrorMessage } from '../../core-model/base/UserErrorMessage'; import { Connection } from '@jsplumb/core'; -@Injectable() +@Injectable({providedIn: 'root'}) export class PipelineValidationService { errorMessages: any = [];
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 index ea985b3..051d7b9 100644 --- a/ui/src/app/files/components/file-overview/file-overview.component.html +++ b/ui/src/app/files/components/file-overview/file-overview.component.html
@@ -16,45 +16,48 @@ ~ --> -<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> +<div fxFlex="100" fxLayout="column" style="margin:1px;"> + <div fxLayout="column" fxFlex="100" *ngIf="filesAvailable"> + <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"> - <button color="accent" mat-button mat-icon-button matTooltip="Delete file" matTooltipPosition="above" + <ng-container matColumnDef="action"> + <th mat-header-cell *matHeaderCellDef> Action</th> + <td mat-cell *matCellDef="let fileMetadata"> + <button color="accent" mat-button mat-icon-button matTooltip="Delete file" + matTooltipPosition="above" (click)="deleteFile(fileMetadata)" data-cy="delete"> <i class="material-icons">delete</i> </button> - </td> - </ng-container> + </td> + </ng-container> - <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> - <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> + <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> + </table> + <div fxFlex="100" fxLayoutAlign="end end"> + <mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" [pageSize]="10"></mat-paginator> + </div> </div> -</div> -<div fxFlex="100" fxLayout="column" fxLayoutAlign="center center" *ngIf="!filesAvailable"> - <h5>(no files available)</h5> + <div fxFlex="100" fxLayout="column" fxLayoutAlign="center center" *ngIf="!filesAvailable"> + <h5>(no files available)</h5> + </div> </div>
diff --git a/ui/src/app/files/components/file-overview/file-overview.component.scss b/ui/src/app/files/components/file-overview/file-overview.component.scss index e37a83c..a1b1300 100644 --- a/ui/src/app/files/components/file-overview/file-overview.component.scss +++ b/ui/src/app/files/components/file-overview/file-overview.component.scss
@@ -26,10 +26,10 @@ } .mat-row:nth-child(even) { - background-color: var(--color-bg-2); + background-color: var(--color-bg-1); } .mat-row:nth-child(odd) { - background-color: var(--color-bg-3); + background-color: var(--color-bg-2); } .filetype-container {
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 index 35f87a0..dda5d58 100644 --- a/ui/src/app/files/components/file-overview/file-overview.component.ts +++ b/ui/src/app/files/components/file-overview/file-overview.component.ts
@@ -35,7 +35,7 @@ dataSource: MatTableDataSource<FileMetadata>; filesAvailable = false; - @ViewChild(MatPaginator) paginator: MatPaginator; + paginator: MatPaginator; pageSize = 1; constructor(private filesService: FilesService, @@ -44,13 +44,14 @@ } ngOnInit() { + this.dataSource = new MatTableDataSource<FileMetadata>([]); this.refreshFiles(); } refreshFiles() { this.filesService.getFileMetadata().subscribe(fm => { - this.dataSource = new MatTableDataSource<FileMetadata>(fm); - this.filesAvailable = true; + this.dataSource.data = fm; + this.filesAvailable = fm && fm.length > 0; setTimeout(() => { this.dataSource.paginator = this.paginator; }); @@ -77,4 +78,8 @@ } }); } + + @ViewChild(MatPaginator) set content(paginator: MatPaginator) { + this.paginator = paginator; + } }
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 index f5961a6..ed88a66 100644 --- 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
@@ -22,12 +22,12 @@ <div fxFlex="100"> <div fxFlex="100" style="margin:5px;width:100%"> <mat-form-field style="width: 95%" (click)="fileInput.click();" color="accent"> - <input matInput placeholder="File" disabled (value)="fileName"> + <input matInput placeholder="File" disabled (value)="fileNames"> <input #fileInput type="file" style="display:none;" (change)="handleFileInput($event.target.files)" - data-cy="sp-file-management-file-input"> + data-cy="sp-file-management-file-input" multiple> <div> - {{fileName}} + <div fxLayout="column" *ngFor="let filename of fileNames">{{filename}}</div> <mat-progress-bar mode="determinate" value="{{uploadStatus}}" *ngIf="uploadStatus > 0" color="accent"></mat-progress-bar> </div> <button color="accent" matSuffix @@ -39,13 +39,20 @@ {{errorMessage}} </mat-error> </mat-form-field> + <button mat-button mat-raised-button class="mat-basic" (click)="removeFilesFromUpload()">Clear</button> </div> </div> </div> <mat-divider></mat-divider> <div class="sp-dialog-actions"> - <button mat-button mat-raised-button color="accent" (click)="store()" data-cy="sp-file-management-store-file" style="margin-right:10px;"> - Store file + <button mat-button + mat-raised-button + color="accent" + (click)="store()" + [disabled]="fileNames.length === 0" + data-cy="sp-file-management-store-file" + style="margin-right:10px;"> + Import files </button> <button mat-button mat-raised-button class="mat-basic" (click)="cancel()" style="margin-right:10px;"> Cancel
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 index d3a9e42..0df31b1 100644 --- 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
@@ -29,9 +29,9 @@ export class FileUploadDialogComponent implements OnInit { inputValue: string; - fileName: string; + fileNames: string[] = []; - selectedUploadFile: File; + selectedUploadFiles: FileList; hasInput: boolean; errorMessage = 'Please enter a value'; @@ -46,29 +46,45 @@ ngOnInit(): void { } - handleFileInput(files: any) { - this.selectedUploadFile = files[0]; - this.fileName = this.selectedUploadFile.name; + handleFileInput(files: FileList) { + this.selectedUploadFiles = files; + for (let i = 0; i < files.length; i++) { + this.fileNames.push(files.item(i).name); + } this.uploadStatus = 0; } + removeFilesFromUpload(): void { + this.selectedUploadFiles = undefined; + this.fileNames = []; + } + 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 => { - }, - ); + if (this.selectedUploadFiles.length > 0) { + this.uploadFile(0); } } + uploadFile(index: number): void { + this.filesService.uploadFile(this.selectedUploadFiles.item(index)).subscribe( + event => { + if (event.type === HttpEventType.UploadProgress) { + this.uploadStatus = Math.round(100 * event.loaded / event.total); + } else if (event instanceof HttpResponse) { + index++; + if (index === (this.selectedUploadFiles.length)) { + this.dialogRef.close(); + } else { + this.uploadFile(index); + } + } + }, + error => { + }, + ); + } + cancel() { this.dialogRef.close(); }
diff --git a/ui/src/app/files/files.component.html b/ui/src/app/files/files.component.html index 52264e7..10e701f 100644 --- a/ui/src/app/files/files.component.html +++ b/ui/src/app/files/files.component.html
@@ -16,40 +16,25 @@ ~ --> -<div fxLayout="column" class="page-container"> - <div fxLayout="row" style="padding:0;" class="sp-tab-bg"> - <div fxFlex="100" class="page-container-nav"> - <div fxFlex="100" fxLayout="row"> - <div fxFlex fxLayoutAlign="start center"> - <mat-tab-group color="accent"> - <mat-tab label="Files"></mat-tab> - </mat-tab-group> - </div> - </div> - </div> +<sp-basic-view [showBackLink]="false" [padding]="true"> + + <div nav fxFlex="100" fxLayoutAlign="start center" fxLayout="row" class="pl-10"> + <button mat-button mat-raised-button color="accent" + (click)="openFileUploadDialog()" + data-cy="sp-open-file-upload-dialog" + class="mr-10"> + <i class="material-icons">cloud_upload</i> + Upload new file + </button> </div> - <div fxLayout="row" class="fixed-height add-options sp-tab-bg"> - <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="accent" - (click)="openFileUploadDialog()" - data-cy="sp-open-file-upload-dialog" - class="mr-10"> - <i class="material-icons">cloud_upload</i> - Upload new file - </button> - </div> + + <div fxFlex="100" fxLayout="column"> + <sp-basic-header-title-component title="My Files"></sp-basic-header-title-component> + <div fxFlex="100" fxLayout="row" fxLayoutAlign="center start"> + <sp-basic-inner-panel [showTitle]="false" innerPadding="0" outerMargin="0" fxFlex="90" [hideToolbar]="true"> + <sp-file-overview #fileOverviewComponent></sp-file-overview> + </sp-basic-inner-panel> </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"> - <sp-file-overview #fileOverviewComponent></sp-file-overview> - </div> - </div> -</div> +</sp-basic-view>
diff --git a/ui/src/app/files/files.component.ts b/ui/src/app/files/files.component.ts index bee4a33..4c5afe0 100644 --- a/ui/src/app/files/files.component.ts +++ b/ui/src/app/files/files.component.ts
@@ -17,8 +17,9 @@ */ import { Component, OnInit, ViewChild } from '@angular/core'; -import { DialogService, PanelType } from '@streampipes/shared-ui'; +import { DialogService, PanelType, SpBreadcrumbService } from '@streampipes/shared-ui'; import { FileUploadDialogComponent } from './dialog/file-upload/file-upload-dialog.component'; +import { SpFilesRoutes } from './files.routes'; @Component({ templateUrl: './files.component.html', @@ -28,12 +29,13 @@ @ViewChild('fileOverviewComponent') fileOverviewComponent; - constructor(private dialogService: DialogService) { + constructor(private dialogService: DialogService, + private breadcrumbService: SpBreadcrumbService) { } ngOnInit() { - + this.breadcrumbService.updateBreadcrumb(this.breadcrumbService.getRootLink(SpFilesRoutes.BASE)); } openFileUploadDialog() {
diff --git a/ui/src/app/files/files.module.ts b/ui/src/app/files/files.module.ts index 7bccd09..7eb7b8d 100644 --- a/ui/src/app/files/files.module.ts +++ b/ui/src/app/files/files.module.ts
@@ -39,36 +39,49 @@ import { MatChipsModule } from '@angular/material/chips'; import { MatTooltipModule } from '@angular/material/tooltip'; import { PlatformServicesModule } from '@streampipes/platform-services'; +import { RouterModule } from '@angular/router'; +import { SharedUiModule } from '@streampipes/shared-ui'; @NgModule({ - imports: [ - CommonModule, - CoreUiModule, - FlexLayoutModule, - FormsModule, - ReactiveFormsModule, - MatButtonModule, - MatChipsModule, - MatFormFieldModule, - MatGridListModule, - MatIconModule, - MatInputModule, - MatDividerModule, - MatListModule, - MatPaginatorModule, - MatProgressBarModule, - MatTableModule, - MatTabsModule, - MatTooltipModule, - PlatformServicesModule, - ServicesModule - ], - declarations: [ - FilesComponent, - FileOverviewComponent, - FileUploadDialogComponent - ], - providers: [] + imports: [ + CommonModule, + CoreUiModule, + FlexLayoutModule, + FormsModule, + ReactiveFormsModule, + MatButtonModule, + MatChipsModule, + MatFormFieldModule, + MatGridListModule, + MatIconModule, + MatInputModule, + MatDividerModule, + MatListModule, + MatPaginatorModule, + MatProgressBarModule, + MatTableModule, + MatTabsModule, + MatTooltipModule, + PlatformServicesModule, + ServicesModule, + SharedUiModule, + RouterModule.forChild([ + { + path: 'files', + children: [ + { + path: '', + component: FilesComponent + }] + }]) + + ], + declarations: [ + FilesComponent, + FileOverviewComponent, + FileUploadDialogComponent + ], + providers: [] }) export class FilesModule { }
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/files/files.routes.ts similarity index 77% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/files/files.routes.ts index 58ba04b..10fb905 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/files/files.routes.ts
@@ -16,3 +16,10 @@ * */ +import { SpBreadcrumbItem, } from '@streampipes/shared-ui'; + +export class SpFilesRoutes { + + static FILES_BASE_LINK = 'files'; + static BASE: SpBreadcrumbItem = {label: 'File Management', link: [SpFilesRoutes.FILES_BASE_LINK]}; +}
diff --git a/ui/src/app/home/home.component.html b/ui/src/app/home/home.component.html index c9699d9..bfad3d3 100644 --- a/ui/src/app/home/home.component.html +++ b/ui/src/app/home/home.component.html
@@ -21,7 +21,7 @@ <div fxFlex="100"> <div fxFlex="100" fxLayout="column"> <div class="p-10 header-margin" fxLayoutAlign="center center"> - <div class="welcome-text">Welcome to {{appConstants.APP_NAME}}!</div> + <div class="welcome-text">Welcome!</div> </div> <div fxLayout="column" fxFlex="100" class="home-margin"> <div fxFlex="100" fxLayoutAlign="start center">
diff --git a/ui/src/app/home/home.component.scss b/ui/src/app/home/home.component.scss index 1bce66f..5cf0033 100644 --- a/ui/src/app/home/home.component.scss +++ b/ui/src/app/home/home.component.scss
@@ -36,7 +36,7 @@ } .welcome-text { - font-size: 30pt; + font-size: 26pt; font-weight: bold; }
diff --git a/ui/src/app/home/home.component.ts b/ui/src/app/home/home.component.ts index e0fba3a..12ef848 100644 --- a/ui/src/app/home/home.component.ts +++ b/ui/src/app/home/home.component.ts
@@ -16,27 +16,33 @@ * */ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'; import { HomeService } from './home.service'; import { Router } from '@angular/router'; import { AppConstants } from '../services/app.constants'; +import { SpBreadcrumbService } from '@streampipes/shared-ui'; @Component({ templateUrl: './home.component.html', styleUrls: ['./home.component.scss'] }) -export class HomeComponent { +export class HomeComponent implements OnInit { serviceLinks = []; constructor(private homeService: HomeService, private sanitizer: DomSanitizer, private router: Router, - public appConstants: AppConstants) { + public appConstants: AppConstants, + private breadcrumbService: SpBreadcrumbService) { this.serviceLinks = this.homeService.getFilteredServiceLinks(); } + ngOnInit() { + this.breadcrumbService.updateBreadcrumb([]); + } + getBackground(url) { return this.sanitizer.bypassSecurityTrustStyle(`url(${url})`); }
diff --git a/ui/src/app/info/info.component.ts b/ui/src/app/info/info.component.ts index b734dc5..6a7c121 100644 --- a/ui/src/app/info/info.component.ts +++ b/ui/src/app/info/info.component.ts
@@ -16,25 +16,29 @@ * */ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { MatTabChangeEvent } from '@angular/material/tabs'; +import { SpBreadcrumbService } from '@streampipes/shared-ui'; @Component({ - templateUrl: './info.component.html', - styleUrls: ['./info.component.css'] + templateUrl: './info.component.html', + styleUrls: ['./info.component.css'] }) -export class InfoComponent { +export class InfoComponent implements OnInit { - currentTabIndex = 0; + currentTabIndex = 0; - constructor() { + constructor(private breadcrumbService: SpBreadcrumbService) { - } + } - tabChanged(tabChangeEvent: MatTabChangeEvent): void { - this.currentTabIndex = tabChangeEvent.index; - } + ngOnInit() { + this.breadcrumbService.updateBreadcrumb([{label: 'Info'}]); + } + tabChanged(tabChangeEvent: MatTabChangeEvent): void { + this.currentTabIndex = tabChangeEvent.index; + } }
diff --git a/ui/src/app/notifications/notifications.component.ts b/ui/src/app/notifications/notifications.component.ts index 33f9ce6..4d31082 100644 --- a/ui/src/app/notifications/notifications.component.ts +++ b/ui/src/app/notifications/notifications.component.ts
@@ -26,6 +26,7 @@ import { FreeTextStaticProperty, Pipeline, PipelineService } from '@streampipes/platform-services'; import { AuthService } from '../services/auth.service'; import { filter, switchMap } from 'rxjs/operators'; +import { SpBreadcrumbService } from '@streampipes/shared-ui'; @Component({ selector: 'notifications', @@ -64,11 +65,13 @@ private pipelineService: PipelineService, public elementIconText: ElementIconText, private notificationService: NotificationsService, - private notificationCountService: NotificationCountService) { + private notificationCountService: NotificationCountService, + private breadcrumbService: SpBreadcrumbService) { this.unreadNotifications = []; } ngOnInit() { + this.breadcrumbService.updateBreadcrumb([{label: 'Notifications'}]); this.getPipelinesWithNotifications(); this.subscription = timer(0, 5000).pipe( filter(() => (this.currentlySelectedNotification !== undefined && this.allNotifications.size > 0)),
diff --git a/ui/src/app/pipeline-details/components/actions/pipeline-actions.component.html b/ui/src/app/pipeline-details/components/actions/pipeline-actions.component.html index 2ee14ea..8bff662 100644 --- a/ui/src/app/pipeline-details/components/actions/pipeline-actions.component.html +++ b/ui/src/app/pipeline-details/components/actions/pipeline-actions.component.html
@@ -16,58 +16,41 @@ ~ --> -<div> - <div class="assembly-options-preview sp-blue-bg"> - <div fxLayout="row" fxLayoutAlign="start center"> - <h4>Actions</h4> +<sp-basic-inner-panel panelTitle="Actions"> + <div fxFlex="100" fxLayoutAlign="center center" fxLayout="row" style="padding:10px"> + <div fxFlex="30"> + <button mat-button mat-raised-button color="accent" + matTooltip="Start Pipeline" matTooltipPosition="above" + (click)="startPipeline()" + [disabled]="starting" *ngIf="!pipeline.running"> + <mat-icon>play_arrow</mat-icon> + <span> Start</span> + </button> + <button mat-button mat-raised-button color="accent" + matTooltip="Stop Pipeline" matTooltipPosition="above" + (click)="stopPipeline()" + [disabled]="stopping" *ngIf="pipeline.running"> + <mat-icon>stop</mat-icon> + <span> Stop</span> + </button> + </div> + <div fxFlex="30"> + <button mat-button mat-raised-button color="accent" + matTooltip="Modify Pipeline" matTooltipPosition="above" + [disabled]="pipeline.running" + (click)="pipelineOperationsService.modifyPipeline(pipeline._id)"> + <mat-icon>mode_edit</mat-icon> + <span> Modify</span> + </button> + </div> + <div fxFlex="30"> + <button mat-button mat-raised-button color="accent" + matTooltip="Delete Pipeline" matTooltipPosition="above" + *ngIf="hasPipelineDeletePrivileges" + (click)="pipelineOperationsService.showDeleteDialog(pipeline, reloadPipelineEmitter, this.switchToPipelineView)"> + <mat-icon>delete</mat-icon> + <span> Delete</span> + </button> </div> </div> - <div class="sp-blue-border"> - <div fxFlex="100" fxLayoutAlign="center center" fxLayout="row" style="padding:10px"> - <div fxFlex="30"> - <button mat-button mat-raised-button color="accent" - matTooltip="Start Pipeline" matTooltipPosition="above" - (click)="startPipeline()" - [disabled]="starting" *ngIf="!pipeline.running"> - <mat-icon>play_arrow</mat-icon> - <span> Start</span> - </button> - <button mat-button mat-raised-button color="accent" - matTooltip="Stop Pipeline" matTooltipPosition="above" - (click)="stopPipeline()" - [disabled]="stopping" *ngIf="pipeline.running"> - <mat-icon>stop</mat-icon> - <span> Stop</span> - </button> - </div> - <div fxFlex="30"> - <button mat-button mat-raised-button color="accent" - matTooltip="Modify Pipeline" matTooltipPosition="above" - [disabled]="pipeline.running" - (click)="pipelineOperationsService.modifyPipeline(pipeline._id)"> - <mat-icon>mode_edit</mat-icon> - <span> Modify</span> - </button> - </div> - <div fxFlex="30"> - <button mat-button mat-raised-button color="accent" - matTooltip="Delete Pipeline" matTooltipPosition="above" - *ngIf="hasPipelineDeletePrivileges" - (click)="pipelineOperationsService.showDeleteDialog(pipeline, reloadPipelineEmitter, this.switchToPipelineView)"> - <mat-icon>delete</mat-icon> - <span> Delete</span> - </button> - </div> -<!-- <div flex="30">--> -<!-- <md-button ng-click="ctrl.PipelineOperationsService.showLogs(ctrl.pipeline._id)" class="md-button">--> -<!-- <md-icon--> -<!-- md-svg-icon="action:ic_info_24px"--> -<!-- aria-label="Logs" class="md-accent"></md-icon>--> -<!-- Logs--> -<!-- <md-tooltip md-direction="top">--> -<!-- Show Logs--> -<!-- </md-tooltip>--> -<!-- </md-button>--> - </div> - </div> -</div> +</sp-basic-inner-panel>
diff --git a/ui/src/app/pipeline-details/components/edit/quickedit.component.html b/ui/src/app/pipeline-details/components/edit/quickedit.component.html index ba52554..c5c44ca 100644 --- a/ui/src/app/pipeline-details/components/edit/quickedit.component.html +++ b/ui/src/app/pipeline-details/components/edit/quickedit.component.html
@@ -16,43 +16,55 @@ ~ --> -<div> - <div class="assembly-options-preview sp-blue-bg"> - <div fxLayout="row" fxLayoutAlign="start center"> - <h4>Edit configuration</h4> - <span fxFlex></span> - <button color="accent" mat-button mat-raised-button matTooltip="Save Pipeline" matTooltipPosition="above" - style="display:flex;align-items:center;" class="settings-bar-icon-button" - [disabled]="(!formValid || pipelineUpdating)" - (click)="updatePipeline()"> - <mat-icon>save</mat-icon> - <span> Update pipeline</span> - </button> - </div> - </div> - <div class="sp-blue-border"> - <div *ngIf="selectedElement"> - <div fxLayout="column" style="padding:5px;padding-left:10px;"> - <pipeline-elements-row [pipeline]="pipeline" - [element]="selectedElement"></pipeline-elements-row> +<sp-basic-nav-tabs [spNavigationItems]="tabs" + [activeLink]="'quick-edit'" + [showBackLink]="true" + [backLinkTarget]="['pipelines']"> - <div fxFlex="100" fxLayout="column" - *ngIf="isInvocable"> - <form [formGroup]="parentForm" fxFlex="100"> - <app-static-property *ngFor="let config of _selectedElement.staticProperties" - [staticProperty]="config" - [displayRecommended]="true" - [staticProperties]="_selectedElement.staticProperties" - [eventSchemas]="eventSchemas" - [parentForm]="parentForm" - [fieldName]="config.internalName"> - </app-static-property> - </form> + <div fxLayout="column" class="page-container-padding" *ngIf="pipeline"> + <pipeline-preview [jspcanvas]="'assembly-preview'" + [pipeline]="pipeline" + (selectedElementEmitter)="selectElement($event)" + style="margin-bottom:15px;" + class="md-padding" + *ngIf="pipelineAvailable"></pipeline-preview> + + <sp-basic-inner-panel panelTitle="Edit Configuration"> + <div header fxLayoutAlign="end center" fxFlex="100" fxLayout="row"> + <button color="accent" mat-button mat-raised-button matTooltip="Save Pipeline" + matTooltipPosition="above" + style="display:flex;align-items:center;" class="settings-bar-icon-button" + [disabled]="(!formValid || pipelineUpdating)" + (click)="updatePipeline()"> + <mat-icon>save</mat-icon> + <span> Update pipeline</span> + </button> + </div> + <div fxFlex="100" fxLayout="column"> + <div *ngIf="selectedElement"> + <div fxLayout="column" style="padding:5px;padding-left:10px;"> + <pipeline-elements-row [pipeline]="pipeline" + [element]="selectedElement"></pipeline-elements-row> + + <div fxFlex="100" fxLayout="column" + *ngIf="isInvocable"> + <form [formGroup]="parentForm" fxFlex="100"> + <app-static-property *ngFor="let config of _selectedElement.staticProperties" + [staticProperty]="config" + [displayRecommended]="true" + [staticProperties]="_selectedElement.staticProperties" + [eventSchemas]="eventSchemas" + [parentForm]="parentForm" + [fieldName]="config.internalName"> + </app-static-property> + </form> + </div> + </div> + </div> + <div fxLayout="column" fxLayoutAlign="center center" *ngIf="!selectedElement"> + (select an element in the preview window to modify it) </div> </div> - </div> - <div fxLayout="column" fxLayoutAlign="center center" *ngIf="!selectedElement"> - (select an element in the preview window to modify it) - </div> + </sp-basic-inner-panel> </div> -</div> +</sp-basic-nav-tabs>
diff --git a/ui/src/app/pipeline-details/components/edit/quickedit.component.ts b/ui/src/app/pipeline-details/components/edit/quickedit.component.ts index 15877ec..5432ce0 100644 --- a/ui/src/app/pipeline-details/components/edit/quickedit.component.ts +++ b/ui/src/app/pipeline-details/components/edit/quickedit.component.ts
@@ -16,135 +16,136 @@ * */ +import { AfterViewInit, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; import { - AfterViewInit, - ChangeDetectorRef, - Component, - EventEmitter, - Input, - OnInit, - Output -} from '@angular/core'; -import { - PipelineService, - DataProcessorInvocation, - DataSinkInvocation, - EventSchema, - Pipeline + DataProcessorInvocation, + DataSinkInvocation, + EventSchema, + PipelineService } from '@streampipes/platform-services'; import { PipelineElementUnion } from '../../../editor/model/editor.model'; import { FormBuilder, FormGroup } from '@angular/forms'; +import { SpPipelineDetailsDirective } from '../sp-pipeline-details.directive'; +import { ActivatedRoute } from '@angular/router'; +import { AuthService } from '../../../services/auth.service'; +import { SpBreadcrumbService } from '@streampipes/shared-ui'; +import { SpPipelineRoutes } from '../../../pipelines/pipelines.routes'; @Component({ - selector: 'quick-edit', - templateUrl: './quickedit.component.html', + selector: 'quick-edit', + templateUrl: './quickedit.component.html', }) -export class QuickEditComponent implements OnInit, AfterViewInit { +export class QuickEditComponent extends SpPipelineDetailsDirective implements OnInit, AfterViewInit { - @Input() - pipeline: Pipeline; + _selectedElement: PipelineElementUnion; - @Output() - reloadPipelineEmitter: EventEmitter<void> = new EventEmitter<void>(); + eventSchemas: EventSchema[]; - _selectedElement: PipelineElementUnion; + parentForm: FormGroup; + formValid: boolean; + viewInitialized = false; - eventSchemas: EventSchema[]; + isInvocable = false; + isDataProcessor = false; - parentForm: FormGroup; - formValid: boolean; - viewInitialized = false; + pipelineUpdating = false; - isInvocable = false; - isDataProcessor = false; + constructor(activatedRoute: ActivatedRoute, + pipelineService: PipelineService, + authService: AuthService, + private fb: FormBuilder, + private changeDetectorRef: ChangeDetectorRef, + breadcrumbService: SpBreadcrumbService) { + super(activatedRoute, pipelineService, authService, breadcrumbService); + } - pipelineUpdating = false; + ngOnInit() { + super.onInit(); + this.parentForm = this.fb.group({}); - constructor(private pipelineService: PipelineService, - private fb: FormBuilder, - private changeDetectorRef: ChangeDetectorRef) { + this.parentForm.statusChanges.subscribe((status) => { + this.formValid = this.viewInitialized && this.parentForm.valid; + }); + } + ngAfterViewInit(): void { + this.viewInitialized = true; + this.formValid = this.viewInitialized && this.parentForm.valid; + this.changeDetectorRef.detectChanges(); + } + + updatePipeline() { + this.pipelineUpdating = true; + this.updatePipelineElement(); + this.pipelineService.updatePipeline(this.pipeline).subscribe(data => { + this.loadPipeline(); + this.pipelineUpdating = false; + }); + } + + updatePipelineElement() { + if (this._selectedElement instanceof DataProcessorInvocation) { + this.updateDataProcessor(); + } else if (this._selectedElement instanceof DataSinkInvocation) { + this.updateDataSink(); } + } - ngOnInit() { - this.parentForm = this.fb.group({ - }); + updateDataProcessor() { + const dataProcessors: DataProcessorInvocation[] = []; + this.pipeline.sepas.forEach(p => { + if (p.dom === this._selectedElement.dom) { + dataProcessors.push(this._selectedElement as DataProcessorInvocation); + } else { + dataProcessors.push(p); + } + }); + this.pipeline.sepas = dataProcessors; + } - this.parentForm.statusChanges.subscribe((status) => { - this.formValid = this.viewInitialized && this.parentForm.valid; - }); + updateDataSink() { + const dataSinks: DataSinkInvocation[] = []; + this.pipeline.actions.forEach(p => { + if (p.dom === this._selectedElement.dom) { + dataSinks.push(this._selectedElement as DataSinkInvocation); + } else { + dataSinks.push(p); + } + }); + this.pipeline.actions = dataSinks; + } + + get selectedElement() { + return this._selectedElement; + } + + @Input() + set selectedElement(selectedElement: PipelineElementUnion) { + if (this._selectedElement) { + this.updatePipelineElement(); } - - ngAfterViewInit(): void { - this.viewInitialized = true; - this.formValid = this.viewInitialized && this.parentForm.valid; - this.changeDetectorRef.detectChanges(); + this._selectedElement = selectedElement; + this.eventSchemas = []; + if (this._selectedElement instanceof DataProcessorInvocation || this._selectedElement instanceof DataSinkInvocation) { + (this._selectedElement as any).inputStreams.forEach(is => { + this.eventSchemas = this.eventSchemas.concat(is.eventSchema); + }); } + this.updateTypeInfo(); + } - updatePipeline() { - this.pipelineUpdating = true; - this.updatePipelineElement(); - this.pipelineService.updatePipeline(this.pipeline).subscribe(data => { - this.reloadPipelineEmitter.emit(); - this.pipelineUpdating = false; - }); - } + updateTypeInfo() { + this.isDataProcessor = this._selectedElement instanceof DataProcessorInvocation; + this.isInvocable = this._selectedElement instanceof DataProcessorInvocation || + this._selectedElement instanceof DataSinkInvocation; + } - updatePipelineElement() { - if (this._selectedElement instanceof DataProcessorInvocation) { - this.updateDataProcessor(); - } else if (this._selectedElement instanceof DataSinkInvocation) { - this.updateDataSink(); - } - } + selectElement(element: PipelineElementUnion) { + this.selectedElement = element; + } - updateDataProcessor() { - const dataProcessors: DataProcessorInvocation[] = []; - this.pipeline.sepas.forEach(p => { - if (p.dom === this._selectedElement.dom) { - dataProcessors.push(this._selectedElement as DataProcessorInvocation); - } else { - dataProcessors.push(p); - } - }); - this.pipeline.sepas = dataProcessors; - } - - updateDataSink() { - const dataSinks: DataSinkInvocation[] = []; - this.pipeline.actions.forEach(p => { - if (p.dom === this._selectedElement.dom) { - dataSinks.push(this._selectedElement as DataSinkInvocation); - } else { - dataSinks.push(p); - } - }); - this.pipeline.actions = dataSinks; - } - - get selectedElement() { - return this._selectedElement; - } - - @Input() - set selectedElement(selectedElement: PipelineElementUnion) { - if (this._selectedElement) { - this.updatePipelineElement(); - } - this._selectedElement = selectedElement; - this.eventSchemas = []; - if (this._selectedElement instanceof DataProcessorInvocation || this._selectedElement instanceof DataSinkInvocation) { - (this._selectedElement as any).inputStreams.forEach(is => { - this.eventSchemas = this.eventSchemas.concat(is.eventSchema); - }); - } - this.updateTypeInfo(); - } - - updateTypeInfo() { - this.isDataProcessor = this._selectedElement instanceof DataProcessorInvocation; - this.isInvocable = this._selectedElement instanceof DataProcessorInvocation || - this._selectedElement instanceof DataSinkInvocation; - } + onPipelineAvailable(): void { + this.breadcrumbService.updateBreadcrumb([SpPipelineRoutes.BASE, {label: this.pipeline.name}, {label: 'Quick Edit'} ]); + } }
diff --git a/ui/src/app/pipeline-details/components/elements/pipeline-elements.component.html b/ui/src/app/pipeline-details/components/elements/pipeline-elements.component.html index 4af2449..c046264 100644 --- a/ui/src/app/pipeline-details/components/elements/pipeline-elements.component.html +++ b/ui/src/app/pipeline-details/components/elements/pipeline-elements.component.html
@@ -16,13 +16,9 @@ ~ --> -<div> - <div class="assembly-options-preview sp-blue-bg"> - <div fxLayout="row" fxLayoutAlign="start center"> - <h4>Element Details</h4> - </div> - </div> - <div class="sp-blue-border" style="max-height: 800px;overflow:auto;"> +<sp-basic-inner-panel panelTitle="Element Details"> + + <div style="max-height: 800px;overflow:auto;"> <div *ngIf="selectedElement"> <div fxLayout="column" style="padding:5px;padding-left:10px;"> <pipeline-elements-row [pipeline]="pipeline" [element]="selectedElement"></pipeline-elements-row> @@ -36,4 +32,4 @@ (select an element in the preview window to see details) </div> </div> -</div> \ No newline at end of file +</sp-basic-inner-panel>
diff --git a/ui/src/app/pipeline-details/components/monitoring/pipeline-monitoring.component.html b/ui/src/app/pipeline-details/components/monitoring/pipeline-monitoring.component.html index 4c27a46..3f4b4c1 100644 --- a/ui/src/app/pipeline-details/components/monitoring/pipeline-monitoring.component.html +++ b/ui/src/app/pipeline-details/components/monitoring/pipeline-monitoring.component.html
@@ -16,51 +16,52 @@ ~ --> +<sp-basic-nav-tabs [spNavigationItems]="tabs" + [activeLink]="'monitoring'" + [showBackLink]="true" + [backLinkTarget]="['pipelines']"> -<div fxFlex="100" fxLayout="column"> - <div fxLayout="column" class="fixed-height add-options"> - <div class="add-options-item" fxLayoutAlign="start center" fxLayout="row" style="padding-right:10px;"> - <div fxFlex="100" fxLayout="row" fxLayoutAlign="end center"> - <mat-slide-toggle [(ngModel)]="autoRefresh" color="accent">Auto refresh</mat-slide-toggle> - </div> - </div> + <div nav fxFlex="100" fxLayout="row" fxLayoutAlign="end center"> + <mat-slide-toggle [(ngModel)]="autoRefresh" color="accent">Auto refresh</mat-slide-toggle> </div> - <div fxFlex="100" fxLayout="column" class="page-container-padding-inner"> - <div fxFlex="100" *ngIf="!pipeline.running" fxLayout="column" fxLayoutAlign="center center"> - <div class="error-message">(monitoring info is only available for running pipelines)</div> - <button mat-button mat-raised-button color="accent" - matTooltip="Start Pipeline" matTooltipPosition="above" - *ngIf="hasPipelineWritePrivileges" - (click)="startPipeline()"> - <mat-icon>play_arrow</mat-icon> - <span> Start pipeline</span> - </button> - </div> - <div fxFlex="100" *ngIf="pipeline.running && pipelineMonitoringInfoAvailable"> - <div *ngFor="let pipelineElement of allElements" fxLayout="column" class="mb-10"> - <div class="assembly-options-preview sp-blue-bg" [id]="pipelineElement.elementId"> - <div fxLayout="row" fxLayoutAlign="start center"> - <h4>{{pipelineElement.name}}</h4> - </div> - </div> - <div class="sp-blue-border pipeline-element-statistics-panel"> - <div fxFlex="100" fxLayout="row"> - <div fxFlex="20" fxLayoutAlign="start start"> - <pipeline-elements-row style="width: 100%;" - [showDescription]="false" - [pipeline]="pipeline" - [element]="pipelineElement"></pipeline-elements-row> + <div fxLayout="column" class="page-container-padding" *ngIf="pipeline"> + <div fxFlex="100" fxLayout="column" class="page-container-padding-inner"> + <div fxFlex="100" *ngIf="!pipeline.running" fxLayout="column" fxLayoutAlign="center center"> + <div class="error-message">(monitoring info is only available for running pipelines)</div> + <button mat-button mat-raised-button color="accent" + matTooltip="Start Pipeline" matTooltipPosition="above" + *ngIf="hasPipelineWritePrivileges" + (click)="startPipeline()"> + <mat-icon>play_arrow</mat-icon> + <span> Start pipeline</span> + </button> + </div> + <div fxFlex="100" *ngIf="pipeline.running && pipelineMonitoringInfoAvailable"> + <div *ngFor="let pipelineElement of allElements" fxLayout="column" class="mb-10"> + <div class="assembly-options-preview sp-blue-bg" [id]="pipelineElement.elementId"> + <div fxLayout="row" fxLayoutAlign="start center"> + <h4>{{pipelineElement.name}}</h4> </div> - <div fxFlex="80" fxLayoutAlign="start center"> - <pipeline-element-statistics - [pipeline]="pipeline" - [pipelineElement]="pipelineElement" - [pipelineElementMonitoringInfo]="pipelineElementMonitoringInfo.get(pipelineElement.elementId)"> - </pipeline-element-statistics> + </div> + <div class="sp-blue-border pipeline-element-statistics-panel"> + <div fxFlex="100" fxLayout="row"> + <div fxFlex="20" fxLayoutAlign="start start"> + <pipeline-elements-row style="width: 100%;" + [showDescription]="false" + [pipeline]="pipeline" + [element]="pipelineElement"></pipeline-elements-row> + </div> + <div fxFlex="80" fxLayoutAlign="start center"> + <pipeline-element-statistics + [pipeline]="pipeline" + [pipelineElement]="pipelineElement" + [pipelineElementMonitoringInfo]="pipelineElementMonitoringInfo.get(pipelineElement.elementId)"> + </pipeline-element-statistics> + </div> </div> </div> </div> </div> </div> </div> -</div> +</sp-basic-nav-tabs>
diff --git a/ui/src/app/pipeline-details/components/monitoring/pipeline-monitoring.component.ts b/ui/src/app/pipeline-details/components/monitoring/pipeline-monitoring.component.ts index ea83eda..0641963 100644 --- a/ui/src/app/pipeline-details/components/monitoring/pipeline-monitoring.component.ts +++ b/ui/src/app/pipeline-details/components/monitoring/pipeline-monitoring.component.ts
@@ -16,29 +16,31 @@ * */ -import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; +import { Component, EventEmitter, OnDestroy, OnInit } from '@angular/core'; import { - DataProcessorInvocation, DataSinkInvocation, - Pipeline, PipelineElementMonitoringInfo, + DataProcessorInvocation, + DataSinkInvocation, + PipelineElementMonitoringInfo, PipelineMonitoringInfo, - SpDataSet, SpDataStream + PipelineMonitoringService, + PipelineService, + SpDataSet, + SpDataStream } from '@streampipes/platform-services'; -import { PipelineMonitoringService } from '@streampipes/platform-services'; import { PipelineOperationsService } from '../../../pipelines/services/pipeline-operations.service'; import { AuthService } from '../../../services/auth.service'; -import { UserPrivilege } from '../../../_enums/user-privilege.enum'; +import { SpPipelineDetailsDirective } from '../sp-pipeline-details.directive'; +import { ActivatedRoute } from '@angular/router'; +import { Subscription } from 'rxjs'; +import { SpBreadcrumbService } from '@streampipes/shared-ui'; +import { SpPipelineRoutes } from '../../../pipelines/pipelines.routes'; @Component({ selector: 'pipeline-monitoring', templateUrl: './pipeline-monitoring.component.html', styleUrls: ['./pipeline-monitoring.component.scss'] }) -export class PipelineMonitoringComponent implements OnInit, OnDestroy { - - _pipeline: Pipeline; - - @Output() - reloadPipelineEmitter: EventEmitter<boolean> = new EventEmitter<boolean>(); +export class PipelineMonitoringComponent extends SpPipelineDetailsDirective implements OnInit, OnDestroy { pipelineMonitoringInfo: PipelineMonitoringInfo; pipelineMonitoringInfoAvailable = false; @@ -49,19 +51,21 @@ pipelineElementMonitoringInfo: Map<string, PipelineElementMonitoringInfo>; - hasPipelineWritePrivileges = false; + reloadPipelinesEmitter: EventEmitter<boolean> = new EventEmitter<boolean>(); + reloadSubscription: Subscription; - constructor(private pipelineMonitoringService: PipelineMonitoringService, + constructor(activatedRoute: ActivatedRoute, + pipelineService: PipelineService, + authService: AuthService, + private pipelineMonitoringService: PipelineMonitoringService, private pipelineOperationsService: PipelineOperationsService, - private authService: AuthService) { + breadcrumbService: SpBreadcrumbService) { + super(activatedRoute, pipelineService, authService, breadcrumbService); } ngOnInit(): void { - this.authService.user$.subscribe(user => { - this.hasPipelineWritePrivileges = this.authService.hasRole(UserPrivilege.PRIVILEGE_WRITE_PIPELINE); - }); - this.collectAllElements(); - this.checkMonitoringInfoCollection(); + super.onInit(); + this.reloadSubscription = this.reloadPipelinesEmitter.subscribe(reload => this.loadPipeline()); } checkMonitoringInfoCollection() { @@ -101,20 +105,17 @@ ngOnDestroy(): void { this.autoRefresh = false; + this.reloadSubscription.unsubscribe(); } startPipeline() { - this.pipelineOperationsService.startPipeline(this.pipeline._id, this.reloadPipelineEmitter); + this.pipelineOperationsService.startPipeline(this.pipeline._id, this.reloadPipelinesEmitter); } - @Input() - set pipeline(pipeline: Pipeline) { - this._pipeline = pipeline; + onPipelineAvailable(): void { + this.breadcrumbService.updateBreadcrumb([SpPipelineRoutes.BASE, {label: this.pipeline.name}, {label: 'Monitoring'} ]); + this.collectAllElements(); this.checkMonitoringInfoCollection(); } - get pipeline() { - return this._pipeline; - } - }
diff --git a/ui/src/app/pipeline-details/components/overview/pipeline-details-overview.component.html b/ui/src/app/pipeline-details/components/overview/pipeline-details-overview.component.html new file mode 100644 index 0000000..eca67ef --- /dev/null +++ b/ui/src/app/pipeline-details/components/overview/pipeline-details-overview.component.html
@@ -0,0 +1,46 @@ +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~ + --> + +<sp-basic-nav-tabs [spNavigationItems]="tabs" [activeLink]="'overview'" [showBackLink]="true" [backLinkTarget]="['pipelines']"> + <div fxLayout="column" class="page-container-padding"> + <div fxFlex="100" fxLayout="column"> + <pipeline-preview [jspcanvas]="'assembly-preview'" + [pipeline]="pipeline" + (selectedElementEmitter)="selectElement($event)" + style="margin-bottom:15px;" + class="md-padding" + *ngIf="pipelineAvailable"></pipeline-preview> + <div fxFlex fxLayout="row" fxLayoutAlign="start top" *ngIf="pipelineAvailable"> + <div fxFlex="60" class="md-padding"> + <div fxFlex fxLayout="column"> + <pipeline-elements [pipeline]="pipeline" + [selectedElement]="selectedElement"></pipeline-elements> + </div> + </div> + <div fxFlex="40" class="md-padding"> + <div fxFlex fxLayout="column"> + <pipeline-actions (reloadPipelineEmitter)="loadPipeline()" [pipeline]="pipeline" + style="margin-bottom:15px;" + *ngIf="hasPipelineWritePrivileges"></pipeline-actions> + <pipeline-status [pipeline]="pipeline"></pipeline-status> + </div> + </div> + </div> + </div> + </div> +</sp-basic-nav-tabs>
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.scss b/ui/src/app/pipeline-details/components/overview/pipeline-details-overview.component.scss similarity index 99% rename from ui/src/app/pipeline-details/pipeline-details.component.scss rename to ui/src/app/pipeline-details/components/overview/pipeline-details-overview.component.scss index a375af7..1100ab4 100644 --- a/ui/src/app/pipeline-details/pipeline-details.component.scss +++ b/ui/src/app/pipeline-details/components/overview/pipeline-details-overview.component.scss
@@ -19,4 +19,3 @@ .md-padding { padding: 10px; } -
diff --git a/ui/src/app/pipeline-details/components/overview/pipeline-details-overview.component.ts b/ui/src/app/pipeline-details/components/overview/pipeline-details-overview.component.ts new file mode 100644 index 0000000..edc0d6a --- /dev/null +++ b/ui/src/app/pipeline-details/components/overview/pipeline-details-overview.component.ts
@@ -0,0 +1,58 @@ +/* + * 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 { ActivatedRoute } from '@angular/router'; +import { SpPipelineDetailsDirective } from '../sp-pipeline-details.directive'; +import { AuthService } from '../../../services/auth.service'; +import { PipelineService } from '@streampipes/platform-services'; +import { PipelineElementUnion } from '../../../editor/model/editor.model'; +import { SpBreadcrumbService } from '@streampipes/shared-ui'; +import { SpPipelineRoutes } from '../../../pipelines/pipelines.routes'; + +@Component({ + selector: 'sp-pipeline-details-overview-component', + templateUrl: './pipeline-details-overview.component.html', + styleUrls: ['./pipeline-details-overview.component.scss'] +}) +export class SpPipelineDetailsOverviewComponent extends SpPipelineDetailsDirective implements OnInit { + + tabs = []; + selectedElement: PipelineElementUnion; + + constructor(activatedRoute: ActivatedRoute, + pipelineService: PipelineService, + authService: AuthService, + breadcrumbService: SpBreadcrumbService) { + super(activatedRoute, pipelineService, authService, breadcrumbService); + } + + ngOnInit(): void { + super.onInit(); + } + + selectElement(element: PipelineElementUnion) { + this.selectedElement = element; + } + + onPipelineAvailable(): void { + this.breadcrumbService.updateBreadcrumb([SpPipelineRoutes.BASE, {label: this.pipeline.name}, {label: 'Overview'} ]); + } + + +}
diff --git a/ui/src/app/pipeline-details/components/preview/pipeline-preview.component.html b/ui/src/app/pipeline-details/components/preview/pipeline-preview.component.html index 93e8f4f..f9a1188 100644 --- a/ui/src/app/pipeline-details/components/preview/pipeline-preview.component.html +++ b/ui/src/app/pipeline-details/components/preview/pipeline-preview.component.html
@@ -16,15 +16,12 @@ ~ --> -<div class="assembly-options-preview sp-blue-bg"> - <div fxLayout="row" fxLayoutAlign="start center"> - <h4>Preview: {{pipeline.name}}</h4> - </div> -</div> -<div class="outer-assembly-preview"> - <div class="canvas-preview-inner"> - <div id="{{jspcanvas}}" class="canvas-preview"> - <pipeline [canvasId]="jspcanvas" [rawPipelineModel]="rawPipelineModel" [preview]="true"></pipeline> +<sp-basic-inner-panel [panelTitle]="'Preview: ' +pipeline.name" innerPadding="0"> + <div class="outer-assembly-preview"> + <div class="canvas-preview-inner"> + <div id="{{jspcanvas}}" class="canvas-preview"> + <pipeline [canvasId]="jspcanvas" [rawPipelineModel]="rawPipelineModel" [preview]="true"></pipeline> + </div> </div> </div> -</div> +</sp-basic-inner-panel>
diff --git a/ui/src/app/pipeline-details/components/sp-pipeline-details.directive.ts b/ui/src/app/pipeline-details/components/sp-pipeline-details.directive.ts new file mode 100644 index 0000000..68712a9 --- /dev/null +++ b/ui/src/app/pipeline-details/components/sp-pipeline-details.directive.ts
@@ -0,0 +1,68 @@ +/* + * 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 { Directive } from '@angular/core'; +import { UserPrivilege } from '../../_enums/user-privilege.enum'; +import { ActivatedRoute } from '@angular/router'; +import { AuthService } from '../../services/auth.service'; +import { Pipeline, PipelineService } from '@streampipes/platform-services'; +import { SpPipelineDetailsTabs } from '../pipeline-details-tabs'; +import { SpBreadcrumbService } from '@streampipes/shared-ui'; + +@Directive() +export abstract class SpPipelineDetailsDirective { + + tabs = []; + hasPipelineWritePrivileges = false; + hasPipelineDeletePrivileges = false; + + currentPipeline: string; + pipeline: Pipeline; + pipelineAvailable = false; + + constructor(protected activatedRoute: ActivatedRoute, + protected pipelineService: PipelineService, + protected authService: AuthService, + protected breadcrumbService: SpBreadcrumbService) { + } + + onInit(): void { + this.authService.user$.subscribe(user => { + this.hasPipelineWritePrivileges = this.authService.hasRole(UserPrivilege.PRIVILEGE_WRITE_PIPELINE); + this.hasPipelineDeletePrivileges = this.authService.hasRole(UserPrivilege.PRIVILEGE_DELETE_PIPELINE); + const pipelineId = this.activatedRoute.snapshot.params.pipelineId; + if (pipelineId) { + this.tabs = new SpPipelineDetailsTabs().getTabs(pipelineId); + this.currentPipeline = pipelineId; + this.loadPipeline(); + } + }); + } + + loadPipeline(): void { + this.pipelineService.getPipelineById(this.currentPipeline) + .subscribe(pipeline => { + this.pipeline = pipeline; + this.pipelineAvailable = true; + this.onPipelineAvailable(); + }); + } + + abstract onPipelineAvailable(): void; + +}
diff --git a/ui/src/app/pipeline-details/components/status/pipeline-status.component.html b/ui/src/app/pipeline-details/components/status/pipeline-status.component.html index 5083595e..813b376 100644 --- a/ui/src/app/pipeline-details/components/status/pipeline-status.component.html +++ b/ui/src/app/pipeline-details/components/status/pipeline-status.component.html
@@ -16,12 +16,7 @@ ~ --> -<div class="assembly-options-preview sp-blue-bg"> - <div fxLayout="row" fxLayoutAlign="start center"> - <h4>Pipeline Status</h4> - </div> -</div> -<div class="sp-blue-border"> +<sp-basic-inner-panel panelTitle="Pipeline Status"> <div fxLayout="column" style="min-height:100px; padding:5px;padding-left:15px;" *ngIf="pipelineStatus.length > 0"> <div fxLayout="row" fxFlex="100"> <div fxFlex="20"><h5><b>Date</b></h5></div> @@ -41,4 +36,4 @@ <div fxLayout="column"fxLayoutAlign="center center" style="min-height:100px; padding:5px;padding-left:15px;" *ngIf="pipelineStatus.length==0"> (no status information available) </div> -</div> \ No newline at end of file +</sp-basic-inner-panel>
diff --git a/ui/src/app/pipeline-details/pipeline-details-tabs.ts b/ui/src/app/pipeline-details/pipeline-details-tabs.ts new file mode 100644 index 0000000..966c4a7 --- /dev/null +++ b/ui/src/app/pipeline-details/pipeline-details-tabs.ts
@@ -0,0 +1,31 @@ +/* + * 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 { SpNavigationItem } from '@streampipes/shared-ui'; + +export class SpPipelineDetailsTabs { + + public getTabs(pipelineId: string): SpNavigationItem[] { + return [ + {itemId: 'overview', itemTitle: 'Overview', itemLink: ['pipelines', 'details', pipelineId, 'overview']}, + {itemId: 'monitoring', itemTitle: 'Monitoring', itemLink: ['pipelines', 'details', pipelineId, 'monitoring']}, + // {itemId: 'errors', itemTitle: 'Errors', itemLink: ['pipelines', 'details', pipelineId, 'errors']}, + {itemId: 'quick-edit', itemTitle: 'Quick Edit', itemLink: ['pipelines', 'details', pipelineId, 'quick-edit']} + ]; + } +}
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.html b/ui/src/app/pipeline-details/pipeline-details.component.html deleted file mode 100644 index 2733ce1..0000000 --- a/ui/src/app/pipeline-details/pipeline-details.component.html +++ /dev/null
@@ -1,65 +0,0 @@ -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one or more - ~ contributor license agreements. See the NOTICE file distributed with - ~ this work for additional information regarding copyright ownership. - ~ The ASF licenses this file to You under the Apache License, Version 2.0 - ~ (the "License"); you may not use this file except in compliance with - ~ the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - ~ - --> - -<div fxLayout="column" class="page-container"> - <div fxLayout="row" class="border sp-tab-bg" style="padding:0px"> - <div fxFlex="100" class="page-container-nav"> - <div fxFlex="100" fxLayout="row"> - <mat-tab-group [selectedIndex]="selectedIndex" (selectedIndexChange)="setSelectedIndex($event)" color="accent"> - <mat-tab label="Overview"></mat-tab> - <mat-tab label="Monitoring"></mat-tab> - <mat-tab label="Errors"></mat-tab> - <mat-tab label="Quick Edit" [disabled]="pipelineAvailable && pipeline.running" *ngIf="hasPipelineWritePrivileges"></mat-tab> - </mat-tab-group> - </div> - </div> - </div> - <div fxFlex="100" fxLayout="column"> - <pipeline-preview [jspcanvas]="'assembly-preview'" - [pipeline]="pipeline" - (selectedElementEmitter)="selectElement($event)" - style="margin-bottom:15px;" - class="md-padding" - *ngIf="pipelineAvailable"></pipeline-preview> - <div fxFlex fxLayout="row" fxLayoutAlign="start top" *ngIf="pipelineAvailable && selectedIndex == 0"> - <div fxFlex="60" class="md-padding"> - <div fxFlex fxLayout="column"> - <pipeline-elements [pipeline]="pipeline" - [selectedElement]="selectedElement"></pipeline-elements> - </div> - </div> - <div fxFlex="40" class="md-padding"> - <div fxFlex fxLayout="column"> - <pipeline-actions (reloadPipelineEmitter)="loadPipeline()" [pipeline]="pipeline" - style="margin-bottom:15px;" *ngIf="hasPipelineWritePrivileges"></pipeline-actions> - <pipeline-status [pipeline]="pipeline"></pipeline-status> - </div> - </div> - </div> - <div fxFlex fxLayout="column" fxLayoutAlign="start top" *ngIf="pipelineAvailable && selectedIndex == 1"> - <pipeline-monitoring [pipeline]="pipeline" (reloadPipelineEmitter)="loadPipeline()"></pipeline-monitoring> - </div> - <div fxFlex fxLayout="row" fxLayoutAlign="start top" *ngIf="pipelineAvailable && selectedIndex == 3"> - <div fxFlex="100" class="md-padding"> - <div fxFlex fxLayout="column"> - <quick-edit [pipeline]="pipeline" [selectedElement]="selectedElement" (reloadPipelineEmitter)="loadPipeline()"></quick-edit> - </div> - </div> - </div> - </div> -</div>
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.ts b/ui/src/app/pipeline-details/pipeline-details.component.ts deleted file mode 100644 index 9350874..0000000 --- a/ui/src/app/pipeline-details/pipeline-details.component.ts +++ /dev/null
@@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Component, OnInit } from '@angular/core'; -import { Pipeline, PipelineService } from '@streampipes/platform-services'; -import { PipelineElementUnion } from '../editor/model/editor.model'; -import { ActivatedRoute } from '@angular/router'; -import { AuthService } from '../services/auth.service'; -import { UserPrivilege } from '../_enums/user-privilege.enum'; - -@Component({ - selector: 'pipeline-details', - templateUrl: './pipeline-details.component.html', - styleUrls: ['./pipeline-details.component.scss'] -}) -export class PipelineDetailsComponent implements OnInit { - - currentPipeline: string; - pipeline: Pipeline; - pipelineAvailable = false; - - selectedIndex = 0; - selectedElement: PipelineElementUnion; - - hasPipelineWritePrivileges = false; - hasPipelineDeletePrivileges = false; - - constructor(private activatedRoute: ActivatedRoute, - private pipelineService: PipelineService, - private authService: AuthService) { - } - - ngOnInit() { - this.authService.user$.subscribe(user => { - this.hasPipelineWritePrivileges = this.authService.hasRole(UserPrivilege.PRIVILEGE_WRITE_PIPELINE); - this.hasPipelineDeletePrivileges = this.authService.hasRole(UserPrivilege.PRIVILEGE_DELETE_PIPELINE); - }); - this.activatedRoute.queryParams.subscribe(params => { - if (params['pipeline']) { - this.currentPipeline = params['pipeline']; - this.loadPipeline(); - } - }); - } - - setSelectedIndex(index: number) { - this.selectedIndex = index; - } - - loadPipeline() { - this.pipelineService.getPipelineById(this.currentPipeline) - .subscribe(pipeline => { - this.pipeline = pipeline; - this.pipelineAvailable = true; - }); - } - - selectElement(element: PipelineElementUnion) { - this.selectedElement = element; - } - -}
diff --git a/ui/src/app/pipeline-details/pipeline-details.module.ts b/ui/src/app/pipeline-details/pipeline-details.module.ts index 8978f7d..7afc3a8 100644 --- a/ui/src/app/pipeline-details/pipeline-details.module.ts +++ b/ui/src/app/pipeline-details/pipeline-details.module.ts
@@ -24,7 +24,6 @@ import { CustomMaterialModule } from '../CustomMaterial/custom-material.module'; import { CommonModule } from '@angular/common'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; -import { PipelineDetailsComponent } from './pipeline-details.component'; import { PipelinePreviewComponent } from './components/preview/pipeline-preview.component'; import { EditorModule } from '../editor/editor.module'; import { PipelineActionsComponent } from './components/actions/pipeline-actions.component'; @@ -39,40 +38,42 @@ import { BarchartWidgetComponent } from './components/monitoring/widget/barchart/barchart-widget.component'; import { StatusWidgetComponent } from './components/monitoring/widget/status/status-widget.component'; import { PlatformServicesModule } from '@streampipes/platform-services'; +import { SpPipelineDetailsOverviewComponent } from './components/overview/pipeline-details-overview.component'; +import { SharedUiModule } from '@streampipes/shared-ui'; @NgModule({ - imports: [ - CoreUiModule, - FlexLayoutModule, - FormsModule, - MatTabsModule, - MatButtonModule, - CustomMaterialModule, - CommonModule, - MatProgressSpinnerModule, - NgxChartsModule, - EditorModule, - FormsModule, - ReactiveFormsModule, - PlatformServicesModule - ], - declarations: [ - PipelineActionsComponent, - PipelineElementsComponent, - PipelineElementsRowComponent, - PipelineElementStatisticsComponent, - PipelineDetailsComponent, - PipelineMonitoringComponent, - PipelineStatusComponent, - PipelinePreviewComponent, - QuickEditComponent, - StatusWidgetComponent, - BarchartWidgetComponent - ], - providers: [], - exports: [ - PipelineDetailsComponent - ] + imports: [ + CoreUiModule, + FlexLayoutModule, + FormsModule, + MatTabsModule, + MatButtonModule, + CustomMaterialModule, + CommonModule, + MatProgressSpinnerModule, + NgxChartsModule, + EditorModule, + FormsModule, + ReactiveFormsModule, + PlatformServicesModule, + SharedUiModule + ], + declarations: [ + PipelineActionsComponent, + PipelineElementsComponent, + PipelineElementsRowComponent, + PipelineElementStatisticsComponent, + PipelineMonitoringComponent, + PipelineStatusComponent, + PipelinePreviewComponent, + QuickEditComponent, + StatusWidgetComponent, + BarchartWidgetComponent, + SpPipelineDetailsOverviewComponent, + ], + providers: [], + exports: [ + ] }) export class PipelineDetailsModule {
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.scss b/ui/src/app/pipeline-details/pipeline-details.routes.ts similarity index 81% copy from ui/src/app/pipeline-details/pipeline-details.component.scss copy to ui/src/app/pipeline-details/pipeline-details.routes.ts index a375af7..b9ff036 100644 --- a/ui/src/app/pipeline-details/pipeline-details.component.scss +++ b/ui/src/app/pipeline-details/pipeline-details.routes.ts
@@ -16,7 +16,10 @@ * */ -.md-padding { - padding: 10px; -} +import { SpBreadcrumbItem, } from '@streampipes/shared-ui'; +export class SpPipelineDetailsRoutes { + + static BASE: SpBreadcrumbItem = {label: 'Pipeline Details', link: ['pipelines']}; + +}
diff --git a/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.html b/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.html index ab7a759..01955e5 100644 --- a/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.html +++ b/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.html
@@ -93,7 +93,7 @@ <button color="accent" mat-button mat-icon-button matTooltip="Delete pipeline" matTooltipPosition="above" (click)="pipelineOperationsService.showDeleteDialog(pipeline, refreshPipelinesEmitter)" - data-cy="delete"> + data-cy="delete-pipeline"> <i class="material-icons">delete</i> </button> </span>
diff --git a/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.scss b/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.scss index c2bef23..7f1e843 100644 --- a/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.scss +++ b/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.scss
@@ -25,10 +25,10 @@ } .mat-row:nth-child(even) { - background-color: var(--color-bg-2); + background-color: var(--color-bg-1); } .mat-row:nth-child(odd) { - background-color: var(--color-bg-3); + background-color: var(--color-bg-2); } .mat-column-status {
diff --git a/ui/src/app/pipelines/dialog/import-pipeline/import-pipeline-dialog.component.html b/ui/src/app/pipelines/dialog/import-pipeline/import-pipeline-dialog.component.html index 68d73c1..168191f 100644 --- a/ui/src/app/pipelines/dialog/import-pipeline/import-pipeline-dialog.component.html +++ b/ui/src/app/pipelines/dialog/import-pipeline/import-pipeline-dialog.component.html
@@ -60,9 +60,9 @@ <button mat-button mat-raised-button class="mat-basic" (click)="back()" *ngIf="!('upload-pipelines'===page)" style="margin-right:10px;"> Back </button> - <button mat-button mat-raised-button color="primary" (click)="startImport()" + <button mat-button mat-raised-button color="accent" (click)="startImport()" *ngIf="page === 'select-pipelines'"> Import </button> </div> -</div> \ No newline at end of file +</div>
diff --git a/ui/src/app/pipelines/dialog/import-pipeline/import-pipeline-dialog.component.ts b/ui/src/app/pipelines/dialog/import-pipeline/import-pipeline-dialog.component.ts index 9e9626d..b790afa 100644 --- a/ui/src/app/pipelines/dialog/import-pipeline/import-pipeline-dialog.component.ts +++ b/ui/src/app/pipelines/dialog/import-pipeline/import-pipeline-dialog.component.ts
@@ -78,8 +78,7 @@ } toggleSelectedPipeline(pipeline: Pipeline) { - console.log(pipeline); - if (this.selectedPipelines.some(p => p._id = pipeline._id)) { + if (this.selectedPipelines.some(p => p._id === pipeline._id)) { this.selectedPipelines.splice(this.selectedPipelines.findIndex(sp => sp._id === pipeline._id), 1); } else { this.selectedPipelines.push(pipeline); @@ -87,7 +86,6 @@ } storePipelines() { - console.log(this.selectedPipelines); const promises = []; this.selectedPipelines.forEach(pipeline => { pipeline._rev = undefined;
diff --git a/ui/src/app/pipelines/dialog/pipeline-notifications/pipeline-notifications.component.html b/ui/src/app/pipelines/dialog/pipeline-notifications/pipeline-notifications.component.html index 65fdce4..3812194 100644 --- a/ui/src/app/pipelines/dialog/pipeline-notifications/pipeline-notifications.component.html +++ b/ui/src/app/pipelines/dialog/pipeline-notifications/pipeline-notifications.component.html
@@ -16,10 +16,10 @@ ~ --> -<div class="sp-dialog-container"> - <div class="sp-dialog-content p-15"> +<div class="sp-dialog-container" fxLayout="column"> + <div class="sp-dialog-content p-15" fxFlex="100" fxLayout="column"> <div class="info-message">Pipeline health monitoring discovered the following issues:</div> - <div class="log-message"> + <div class="log-message" fxFlex="100" fxLayout="column"> <span *ngFor="let notification of pipeline.pipelineNotifications"> <p>{{notification}}</p> </span>
diff --git a/ui/src/app/pipelines/dialog/pipeline-notifications/pipeline-notifications.component.scss b/ui/src/app/pipelines/dialog/pipeline-notifications/pipeline-notifications.component.scss index 04c6ace..0a47a46 100644 --- a/ui/src/app/pipelines/dialog/pipeline-notifications/pipeline-notifications.component.scss +++ b/ui/src/app/pipelines/dialog/pipeline-notifications/pipeline-notifications.component.scss
@@ -21,15 +21,15 @@ .log-message { background-color: black; - font: 1.3rem Inconsolata, monospace; + font: 11pt Inconsolata, monospace; text-shadow: 0 0 5px #C8C8C8; color: white; padding: 10px; - width: 100%; + max-width: 100%; } .info-message { - font-size: 1.5rem; + font-size: 12pt; margin-top: 10px; margin-bottom: 5px; }
diff --git a/ui/src/app/pipelines/pipelines.component.html b/ui/src/app/pipelines/pipelines.component.html index cb8f87e..fb08754 100644 --- a/ui/src/app/pipelines/pipelines.component.html +++ b/ui/src/app/pipelines/pipelines.component.html
@@ -16,65 +16,69 @@ ~ --> -<div fxLayout="column" class="page-container"> - <div fxLayout="row" class="border sp-tab-bg" style="padding:0;"> - <div fxFlex="100" class="page-container-nav"> - <div fxFlex="100" fxLayout="row"> - <button mat-button mat-flat-button color="accent" (click)="showPipelineCategoriesDialog()">Manage Categories</button> - <div fxFlex fxLayoutAlign="start center" [attr.id]="'peType'"> - <mat-tab-group [selectedIndex]="selectedCategoryIndex" (selectedIndexChange)="setSelectedTab($event)" color="accent"> - <mat-tab label="All pipelines"></mat-tab> - <mat-tab *ngFor="let category of pipelineCategories" label="{{category.categoryName}}"></mat-tab> - </mat-tab-group> +<sp-basic-view [showBackLink]="false" [padding]="true"> + <div nav fxFlex="100" fxLayoutAlign="start center" fxLayout="row" class="pl-10"> + <button mat-button mat-raised-button color="accent" (click)="navigateToPipelineEditor()" data-cy="pipelines-navigate-to-editor"> + <i class="material-icons">add</i> New pipeline + </button> + <button class="mr-10" mat-button color="accent" (click)="startAllPipelines(true)" + [disabled]="checkCurrentSelectionStatus(false)" *ngIf="hasPipelineWritePrivileges"> + <mat-icon>play_arrow</mat-icon><span>Start all pipelines</span> + </button> + <button mat-button color="accent" (click)="startAllPipelines(false)" + [disabled]="checkCurrentSelectionStatus(true)" *ngIf="hasPipelineWritePrivileges"> + <mat-icon>stop</mat-icon> + <span>Stop all pipelines</span> + </button> + <span fxFlex></span> + <button mat-button mat-icon-button color="accent" matTooltip="Refresh pipelines" matTooltipPosition="above" + (click)="refreshPipelines()"> + <i class="material-icons"> + refresh + </i> + </button> + <button mat-button mat-icon-button color="accent" matTooltip="Export pipelines" matTooltipPosition="above" + (click)="exportPipelines()"> + <i class="material-icons"> + cloud_download + </i> + </button> + <button mat-button mat-icon-button color="accent" matTooltip="Import pipelines" matTooltipPosition="above" + (click)="openImportPipelinesDialog()"> + <i class="material-icons"> + cloud_upload + </i> + </button> + </div> + <div fxFlex="100" fxLayout="column"> + <div fxLayout="column"> + <sp-basic-header-title-component title="My pipelines"></sp-basic-header-title-component> + <div fxFlex="100" fxLayout="row" fxLayoutAlign="center start"> + <sp-basic-inner-panel [showTitle]="false" innerPadding="0" outerMargin="0" fxFlex="90" + [hideToolbar]="true"> + <div fxFlex="100"> + <pipeline-overview [activeCategoryId]="activeCategoryId" [pipelines]="pipelines" + [pipelineToStart]="pipelineToStart" + (refreshPipelinesEmitter)="refreshPipelines()" + *ngIf="pipelinesReady"></pipeline-overview> + </div> + </sp-basic-inner-panel> + </div> + <div fxFlex="100" fxLayout="column" style="margin-top: 20px;"> + <sp-basic-header-title-component title="System-generated pipelines"></sp-basic-header-title-component> + <div fxFlex="100" fxLayout="row" fxLayoutAlign="center start"> + <sp-basic-inner-panel [showTitle]="false" innerPadding="0" outerMargin="0" fxFlex="90" + [hideToolbar]="true"> + <div fxFlex="100"> + <pipeline-overview [activeCategoryId]="activeCategoryId" [pipelines]="systemPipelines" + [pipelineToStart]="systemPipelineToStart" + (refreshPipelinesEmitter)="refreshPipelines()" + *ngIf="pipelinesReady"></pipeline-overview> + </div> + </sp-basic-inner-panel> </div> </div> </div> </div> - <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100"> - <div fxLayout="row"> - <button class="mr-10" mat-button mat-raised-button color="accent" (click)="startAllPipelines(true)" - [disabled]="checkCurrentSelectionStatus(false)" *ngIf="hasPipelineWritePrivileges">Start all pipelines - </button> - <button mat-button mat-raised-button color="accent" (click)="startAllPipelines(false)" - [disabled]="checkCurrentSelectionStatus(true)" *ngIf="hasPipelineWritePrivileges">Stop all pipelines - </button> - </div> - <div class="assemblyOptions sp-blue-bg mt-20" style="padding:5px;"> - <div fxLayout="row" fxLayoutAlign="start center"> - <h4>My pipelines</h4> - <span fxFlex></span> - <button mat-button mat-icon-button matTooltip="Refresh pipelines" matTooltipPosition="above" - (click)="refreshPipelines()"> - <i class="material-icons"> - refresh - </i> - </button> - <button mat-button mat-icon-button matTooltip="Export pipelines" matTooltipPosition="above" - (click)="exportPipelines()"> - <i class="material-icons"> - cloud_download - </i> - </button> - <button mat-button mat-icon-button matTooltip="Import pipelines" matTooltipPosition="above" - (click)="openImportPipelinesDialog()"> - <i class="material-icons"> - cloud_upload - </i> - </button> - </div> - </div> - <div class="sp-blue-border"> - <pipeline-overview [activeCategoryId]="activeCategoryId" [pipelines]="pipelines" [pipelineToStart]="pipelineToStart" - (refreshPipelinesEmitter)="refreshPipelines()" *ngIf="pipelinesReady"></pipeline-overview> - </div> - <div style="margin-top:20px;margin-bottom:20px;"></div> - <div class="assemblyOptions sp-blue-bg"> - <h4>System-generated pipelines</h4> - </div> - <div class="sp-blue-border"> - <pipeline-overview [activeCategoryId]="activeCategoryId" [pipelines]="systemPipelines" [pipelineToStart]="systemPipelineToStart" - (refreshPipelinesEmitter)="refreshPipelines()" *ngIf="pipelinesReady"></pipeline-overview> - </div> - </div> -</div> +</sp-basic-view>
diff --git a/ui/src/app/pipelines/pipelines.component.ts b/ui/src/app/pipelines/pipelines.component.ts index 316810d..c966ff0 100644 --- a/ui/src/app/pipelines/pipelines.component.ts +++ b/ui/src/app/pipelines/pipelines.component.ts
@@ -19,14 +19,15 @@ import * as FileSaver from 'file-saver'; import { Component, OnInit } from '@angular/core'; import { Pipeline, PipelineCategory, PipelineService } from '@streampipes/platform-services'; -import { DialogService, PanelType, DialogRef } from '@streampipes/shared-ui'; +import { DialogRef, DialogService, PanelType, SpBreadcrumbService } from '@streampipes/shared-ui'; import { ImportPipelineDialogComponent } from './dialog/import-pipeline/import-pipeline-dialog.component'; import { StartAllPipelinesDialogComponent } from './dialog/start-all-pipelines/start-all-pipelines-dialog.component'; import { PipelineCategoriesDialogComponent } from './dialog/pipeline-categories/pipeline-categories-dialog.component'; import { zip } from 'rxjs'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { AuthService } from '../services/auth.service'; import { UserPrivilege } from '../_enums/user-privilege.enum'; +import { SpPipelineRoutes } from './pipelines.routes'; @Component({ selector: 'pipelines', @@ -56,13 +57,16 @@ constructor(private pipelineService: PipelineService, private dialogService: DialogService, private activatedRoute: ActivatedRoute, - private authService: AuthService) { + private authService: AuthService, + private router: Router, + private breadcrumbService: SpBreadcrumbService) { this.pipelineCategories = []; this.starting = false; this.stopping = false; } ngOnInit() { + this.breadcrumbService.updateBreadcrumb(this.breadcrumbService.getRootLink(SpPipelineRoutes.BASE)); this.authService.user$.subscribe(user => { this.hasPipelineWritePrivileges = this.authService.hasRole(UserPrivilege.PRIVILEGE_WRITE_PIPELINE); }); @@ -192,4 +196,8 @@ showPipeline(pipeline) { pipeline.display = !pipeline.display; } + + navigateToPipelineEditor() { + this.router.navigate(['pipelines', 'create']); + } }
diff --git a/ui/src/app/pipelines/pipelines.module.ts b/ui/src/app/pipelines/pipelines.module.ts index 0049362..17ca3ec 100644 --- a/ui/src/app/pipelines/pipelines.module.ts +++ b/ui/src/app/pipelines/pipelines.module.ts
@@ -39,6 +39,14 @@ import { PipelineNotificationsComponent } from './dialog/pipeline-notifications/pipeline-notifications.component'; import { CoreUiModule } from '../core-ui/core-ui.module'; import { PlatformServicesModule } from '@streampipes/platform-services'; +import { SharedUiModule } from '../../../projects/streampipes/shared-ui/src/lib/shared-ui.module'; +import { EditorModule } from '../editor/editor.module'; +import { PipelineDetailsModule } from '../pipeline-details/pipeline-details.module'; +import { RouterModule } from '@angular/router'; +import { EditorComponent } from '../editor/editor.component'; +import { SpPipelineDetailsOverviewComponent } from '../pipeline-details/components/overview/pipeline-details-overview.component'; +import { PipelineMonitoringComponent } from '../pipeline-details/components/monitoring/pipeline-monitoring.component'; +import { QuickEditComponent } from '../pipeline-details/components/edit/quickedit.component'; @NgModule({ imports: [ @@ -53,6 +61,50 @@ MatTableModule, CoreUiModule, PlatformServicesModule, + EditorModule, + PipelineDetailsModule, + SharedUiModule, + RouterModule.forChild([ + { + path: 'pipelines', + children: [ + { + path: '', + component: PipelinesComponent + }, + { + path: 'details/:pipelineId', + children: [ + { + path: '', + redirectTo: 'overview', + pathMatch: 'full' + }, + { + path: 'overview', + component: SpPipelineDetailsOverviewComponent, + }, + { + path: 'monitoring', + component: PipelineMonitoringComponent, + }, + { + path: 'quick-edit', + component: QuickEditComponent, + } + ] + }, + { + path: 'create', + component: EditorComponent + }, + { + path: 'modify/:pipelineId', + component: EditorComponent + } + ] + } + ]), ], declarations: [ DeletePipelineDialogComponent,
diff --git a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss b/ui/src/app/pipelines/pipelines.routes.ts similarity index 81% copy from ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss copy to ui/src/app/pipelines/pipelines.routes.ts index 58ba04b..5b4ccc7 100644 --- a/ui/src/app/connect/components/schema-editor/error-message/error-message.component.scss +++ b/ui/src/app/pipelines/pipelines.routes.ts
@@ -16,3 +16,10 @@ * */ +import { SpBreadcrumbItem, } from '@streampipes/shared-ui'; + +export class SpPipelineRoutes { + + static BASE: SpBreadcrumbItem = {label: 'Pipelines', link: ['pipelines']}; + +}
diff --git a/ui/src/app/pipelines/services/pipeline-operations.service.ts b/ui/src/app/pipelines/services/pipeline-operations.service.ts index 0135fca..997d0f1 100644 --- a/ui/src/app/pipelines/services/pipeline-operations.service.ts +++ b/ui/src/app/pipelines/services/pipeline-operations.service.ts
@@ -141,12 +141,12 @@ }); } - showPipelineInEditor(id) { - this.router.navigate(['editor'], { queryParams: { pipeline: id }}); + showPipelineInEditor(id: string) { + this.router.navigate(['pipelines', 'modify', id]); } - showPipelineDetails(id) { - this.router.navigate(['pipeline-details'], { queryParams: { pipeline: id }}); + showPipelineDetails(id: string) { + this.router.navigate(['pipelines', 'details', id]); } modifyPipeline(pipeline) {
diff --git a/ui/src/app/profile/profile.component.ts b/ui/src/app/profile/profile.component.ts index 2687fb7..84dd97e 100644 --- a/ui/src/app/profile/profile.component.ts +++ b/ui/src/app/profile/profile.component.ts
@@ -17,6 +17,7 @@ */ import { Component, OnInit } from '@angular/core'; +import { SpBreadcrumbService } from '@streampipes/shared-ui'; @Component({ selector: 'profile', @@ -27,7 +28,11 @@ selectedIndex = 0; + constructor(private breadcrumbService: SpBreadcrumbService) { + } + ngOnInit(): void { + this.breadcrumbService.updateBreadcrumb([{label: 'Profile'}]); } selectedIndexChange(index: number) {
diff --git a/ui/src/app/services/auth.service.ts b/ui/src/app/services/auth.service.ts index ab8d5e7..feb406d 100644 --- a/ui/src/app/services/auth.service.ts +++ b/ui/src/app/services/auth.service.ts
@@ -177,6 +177,8 @@ return this.hasAnyRole(['ROLE_ADMIN']); case PageName.NOTIFICATIONS: return this.hasAnyRole(['ROLE_PIPELINE_ADMIN']); + case PageName.ASSETS: + return this.hasAnyRole(['ROLE_ADMIN']); case PageName.SETTINGS: return this.hasAnyRole(['ROLE_ADMIN']); default:
diff --git a/ui/src/assets/img/favicon/android-icon-144x144.png b/ui/src/assets/img/favicon/android-icon-144x144.png deleted file mode 100644 index f7bb667..0000000 --- a/ui/src/assets/img/favicon/android-icon-144x144.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/android-icon-192x192.png b/ui/src/assets/img/favicon/android-icon-192x192.png deleted file mode 100644 index 3cb803c..0000000 --- a/ui/src/assets/img/favicon/android-icon-192x192.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/android-icon-36x36.png b/ui/src/assets/img/favicon/android-icon-36x36.png deleted file mode 100644 index 937f4c1..0000000 --- a/ui/src/assets/img/favicon/android-icon-36x36.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/android-icon-48x48.png b/ui/src/assets/img/favicon/android-icon-48x48.png deleted file mode 100644 index f293d4c..0000000 --- a/ui/src/assets/img/favicon/android-icon-48x48.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/android-icon-72x72.png b/ui/src/assets/img/favicon/android-icon-72x72.png deleted file mode 100644 index 371718e..0000000 --- a/ui/src/assets/img/favicon/android-icon-72x72.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/android-icon-96x96.png b/ui/src/assets/img/favicon/android-icon-96x96.png deleted file mode 100644 index 92f2f5a..0000000 --- a/ui/src/assets/img/favicon/android-icon-96x96.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/apple-icon-114x114.png b/ui/src/assets/img/favicon/apple-icon-114x114.png deleted file mode 100644 index c46d66d..0000000 --- a/ui/src/assets/img/favicon/apple-icon-114x114.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/apple-icon-120x120.png b/ui/src/assets/img/favicon/apple-icon-120x120.png deleted file mode 100644 index e534180..0000000 --- a/ui/src/assets/img/favicon/apple-icon-120x120.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/apple-icon-144x144.png b/ui/src/assets/img/favicon/apple-icon-144x144.png deleted file mode 100644 index f7bb667..0000000 --- a/ui/src/assets/img/favicon/apple-icon-144x144.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/apple-icon-152x152.png b/ui/src/assets/img/favicon/apple-icon-152x152.png deleted file mode 100644 index f602ff3..0000000 --- a/ui/src/assets/img/favicon/apple-icon-152x152.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/apple-icon-180x180.png b/ui/src/assets/img/favicon/apple-icon-180x180.png deleted file mode 100644 index e737774..0000000 --- a/ui/src/assets/img/favicon/apple-icon-180x180.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/apple-icon-57x57.png b/ui/src/assets/img/favicon/apple-icon-57x57.png deleted file mode 100644 index 251772f..0000000 --- a/ui/src/assets/img/favicon/apple-icon-57x57.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/apple-icon-60x60.png b/ui/src/assets/img/favicon/apple-icon-60x60.png deleted file mode 100644 index ecc0c22..0000000 --- a/ui/src/assets/img/favicon/apple-icon-60x60.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/apple-icon-72x72.png b/ui/src/assets/img/favicon/apple-icon-72x72.png deleted file mode 100644 index 371718e..0000000 --- a/ui/src/assets/img/favicon/apple-icon-72x72.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/apple-icon-76x76.png b/ui/src/assets/img/favicon/apple-icon-76x76.png deleted file mode 100644 index 3ed8f32..0000000 --- a/ui/src/assets/img/favicon/apple-icon-76x76.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/apple-icon-precomposed.png b/ui/src/assets/img/favicon/apple-icon-precomposed.png deleted file mode 100644 index d81fe77..0000000 --- a/ui/src/assets/img/favicon/apple-icon-precomposed.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/apple-icon.png b/ui/src/assets/img/favicon/apple-icon.png deleted file mode 100644 index d81fe77..0000000 --- a/ui/src/assets/img/favicon/apple-icon.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/favicon-16x16.png b/ui/src/assets/img/favicon/favicon-16x16.png deleted file mode 100644 index 8487ca2..0000000 --- a/ui/src/assets/img/favicon/favicon-16x16.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/favicon-32x32.png b/ui/src/assets/img/favicon/favicon-32x32.png deleted file mode 100644 index 11587ee..0000000 --- a/ui/src/assets/img/favicon/favicon-32x32.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/ms-icon-144x144.png b/ui/src/assets/img/favicon/ms-icon-144x144.png deleted file mode 100644 index f7bb667..0000000 --- a/ui/src/assets/img/favicon/ms-icon-144x144.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/ms-icon-150x150.png b/ui/src/assets/img/favicon/ms-icon-150x150.png deleted file mode 100644 index 98e5129..0000000 --- a/ui/src/assets/img/favicon/ms-icon-150x150.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/ms-icon-310x310.png b/ui/src/assets/img/favicon/ms-icon-310x310.png deleted file mode 100644 index b9b4fa9..0000000 --- a/ui/src/assets/img/favicon/ms-icon-310x310.png +++ /dev/null Binary files differ
diff --git a/ui/src/assets/img/favicon/ms-icon-70x70.png b/ui/src/assets/img/favicon/ms-icon-70x70.png deleted file mode 100644 index 67ae884..0000000 --- a/ui/src/assets/img/favicon/ms-icon-70x70.png +++ /dev/null Binary files differ
diff --git a/ui/src/scss/_variables.scss b/ui/src/scss/_variables.scss index e440d68..5d137a4 100644 --- a/ui/src/scss/_variables.scss +++ b/ui/src/scss/_variables.scss
@@ -16,7 +16,7 @@ * */ -$sp-color-primary: rgb(57, 181, 74); +$sp-color-primary: rgb(57, 181, 74); $sp-color-primary-light: rgb(59, 205, 76); $sp-color-accent: #1b1464; $sp-color-accent-light-blue: rgb(59, 92, 149); @@ -29,3 +29,14 @@ $sp-color-sink: #3F51B5; $sp-color-error: #B71C1C; + +body { + --color-data-view: rgb(122, 206, 227); + --color-dashboard: rgb(76, 115, 164); + --color-adapter: rgb(182, 140, 97); + --color-data-source: #ffa23b; + --color-pipeline: rgb(102, 185, 114); + --color-measurement: rgb(39, 164, 155); + --color-file: rgb(163, 98, 190); + +}
diff --git a/ui/src/scss/main.scss b/ui/src/scss/main.scss index 083b9b7..c50faa0 100644 --- a/ui/src/scss/main.scss +++ b/ui/src/scss/main.scss
@@ -37,7 +37,6 @@ @import './sp/main'; @import './sp/data-explorer'; -@import './sp/loading-bar'; @import './sp/buttons'; @import './sp/buttons.ng1'; @import './sp/spinner';
diff --git a/ui/src/scss/sp/layout.scss b/ui/src/scss/sp/layout.scss index 2ed1065..408188e 100644 --- a/ui/src/scss/sp/layout.scss +++ b/ui/src/scss/sp/layout.scss
@@ -88,6 +88,9 @@ margin-right: 5px; } +.ml-5 { + margin-left: 5px; +} .mr-15 { margin-right: 15px; @@ -163,3 +166,40 @@ .mat-expansion-panel-body { padding: 0 !important; } + +.small-select mat-select { + background-color: rgba(58, 40, 8, 0.12); + padding: 6px 10px 6px 10px; + box-sizing: border-box; + border-radius: 5px; +} + +.small-select .mat-select-value { + font-size: 16px; + color: var(--color-accent); +} + +.small-select .mat-form-field-underline { + display: none; +} + +.small-select mat-select-trigger div>i { + margin-right: 8px; +} + +.small-select .mat-form-field-infix { + padding: 0; + border-top: 0; +} + +.small-select .mat-form-field-wrapper { + padding-bottom: 0; +} + +.large-checkbox .mat-checkbox-inner-container { + width: 20px; + height: 20px; +} + +.mat-menu-panel.large-menu { max-width: none; } +
diff --git a/ui/src/scss/sp/loading-bar.scss b/ui/src/scss/sp/loading-bar.scss deleted file mode 100644 index e50006b..0000000 --- a/ui/src/scss/sp/loading-bar.scss +++ /dev/null
@@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#loading-bar .bar { - -webkit-transition: width 350ms; - -moz-transition: width 350ms; - -o-transition: width 350ms; - transition: width 350ms; - - background: $sp-color-accent; - position: fixed; - z-index: 10002; - top: 0px; - left: 0; - width: 100%; - height: 3px; - border-bottom-right-radius: 1px; - border-top-right-radius: 1px; -} - -#loading-bar-spinner .spinner-icon { - width: 14px; - height: 14px; - - border: solid 2px transparent; - border-top-color: $sp-color-accent; - border-left-color: $sp-color-accent; - border-radius: 50%; - - -webkit-animation: loading-bar-spinner 400ms linear infinite; - -moz-animation: loading-bar-spinner 400ms linear infinite; - -ms-animation: loading-bar-spinner 400ms linear infinite; - -o-animation: loading-bar-spinner 400ms linear infinite; - animation: loading-bar-spinner 400ms linear infinite; -} \ No newline at end of file
diff --git a/ui/src/scss/sp/main.scss b/ui/src/scss/sp/main.scss index 69dfbbb..a934bee 100644 --- a/ui/src/scss/sp/main.scss +++ b/ui/src/scss/sp/main.scss
@@ -367,10 +367,14 @@ .page-container { margin: 10px; border: 1px solid var(--color-bg-3); - min-height: calc(100% - 20px); + min-height: calc(100% - 60px); //height: 100%; } +.sp-full-height { + min-height: calc(100% - 20px); +} + .page-container-padding-inner { margin: 10px; } @@ -911,7 +915,7 @@ padding: 5px; border: 1px solid var(--color-bg-2); height: 300px; - width: 100%; + max-width: 100%; background-color: var(--color-bg-1); background-image: var(--canvas-color);
diff --git a/ui/src/scss/sp/mat-tab.scss b/ui/src/scss/sp/mat-tab.scss index 6549b2e..66c20ba 100644 --- a/ui/src/scss/sp/mat-tab.scss +++ b/ui/src/scss/sp/mat-tab.scss
@@ -18,4 +18,10 @@ .mat-tab-label-content { text-transform: uppercase; -} \ No newline at end of file +} + +.small .mat-tab-label { + min-width: 100px; + height: 32px; + font-size: 10pt; +}
diff --git a/ui/src/scss/sp/widgets.scss b/ui/src/scss/sp/widgets.scss index 58f8c6e..fca4f06 100644 --- a/ui/src/scss/sp/widgets.scss +++ b/ui/src/scss/sp/widgets.scss
@@ -42,14 +42,17 @@ .general-options-panel { margin-top: 4px; - margin-bottom: 4px; + margin-bottom: 8px; border: 1px solid var(--color-bg-3); background: var(--color-bg-1); padding: 5px; } .general-options-header { - margin-right: 10px; + //margin-right: 10px; margin-bottom: 10px; font-weight: bold; + border-left: 4px solid var(--color-primary); + padding-left: 5px; + font-size: 13pt; }
diff --git a/ui/webpack.partial.base.js b/ui/webpack.partial.base.js index f2930c2..6e34715 100644 --- a/ui/webpack.partial.base.js +++ b/ui/webpack.partial.base.js
@@ -66,9 +66,15 @@ "@angular/forms": { singleton: true, strictVersion: true, requiredVersion: 'auto' , eager: true}, "@angular/router": { singleton: true, strictVersion: true, requiredVersion: 'auto' , eager: true}, "@angular/cdk": { singleton: true, strictVersion: true, requiredVersion: 'auto' , eager: true}, + "@angular/cdk/overlay": { singleton: true, strictVersion: false, requiredVersion: 'auto', eager: true}, + "@angular/cdk/portal": { singleton: true, strictVersion: false, requiredVersion: 'auto', eager: true}, "@angular/material": { singleton: true, strictVersion: true, requiredVersion:'auto', eager: true}, + "@angular/material/core": { singleton: true, strictVersion: false, requiredVersion: 'auto', eager: true}, + "@angular/material/menu": { singleton: true, strictVersion: false, requiredVersion: 'auto', eager: true}, "@angular/material/tooltip": { singleton: true, strictVersion: true, requiredVersion:'auto', eager: true }, "@angular/material/dialog": { singleton: true, strictVersion: true, requiredVersion:'auto', eager: true }, + "@angular/material/select": { singleton: true, strictVersion: true, requiredVersion:'auto', eager: true }, + "@angular/material/form-field": { singleton: true, strictVersion: true, requiredVersion:'auto', eager: true }, "@streampipes/shared-ui": { singleton: true, strictVersion: true, eager: true}, "@streampipes/platform-services": { singleton: true, strictVersion: true, eager: true}, ...sharedMappings.getDescriptors()