You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by ri...@apache.org on 2022/08/21 08:40:11 UTC
[incubator-streampipes] branch dev updated: [STREAMPIPES-545] Improve assignment of multiple resource links
This is an automated email from the ASF dual-hosted git repository.
riemer pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git
The following commit(s) were added to refs/heads/dev by this push:
new 4f2617913 [STREAMPIPES-545] Improve assignment of multiple resource links
4f2617913 is described below
commit 4f261791301ac5c2d7ba74bccbbdc2e50fc5efa7
Author: Dominik Riemer <do...@gmail.com>
AuthorDate: Sun Aug 21 10:40:01 2022 +0200
[STREAMPIPES-545] Improve assignment of multiple resource links
---
.../export/dataimport/ImportGenerator.java | 78 ++++++--
.../export/resolver/AbstractResolver.java | 3 +-
.../export/resolver/AdapterResolver.java | 3 +-
.../export/resolver/DataSourceResolver.java | 4 +-
.../AbstractPipelineElementResourceManager.java | 6 +-
.../couchdb/impl/AdapterInstanceStorageImpl.java | 2 +-
ui/src/app/assets/assets.module.ts | 4 +-
.../asset-details-panel.component.html | 1 +
.../asset-details-panel.component.ts | 19 ++
.../assets/dialog/base-asset-links.directive.ts | 97 +++++++++
.../edit-asset-link-dialog.component.ts | 79 +++-----
.../manage-asset-links-dialog.component.html | 216 +++++++++++++++++++++
.../manage-asset-links-dialog.component.scss | 31 +++
.../manage-asset-links-dialog.component.ts | 159 +++++++++++++++
.../event-schema/event-schema.component.ts | 14 +-
.../core/components/toolbar/toolbar.component.html | 2 +-
16 files changed, 642 insertions(+), 76 deletions(-)
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/ImportGenerator.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/ImportGenerator.java
index d2dbe2231..23bd41d53 100644
--- a/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/ImportGenerator.java
+++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/dataimport/ImportGenerator.java
@@ -24,6 +24,9 @@ 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;
@@ -32,6 +35,8 @@ import java.util.Map;
public abstract class ImportGenerator<T> {
+ private static final Logger LOG = LoggerFactory.getLogger(ImportGenerator.class);
+
protected ObjectMapper spMapper;
protected ObjectMapper defaultMapper;
@@ -45,44 +50,84 @@ public abstract class ImportGenerator<T> {
var manifest = getManifest(previewFiles);
- for (String assetId: manifest.getAssets()) {
- handleAsset(previewFiles, assetId);
+ 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()) {
- handleAdapter(asString(previewFiles.get(adapterId)), adapterId);
+ 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()) {
+ 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()) {
+ 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()) {
+ 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()) {
+ 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()) {
+ 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()) {
+ 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()) {
+ 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()) {
+ 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();
@@ -99,14 +144,23 @@ public abstract class ImportGenerator<T> {
}
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();
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AbstractResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AbstractResolver.java
index 8e085240f..c0bae151f 100644
--- a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AbstractResolver.java
+++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AbstractResolver.java
@@ -25,6 +25,7 @@ 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.Set;
import java.util.stream.Collectors;
@@ -61,7 +62,7 @@ public abstract class AbstractResolver<T> {
public abstract ExportItem convert(T document);
- public abstract void writeDocument(String document) throws JsonProcessingException;
+ 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
index c879d982c..681afbaab 100644
--- a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AdapterResolver.java
+++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/AdapterResolver.java
@@ -30,7 +30,7 @@ public class AdapterResolver extends AbstractResolver<AdapterDescription> {
@Override
public AdapterDescription findDocument(String resourceId) {
- var doc = getNoSqlStore().getAdapterInstanceStorage().getAdapter(resourceId);
+ var doc = getNoSqlStore().getAdapterInstanceStorage().getAdapter(resourceId);
doc.setRev(null);
doc.setSelectedEndpointUrl(null);
if (doc instanceof AdapterStreamDescription) {
@@ -67,4 +67,5 @@ public class AdapterResolver extends AbstractResolver<AdapterDescription> {
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/DataSourceResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataSourceResolver.java
index a38bc810a..98a338b8a 100644
--- a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataSourceResolver.java
+++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/DataSourceResolver.java
@@ -52,7 +52,9 @@ public class DataSourceResolver extends AbstractResolver<SpDataStream> {
boolean overrideDocument) throws JsonProcessingException {
var dataStream = deserializeDocument(document);
if (overrideDocument) {
- EventGroundingProcessor.applyOverride(dataStream.getEventGrounding().getTransportProtocol());
+ if (dataStream.getEventGrounding() != null) {
+ EventGroundingProcessor.applyOverride(dataStream.getEventGrounding().getTransportProtocol());
+ }
}
getNoSqlStore().getDataStreamStorage().createElement(dataStream);
}
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 90b31c39d..ad77da9aa 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 abstract class AbstractPipelineElementResourceManager<T extends CRUDStora
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-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 da84fb826..ff6540b98 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 @@ public class AdapterInstanceStorageImpl extends AbstractDao<AdapterDescription>
@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/ui/src/app/assets/assets.module.ts b/ui/src/app/assets/assets.module.ts
index f3417b778..89d9314cc 100644
--- a/ui/src/app/assets/assets.module.ts
+++ b/ui/src/app/assets/assets.module.ts
@@ -43,6 +43,7 @@ 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: [
@@ -93,7 +94,8 @@ import { SpCreateAssetDialogComponent } from './dialog/create-asset/create-asset
SpAssetLinkItemComponent,
SpAssetOverviewComponent,
SpAssetSelectionPanelComponent,
- SpCreateAssetDialogComponent
+ SpCreateAssetDialogComponent,
+ SpManageAssetLinksDialogComponent
],
providers: [],
})
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
index 064bfa416..a3cc3d1fd 100644
--- 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
@@ -39,6 +39,7 @@
<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">
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
index 6d8e3d66b..9bb97559c 100644
--- 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
@@ -22,6 +22,7 @@ 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({
@@ -53,6 +54,24 @@ export class SpAssetDetailsPanelComponent implements OnInit {
});
}
+ 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,
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 000000000..79002369b
--- /dev/null
+++ b/ui/src/app/assets/dialog/base-asset-links.directive.ts
@@ -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.
+ *
+ */
+
+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
+ ];
+ });
+ }
+
+ abstract afterResourcesLoaded(): void;
+}
+
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
index fee3b0d9e..0a1b8b6f5 100644
--- 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
@@ -36,13 +36,14 @@ import {
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 implements OnInit {
+export class EditAssetLinkDialogComponent extends BaseAssetLinksDirective implements OnInit {
@Input()
assetLink: AssetLink;
@@ -57,33 +58,33 @@ export class EditAssetLinkDialogComponent implements OnInit {
clonedAssetLink: AssetLink;
- // Resources
- pipelines: Pipeline[];
- dataViews: Dashboard[];
- dashboards: Dashboard[];
- dataLakeMeasures: DataLakeMeasure[];
- dataSources: SpDataStream[];
- adapters: AdapterDescriptionUnion[];
- files: FileMetadata[];
- allResources: any[] = [];
currentResource: any;
selectedLinkType: AssetLinkType;
constructor(private dialogRef: DialogRef<EditAssetLinkDialogComponent>,
- private genericStorageService: GenericStorageService,
- private pipelineService: PipelineService,
- private dataViewService: DataViewDataExplorerService,
- private dashboardService: DashboardService,
- private dataLakeService: DatalakeRestService,
- private pipelineElementService: PipelineElementService,
- private adapterService: AdapterService,
- private filesService: FilesService) {
+ 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 {
- this.getAllResources();
+ super.onInit();
this.clonedAssetLink = {...this.assetLink};
this.selectedLinkType = this.getCurrAssetLinkType();
}
@@ -101,39 +102,6 @@ export class EditAssetLinkDialogComponent implements OnInit {
this.dialogRef.close();
}
- getAllResources() {
- zip(
- this.pipelineService.getOwnPipelines(),
- this.dataViewService.getDataViews(),
- this.dashboardService.getDashboards(),
- this.pipelineElementService.getDataStreams(),
- this.dataLakeService.getAllMeasurementSeries(),
- this.filesService.getFileMetadata(),
- this.adapterService.getAdapters()).subscribe(response => {
- this.pipelines = response[0];
- this.dataViews = response[1];
- this.dashboards = response[2];
- this.dataSources = response[3];
- this.dataLakeMeasures = response[4];
- this.files = response[5];
- this.adapters = response[6];
-
- this.allResources = [
- ...this.pipelines,
- ...this.dataViews,
- ...this.dashboards,
- ...this.dataSources,
- ...this.dataLakeMeasures,
- ...this.files,
- ...this.adapters
- ];
- if (!this.createMode) {
- this.currentResource = this.allResources.find(r => r._id === this.clonedAssetLink.resourceId ||
- r.elementId === this.clonedAssetLink.resourceId);
- }
- });
- }
-
onLinkTypeChanged(event: MatSelectChange): void {
this.selectedLinkType = event.value;
const linkType = this.assetLinkTypes.find(a => a.linkType === this.selectedLinkType.linkType);
@@ -149,4 +117,11 @@ export class EditAssetLinkDialogComponent implements OnInit {
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 000000000..eba2f811f
--- /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/assets/dialog/manage-asset-links/manage-asset-links-dialog.component.scss b/ui/src/app/assets/dialog/manage-asset-links/manage-asset-links-dialog.component.scss
new file mode 100644
index 000000000..c7debbd6e
--- /dev/null
+++ b/ui/src/app/assets/dialog/manage-asset-links/manage-asset-links-dialog.component.scss
@@ -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 '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 000000000..320bf835a
--- /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/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.ts b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.ts
index 76d9bdaf1..b18a8e13c 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.ts
+++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.ts
@@ -146,6 +146,7 @@ export class EventSchemaComponent implements OnChanges {
this.nodes = new Array<EventProperty>();
this.nodes.push(this.eventSchema as unknown as EventProperty);
this.validEventSchema = this.checkIfValid(this.eventSchema);
+ this.updatePreview();
}
public addNestedProperty(eventProperty?: EventPropertyNested): void {
@@ -213,10 +214,15 @@ export class EventSchemaComponent implements OnChanges {
this.transformationRuleService.setOldEventSchema(this.oldEventSchema);
this.transformationRuleService.setNewEventSchema(this.eventSchema);
const ruleDescriptions = this.transformationRuleService.getTransformationRuleDescriptions();
- this.restService.getAdapterEventPreview({rules: ruleDescriptions, inputData: this.eventPreview[0]}).subscribe(preview => {
- this.desiredPreview = preview;
- this.isPreviewEnabled = true;
- });
+ 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) {
diff --git a/ui/src/app/core/components/toolbar/toolbar.component.html b/ui/src/app/core/components/toolbar/toolbar.component.html
index b64c19756..2767609f5 100644
--- a/ui/src/app/core/components/toolbar/toolbar.component.html
+++ b/ui/src/app/core/components/toolbar/toolbar.component.html
@@ -34,7 +34,7 @@
<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="bottom">
+ matTooltip="Notifications" matTooltipPosition="below">
<mat-icon [matBadge]="unreadNotificationCount"
matBadgeColor="accent"
matBadgePosition="below after"