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/streampipes.git
The following commit(s) were added to refs/heads/dev by this push:
new dd8213ef52 feat(#3141): Add option to configure production sites
(#3142)
dd8213ef52 is described below
commit dd8213ef521160908552904878a955d781096dd5
Author: Dominik Riemer <[email protected]>
AuthorDate: Fri Aug 16 17:01:37 2024 +0200
feat(#3141): Add option to configure production sites (#3142)
* feat(#3141): Add option to configure production sites
* Add headers
* Fix import
* feat: Show asset location on map
* Remove scss
* Fix formatting
---
.../model/configuration/LocationConfig.java | 12 +-
.../model/configuration/SpCoreConfiguration.java | 10 ++
.../apache/streampipes/rest/ResetManagement.java | 42 +++++--
.../impl/admin/LocationConfigurationResource.java | 53 +++++++++
...ConfigutationUtils.ts => ConfigurationUtils.ts} | 8 ++
.../support/utils/configuration/SiteUtils.ts | 65 +++++++++++
.../tests/assetManagement/createAsset.spec.ts | 2 +-
.../sites/sites-geo-features.spec.ts} | 35 +++---
ui/cypress/tests/configuration/sites/sites.spec.ts | 64 ++++++++++
.../src/lib/apis/datalake-rest.service.ts | 32 +----
.../src/lib/apis/location-config.service.ts | 48 ++++++++
.../src/lib/model/assets/asset.model.ts | 29 ++++-
.../src/lib/model/gen/streampipes-model.ts | 71 ++++--------
.../platform-services/src/public-api.ts | 1 +
.../basic-field-description.component.html | 3 +-
ui/src/app/assets/assets.module.ts | 4 +
.../asset-details-basics.component.html | 19 ++-
.../asset-details-basics.component.ts | 38 ++++--
.../asset-details-labels.component.ts | 2 +-
.../asset-details-site.component.html | 46 ++++++++
.../asset-details-site.component.ts | 63 ++++++++++
.../asset-location/asset-location.component.html} | 26 +++--
.../asset-location/asset-location.component.ts} | 31 ++---
.../asset-details-links.component.html | 4 +-
.../asset-details-links.component.ts | 2 +-
.../asset-link-item/asset-link-item.component.ts | 2 +-
.../asset-link-section.component.html | 4 +-
.../asset-link-section.component.ts | 2 +-
.../asset-details-panel.component.html | 10 +-
.../asset-details-panel.component.ts | 10 +-
.../asset-details/asset-details.component.html | 12 +-
.../asset-details/asset-details.component.ts | 47 +++++---
.../asset-selection-panel.component.html | 4 +-
.../asset-selection-panel.component.ts | 10 +-
.../asset-overview/asset-overview.component.ts | 2 +-
ui/src/app/assets/constants/asset.constants.ts | 1 +
ui/src/app/configuration/configuration-tabs.ts | 5 +
ui/src/app/configuration/configuration.module.ts | 18 +++
ui/src/app/configuration/configuration.routes.ts | 1 -
.../edit-location-area.component.html | 68 +++++++++++
.../edit-location-area.component.scss} | 15 ++-
.../edit-location-area.component.ts} | 26 +++--
.../edit-location/edit-location.component.html | 59 ++++++++++
.../edit-location/edit-location.component.ts} | 16 ++-
.../manage-site/manage-site-dialog.component.html | 52 +++++++++
.../manage-site/manage-site-dialog.component.scss} | 21 +++-
.../manage-site/manage-site-dialog.component.ts | 83 +++++++++++++
.../location-features-configuration.component.html | 83 +++++++++++++
.../location-features-configuration.component.ts | 107 +++++++++++++++++
.../site-area-configuration.component.html | 80 +++++++++++++
.../site-area-configuration.component.ts | 88 ++++++++++++++
.../sites-configuration.component.html} | 21 ++--
.../sites-configuration.component.ts} | 30 +++--
ui/src/app/core-ui/core-ui.module.ts | 5 +
.../single-marker-map.component.html} | 19 ++-
.../single-marker-map.component.ts | 129 +++++++++++++++++++++
56 files changed, 1481 insertions(+), 259 deletions(-)
diff --git a/ui/src/app/configuration/configuration.routes.ts
b/streampipes-model/src/main/java/org/apache/streampipes/model/configuration/LocationConfig.java
similarity index 73%
copy from ui/src/app/configuration/configuration.routes.ts
copy to
streampipes-model/src/main/java/org/apache/streampipes/model/configuration/LocationConfig.java
index 14ac644c49..573e9abe70 100644
--- a/ui/src/app/configuration/configuration.routes.ts
+++
b/streampipes-model/src/main/java/org/apache/streampipes/model/configuration/LocationConfig.java
@@ -16,9 +16,11 @@
*
*/
-import { SpBreadcrumbItem } from '@streampipes/shared-ui';
+package org.apache.streampipes.model.configuration;
-export class SpConfigurationRoutes {
- static CONFIGURATION_BASE_LINK = 'configuration';
- static BASE: SpBreadcrumbItem = { label: 'Configuration' };
-}
+import org.apache.streampipes.model.shared.annotation.TsModel;
+
+@TsModel
+public record LocationConfig(boolean locationEnabled,
+ String tileServerUrl,
+ String attributionText) {}
diff --git
a/streampipes-model/src/main/java/org/apache/streampipes/model/configuration/SpCoreConfiguration.java
b/streampipes-model/src/main/java/org/apache/streampipes/model/configuration/SpCoreConfiguration.java
index 6aad62a172..b5766bd3f6 100644
---
a/streampipes-model/src/main/java/org/apache/streampipes/model/configuration/SpCoreConfiguration.java
+++
b/streampipes-model/src/main/java/org/apache/streampipes/model/configuration/SpCoreConfiguration.java
@@ -32,6 +32,7 @@ public class SpCoreConfiguration {
private EmailConfig emailConfig;
private EmailTemplateConfig emailTemplateConfig;
private GeneralConfig generalConfig;
+ private LocationConfig locationConfig;
private boolean isConfigured;
private SpCoreConfigurationStatus serviceStatus;
@@ -40,6 +41,7 @@ public class SpCoreConfiguration {
private String filesDir;
public SpCoreConfiguration() {
+ this.locationConfig = new LocationConfig(false, "", "");
}
public String getRev() {
@@ -129,4 +131,12 @@ public class SpCoreConfiguration {
public void setServiceStatus(SpCoreConfigurationStatus serviceStatus) {
this.serviceStatus = serviceStatus;
}
+
+ public LocationConfig getLocationConfig() {
+ return locationConfig;
+ }
+
+ public void setLocationConfig(LocationConfig locationConfig) {
+ this.locationConfig = locationConfig;
+ }
}
diff --git
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/ResetManagement.java
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/ResetManagement.java
index 5bce889136..caca0dac6c 100644
---
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/ResetManagement.java
+++
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/ResetManagement.java
@@ -83,6 +83,8 @@ public class ResetManagement {
removeAllPipelineTemplates();
+ clearGenericStorage();
+
logger.info("Resetting the system was completed");
}
@@ -106,7 +108,7 @@ public class ResetManagement {
private static void stopAndDeleteAllAdapters() {
AdapterMasterManagement adapterMasterManagement = new
AdapterMasterManagement(
StorageDispatcher.INSTANCE.getNoSqlStore()
- .getAdapterInstanceStorage(),
+ .getAdapterInstanceStorage(),
new SpResourceManager().manageAdapters(),
new SpResourceManager().manageDataStreams(),
AdapterMetricsManager.INSTANCE.getAdapterMetrics()
@@ -152,37 +154,37 @@ public class ResetManagement {
private static void removeAllDataViewWidgets() {
var widgetStorage =
StorageDispatcher.INSTANCE.getNoSqlStore()
- .getDataExplorerWidgetStorage();
+ .getDataExplorerWidgetStorage();
widgetStorage.findAll()
- .forEach(widget ->
widgetStorage.deleteElementById(widget.getElementId()));
+ .forEach(widget ->
widgetStorage.deleteElementById(widget.getElementId()));
}
private static void removeAllDataViews() {
var dataLakeDashboardStorage =
StorageDispatcher.INSTANCE.getNoSqlStore()
- .getDataExplorerDashboardStorage();
+ .getDataExplorerDashboardStorage();
dataLakeDashboardStorage.findAll()
- .forEach(dashboard ->
dataLakeDashboardStorage.deleteElementById(dashboard.getElementId()));
+ .forEach(dashboard ->
dataLakeDashboardStorage.deleteElementById(dashboard.getElementId()));
}
private static void removeAllDashboardWidgets() {
var dashboardWidgetStorage =
StorageDispatcher.INSTANCE.getNoSqlStore()
- .getDashboardWidgetStorage();
+ .getDashboardWidgetStorage();
dashboardWidgetStorage.findAll()
- .forEach(widget ->
dashboardWidgetStorage.deleteElementById(widget.getElementId()));
+ .forEach(widget ->
dashboardWidgetStorage.deleteElementById(widget.getElementId()));
}
private static void removeAllDashboards() {
var dashboardStorage = StorageDispatcher.INSTANCE.getNoSqlStore()
-
.getDashboardStorage();
+ .getDashboardStorage();
dashboardStorage.findAll()
- .forEach(dashboard ->
dashboardStorage.deleteElementById(dashboard.getElementId()));
+ .forEach(dashboard ->
dashboardStorage.deleteElementById(dashboard.getElementId()));
}
private static void removeAllAssets(String username) {
IGenericStorage genericStorage = StorageDispatcher.INSTANCE.getNoSqlStore()
-
.getGenericStorage();
+ .getGenericStorage();
try {
for (Map<String, Object> asset :
genericStorage.findAll("asset-management")) {
genericStorage.delete((String) asset.get("_id"), (String)
asset.get("_rev"));
@@ -203,4 +205,24 @@ public class ResetManagement {
.forEach(pipelineElementTemplateStorage::deleteElement);
}
+
+ private static void clearGenericStorage() {
+ var appDocTypesToDelete = List.of(
+ "asset-management",
+ "asset-sites"
+ );
+ var genericStorage =
StorageDispatcher.INSTANCE.getNoSqlStore().getGenericStorage();
+
+ appDocTypesToDelete.forEach(docType -> {
+ try {
+ var allDocs = genericStorage.findAll(docType);
+ for (var doc : allDocs) {
+ genericStorage.delete(doc.get("_id").toString(),
doc.get("_rev").toString());
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ }
}
diff --git
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/LocationConfigurationResource.java
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/LocationConfigurationResource.java
new file mode 100644
index 0000000000..7872efed0b
--- /dev/null
+++
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/LocationConfigurationResource.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.rest.impl.admin;
+
+import org.apache.streampipes.model.configuration.LocationConfig;
+import
org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource;
+import org.apache.streampipes.rest.security.AuthConstants;
+
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/api/v2/admin/location-config")
+public class LocationConfigurationResource extends
AbstractAuthGuardedRestResource {
+
+ @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
+ public LocationConfig getLocationConfig() {
+ return getSpCoreConfigurationStorage().get().getLocationConfig();
+ }
+
+ @PutMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
+ @PreAuthorize(AuthConstants.IS_ADMIN_ROLE)
+ public ResponseEntity<Void> updateGeneralConfiguration(@RequestBody
LocationConfig config) {
+ var storage = getSpCoreConfigurationStorage();
+ var cfg = storage.get();
+ cfg.setLocationConfig(config);
+ storage.updateElement(cfg);
+
+ return ok();
+ }
+}
diff --git a/ui/cypress/support/utils/configuration/ConfigutationUtils.ts
b/ui/cypress/support/utils/configuration/ConfigurationUtils.ts
similarity index 82%
copy from ui/cypress/support/utils/configuration/ConfigutationUtils.ts
copy to ui/cypress/support/utils/configuration/ConfigurationUtils.ts
index 44731e6e4f..f8148033e5 100644
--- a/ui/cypress/support/utils/configuration/ConfigutationUtils.ts
+++ b/ui/cypress/support/utils/configuration/ConfigurationUtils.ts
@@ -20,4 +20,12 @@ export class ConfigurationUtils {
public static goToConfigurationExport() {
cy.visit('#/configuration/export');
}
+
+ public static goToSitesConfiguration() {
+ cy.visit('#/configuration/sites');
+ }
+
+ public static goToGeneralConfiguration() {
+ cy.visit('#/configuration/general');
+ }
}
diff --git a/ui/cypress/support/utils/configuration/SiteUtils.ts
b/ui/cypress/support/utils/configuration/SiteUtils.ts
new file mode 100644
index 0000000000..59bbf0900e
--- /dev/null
+++ b/ui/cypress/support/utils/configuration/SiteUtils.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.
+ *
+ */
+
+export class SiteUtils {
+ public static CHECKBOX_ENABLE_LOCATION_FEATURES =
+ 'sites-enable-location-features-checkbox';
+ public static INPUT_TILE_SERVER_URL = 'sites-location-config-tile-server';
+
+ public static BUTTON_MANAGE_SITES = 'sites-manage-sites-button';
+ public static BUTTON_EDIT_SITE = 'sites-edit-button';
+ public static BUTTON_DELETE_SITE = 'sites-delete-button';
+ public static BUTTON_SITE_DIALOG_SAVE = 'sites-dialog-save-button';
+ public static BUTTON_SITE_DIALOG_CANCEL = 'sites-dialog-cancel-button';
+ public static BUTTON_SITE_DIALOG_REMOVE_AREA =
+ 'sites-dialog-remove-area-button';
+ public static BUTTON_SITE_DIALOG_ADD_AREA = 'sites-dialog-add-area-button';
+
+ public static INPUT_SITE_DIALOG_SITE_INPUT = 'sites-dialog-site-input';
+ public static INPUT_SITE_DIALOG_NEW_AREA_INPUT =
+ 'sites-dialog-new-area-input';
+
+ public static LABEL_TABLE_NAME = 'site-table-row-label';
+ public static LABEL_TABLE_AREA = 'site-table-row-areas';
+
+ public static enableGeoFeatures(tileServerUrl: string): void {
+ cy.dataCy(SiteUtils.CHECKBOX_ENABLE_LOCATION_FEATURES).click();
+ cy.dataCy(SiteUtils.INPUT_TILE_SERVER_URL).clear().type(tileServerUrl);
+ cy.dataCy('sites-location-features-button').click();
+ }
+
+ public static createNewSite(name: string, areas: string[]): void {
+ cy.dataCy(SiteUtils.BUTTON_MANAGE_SITES).click();
+ cy.dataCy(SiteUtils.INPUT_SITE_DIALOG_SITE_INPUT, { timeout: 2000 })
+ .clear()
+ .type(name);
+
+ areas.forEach(area => {
+ cy.dataCy(SiteUtils.INPUT_SITE_DIALOG_NEW_AREA_INPUT)
+ .clear()
+ .type(area);
+ cy.dataCy(SiteUtils.BUTTON_SITE_DIALOG_ADD_AREA).click();
+ });
+
+ cy.dataCy(this.BUTTON_SITE_DIALOG_SAVE).click();
+ }
+
+ public static openEditSiteDialog() {
+ cy.dataCy(SiteUtils.BUTTON_EDIT_SITE).first().click();
+ }
+}
diff --git a/ui/cypress/tests/assetManagement/createAsset.spec.ts
b/ui/cypress/tests/assetManagement/createAsset.spec.ts
index e52d7b500c..7f5171631a 100644
--- a/ui/cypress/tests/assetManagement/createAsset.spec.ts
+++ b/ui/cypress/tests/assetManagement/createAsset.spec.ts
@@ -20,7 +20,7 @@ import { AdapterBuilder } from
'../../support/builder/AdapterBuilder';
import { ConnectUtils } from '../../support/utils/connect/ConnectUtils';
import { AssetUtils } from '../../support/utils/asset/AssetUtils';
import { DashboardUtils } from '../../support/utils/DashboardUtils';
-import { ConfigurationUtils } from
'../../support/utils/configuration/ConfigutationUtils';
+import { ConfigurationUtils } from
'../../support/utils/configuration/ConfigurationUtils';
describe('Creates a new adapter, add to assets and export assets', () => {
beforeEach('Setup Test', () => {
diff --git
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-panel.component.ts
b/ui/cypress/tests/configuration/sites/sites-geo-features.spec.ts
similarity index 50%
copy from
ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-panel.component.ts
copy to ui/cypress/tests/configuration/sites/sites-geo-features.spec.ts
index e61b6d379b..4f8649f8e0 100644
---
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-panel.component.ts
+++ b/ui/cypress/tests/configuration/sites/sites-geo-features.spec.ts
@@ -16,21 +16,26 @@
*
*/
-import { Component, EventEmitter, Input, Output } from '@angular/core';
-import { SpAsset } from '@streampipes/platform-services';
+import { SiteUtils } from '../../../support/utils/configuration/SiteUtils';
+import { ConfigurationUtils } from
'../../../support/utils/configuration/ConfigurationUtils';
-@Component({
- selector: 'sp-asset-details-panel-component',
- templateUrl: './asset-details-panel.component.html',
- styleUrls: ['./asset-details-panel.component.scss'],
-})
-export class SpAssetDetailsPanelComponent {
- @Input()
- asset: SpAsset;
+describe('Test geo features settings', () => {
+ beforeEach('Setup Test', () => {
+ cy.initStreamPipesTest();
+ });
- @Input()
- editMode: boolean;
+ it('Perform Test', () => {
+ // enable geo features
+ ConfigurationUtils.goToSitesConfiguration();
+ SiteUtils.enableGeoFeatures('url');
- @Output()
- updateAssetEmitter: EventEmitter<SpAsset> = new EventEmitter<SpAsset>();
-}
+ ConfigurationUtils.goToGeneralConfiguration();
+ ConfigurationUtils.goToSitesConfiguration();
+
+ cy.dataCy(SiteUtils.CHECKBOX_ENABLE_LOCATION_FEATURES)
+ .find('input')
+ .should('be.checked');
+
+ cy.dataCy(SiteUtils.INPUT_TILE_SERVER_URL).should('have.value', 'url');
+ });
+});
diff --git a/ui/cypress/tests/configuration/sites/sites.spec.ts
b/ui/cypress/tests/configuration/sites/sites.spec.ts
new file mode 100644
index 0000000000..5b0fb8b861
--- /dev/null
+++ b/ui/cypress/tests/configuration/sites/sites.spec.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.
+ *
+ */
+
+import { SiteUtils } from '../../../support/utils/configuration/SiteUtils';
+import { ConfigurationUtils } from
'../../../support/utils/configuration/ConfigurationUtils';
+
+describe('Test configuration of sites', () => {
+ beforeEach('Setup Test', () => {
+ cy.initStreamPipesTest();
+ });
+
+ it('Perform Test', () => {
+ const site = 'My Site';
+ const newSite = 'My modified Site';
+ const areas = ['Area A', 'Area B'];
+ ConfigurationUtils.goToSitesConfiguration();
+ SiteUtils.createNewSite(site, areas);
+
+ cy.dataCy(SiteUtils.LABEL_TABLE_NAME).should('have.length', 1);
+
+ cy.dataCy(SiteUtils.LABEL_TABLE_NAME)
+ .first()
+ .should('contain.text', site);
+ cy.dataCy(SiteUtils.LABEL_TABLE_AREA)
+ .first()
+ .should('contains.text', areas.toString());
+
+ SiteUtils.openEditSiteDialog();
+
+ cy.dataCy(SiteUtils.INPUT_SITE_DIALOG_SITE_INPUT, { timeout: 2000 })
+ .clear()
+ .type(newSite);
+
+ cy.dataCy(SiteUtils.BUTTON_SITE_DIALOG_REMOVE_AREA +
'_Area_A').click();
+ cy.dataCy(SiteUtils.BUTTON_SITE_DIALOG_SAVE).click();
+
+ cy.dataCy(SiteUtils.LABEL_TABLE_NAME).should('have.length', 1);
+
+ cy.dataCy(SiteUtils.LABEL_TABLE_NAME)
+ .first()
+ .should('contain.text', newSite);
+ cy.dataCy(SiteUtils.LABEL_TABLE_AREA)
+ .first()
+ .should('have.text', ' Area B ');
+
+ cy.dataCy(SiteUtils.BUTTON_DELETE_SITE + '-My_modified_Site').click();
+ cy.dataCy(SiteUtils.LABEL_TABLE_NAME).should('have.length', 0);
+ });
+});
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 a8e8c8928f..a2cb61594b 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
@@ -19,11 +19,7 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http';
import { Observable, of } from 'rxjs';
-import {
- DataLakeMeasure,
- PageResult,
- SpQueryResult,
-} from '../model/gen/streampipes-model';
+import { DataLakeMeasure, SpQueryResult } from
'../model/gen/streampipes-model';
import { map } from 'rxjs/operators';
import { DatalakeQueryParameters } from
'../model/datalake/DatalakeQueryParameters';
@@ -103,32 +99,6 @@ export class DatalakeRestService {
}
}
- getPagedData(
- index: string,
- itemsPerPage: number,
- page: number,
- columns?: string,
- order?: string,
- ): Observable<PageResult> {
- const url = this.dataLakeUrl + '/measurements/' + index;
-
- const queryParams: DatalakeQueryParameters = this.getQueryParameters(
- columns,
- undefined,
- undefined,
- page,
- itemsPerPage,
- undefined,
- undefined,
- order,
- undefined,
- undefined,
- );
-
- // @ts-ignore
- return this.http.get<PageResult>(url, { params: queryParams });
- }
-
getTagValues(
index: string,
fieldNames: string[],
diff --git
a/ui/projects/streampipes/platform-services/src/lib/apis/location-config.service.ts
b/ui/projects/streampipes/platform-services/src/lib/apis/location-config.service.ts
new file mode 100644
index 0000000000..d07e8b8e13
--- /dev/null
+++
b/ui/projects/streampipes/platform-services/src/lib/apis/location-config.service.ts
@@ -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.
+ *
+ */
+
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+import { PlatformServicesCommons } from './commons.service';
+import { LocationConfig } from '../model/gen/streampipes-model';
+
+@Injectable({
+ providedIn: 'root',
+})
+export class LocationConfigService {
+ constructor(
+ private http: HttpClient,
+ private platformServicesCommons: PlatformServicesCommons,
+ ) {}
+
+ getLocationConfig(): Observable<LocationConfig> {
+ return this.http
+ .get(this.locationConfigPath)
+ .pipe(map(response => response as LocationConfig));
+ }
+
+ updateLocationConfig(config: LocationConfig): Observable<any> {
+ return this.http.put(this.locationConfigPath, config);
+ }
+
+ private get locationConfigPath() {
+ return
`${this.platformServicesCommons.apiBasePath}/admin/location-config`;
+ }
+}
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
index c1872f5f31..084b874214 100644
---
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
@@ -48,15 +48,40 @@ export interface Isa95TypeDesc {
type: Isa95Type;
}
+export interface AssetLocation {
+ coordinates: LatLng;
+ zoom?: number;
+}
+
+export interface AssetSiteDesc {
+ _id: string;
+ _rev?: string;
+ appDocType: string;
+ label: string;
+ location?: AssetLocation;
+ areas: string[];
+}
+
+export interface LatLng {
+ latitude: number;
+ longitude: number;
+}
+
+export interface AssetSite {
+ siteId: string;
+ area: string;
+ hasExactLocation: boolean;
+ location?: AssetLocation;
+}
+
export interface SpAsset {
assetId: string;
assetName: string;
assetDescription: string;
-
assetType: AssetType;
labelIds?: string[];
assetLinks: AssetLink[];
-
+ assetSite?: AssetSite;
assets: SpAsset[];
}
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 29b7a7f837..59568c24a9 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
@@ -20,11 +20,10 @@
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
-// Generated using typescript-generator version 3.2.1263 on 2024-07-29
21:03:44.
+// Generated using typescript-generator version 3.2.1263 on 2024-08-15
17:36:05.
export class NamedStreamPipesEntity implements Storable {
'@class':
- | 'org.apache.streampipes.model.connect.grounding.ProtocolDescription'
| 'org.apache.streampipes.model.template.PipelineTemplateDescription'
| 'org.apache.streampipes.model.SpDataStream'
| 'org.apache.streampipes.model.base.VersionedNamedStreamPipesEntity'
@@ -2137,6 +2136,26 @@ export class ListOutputStrategy extends OutputStrategy {
}
}
+export class LocationConfig {
+ attributionText: string;
+ locationEnabled: boolean;
+ tileServerUrl: string;
+
+ static fromData(
+ data: LocationConfig,
+ target?: LocationConfig,
+ ): LocationConfig {
+ if (!data) {
+ return data;
+ }
+ const instance = target || new LocationConfig();
+ instance.attributionText = data.attributionText;
+ instance.locationEnabled = data.locationEnabled;
+ instance.tileServerUrl = data.tileServerUrl;
+ return instance;
+ }
+}
+
export class MappingProperty extends StaticProperty {
'@class':
| 'org.apache.streampipes.model.staticproperty.MappingProperty'
@@ -2430,25 +2449,6 @@ export class Option {
}
}
-/**
- * @deprecated since 0.92.0, for removal
- */
-export class PageResult extends DataSeries {
- page: number;
- pageSum: number;
-
- static fromData(data: PageResult, target?: PageResult): PageResult {
- if (!data) {
- return data;
- }
- const instance = target || new PageResult();
- super.fromData(data, instance);
- instance.page = data.page;
- instance.pageSum = data.pageSum;
- return instance;
- }
-}
-
export class Pipeline implements Storable {
_id: string;
_rev: string;
@@ -3054,35 +3054,6 @@ export class PropertyValueSpecification {
}
}
-/**
- * @deprecated since 0.93.0, for removal
- */
-export class ProtocolDescription extends NamedStreamPipesEntity {
- '@class':
'org.apache.streampipes.model.connect.grounding.ProtocolDescription';
- 'category': string[];
- 'config': StaticPropertyUnion[];
- 'sourceType': string;
-
- static 'fromData'(
- data: ProtocolDescription,
- target?: ProtocolDescription,
- ): ProtocolDescription {
- if (!data) {
- return data;
- }
- const instance = target || new ProtocolDescription();
- super.fromData(data, instance);
- instance.category = __getCopyArrayFn(__identity<string>())(
- data.category,
- );
- instance.config = __getCopyArrayFn(StaticProperty.fromDataUnion)(
- data.config,
- );
- instance.sourceType = data.sourceType;
- return instance;
- }
-}
-
export class PulsarTransportProtocol extends TransportProtocol {
'@class': 'org.apache.streampipes.model.grounding.PulsarTransportProtocol';
diff --git a/ui/projects/streampipes/platform-services/src/public-api.ts
b/ui/projects/streampipes/platform-services/src/public-api.ts
index ce377827b3..8e0d2d428c 100644
--- a/ui/projects/streampipes/platform-services/src/public-api.ts
+++ b/ui/projects/streampipes/platform-services/src/public-api.ts
@@ -34,6 +34,7 @@ export * from './lib/apis/functions.service';
export * from './lib/apis/general-config.service';
export * from './lib/apis/generic-storage.service';
export * from './lib/apis/labels.service';
+export * from './lib/apis/location-config.service';
export * from './lib/apis/mail-config.service';
export * from './lib/apis/measurement-units.service';
export * from './lib/apis/permissions.service';
diff --git
a/ui/projects/streampipes/shared-ui/src/lib/components/basic-field-description/basic-field-description.component.html
b/ui/projects/streampipes/shared-ui/src/lib/components/basic-field-description/basic-field-description.component.html
index 83115501f2..a33844fb7d 100644
---
a/ui/projects/streampipes/shared-ui/src/lib/components/basic-field-description/basic-field-description.component.html
+++
b/ui/projects/streampipes/shared-ui/src/lib/components/basic-field-description/basic-field-description.component.html
@@ -19,7 +19,8 @@
<div
fxFlex="100"
fxLayout="row"
- fxLayoutAlign="start center"
+ fxLayoutGap="10px"
+ fxLayoutAlign="start start"
class="field-description-outer"
>
<div [fxFlex]="descriptionPanelWidth" fxLayout="column">
diff --git a/ui/src/app/assets/assets.module.ts
b/ui/src/app/assets/assets.module.ts
index c8adc3fa06..fc81b953f7 100644
--- a/ui/src/app/assets/assets.module.ts
+++ b/ui/src/app/assets/assets.module.ts
@@ -57,6 +57,8 @@ import { MatButtonToggleModule } from
'@angular/material/button-toggle';
import { AssetDetailsLabelsComponent } from
'./components/asset-details/asset-details-panel/asset-details-basics/asset-details-labels/asset-details-labels.component';
import { MatChipGrid, MatChipsModule } from '@angular/material/chips';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
+import { AssetDetailsSiteComponent } from
'./components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-details-site.component';
+import { AssetLocationComponent } from
'./components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-location/asset-location.component';
@NgModule({
imports: [
@@ -112,7 +114,9 @@ import { MatAutocompleteModule } from
'@angular/material/autocomplete';
AssetDetailsBasicsComponent,
AssetDetailsLabelsComponent,
AssetDetailsLinksComponent,
+ AssetDetailsSiteComponent,
AssetLinkSectionComponent,
+ AssetLocationComponent,
AssetUploadDialogComponent,
EditAssetLinkDialogComponent,
SpAssetDetailsComponent,
diff --git
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-basics.component.html
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-basics.component.html
index 71f9b00b9c..0cc81d4e70 100644
---
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-basics.component.html
+++
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-basics.component.html
@@ -100,12 +100,27 @@
label="Labels"
description="Assign additional labels to better discover your
assets"
>
- <sp-asset-details-labels-component
+ <sp-asset-details-labels
[asset]="asset"
[editMode]="editMode"
class="w-100"
>
- </sp-asset-details-labels-component>
+ </sp-asset-details-labels>
+ </sp-basic-field-description>
+ <sp-basic-field-description
+ *ngIf="rootNode"
+ fxFlex="100"
+ descriptionPanelWidth="30"
+ label="Sites"
+ description="Assign a location (site and area) to this asset"
+ >
+ <sp-asset-details-site
+ class="w-100"
+ [asset]="asset"
+ [sites]="sites"
+ [editMode]="editMode"
+ >
+ </sp-asset-details-site>
</sp-basic-field-description>
</div>
</div>
diff --git
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-basics.component.ts
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-basics.component.ts
index f84ef1fd3b..7315d5e4c4 100644
---
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-basics.component.ts
+++
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-basics.component.ts
@@ -16,37 +16,55 @@
*
*/
-import { Component, Input, OnInit } from '@angular/core';
import {
+ Component,
+ Input,
+ OnChanges,
+ OnInit,
+ SimpleChanges,
+} from '@angular/core';
+import {
+ AssetSiteDesc,
Isa95TypeDesc,
Isa95TypeService,
SpAsset,
} from '@streampipes/platform-services';
@Component({
- selector: 'sp-asset-details-basics-component',
+ selector: 'sp-asset-details-basics',
templateUrl: './asset-details-basics.component.html',
styleUrls: ['./asset-details-basics.component.scss'],
})
-export class AssetDetailsBasicsComponent implements OnInit {
+export class AssetDetailsBasicsComponent implements OnInit, OnChanges {
@Input()
asset: SpAsset;
@Input()
editMode: boolean;
+ @Input()
+ rootNode: boolean;
+
+ @Input()
+ sites: AssetSiteDesc[];
+
isa95Types: Isa95TypeDesc[] = [];
constructor(private isa95TypeService: Isa95TypeService) {}
ngOnInit() {
- this.asset.assetType ??= {
- assetIcon: undefined,
- assetIconColor: undefined,
- assetTypeCategory: undefined,
- assetTypeLabel: undefined,
- isa95AssetType: 'OTHER',
- };
this.isa95Types = this.isa95TypeService.getTypeDescriptions();
}
+
+ ngOnChanges(changes: SimpleChanges) {
+ if (changes['asset']) {
+ this.asset.assetType ??= {
+ assetIcon: undefined,
+ assetIconColor: undefined,
+ assetTypeCategory: undefined,
+ assetTypeLabel: undefined,
+ isa95AssetType: 'OTHER',
+ };
+ }
+ }
}
diff --git
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-labels/asset-details-labels.component.ts
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-labels/asset-details-labels.component.ts
index 445072cf5d..b26fbcde6a 100644
---
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-labels/asset-details-labels.component.ts
+++
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-labels/asset-details-labels.component.ts
@@ -39,7 +39,7 @@ import { map, startWith } from 'rxjs/operators';
import { SpColorizationService } from '@streampipes/shared-ui';
@Component({
- selector: 'sp-asset-details-labels-component',
+ selector: 'sp-asset-details-labels',
templateUrl: './asset-details-labels.component.html',
})
export class AssetDetailsLabelsComponent implements OnInit, OnChanges {
diff --git
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-details-site.component.html
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-details-site.component.html
new file mode 100644
index 0000000000..5b0c819560
--- /dev/null
+++
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-details-site.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.
+ ~
+ -->
+
+<div fxLayout="column">
+ <mat-form-field color="accent" class="w-100">
+ <mat-label>Site</mat-label>
+ <mat-select
+ [disabled]="!editMode"
+ [(ngModel)]="asset.assetSite.siteId"
+ (selectionChange)="handleLocationChange($event)"
+ >
+ <mat-option *ngFor="let site of sites" [value]="site._id">
+ {{ site.label }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+ <mat-form-field color="accent" class="w-100" *ngIf="currentSite">
+ <mat-label>Area</mat-label>
+ <mat-select [disabled]="!editMode" [(ngModel)]="asset.assetSite.area">
+ <mat-option *ngFor="let area of currentSite.areas" [value]="area">
+ {{ area }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+ <sp-asset-location
+ [asset]="asset"
+ [editMode]="editMode"
+ *ngIf="asset.assetSite?.siteId"
+ >
+ </sp-asset-location>
+</div>
diff --git
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-details-site.component.ts
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-details-site.component.ts
new file mode 100644
index 0000000000..50988ff75a
--- /dev/null
+++
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-details-site.component.ts
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
+import { AssetSiteDesc, SpAsset } from '@streampipes/platform-services';
+import { MatSelectChange } from '@angular/material/select';
+
+@Component({
+ selector: 'sp-asset-details-site',
+ templateUrl: './asset-details-site.component.html',
+})
+export class AssetDetailsSiteComponent implements OnChanges {
+ @Input()
+ asset: SpAsset;
+
+ @Input()
+ editMode: boolean;
+
+ @Input()
+ sites: AssetSiteDesc[];
+
+ currentSite: AssetSiteDesc;
+
+ constructor() {}
+
+ ngOnChanges(changes: SimpleChanges) {
+ if (changes['asset']) {
+ this.asset.assetSite ??= {
+ area: undefined,
+ siteId: undefined,
+ hasExactLocation: false,
+ };
+ if (this.sites.length > 0) {
+ if (this.asset.assetSite.siteId !== undefined) {
+ this.selectCurrentSite(this.asset.assetSite.siteId);
+ }
+ }
+ }
+ }
+
+ handleLocationChange(event: MatSelectChange) {
+ this.selectCurrentSite(event.value);
+ }
+
+ selectCurrentSite(siteId: string): void {
+ this.currentSite = this.sites.find(loc => loc._id === siteId);
+ }
+}
diff --git
a/ui/projects/streampipes/shared-ui/src/lib/components/basic-field-description/basic-field-description.component.html
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-location/asset-location.component.html
similarity index 63%
copy from
ui/projects/streampipes/shared-ui/src/lib/components/basic-field-description/basic-field-description.component.html
copy to
ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-location/asset-location.component.html
index 83115501f2..64443f8483 100644
---
a/ui/projects/streampipes/shared-ui/src/lib/components/basic-field-description/basic-field-description.component.html
+++
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-location/asset-location.component.html
@@ -16,17 +16,19 @@
~
-->
-<div
- fxFlex="100"
- fxLayout="row"
- fxLayoutAlign="start center"
- class="field-description-outer"
->
- <div [fxFlex]="descriptionPanelWidth" fxLayout="column">
- <div class="field-description-label">{{ label }}</div>
- <div class="field-description">{{ description }}</div>
- </div>
- <div fxFlex fxLayoutAlign="start center">
- <ng-content></ng-content>
+<div fxFlex="100" *ngIf="locationConfig && locationConfig.locationEnabled">
+ <mat-checkbox
+ [disabled]="!editMode"
+ [(ngModel)]="asset.assetSite.hasExactLocation"
+ >
+ Add exact location
+ </mat-checkbox>
+ <div *ngIf="asset.assetSite.hasExactLocation">
+ <sp-single-marker-map
+ [readonly]="!editMode"
+ [assetLocation]="asset.assetSite.location"
+ [locationConfig]="locationConfig"
+ >
+ </sp-single-marker-map>
</div>
</div>
diff --git
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-basics.component.ts
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-location/asset-location.component.ts
similarity index 61%
copy from
ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-basics.component.ts
copy to
ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-location/asset-location.component.ts
index f84ef1fd3b..f0a7f7efe3 100644
---
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-basics.component.ts
+++
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-location/asset-location.component.ts
@@ -18,35 +18,36 @@
import { Component, Input, OnInit } from '@angular/core';
import {
- Isa95TypeDesc,
- Isa95TypeService,
+ LocationConfig,
+ LocationConfigService,
SpAsset,
} from '@streampipes/platform-services';
@Component({
- selector: 'sp-asset-details-basics-component',
- templateUrl: './asset-details-basics.component.html',
- styleUrls: ['./asset-details-basics.component.scss'],
+ selector: 'sp-asset-location',
+ templateUrl: './asset-location.component.html',
})
-export class AssetDetailsBasicsComponent implements OnInit {
+export class AssetLocationComponent implements OnInit {
@Input()
asset: SpAsset;
@Input()
editMode: boolean;
- isa95Types: Isa95TypeDesc[] = [];
+ locationConfig: LocationConfig;
- constructor(private isa95TypeService: Isa95TypeService) {}
+ constructor(private locationConfigService: LocationConfigService) {}
ngOnInit() {
- this.asset.assetType ??= {
- assetIcon: undefined,
- assetIconColor: undefined,
- assetTypeCategory: undefined,
- assetTypeLabel: undefined,
- isa95AssetType: 'OTHER',
+ this.asset.assetSite.location ??= {
+ coordinates: {
+ latitude: 0,
+ longitude: 0,
+ },
+ zoom: 1,
};
- this.isa95Types = this.isa95TypeService.getTypeDescriptions();
+ this.locationConfigService
+ .getLocationConfig()
+ .subscribe(res => (this.locationConfig = res));
}
}
diff --git
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-details-links.component.html
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-details-links.component.html
index 10795c7ac6..bb5d58a2bc 100644
---
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-details-links.component.html
+++
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-details-links.component.html
@@ -50,7 +50,7 @@
class="mt-10"
>
<div *ngFor="let assetLinkType of assetLinkTypes">
- <sp-asset-link-section-component
+ <sp-asset-link-section
[assetLinkType]="assetLinkType"
[asset]="asset"
[editMode]="editMode"
@@ -58,7 +58,7 @@
openEditAssetLinkDialog($event, false)
"
>
- </sp-asset-link-section-component>
+ </sp-asset-link-section>
</div>
</div>
</div>
diff --git
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-details-links.component.ts
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-details-links.component.ts
index c56cf74786..b9baa36975 100644
---
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-details-links.component.ts
+++
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-details-links.component.ts
@@ -29,7 +29,7 @@ import { EditAssetLinkDialogComponent } from
'../../../../dialog/edit-asset-link
import { AssetConstants } from '../../../../constants/asset.constants';
@Component({
- selector: 'sp-asset-details-links-component',
+ selector: 'sp-asset-details-links',
templateUrl: './asset-details-links.component.html',
})
export class AssetDetailsLinksComponent implements OnInit {
diff --git
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-link-section/asset-link-item/asset-link-item.component.ts
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-link-section/asset-link-item/asset-link-item.component.ts
index 34825aba31..46eda1e238 100644
---
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-link-section/asset-link-item/asset-link-item.component.ts
+++
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-link-section/asset-link-item/asset-link-item.component.ts
@@ -21,7 +21,7 @@ import { AssetLink, AssetLinkType } from
'@streampipes/platform-services';
import { Router } from '@angular/router';
@Component({
- selector: 'sp-asset-link-item-component',
+ selector: 'sp-asset-link-item',
templateUrl: './asset-link-item.component.html',
styleUrls: ['./asset-link-item.component.scss'],
})
diff --git
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-link-section/asset-link-section.component.html
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-link-section/asset-link-section.component.html
index d5e20ef909..8d936f3f62 100644
---
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-link-section/asset-link-section.component.html
+++
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-link-section/asset-link-section.component.html
@@ -27,7 +27,7 @@
| assetTypeFilter: assetLinkType.linkType
"
>
- <sp-asset-link-item-component
+ <sp-asset-link-item
[assetLink]="link"
[assetLinkType]="assetLinkType"
[editMode]="editMode"
@@ -35,6 +35,6 @@
(deleteAssetLinkEmitter)="deleteAssetLink($event)"
class="asset-link-item"
>
- </sp-asset-link-item-component>
+ </sp-asset-link-item>
</div>
</div>
diff --git
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-link-section/asset-link-section.component.ts
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-link-section/asset-link-section.component.ts
index ebfe1055ff..f92f3a6287 100644
---
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-link-section/asset-link-section.component.ts
+++
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-links/asset-link-section/asset-link-section.component.ts
@@ -24,7 +24,7 @@ import {
} from '@streampipes/platform-services';
@Component({
- selector: 'sp-asset-link-section-component',
+ selector: 'sp-asset-link-section',
templateUrl: './asset-link-section.component.html',
styleUrls: ['./asset-link-section.component.scss'],
})
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 9b9157f43c..0e95be38a9 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
@@ -19,19 +19,21 @@
<div fxFlex="100" fxLayout="column" *ngIf="asset">
<mat-tab-group color="accent" [mat-stretch-tabs]="false">
<mat-tab label="Basics" data-cy="asset-tab-basic">
- <sp-asset-details-basics-component
+ <sp-asset-details-basics
[asset]="asset"
+ [sites]="sites"
+ [rootNode]="rootNode"
[editMode]="editMode"
>
- </sp-asset-details-basics-component>
+ </sp-asset-details-basics>
</mat-tab>
<mat-tab label="Asset Links" data-cy="asset-tab-asset-links">
- <sp-asset-details-links-component
+ <sp-asset-details-links
[asset]="asset"
[editMode]="editMode"
(updateAssetEmitter)="updateAssetEmitter.emit($event)"
>
- </sp-asset-details-links-component>
+ </sp-asset-details-links>
</mat-tab>
</mat-tab-group>
</div>
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 e61b6d379b..c4a7a55fc2 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
@@ -17,10 +17,10 @@
*/
import { Component, EventEmitter, Input, Output } from '@angular/core';
-import { SpAsset } from '@streampipes/platform-services';
+import { AssetSiteDesc, SpAsset } from '@streampipes/platform-services';
@Component({
- selector: 'sp-asset-details-panel-component',
+ selector: 'sp-asset-details-panel',
templateUrl: './asset-details-panel.component.html',
styleUrls: ['./asset-details-panel.component.scss'],
})
@@ -31,6 +31,12 @@ export class SpAssetDetailsPanelComponent {
@Input()
editMode: boolean;
+ @Input()
+ rootNode: boolean;
+
+ @Input()
+ sites: AssetSiteDesc[];
+
@Output()
updateAssetEmitter: EventEmitter<SpAsset> = new EventEmitter<SpAsset>();
}
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
index e99f362281..2e0928fd96 100644
--- a/ui/src/app/assets/components/asset-details/asset-details.component.html
+++ b/ui/src/app/assets/components/asset-details/asset-details.component.html
@@ -51,25 +51,27 @@
class="asset-tree-panel"
>
<div fxLayout="column" fxFlex="100">
- <sp-asset-selection-panel-component
+ <sp-asset-selection-panel
[editMode]="editMode"
[assetModel]="asset"
[selectedAsset]="selectedAsset"
- (selectedAssetEmitter)="selectedAsset = $event"
+ (selectedAssetEmitter)="applySelectedAsset($event)"
>
- </sp-asset-selection-panel-component>
+ </sp-asset-selection-panel>
</div>
</mat-drawer>
<mat-drawer-content class="h-100 asset-details-panel">
- <sp-asset-details-panel-component
+ <sp-asset-details-panel
*ngIf="selectedAsset"
[asset]="selectedAsset"
+ [sites]="sites"
+ [rootNode]="rootNode"
[editMode]="editMode"
(updateAssetEmitter)="updateAsset()"
fxFlex="100"
fxLayout="row"
>
- </sp-asset-details-panel-component>
+ </sp-asset-details-panel>
</mat-drawer-content>
</mat-drawer-container>
</div>
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
index 7956dae908..cbb53dc398 100644
--- a/ui/src/app/assets/components/asset-details/asset-details.component.ts
+++ b/ui/src/app/assets/components/asset-details/asset-details.component.ts
@@ -21,21 +21,25 @@ import { SpBreadcrumbService } from
'@streampipes/shared-ui';
import { ActivatedRoute } from '@angular/router';
import { AssetConstants } from '../../constants/asset.constants';
import {
+ AssetSiteDesc,
GenericStorageService,
SpAsset,
SpAssetModel,
} from '@streampipes/platform-services';
import { SpAssetRoutes } from '../../assets.routes';
+import { zip } from 'rxjs';
@Component({
- selector: 'sp-asset-details-component',
+ selector: 'sp-asset-details',
templateUrl: './asset-details.component.html',
styleUrls: ['./asset-details.component.scss'],
})
export class SpAssetDetailsComponent implements OnInit {
asset: SpAssetModel;
+ sites: AssetSiteDesc[] = [];
selectedAsset: SpAsset;
+ rootNode = true;
editMode: boolean;
@@ -50,22 +54,33 @@ export class SpAssetDetailsComponent implements OnInit {
ngOnInit(): void {
this.assetModelId = this.route.snapshot.params.assetId;
this.editMode = this.route.snapshot.queryParams.editMode;
- this.loadAsset();
+ this.loadResources();
}
- 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 },
- ]);
- });
+ loadResources(): void {
+ const assetReq = this.genericStorageService.getDocument(
+ AssetConstants.ASSET_APP_DOC_NAME,
+ this.assetModelId,
+ );
+ const locationsReq = this.genericStorageService.getAllDocuments(
+ AssetConstants.ASSET_SITES_APP_DOC_NAME,
+ );
+ zip([assetReq, locationsReq]).subscribe(res => {
+ this.asset = res[0];
+ this.sites = res[1];
+ if (!this.selectedAsset) {
+ this.selectedAsset = this.asset;
+ }
+ this.breadcrumbService.updateBreadcrumb([
+ SpAssetRoutes.BASE,
+ { label: this.asset.assetName },
+ ]);
+ });
+ }
+
+ applySelectedAsset(event: { asset: SpAsset; rootNode: boolean }): void {
+ this.selectedAsset = event.asset;
+ this.rootNode = event.rootNode;
}
updateAsset() {
@@ -76,7 +91,7 @@ export class SpAssetDetailsComponent implements OnInit {
this.genericStorageService
.updateDocument(AssetConstants.ASSET_APP_DOC_NAME, this.asset)
.subscribe(res => {
- this.loadAsset();
+ this.loadResources();
this.editMode = false;
});
}
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
index 851c39ef78..bf93eed73a 100644
---
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
@@ -45,7 +45,7 @@
"
fxLayout="row"
fxFlex="100"
- (click)="selectNode(node)"
+ (click)="selectNode(node, false)"
>
<span fxLayoutAlign="end center">{{
node.assetName
@@ -94,7 +94,7 @@
"
fxLayout="row"
fxFlex="100"
- (click)="selectNode(node)"
+ (click)="selectNode(node, true)"
>
<span fxLayoutAlign="start center">{{
node.assetName
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
index b69e8566aa..80674a89ed 100644
---
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
@@ -17,7 +17,6 @@
*/
import {
- AfterViewInit,
Component,
EventEmitter,
Input,
@@ -30,7 +29,7 @@ import { NestedTreeControl } from '@angular/cdk/tree';
import { MatTreeNestedDataSource } from '@angular/material/tree';
@Component({
- selector: 'sp-asset-selection-panel-component',
+ selector: 'sp-asset-selection-panel',
templateUrl: './asset-selection-panel.component.html',
styleUrls: ['./asset-selection-panel.component.scss'],
})
@@ -45,7 +44,8 @@ export class SpAssetSelectionPanelComponent implements OnInit
{
editMode: boolean;
@Output()
- selectedAssetEmitter: EventEmitter<SpAsset> = new EventEmitter<SpAsset>();
+ selectedAssetEmitter: EventEmitter<{ asset: SpAsset; rootNode: boolean }> =
+ new EventEmitter<{ asset: SpAsset; rootNode: boolean }>();
treeControl = new NestedTreeControl<SpAsset>(node => node.assets);
dataSource = new MatTreeNestedDataSource<SpAsset>();
@@ -63,8 +63,8 @@ export class SpAssetSelectionPanelComponent implements OnInit
{
this.treeControl.expandAll();
}
- selectNode(asset: SpAsset) {
- this.selectedAssetEmitter.emit(asset);
+ selectNode(asset: SpAsset, rootNode: boolean) {
+ this.selectedAssetEmitter.emit({ asset, rootNode });
}
addAsset(node: SpAsset) {
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
index ba13abcf04..956c37fb0a 100644
--- a/ui/src/app/assets/components/asset-overview/asset-overview.component.ts
+++ b/ui/src/app/assets/components/asset-overview/asset-overview.component.ts
@@ -38,7 +38,7 @@ import { saveAs } from 'file-saver';
import { IdGeneratorService } from
'../../../core-services/id-generator/id-generator.service';
@Component({
- selector: 'sp-asset-overview-component',
+ selector: 'sp-asset-overview',
templateUrl: './asset-overview.component.html',
styleUrls: ['./asset-overview.component.scss'],
})
diff --git a/ui/src/app/assets/constants/asset.constants.ts
b/ui/src/app/assets/constants/asset.constants.ts
index 9d99800ca1..879e1a1243 100644
--- a/ui/src/app/assets/constants/asset.constants.ts
+++ b/ui/src/app/assets/constants/asset.constants.ts
@@ -18,5 +18,6 @@
export class AssetConstants {
public static ASSET_APP_DOC_NAME = 'asset-management';
+ public static ASSET_SITES_APP_DOC_NAME = 'asset-sites';
public static ASSET_LINK_TYPES_DOC_NAME = 'asset-link-type';
}
diff --git a/ui/src/app/configuration/configuration-tabs.ts
b/ui/src/app/configuration/configuration-tabs.ts
index f897f212a5..e3359dd72f 100644
--- a/ui/src/app/configuration/configuration-tabs.ts
+++ b/ui/src/app/configuration/configuration-tabs.ts
@@ -66,6 +66,11 @@ export class SpConfigurationTabs {
itemTitle: 'Security',
itemLink: ['configuration', 'security'],
},
+ {
+ itemId: 'sites',
+ itemTitle: 'Sites',
+ itemLink: ['configuration', 'sites'],
+ },
];
}
}
diff --git a/ui/src/app/configuration/configuration.module.ts
b/ui/src/app/configuration/configuration.module.ts
index 305a667d6d..3d781332a1 100644
--- a/ui/src/app/configuration/configuration.module.ts
+++ b/ui/src/app/configuration/configuration.module.ts
@@ -79,6 +79,13 @@ import { EndpointItemComponent } from
'./extensions-installation/endpoint-item/e
import { SpExtensionsInstallationComponent } from
'./extensions-installation/extensions-installation.component';
import { MatMenuModule } from '@angular/material/menu';
import { SpConfigurationLinkSettingsComponent } from
'./general-configuration/link-settings/link-settings.component';
+import { SitesConfigurationComponent } from
'./sites-configuration/sites-configuration.component';
+import { LocationFeaturesConfigurationComponent } from
'./sites-configuration/location-features-configuration/location-features-configuration.component';
+import { SiteAreaConfigurationComponent } from
'./sites-configuration/site-area-configuration/site-area-configuration.component';
+import { MatSort } from '@angular/material/sort';
+import { ManageSiteDialogComponent } from
'./dialog/manage-site/manage-site-dialog.component';
+import { EditAssetLocationComponent } from
'./dialog/manage-site/edit-location/edit-location.component';
+import { EditAssetLocationAreaComponent } from
'./dialog/manage-site/edit-location/edit-location-area/edit-location-area.component';
@NgModule({
imports: [
@@ -148,12 +155,17 @@ import { SpConfigurationLinkSettingsComponent } from
'./general-configuration/li
path: 'security',
component: SecurityConfigurationComponent,
},
+ {
+ path: 'sites',
+ component: SitesConfigurationComponent,
+ },
],
},
]),
SharedUiModule,
ColorPickerModule,
CodemirrorModule,
+ MatSort,
],
declarations: [
ServiceConfigsComponent,
@@ -162,16 +174,22 @@ import { SpConfigurationLinkSettingsComponent } from
'./general-configuration/li
ServiceConfigsBooleanComponent,
ServiceConfigsNumberComponent,
DeleteDatalakeIndexComponent,
+ EditAssetLocationComponent,
+ EditAssetLocationAreaComponent,
EditUserDialogComponent,
EditGroupDialogComponent,
EmailConfigurationComponent,
GeneralConfigurationComponent,
ExtensionsServiceManagementComponent,
+ LocationFeaturesConfigurationComponent,
+ ManageSiteDialogComponent,
+ SitesConfigurationComponent,
SecurityAuthenticationConfigurationComponent,
SecurityConfigurationComponent,
SecurityUserConfigComponent,
SecurityUserGroupConfigComponent,
SecurityServiceConfigComponent,
+ SiteAreaConfigurationComponent,
MessagingConfigurationComponent,
DatalakeConfigurationComponent,
SpConfigurationLinkSettingsComponent,
diff --git a/ui/src/app/configuration/configuration.routes.ts
b/ui/src/app/configuration/configuration.routes.ts
index 14ac644c49..83500ea14d 100644
--- a/ui/src/app/configuration/configuration.routes.ts
+++ b/ui/src/app/configuration/configuration.routes.ts
@@ -19,6 +19,5 @@
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/dialog/manage-site/edit-location/edit-location-area/edit-location-area.component.html
b/ui/src/app/configuration/dialog/manage-site/edit-location/edit-location-area/edit-location-area.component.html
new file mode 100644
index 0000000000..ad0392c3e0
--- /dev/null
+++
b/ui/src/app/configuration/dialog/manage-site/edit-location/edit-location-area/edit-location-area.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 fxLayout="column" class="w-100" fxLayoutGap="10px">
+ <div
+ *ngFor="let area of site.areas; let i = index"
+ fxLayout="row"
+ fxFlex="100"
+ class="area"
+ >
+ <div fxFlex fxLayoutAlign="start center">{{ area }}</div>
+ <div fxLayoutAlign="end center">
+ <button
+ [attr.data-cy]="
+ 'sites-dialog-remove-area-button_' + area.replace(' ', '_')
+ "
+ mat-icon-button
+ color="accent"
+ (click)="removeArea(area)"
+ >
+ <mat-icon>remove</mat-icon>
+ </button>
+ </div>
+ </div>
+ <div *ngIf="site.areas.length === 0" fxLayoutAlign="start center">
+ <div class="no-areas-defined">No areas defined yet.</div>
+ </div>
+ <div fxLayout="row" fxLayoutGap="10px" class="w-100 mt-10">
+ <div fxFlex fxLayoutAlign="start center">
+ <mat-form-field
+ color="accent"
+ class="w-100"
+ subscriptSizing="dynamic"
+ >
+ <input
+ data-cy="sites-dialog-new-area-input"
+ matInput
+ [(ngModel)]="newArea"
+ />
+ </mat-form-field>
+ </div>
+ <div fxLayoutAlign="end center">
+ <button
+ data-cy="sites-dialog-add-area-button"
+ mat-icon-button
+ color="accent"
+ (click)="addNewArea()"
+ >
+ <mat-icon>add</mat-icon>
+ </button>
+ </div>
+ </div>
+</div>
diff --git a/ui/cypress/support/utils/configuration/ConfigutationUtils.ts
b/ui/src/app/configuration/dialog/manage-site/edit-location/edit-location-area/edit-location-area.component.scss
similarity index 84%
rename from ui/cypress/support/utils/configuration/ConfigutationUtils.ts
rename to
ui/src/app/configuration/dialog/manage-site/edit-location/edit-location-area/edit-location-area.component.scss
index 44731e6e4f..d1743a813a 100644
--- a/ui/cypress/support/utils/configuration/ConfigutationUtils.ts
+++
b/ui/src/app/configuration/dialog/manage-site/edit-location/edit-location-area/edit-location-area.component.scss
@@ -1,4 +1,4 @@
-/*
+/*!
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
@@ -16,8 +16,13 @@
*
*/
-export class ConfigurationUtils {
- public static goToConfigurationExport() {
- cy.visit('#/configuration/export');
- }
+.no-areas-defined {
+ margin-top: 5px;
+ margin-bottom: 5px;
+ font-size: smaller;
+}
+
+.area {
+ padding: 5px;
+ font-weight: bold;
}
diff --git
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-panel.component.ts
b/ui/src/app/configuration/dialog/manage-site/edit-location/edit-location-area/edit-location-area.component.ts
similarity index 59%
copy from
ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-panel.component.ts
copy to
ui/src/app/configuration/dialog/manage-site/edit-location/edit-location-area/edit-location-area.component.ts
index e61b6d379b..ddd7baab40 100644
---
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-panel.component.ts
+++
b/ui/src/app/configuration/dialog/manage-site/edit-location/edit-location-area/edit-location-area.component.ts
@@ -16,21 +16,25 @@
*
*/
-import { Component, EventEmitter, Input, Output } from '@angular/core';
-import { SpAsset } from '@streampipes/platform-services';
+import { Component, Input } from '@angular/core';
+import { AssetSiteDesc } from '@streampipes/platform-services';
@Component({
- selector: 'sp-asset-details-panel-component',
- templateUrl: './asset-details-panel.component.html',
- styleUrls: ['./asset-details-panel.component.scss'],
+ selector: 'sp-edit-asset-location-area-component',
+ templateUrl: './edit-location-area.component.html',
+ styleUrls: ['./edit-location-area.component.scss'],
})
-export class SpAssetDetailsPanelComponent {
+export class EditAssetLocationAreaComponent {
@Input()
- asset: SpAsset;
+ site: AssetSiteDesc;
- @Input()
- editMode: boolean;
+ newArea: string = '';
+
+ addNewArea(): void {
+ this.site.areas.push(this.newArea);
+ }
- @Output()
- updateAssetEmitter: EventEmitter<SpAsset> = new EventEmitter<SpAsset>();
+ removeArea(area: string): void {
+ this.site.areas.splice(this.site.areas.indexOf(area), 1);
+ }
}
diff --git
a/ui/src/app/configuration/dialog/manage-site/edit-location/edit-location.component.html
b/ui/src/app/configuration/dialog/manage-site/edit-location/edit-location.component.html
new file mode 100644
index 0000000000..0c24fba58f
--- /dev/null
+++
b/ui/src/app/configuration/dialog/manage-site/edit-location/edit-location.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 fxLayout="column">
+ <sp-basic-field-description
+ fxFlex="100"
+ descriptionPanelWidth="30"
+ label="Label"
+ description="A label which describes the location"
+ >
+ <mat-form-field color="accent" class="w-100" subscriptSizing="dynamic">
+ <input
+ data-cy="sites-dialog-site-input"
+ matInput
+ [(ngModel)]="site.label"
+ />
+ </mat-form-field>
+ </sp-basic-field-description>
+ <sp-basic-field-description
+ fxFlex="100"
+ descriptionPanelWidth="30"
+ class="mt-10"
+ label="Areas"
+ description="Available areas within the location"
+ >
+ <sp-edit-asset-location-area-component [site]="site" fxFlex="100">
+ </sp-edit-asset-location-area-component>
+ </sp-basic-field-description>
+ <sp-basic-field-description
+ *ngIf="locationConfig.locationEnabled"
+ fxFlex="100"
+ descriptionPanelWidth="30"
+ class="mt-10"
+ label="Location"
+ description="Exact location of the site"
+ >
+ <sp-single-marker-map
+ fxFlex="100"
+ [locationConfig]="locationConfig"
+ [assetLocation]="site.location"
+ >
+ </sp-single-marker-map>
+ </sp-basic-field-description>
+</div>
diff --git a/ui/src/app/configuration/configuration.routes.ts
b/ui/src/app/configuration/dialog/manage-site/edit-location/edit-location.component.ts
similarity index 68%
copy from ui/src/app/configuration/configuration.routes.ts
copy to
ui/src/app/configuration/dialog/manage-site/edit-location/edit-location.component.ts
index 14ac644c49..9b1bc554c9 100644
--- a/ui/src/app/configuration/configuration.routes.ts
+++
b/ui/src/app/configuration/dialog/manage-site/edit-location/edit-location.component.ts
@@ -16,9 +16,17 @@
*
*/
-import { SpBreadcrumbItem } from '@streampipes/shared-ui';
+import { Component, Input } from '@angular/core';
+import { AssetSiteDesc, LocationConfig } from '@streampipes/platform-services';
-export class SpConfigurationRoutes {
- static CONFIGURATION_BASE_LINK = 'configuration';
- static BASE: SpBreadcrumbItem = { label: 'Configuration' };
+@Component({
+ selector: 'sp-edit-asset-location-component',
+ templateUrl: './edit-location.component.html',
+})
+export class EditAssetLocationComponent {
+ @Input()
+ site: AssetSiteDesc;
+
+ @Input()
+ locationConfig: LocationConfig;
}
diff --git
a/ui/src/app/configuration/dialog/manage-site/manage-site-dialog.component.html
b/ui/src/app/configuration/dialog/manage-site/manage-site-dialog.component.html
new file mode 100644
index 0000000000..5cff55e084
--- /dev/null
+++
b/ui/src/app/configuration/dialog/manage-site/manage-site-dialog.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.
+ ~
+ -->
+
+<div class="sp-dialog-container">
+ <div class="sp-dialog-content p-15">
+ <div *ngIf="clonedSite !== undefined">
+ <sp-edit-asset-location-component
+ [site]="clonedSite"
+ [locationConfig]="locationConfig"
+ >
+ </sp-edit-asset-location-component>
+ </div>
+ </div>
+ <mat-divider></mat-divider>
+ <div class="sp-dialog-actions">
+ <button
+ mat-button
+ mat-raised-button
+ data-cy="sites-dialog-save-button"
+ color="accent"
+ (click)="store()"
+ style="margin-right: 10px"
+ >
+ Save changes
+ </button>
+ <button
+ mat-button
+ mat-raised-button
+ class="mat-basic"
+ data-cy="sites-dialog-cancel-button"
+ (click)="close()"
+ style="margin-right: 10px"
+ >
+ Cancel
+ </button>
+ </div>
+</div>
diff --git a/ui/src/app/configuration/configuration.routes.ts
b/ui/src/app/configuration/dialog/manage-site/manage-site-dialog.component.scss
similarity index 72%
copy from ui/src/app/configuration/configuration.routes.ts
copy to
ui/src/app/configuration/dialog/manage-site/manage-site-dialog.component.scss
index 14ac644c49..18577c0d5e 100644
--- a/ui/src/app/configuration/configuration.routes.ts
+++
b/ui/src/app/configuration/dialog/manage-site/manage-site-dialog.component.scss
@@ -1,4 +1,4 @@
-/*
+/*!
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
@@ -16,9 +16,20 @@
*
*/
-import { SpBreadcrumbItem } from '@streampipes/shared-ui';
+.location-selection-panel {
+ border-right: 1px solid var(--color-bg-2);
+}
+
+.location {
+ padding: 15px;
+ border-bottom: 1px solid var(--color-bg-2);
+}
+
+.location:hover {
+ background: var(--color-bg-2);
+ cursor: pointer;
+}
-export class SpConfigurationRoutes {
- static CONFIGURATION_BASE_LINK = 'configuration';
- static BASE: SpBreadcrumbItem = { label: 'Configuration' };
+.add-location-button {
+ border-bottom: 1px solid var(--color-bg-3);
}
diff --git
a/ui/src/app/configuration/dialog/manage-site/manage-site-dialog.component.ts
b/ui/src/app/configuration/dialog/manage-site/manage-site-dialog.component.ts
new file mode 100644
index 0000000000..0c69f44770
--- /dev/null
+++
b/ui/src/app/configuration/dialog/manage-site/manage-site-dialog.component.ts
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 {
+ AssetSiteDesc,
+ GenericStorageService,
+ LocationConfig,
+} from '@streampipes/platform-services';
+import { AssetConstants } from '../../../assets/constants/asset.constants';
+
+@Component({
+ selector: 'sp-manage-site-dialog-component',
+ templateUrl: './manage-site-dialog.component.html',
+ styleUrls: ['./manage-site-dialog.component.scss'],
+})
+export class ManageSiteDialogComponent implements OnInit {
+ @Input()
+ site: AssetSiteDesc;
+
+ @Input()
+ locationConfig: LocationConfig;
+
+ clonedSite: AssetSiteDesc;
+ createMode = false;
+
+ constructor(
+ private dialogRef: DialogRef<ManageSiteDialogComponent>,
+ private genericStorageService: GenericStorageService,
+ ) {}
+
+ ngOnInit(): void {
+ if (this.site !== undefined) {
+ this.clonedSite = JSON.parse(JSON.stringify(this.site));
+ } else {
+ this.initializeNewSite();
+ }
+ }
+
+ close(emitReload = false): void {
+ this.dialogRef.close(emitReload);
+ }
+
+ initializeNewSite(): void {
+ this.clonedSite = {
+ appDocType: AssetConstants.ASSET_SITES_APP_DOC_NAME,
+ _id: undefined,
+ label: 'New site',
+ location: { coordinates: { latitude: 0, longitude: 0 } },
+ areas: [],
+ };
+ this.createMode = true;
+ }
+
+ store(): void {
+ const observable = this.createMode
+ ? this.genericStorageService.createDocument(
+ AssetConstants.ASSET_SITES_APP_DOC_NAME,
+ this.clonedSite,
+ )
+ : this.genericStorageService.updateDocument(
+ AssetConstants.ASSET_SITES_APP_DOC_NAME,
+ this.clonedSite,
+ );
+ observable.subscribe(res => this.close(true));
+ }
+}
diff --git
a/ui/src/app/configuration/sites-configuration/location-features-configuration/location-features-configuration.component.html
b/ui/src/app/configuration/sites-configuration/location-features-configuration/location-features-configuration.component.html
new file mode 100644
index 0000000000..eb6e28df23
--- /dev/null
+++
b/ui/src/app/configuration/sites-configuration/location-features-configuration/location-features-configuration.component.html
@@ -0,0 +1,83 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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">
+ <form
+ [formGroup]="locationForm"
+ fxFlex="100"
+ fxLayout="column"
+ *ngIf="locationConfig"
+ >
+ <sp-split-section
+ title="Geo features"
+ subtitle="Geo features are used to better organize assets."
+ >
+ <mat-checkbox
+ formControlName="locationFeaturesEnabled"
+ data-cy="sites-enable-location-features-checkbox"
+ >Enable geo features
+ </mat-checkbox>
+ <div *ngIf="showLocationDetails" class="mt-10">
+ <div class="subsection-title">
+ Tile server URL (use placeholders for x, y and z
+ coordinates)
+ </div>
+ <mat-form-field
+ color="accent"
+ class="w-100"
+ subscriptSizing="dynamic"
+ >
+ <input
+ formControlName="tileServerUrl"
+ fxFlex
+ matInput
+ data-cy="sites-location-config-tile-server"
+ />
+ </mat-form-field>
+ <div class="subsection-title mt-10">
+ Attribution text if required by the tile server
+ </div>
+ <mat-form-field
+ color="accent"
+ class="w-100"
+ subscriptSizing="dynamic"
+ >
+ <input
+ formControlName="attributionText"
+ fxFlex
+ matInput
+ data-cy="sites-location-config-attribution-text"
+ />
+ </mat-form-field>
+ </div>
+ </sp-split-section>
+ <sp-split-section>
+ <div>
+ <button
+ mat-raised-button
+ color="accent"
+ data-cy="sites-location-features-button"
+ [disabled]="!locationForm.valid"
+ (click)="save()"
+ >
+ Save
+ </button>
+ </div>
+ </sp-split-section>
+ </form>
+</div>
diff --git
a/ui/src/app/configuration/sites-configuration/location-features-configuration/location-features-configuration.component.ts
b/ui/src/app/configuration/sites-configuration/location-features-configuration/location-features-configuration.component.ts
new file mode 100644
index 0000000000..9e878f9a30
--- /dev/null
+++
b/ui/src/app/configuration/sites-configuration/location-features-configuration/location-features-configuration.component.ts
@@ -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.
+ *
+ */
+
+import { Component, Input, OnDestroy, OnInit } from '@angular/core';
+import {
+ UntypedFormBuilder,
+ UntypedFormControl,
+ UntypedFormGroup,
+ Validators,
+} from '@angular/forms';
+import {
+ LocationConfig,
+ LocationConfigService,
+} from '@streampipes/platform-services';
+import { Subscription } from 'rxjs';
+import { MatSnackBar } from '@angular/material/snack-bar';
+
+@Component({
+ selector: 'sp-location-features-configuration',
+ templateUrl: './location-features-configuration.component.html',
+})
+export class LocationFeaturesConfigurationComponent
+ implements OnInit, OnDestroy
+{
+ @Input()
+ locationConfig: LocationConfig;
+
+ locationForm: UntypedFormGroup;
+ formSubscription: Subscription;
+ showLocationDetails = false;
+
+ constructor(
+ private fb: UntypedFormBuilder,
+ private snackBar: MatSnackBar,
+ private locationConfigService: LocationConfigService,
+ ) {}
+
+ ngOnInit(): void {
+ this.locationForm = this.fb.group({});
+ this.showLocationDetails = this.locationConfig.locationEnabled;
+ this.locationForm.addControl(
+ 'locationFeaturesEnabled',
+ new UntypedFormControl(this.locationConfig.locationEnabled),
+ );
+ this.locationForm.addControl(
+ 'tileServerUrl',
+ new UntypedFormControl(
+ this.locationConfig.tileServerUrl,
+ this.showLocationDetails ? Validators.required : [],
+ ),
+ );
+ this.locationForm.addControl(
+ 'attributionText',
+ new UntypedFormControl(this.locationConfig.attributionText || ''),
+ );
+ this.formSubscription = this.locationForm
+ .get('locationFeaturesEnabled')
+ .valueChanges.subscribe(checked => {
+ this.showLocationDetails = checked;
+ if (checked) {
+ this.locationForm.controls.tileServerUrl.setValidators(
+ Validators.required,
+ );
+ } else {
+ this.locationForm.controls.tileServerUrl.setValidators([]);
+ }
+ });
+ }
+
+ save(): void {
+ this.locationConfig.locationEnabled = this.locationForm.get(
+ 'locationFeaturesEnabled',
+ ).value;
+ if (this.locationConfig.locationEnabled) {
+ this.locationConfig.tileServerUrl =
+ this.locationForm.get('tileServerUrl').value;
+ this.locationConfig.attributionText =
+ this.locationForm.get('attributionText').value;
+ }
+ this.locationConfigService
+ .updateLocationConfig(this.locationConfig)
+ .subscribe(() => {
+ this.snackBar.open('Location configuration updated', 'Ok', {
+ duration: 3000,
+ });
+ });
+ }
+
+ ngOnDestroy() {
+ this.formSubscription?.unsubscribe();
+ }
+}
diff --git
a/ui/src/app/configuration/sites-configuration/site-area-configuration/site-area-configuration.component.html
b/ui/src/app/configuration/sites-configuration/site-area-configuration/site-area-configuration.component.html
new file mode 100644
index 0000000000..c7705c3c93
--- /dev/null
+++
b/ui/src/app/configuration/sites-configuration/site-area-configuration/site-area-configuration.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.
+ ~
+ -->
+
+<sp-split-section
+ title="Sites & Areas"
+ subtitle="Manage your organization's sites and production areas"
+>
+ <div fxLayout="row">
+ <button
+ mat-raised-button
+ color="accent"
+ data-cy="sites-manage-sites-button"
+ (click)="openManageSitesDialog(undefined)"
+ >
+ <mat-icon>add</mat-icon>
+ <span>New site</span>
+ </button>
+ </div>
+ <sp-table
+ class="mt-10"
+ [dataSource]="dataSource"
+ [columns]="displayedColumns"
+ matSort
+ data-cy="all-sites-table"
+ >
+ <ng-container matColumnDef="name">
+ <th mat-header-cell *matHeaderCellDef><b>Site</b></th>
+ <td mat-cell *matCellDef="let site" data-cy="site-table-row-label">
+ {{ site.label }}
+ </td>
+ </ng-container>
+ <ng-container matColumnDef="areas">
+ <th mat-header-cell *matHeaderCellDef><b>Areas</b></th>
+ <td mat-cell *matCellDef="let site" data-cy="site-table-row-areas">
+ {{ site.areas.toString() }}
+ </td>
+ </ng-container>
+ <ng-container matColumnDef="actions">
+ <th mat-header-cell *matHeaderCellDef></th>
+ <td mat-cell *matCellDef="let site">
+ <div fxLayout="row" fxLayoutAlign="end center">
+ <button
+ mat-icon-button
+ color="accent"
+ data-cy="sites-edit-button"
+ (click)="openManageSitesDialog(site)"
+ >
+ <mat-icon>edit</mat-icon>
+ </button>
+ <button
+ [attr.data-cy]="
+ 'sites-delete-button-' +
+ site.label.replaceAll(' ', '_')
+ "
+ (click)="deleteSite(site)"
+ mat-icon-button
+ color="accent"
+ >
+ <mat-icon>delete</mat-icon>
+ </button>
+ </div>
+ </td>
+ </ng-container>
+ </sp-table>
+</sp-split-section>
diff --git
a/ui/src/app/configuration/sites-configuration/site-area-configuration/site-area-configuration.component.ts
b/ui/src/app/configuration/sites-configuration/site-area-configuration/site-area-configuration.component.ts
new file mode 100644
index 0000000000..d0de6e25e9
--- /dev/null
+++
b/ui/src/app/configuration/sites-configuration/site-area-configuration/site-area-configuration.component.ts
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 {
+ AssetSiteDesc,
+ GenericStorageService,
+ LocationConfig,
+} from '@streampipes/platform-services';
+import { AssetConstants } from '../../../assets/constants/asset.constants';
+import { MatTableDataSource } from '@angular/material/table';
+import { ManageSiteDialogComponent } from
'../../dialog/manage-site/manage-site-dialog.component';
+import { DialogService, PanelType } from '@streampipes/shared-ui';
+
+@Component({
+ selector: 'sp-site-area-configuration',
+ templateUrl: './site-area-configuration.component.html',
+})
+export class SiteAreaConfigurationComponent implements OnInit {
+ @Input()
+ locationConfig: LocationConfig;
+
+ allSites: AssetSiteDesc[] = [];
+ dataSource: MatTableDataSource<AssetSiteDesc> =
+ new MatTableDataSource<AssetSiteDesc>();
+ displayedColumns = ['name', 'areas', 'actions'];
+
+ constructor(
+ private genericStorageService: GenericStorageService,
+ private dialogService: DialogService,
+ ) {}
+
+ ngOnInit() {
+ this.loadSites();
+ }
+
+ loadSites(): void {
+ this.genericStorageService
+ .getAllDocuments(AssetConstants.ASSET_SITES_APP_DOC_NAME)
+ .subscribe(res => {
+ this.allSites = res;
+ this.dataSource.data = this.allSites;
+ });
+ }
+
+ deleteSite(site: AssetSiteDesc): void {
+ this.genericStorageService
+ .deleteDocument(
+ AssetConstants.ASSET_SITES_APP_DOC_NAME,
+ site._id,
+ site._rev,
+ )
+ .subscribe(() => this.loadSites());
+ }
+
+ openManageSitesDialog(site: AssetSiteDesc): void {
+ const dialogRef = this.dialogService.open(ManageSiteDialogComponent, {
+ panelType: PanelType.SLIDE_IN_PANEL,
+ title: 'Manage site',
+ width: '50vw',
+ data: {
+ site,
+ locationConfig: this.locationConfig,
+ },
+ });
+
+ dialogRef.afterClosed().subscribe(reload => {
+ if (reload) {
+ this.loadSites();
+ }
+ });
+ }
+}
diff --git
a/ui/projects/streampipes/shared-ui/src/lib/components/basic-field-description/basic-field-description.component.html
b/ui/src/app/configuration/sites-configuration/sites-configuration.component.html
similarity index 67%
copy from
ui/projects/streampipes/shared-ui/src/lib/components/basic-field-description/basic-field-description.component.html
copy to
ui/src/app/configuration/sites-configuration/sites-configuration.component.html
index 83115501f2..939208cfb5 100644
---
a/ui/projects/streampipes/shared-ui/src/lib/components/basic-field-description/basic-field-description.component.html
+++
b/ui/src/app/configuration/sites-configuration/sites-configuration.component.html
@@ -16,17 +16,12 @@
~
-->
-<div
- fxFlex="100"
- fxLayout="row"
- fxLayoutAlign="start center"
- class="field-description-outer"
->
- <div [fxFlex]="descriptionPanelWidth" fxLayout="column">
- <div class="field-description-label">{{ label }}</div>
- <div class="field-description">{{ description }}</div>
- </div>
- <div fxFlex fxLayoutAlign="start center">
- <ng-content></ng-content>
+<sp-basic-nav-tabs [spNavigationItems]="tabs" [activeLink]="'sites'">
+ <div fxLayout="column" *ngIf="locationConfig">
+ <sp-location-features-configuration [locationConfig]="locationConfig">
+ </sp-location-features-configuration>
+
+ <sp-site-area-configuration [locationConfig]="locationConfig">
+ </sp-site-area-configuration>
</div>
-</div>
+</sp-basic-nav-tabs>
diff --git
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-panel.component.ts
b/ui/src/app/configuration/sites-configuration/sites-configuration.component.ts
similarity index 55%
copy from
ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-panel.component.ts
copy to
ui/src/app/configuration/sites-configuration/sites-configuration.component.ts
index e61b6d379b..2f26fe2b32 100644
---
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-panel.component.ts
+++
b/ui/src/app/configuration/sites-configuration/sites-configuration.component.ts
@@ -16,21 +16,27 @@
*
*/
-import { Component, EventEmitter, Input, Output } from '@angular/core';
-import { SpAsset } from '@streampipes/platform-services';
+import { Component, OnInit } from '@angular/core';
+import { SpConfigurationTabs } from '../configuration-tabs';
+import {
+ LocationConfig,
+ LocationConfigService,
+} from '@streampipes/platform-services';
@Component({
- selector: 'sp-asset-details-panel-component',
- templateUrl: './asset-details-panel.component.html',
- styleUrls: ['./asset-details-panel.component.scss'],
+ selector: 'sp-sites-configuration',
+ templateUrl: './sites-configuration.component.html',
})
-export class SpAssetDetailsPanelComponent {
- @Input()
- asset: SpAsset;
+export class SitesConfigurationComponent implements OnInit {
+ tabs = SpConfigurationTabs.getTabs();
- @Input()
- editMode: boolean;
+ locationConfig: LocationConfig;
- @Output()
- updateAssetEmitter: EventEmitter<SpAsset> = new EventEmitter<SpAsset>();
+ constructor(private locationConfigService: LocationConfigService) {}
+
+ ngOnInit() {
+ this.locationConfigService.getLocationConfig().subscribe(res => {
+ this.locationConfig = res;
+ });
+ }
}
diff --git a/ui/src/app/core-ui/core-ui.module.ts
b/ui/src/app/core-ui/core-ui.module.ts
index 971206876f..bf9a91ff30 100644
--- a/ui/src/app/core-ui/core-ui.module.ts
+++ b/ui/src/app/core-ui/core-ui.module.ts
@@ -113,6 +113,8 @@ import { StaticTreeInputButtonMenuComponent } from
'./static-properties/static-r
import { StaticTreeInputSelectedNodesComponent } from
'./static-properties/static-runtime-resolvable-tree-input/static-tree-input-selected-nodes/static-tree-input-selected-nodes.component';
import { StaticTreeInputBrowseNodesComponent } from
'./static-properties/static-runtime-resolvable-tree-input/static-tree-input-browse-nodes/static-tree-input-browse-nodes.component';
import { StaticTreeInputNodeDetailsComponent } from
'./static-properties/static-runtime-resolvable-tree-input/static-tree-input-node-details/static-tree-input-node-details.component';
+import { SingleMarkerMapComponent } from
'./single-marker-map/single-marker-map.component';
+import { LeafletModule } from '@asymmetrik/ngx-leaflet';
import { StaticTreeInputTextEditorComponent } from
'./static-properties/static-runtime-resolvable-tree-input/static-tree-input-text-editor/static-tree-input-text-editor.component';
@NgModule({
@@ -163,6 +165,7 @@ import { StaticTreeInputTextEditorComponent } from
'./static-properties/static-r
QuillModule.forRoot(),
MatTreeModule,
MarkdownModule.forRoot(),
+ LeafletModule,
],
declarations: [
DataDownloadDialogComponent,
@@ -197,6 +200,7 @@ import { StaticTreeInputTextEditorComponent } from
'./static-properties/static-r
StaticTreeInputNodeDetailsComponent,
StaticTreeInputTextEditorComponent,
StaticSlideToggleComponent,
+ SingleMarkerMapComponent,
ErrorHintComponent,
AddToCollectionComponent,
PipelineStartedStatusComponent,
@@ -250,6 +254,7 @@ import { StaticTreeInputTextEditorComponent } from
'./static-properties/static-r
StatusIndicatorComponent,
MultiStepStatusIndicatorComponent,
PipelineOperationStatusComponent,
+ SingleMarkerMapComponent,
],
})
export class CoreUiModule {}
diff --git
a/ui/projects/streampipes/shared-ui/src/lib/components/basic-field-description/basic-field-description.component.html
b/ui/src/app/core-ui/single-marker-map/single-marker-map.component.html
similarity index 68%
copy from
ui/projects/streampipes/shared-ui/src/lib/components/basic-field-description/basic-field-description.component.html
copy to ui/src/app/core-ui/single-marker-map/single-marker-map.component.html
index 83115501f2..921d108a40 100644
---
a/ui/projects/streampipes/shared-ui/src/lib/components/basic-field-description/basic-field-description.component.html
+++ b/ui/src/app/core-ui/single-marker-map/single-marker-map.component.html
@@ -17,16 +17,13 @@
-->
<div
- fxFlex="100"
- fxLayout="row"
- fxLayoutAlign="start center"
- class="field-description-outer"
+ class="w-100"
+ [ngStyle]="{ height: mapHeight + 'px' }"
+ leaflet
+ (leafletClick)="onMarkerAdded($event)"
+ [leafletOptions]="mapOptions"
+ (leafletZoomChange)="onZoomChange($event)"
+ (leafletMapReady)="onMapReady($event)"
>
- <div [fxFlex]="descriptionPanelWidth" fxLayout="column">
- <div class="field-description-label">{{ label }}</div>
- <div class="field-description">{{ description }}</div>
- </div>
- <div fxFlex fxLayoutAlign="start center">
- <ng-content></ng-content>
- </div>
+ <div *ngFor="let layer of layers" [leafletLayer]="layer"></div>
</div>
diff --git
a/ui/src/app/core-ui/single-marker-map/single-marker-map.component.ts
b/ui/src/app/core-ui/single-marker-map/single-marker-map.component.ts
new file mode 100644
index 0000000000..ffeb12657b
--- /dev/null
+++ b/ui/src/app/core-ui/single-marker-map/single-marker-map.component.ts
@@ -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.
+ *
+ */
+
+import { Component, Input, OnInit } from '@angular/core';
+import {
+ icon,
+ Layer,
+ LeafletMouseEvent,
+ Map,
+ MapOptions,
+ marker,
+ Marker,
+ tileLayer,
+} from 'leaflet';
+import {
+ AssetLocation,
+ LatLng,
+ LocationConfig,
+} from '@streampipes/platform-services';
+
+@Component({
+ selector: 'sp-single-marker-map',
+ templateUrl: './single-marker-map.component.html',
+})
+export class SingleMarkerMapComponent implements OnInit {
+ @Input()
+ locationConfig: LocationConfig;
+
+ @Input()
+ assetLocation: AssetLocation;
+
+ @Input()
+ mapHeight: number = 400;
+
+ @Input()
+ readonly = false;
+
+ map: Map;
+ mapOptions: MapOptions;
+ layers: Layer[];
+ marker: Marker;
+
+ ngOnInit() {
+ this.assetLocation ??= {
+ coordinates: {
+ latitude: 0,
+ longitude: 0,
+ },
+ zoom: 1,
+ };
+ this.mapOptions = {
+ layers: [
+ tileLayer(this.locationConfig.tileServerUrl, {
+ maxZoom: 18,
+ attribution: this.locationConfig.attributionText,
+ }),
+ ],
+ zoom: this.assetLocation.zoom || 1,
+ center: {
+ lat: this.assetLocation.coordinates.latitude,
+ lng: this.assetLocation.coordinates.longitude,
+ },
+ };
+ }
+
+ makeMarker(location: LatLng): Marker {
+ return marker(
+ { lat: location.latitude, lng: location.longitude },
+ {
+ icon: icon({
+ iconSize: [25, 41],
+ iconAnchor: [13, 41],
+ iconUrl: 'assets/img/marker-icon.png',
+ shadowUrl: 'assets/img/marker-shadow.png',
+ }),
+ },
+ );
+ }
+
+ onMapReady(map: Map) {
+ this.map = map;
+ this.map.attributionControl.setPrefix('');
+ this.map.invalidateSize();
+ this.addMarker(this.assetLocation.coordinates);
+ }
+
+ onZoomChange(zoom: number): void {
+ this.assetLocation.zoom = zoom;
+ }
+
+ onMarkerAdded(e: LeafletMouseEvent) {
+ if (!this.readonly) {
+ this.addMarker({
+ latitude: e.latlng.lat,
+ longitude: e.latlng.lng,
+ });
+ }
+ }
+
+ addMarker(location: LatLng): void {
+ if (location) {
+ if (!this.marker) {
+ this.marker = this.makeMarker(location);
+ this.marker.addTo(this.map);
+ } else {
+ this.marker.setLatLng({
+ lat: location.latitude,
+ lng: location.longitude,
+ });
+ }
+ this.assetLocation.coordinates = location;
+ }
+ }
+}