This is an automated email from the ASF dual-hosted git repository.
riemer pushed a commit to branch 3141-add-site-and-area-configuration-to-assets
in repository https://gitbox.apache.org/repos/asf/streampipes.git
The following commit(s) were added to
refs/heads/3141-add-site-and-area-configuration-to-assets by this push:
new 41bc47c533 feat(#3141): Add option to configure production sites
41bc47c533 is described below
commit 41bc47c53393e60371bd2636b50360b672e8c75c
Author: Dominik Riemer <[email protected]>
AuthorDate: Wed Aug 14 21:22:10 2024 +0200
feat(#3141): Add option to configure production sites
---
.../model/configuration/LocationConfig.java | 11 ++-
.../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 | 24 ++++-
.../src/lib/model/gen/streampipes-model.ts | 69 ++++----------
.../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 | 15 +++
.../asset-details-basics.component.ts | 36 +++++--
.../asset-details-site.component.html} | 38 ++++----
.../asset-details-site.component.scss | 0
.../asset-details-site.component.ts | 62 ++++++++++++
.../asset-location/asset-location.component.html | 0
.../asset-location/asset-location.component.scss | 0
.../asset-location/asset-location.component.ts} | 11 ++-
.../asset-details-panel.component.html | 2 +
.../asset-details-panel.component.ts | 8 +-
.../asset-details/asset-details.component.html | 4 +-
.../asset-details/asset-details.component.ts | 45 ++++++---
.../asset-selection-panel.component.html | 4 +-
.../asset-selection-panel.component.ts | 8 +-
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 | 44 +++++++++
.../edit-location/edit-location.component.scss | 0
.../edit-location/edit-location.component.ts} | 14 ++-
.../manage-site/manage-site-dialog.component.html | 31 ++++++
.../manage-site/manage-site-dialog.component.scss} | 21 ++++-
.../manage-site/manage-site-dialog.component.ts | 80 ++++++++++++++++
.../location-features-configuration.component.html | 67 +++++++++++++
.../location-features-configuration.component.ts | 105 +++++++++++++++++++++
.../site-area-configuration.component.html | 80 ++++++++++++++++
.../site-area-configuration.component.ts | 83 ++++++++++++++++
.../sites-configuration.component.html} | 19 +---
.../sites-configuration.component.scss | 0
.../sites-configuration.component.ts} | 13 ++-
50 files changed, 1161 insertions(+), 234 deletions(-)
diff --git a/ui/src/app/assets/constants/asset.constants.ts
b/streampipes-model/src/main/java/org/apache/streampipes/model/configuration/LocationConfig.java
similarity index 77%
copy from ui/src/app/assets/constants/asset.constants.ts
copy to
streampipes-model/src/main/java/org/apache/streampipes/model/configuration/LocationConfig.java
index 9d99800ca1..fe7bc35c60 100644
--- a/ui/src/app/assets/constants/asset.constants.ts
+++
b/streampipes-model/src/main/java/org/apache/streampipes/model/configuration/LocationConfig.java
@@ -16,7 +16,10 @@
*
*/
-export class AssetConstants {
- public static ASSET_APP_DOC_NAME = 'asset-management';
- public static ASSET_LINK_TYPES_DOC_NAME = 'asset-link-type';
-}
+package org.apache.streampipes.model.configuration;
+
+import org.apache.streampipes.model.shared.annotation.TsModel;
+
+@TsModel
+public record LocationConfig(boolean locationEnabled,
+ String tileServerUrl) {}
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..5c04e6b1c7 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/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-basics.component.ts
b/ui/projects/streampipes/platform-services/src/lib/apis/location-config.service.ts
similarity index 50%
copy from
ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-basics.component.ts
copy to
ui/projects/streampipes/platform-services/src/lib/apis/location-config.service.ts
index f84ef1fd3b..f69cf16f64 100644
---
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-basics.component.ts
+++
b/ui/projects/streampipes/platform-services/src/lib/apis/location-config.service.ts
@@ -16,37 +16,35 @@
*
*/
-import { Component, Input, OnInit } from '@angular/core';
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
import {
- Isa95TypeDesc,
- Isa95TypeService,
- SpAsset,
+ LocationConfig,
+ PlatformServicesCommons,
} from '@streampipes/platform-services';
+import { Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
-@Component({
- selector: 'sp-asset-details-basics-component',
- templateUrl: './asset-details-basics.component.html',
- styleUrls: ['./asset-details-basics.component.scss'],
+@Injectable({
+ providedIn: 'root',
})
-export class AssetDetailsBasicsComponent implements OnInit {
- @Input()
- asset: SpAsset;
+export class LocationConfigService {
+ constructor(
+ private http: HttpClient,
+ private platformServicesCommons: PlatformServicesCommons,
+ ) {}
- @Input()
- editMode: boolean;
-
- isa95Types: Isa95TypeDesc[] = [];
+ getLocationConfig(): Observable<LocationConfig> {
+ return this.http
+ .get(this.locationConfigPath)
+ .pipe(map(response => response as LocationConfig));
+ }
- constructor(private isa95TypeService: Isa95TypeService) {}
+ updateLocationConfig(config: LocationConfig): Observable<any> {
+ return this.http.put(this.locationConfigPath, config);
+ }
- ngOnInit() {
- this.asset.assetType ??= {
- assetIcon: undefined,
- assetIconColor: undefined,
- assetTypeCategory: undefined,
- assetTypeLabel: undefined,
- isa95AssetType: 'OTHER',
- };
- this.isa95Types = this.isa95TypeService.getTypeDescriptions();
+ 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..1f353ed9c2 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,35 @@ export interface Isa95TypeDesc {
type: Isa95Type;
}
+export interface AssetSiteDesc {
+ _id: string;
+ _rev?: string;
+ appDocType: string;
+ label: string;
+ location: LatLng;
+ areas: string[];
+}
+
+export interface LatLng {
+ latitude: number;
+ longitude: number;
+}
+
+export interface AssetLocation {
+ siteId: string;
+ area: string;
+ exactLocation?: LatLng;
+ zoom?: number;
+}
+
export interface SpAsset {
assetId: string;
assetName: string;
assetDescription: string;
-
assetType: AssetType;
labelIds?: string[];
assetLinks: AssetLink[];
-
+ assetLocation?: AssetLocation;
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..b48be6e884 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-14
12:45:11.
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,24 @@ export class ListOutputStrategy extends OutputStrategy {
}
}
+export class LocationConfig {
+ locationEnabled: boolean;
+ tileServerUrl: string;
+
+ static fromData(
+ data: LocationConfig,
+ target?: LocationConfig,
+ ): LocationConfig {
+ if (!data) {
+ return data;
+ }
+ const instance = target || new LocationConfig();
+ instance.locationEnabled = data.locationEnabled;
+ instance.tileServerUrl = data.tileServerUrl;
+ return instance;
+ }
+}
+
export class MappingProperty extends StaticProperty {
'@class':
| 'org.apache.streampipes.model.staticproperty.MappingProperty'
@@ -2430,25 +2447,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 +3052,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..9d427ea958 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
@@ -107,6 +107,21 @@
>
</sp-asset-details-labels-component>
</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-component
+ class="w-100"
+ [asset]="asset"
+ [locations]="locations"
+ [editMode]="editMode"
+ >
+ </sp-asset-details-site-component>
+ </sp-basic-field-description>
</div>
</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..beb0405276 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,8 +16,15 @@
*
*/
-import { Component, Input, OnInit } from '@angular/core';
import {
+ Component,
+ Input,
+ OnChanges,
+ OnInit,
+ SimpleChanges,
+} from '@angular/core';
+import {
+ AssetSiteDesc,
Isa95TypeDesc,
Isa95TypeService,
SpAsset,
@@ -28,25 +35,36 @@ import {
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()
+ locations: 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-panel.component.html
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-details-site.component.html
similarity index 51%
copy from
ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-panel.component.html
copy to
ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-details-site.component.html
index 9b9157f43c..37fc98499a 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-basics/asset-details-site/asset-details-site.component.html
@@ -16,22 +16,24 @@
~
-->
-<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
- [asset]="asset"
- [editMode]="editMode"
- >
- </sp-asset-details-basics-component>
- </mat-tab>
- <mat-tab label="Asset Links" data-cy="asset-tab-asset-links">
- <sp-asset-details-links-component
- [asset]="asset"
- [editMode]="editMode"
- (updateAssetEmitter)="updateAssetEmitter.emit($event)"
- >
- </sp-asset-details-links-component>
- </mat-tab>
- </mat-tab-group>
+<div fxLayout="column">
+ <mat-form-field color="accent" class="w-100">
+ <mat-label>Site</mat-label>
+ <mat-select
+ [(ngModel)]="asset.assetLocation.siteId"
+ (selectionChange)="handleLocationChange($event)"
+ >
+ <mat-option *ngFor="let site of allSites" [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 [(ngModel)]="asset.assetLocation.area">
+ <mat-option *ngFor="let area of currentSite.areas" [value]="area">
+ {{ area }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
</div>
diff --git
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-details-site.component.scss
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-details-site.component.scss
new file mode 100644
index 0000000000..e69de29bb2
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..085bbb2d42
--- /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,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+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-component',
+ templateUrl: './asset-details-site.component.html',
+})
+export class AssetDetailsSiteComponent implements OnChanges {
+ @Input()
+ asset: SpAsset;
+
+ @Input()
+ editMode: boolean;
+
+ @Input()
+ allSites: AssetSiteDesc[];
+
+ currentSite: AssetSiteDesc;
+
+ constructor() {}
+
+ ngOnChanges(changes: SimpleChanges) {
+ if (changes['asset']) {
+ this.asset.assetLocation ??= {
+ area: undefined,
+ siteId: undefined,
+ };
+ if (this.allSites.length > 0) {
+ if (this.asset.assetLocation.siteId !== undefined) {
+ this.selectCurrentSite(this.asset.assetLocation.siteId);
+ }
+ }
+ }
+ }
+
+ handleLocationChange(event: MatSelectChange) {
+ this.selectCurrentSite(event.value);
+ }
+
+ selectCurrentSite(siteId: string): void {
+ this.currentSite = this.allSites.find(loc => loc._id === siteId);
+ }
+}
diff --git
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-location/asset-location.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
new file mode 100644
index 0000000000..e69de29bb2
diff --git
a/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-location/asset-location.component.scss
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-location/asset-location.component.scss
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/ui/src/app/assets/constants/asset.constants.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 80%
copy from ui/src/app/assets/constants/asset.constants.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 9d99800ca1..51e0050bae 100644
--- a/ui/src/app/assets/constants/asset.constants.ts
+++
b/ui/src/app/assets/components/asset-details/asset-details-panel/asset-details-basics/asset-details-site/asset-location/asset-location.component.ts
@@ -16,7 +16,10 @@
*
*/
-export class AssetConstants {
- public static ASSET_APP_DOC_NAME = 'asset-management';
- public static ASSET_LINK_TYPES_DOC_NAME = 'asset-link-type';
-}
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'sp-asset-location-component',
+ templateUrl: './asset-location.component.html',
+})
+export class AssetLocationComponent {}
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..589babcbfb 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
@@ -21,6 +21,8 @@
<mat-tab label="Basics" data-cy="asset-tab-basic">
<sp-asset-details-basics-component
[asset]="asset"
+ [locations]="locations"
+ [rootNode]="rootNode"
[editMode]="editMode"
>
</sp-asset-details-basics-component>
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..e25a3c1afe 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,7 +17,7 @@
*/
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',
@@ -31,6 +31,12 @@ export class SpAssetDetailsPanelComponent {
@Input()
editMode: boolean;
+ @Input()
+ rootNode: boolean;
+
+ @Input()
+ locations: 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..02d4ab506a 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
@@ -55,7 +55,7 @@
[editMode]="editMode"
[assetModel]="asset"
[selectedAsset]="selectedAsset"
- (selectedAssetEmitter)="selectedAsset = $event"
+ (selectedAssetEmitter)="applySelectedAsset($event)"
>
</sp-asset-selection-panel-component>
</div>
@@ -64,6 +64,8 @@
<sp-asset-details-panel-component
*ngIf="selectedAsset"
[asset]="selectedAsset"
+ [locations]="locations"
+ [rootNode]="rootNode"
[editMode]="editMode"
(updateAssetEmitter)="updateAsset()"
fxFlex="100"
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..b0c8a1682d 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,11 +21,13 @@ 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',
@@ -34,8 +36,10 @@ import { SpAssetRoutes } from '../../assets.routes';
})
export class SpAssetDetailsComponent implements OnInit {
asset: SpAssetModel;
+ locations: 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.locations = 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..14fe8d1511 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,
@@ -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/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 83%
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..ccbab50832 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;
+ border: 1px solid var(--color-bg-2);
}
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..c4e7a5f9cb
--- /dev/null
+++
b/ui/src/app/configuration/dialog/manage-site/edit-location/edit-location.component.html
@@ -0,0 +1,44 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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>
+</div>
diff --git
a/ui/src/app/configuration/dialog/manage-site/edit-location/edit-location.component.scss
b/ui/src/app/configuration/dialog/manage-site/edit-location/edit-location.component.scss
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/ui/src/app/assets/constants/asset.constants.ts
b/ui/src/app/configuration/dialog/manage-site/edit-location/edit-location.component.ts
similarity index 69%
copy from ui/src/app/assets/constants/asset.constants.ts
copy to
ui/src/app/configuration/dialog/manage-site/edit-location/edit-location.component.ts
index 9d99800ca1..750eabd46b 100644
--- a/ui/src/app/assets/constants/asset.constants.ts
+++
b/ui/src/app/configuration/dialog/manage-site/edit-location/edit-location.component.ts
@@ -16,7 +16,15 @@
*
*/
-export class AssetConstants {
- public static ASSET_APP_DOC_NAME = 'asset-management';
- public static ASSET_LINK_TYPES_DOC_NAME = 'asset-link-type';
+import { Component, Input } from '@angular/core';
+import { AssetSiteDesc } from '@streampipes/platform-services';
+
+@Component({
+ selector: 'sp-edit-asset-location-component',
+ templateUrl: './edit-location.component.html',
+ styleUrls: ['./edit-location.component.scss'],
+})
+export class EditAssetLocationComponent {
+ @Input()
+ site: AssetSiteDesc;
}
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..2fc0c2e110
--- /dev/null
+++
b/ui/src/app/configuration/dialog/manage-site/manage-site-dialog.component.html
@@ -0,0 +1,31 @@
+<div class="sp-dialog-container">
+ <div class="sp-dialog-content p-15">
+ <div *ngIf="clonedSite !== undefined">
+ <sp-edit-asset-location-component [site]="clonedSite">
+ </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/assets/constants/asset.constants.ts
b/ui/src/app/configuration/dialog/manage-site/manage-site-dialog.component.scss
similarity index 72%
copy from ui/src/app/assets/constants/asset.constants.ts
copy to
ui/src/app/configuration/dialog/manage-site/manage-site-dialog.component.scss
index 9d99800ca1..18577c0d5e 100644
--- a/ui/src/app/assets/constants/asset.constants.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,7 +16,20 @@
*
*/
-export class AssetConstants {
- public static ASSET_APP_DOC_NAME = 'asset-management';
- public static ASSET_LINK_TYPES_DOC_NAME = 'asset-link-type';
+.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;
+}
+
+.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..c15d8e01cf
--- /dev/null
+++
b/ui/src/app/configuration/dialog/manage-site/manage-site-dialog.component.ts
@@ -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.
+ *
+ */
+
+import { Component, Input, OnInit } from '@angular/core';
+import { DialogRef } from '@streampipes/shared-ui';
+import {
+ AssetSiteDesc,
+ GenericStorageService,
+} 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;
+
+ 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: { latitude: 0, longitude: 0 },
+ areas: [],
+ };
+ this.createMode = true;
+ }
+
+ store(): void {
+ console.log(this.clonedSite);
+ 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..1ea40f2869
--- /dev/null
+++
b/ui/src/app/configuration/sites-configuration/location-features-configuration/location-features-configuration.component.html
@@ -0,0 +1,67 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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]="parentForm"
+ 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="showTileUrlInput" class="mt-10">
+ <div class="subsection-title">
+ Tile server URL (use placeholders for x, y
+ </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>
+ </sp-split-section>
+ <sp-split-section>
+ <div>
+ <button
+ mat-raised-button
+ color="accent"
+ data-cy="sites-location-features-button"
+ [disabled]="!parentForm.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..7acfaeb750
--- /dev/null
+++
b/ui/src/app/configuration/sites-configuration/location-features-configuration/location-features-configuration.component.ts
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { Component, 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
+{
+ locationConfig: LocationConfig;
+
+ parentForm: UntypedFormGroup;
+ formSubscription: Subscription;
+ showTileUrlInput = false;
+
+ constructor(
+ private fb: UntypedFormBuilder,
+ private snackBar: MatSnackBar,
+ private locationConfigService: LocationConfigService,
+ ) {}
+
+ ngOnInit(): void {
+ this.parentForm = this.fb.group({});
+ this.locationConfigService.getLocationConfig().subscribe(res => {
+ this.locationConfig = res;
+ this.showTileUrlInput = res.locationEnabled;
+ this.parentForm.addControl(
+ 'locationFeaturesEnabled',
+ new UntypedFormControl(this.locationConfig.locationEnabled),
+ );
+ this.parentForm.addControl(
+ 'tileServerUrl',
+ new UntypedFormControl(
+ this.locationConfig.tileServerUrl,
+ this.showTileUrlInput ? Validators.required : [],
+ ),
+ );
+ this.formSubscription = this.parentForm
+ .get('locationFeaturesEnabled')
+ .valueChanges.subscribe(checked => {
+ this.showTileUrlInput = checked;
+ if (checked) {
+ this.parentForm.controls.tileServerUrl.setValidators(
+ Validators.required,
+ );
+ } else {
+ this.parentForm.controls.tileServerUrl.setValidators(
+ [],
+ );
+ }
+ });
+ });
+ }
+
+ save(): void {
+ this.locationConfig.locationEnabled = this.parentForm.get(
+ 'locationFeaturesEnabled',
+ ).value;
+ if (this.locationConfig.locationEnabled) {
+ this.locationConfig.tileServerUrl =
+ this.parentForm.get('tileServerUrl').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..fdecc2259f
--- /dev/null
+++
b/ui/src/app/configuration/sites-configuration/site-area-configuration/site-area-configuration.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, OnInit } from '@angular/core';
+import {
+ AssetSiteDesc,
+ GenericStorageService,
+} 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 {
+ 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,
+ },
+ });
+
+ 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 66%
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..05a204d305 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,8 @@
~
-->
-<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>
-</div>
+<sp-basic-nav-tabs [spNavigationItems]="tabs" [activeLink]="'sites'">
+ <sp-location-features-configuration> </sp-location-features-configuration>
+
+ <sp-site-area-configuration> </sp-site-area-configuration>
+</sp-basic-nav-tabs>
diff --git
a/ui/src/app/configuration/sites-configuration/sites-configuration.component.scss
b/ui/src/app/configuration/sites-configuration/sites-configuration.component.scss
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/ui/src/app/assets/constants/asset.constants.ts
b/ui/src/app/configuration/sites-configuration/sites-configuration.component.ts
similarity index 69%
copy from ui/src/app/assets/constants/asset.constants.ts
copy to
ui/src/app/configuration/sites-configuration/sites-configuration.component.ts
index 9d99800ca1..7254d234e1 100644
--- a/ui/src/app/assets/constants/asset.constants.ts
+++
b/ui/src/app/configuration/sites-configuration/sites-configuration.component.ts
@@ -16,7 +16,14 @@
*
*/
-export class AssetConstants {
- public static ASSET_APP_DOC_NAME = 'asset-management';
- public static ASSET_LINK_TYPES_DOC_NAME = 'asset-link-type';
+import { Component } from '@angular/core';
+import { SpConfigurationTabs } from '../configuration-tabs';
+
+@Component({
+ selector: 'sp-sites-configuration',
+ templateUrl: './sites-configuration.component.html',
+ styleUrls: ['./sites-configuration.component.scss'],
+})
+export class SitesConfigurationComponent {
+ tabs = SpConfigurationTabs.getTabs();
}