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 e30aa2b845 chore: Load dashboard in single request (#3715)
e30aa2b845 is described below
commit e30aa2b845bab08ab5dbda1d0c7ae4a486514fd4
Author: Dominik Riemer <[email protected]>
AuthorDate: Thu Aug 7 08:50:20 2025 +0200
chore: Load dashboard in single request (#3715)
* chore: Add API to load dashboard resources in a single request
* Improve widget loading in dashboard
---
.../model/dashboard/CompositeDashboardModel.java | 15 +--
.../model/datalake/DataExplorerWidgetModel.java | 20 ----
.../manager/setup/CouchDbInstallationStep.java | 6 ++
.../setup/tasks/AddDataLakeMeasureViewTask.java | 49 +++++++++
.../management/DataExplorerResourceManager.java | 31 ++++++
.../impl/dashboard/DataLakeDashboardResource.java | 11 +-
.../core/migrations/AvailableMigrations.java | 4 +-
.../v0980/AddDataLakeMeasureViewMigration.java | 61 +++++++++++
.../storage/api/IDataLakeMeasureStorage.java | 12 +--
.../streampipes/storage/api/INoSqlStorage.java | 3 +-
.../storage/couchdb/CouchDbStorageManager.java | 8 +-
.../couchdb/impl/DataLakeMeasureStorage.java | 60 +++++++++++
.../streampipes/storage/couchdb/utils/Utils.java | 1 +
.../src/lib/apis/dashboard.service.ts | 16 ++-
.../src/lib/model/dashboard/dashboard.model.ts | 13 ++-
.../chart-view/abstract-chart-view.directive.ts | 47 +++-----
.../grid-view/dashboard-grid-view.component.ts | 16 +--
.../slide-view/dashboard-slide-view.component.ts | 25 ++---
.../panel/dashboard-panel.component.html | 14 ++-
.../components/panel/dashboard-panel.component.ts | 120 +++++++++++++--------
.../data-explorer-chart-container.component.ts | 4 +-
.../base/base-data-explorer-widget.directive.ts | 7 +-
.../charts/image/image-widget.component.ts | 8 +-
.../models/dataview-dashboard.model.ts | 4 +-
24 files changed, 384 insertions(+), 171 deletions(-)
diff --git
a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/DataExplorerResourceManager.java
b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/CompositeDashboardModel.java
similarity index 65%
copy from
streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/DataExplorerResourceManager.java
copy to
streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/CompositeDashboardModel.java
index 38cca4a759..cb06527e42 100644
---
a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/DataExplorerResourceManager.java
+++
b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/CompositeDashboardModel.java
@@ -15,14 +15,15 @@
* limitations under the License.
*
*/
-package org.apache.streampipes.resource.management;
-import org.apache.streampipes.model.dashboard.DashboardModel;
-import org.apache.streampipes.storage.management.StorageDispatcher;
+package org.apache.streampipes.model.dashboard;
-public class DataExplorerResourceManager extends
AbstractCRUDResourceManager<DashboardModel> {
+import org.apache.streampipes.model.datalake.DataExplorerWidgetModel;
+import org.apache.streampipes.model.datalake.DataLakeMeasure;
- public DataExplorerResourceManager() {
-
super(StorageDispatcher.INSTANCE.getNoSqlStore().getDataExplorerDashboardStorage(),
DashboardModel.class);
- }
+import java.util.List;
+
+public record CompositeDashboardModel(DashboardModel dashboard,
+ List<DataExplorerWidgetModel> widgets,
+ List<DataLakeMeasure> dataLakeMeasures) {
}
diff --git
a/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/DataExplorerWidgetModel.java
b/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/DataExplorerWidgetModel.java
index 8e302ae163..af5d2739c9 100644
---
a/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/DataExplorerWidgetModel.java
+++
b/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/DataExplorerWidgetModel.java
@@ -45,10 +45,6 @@ public class DataExplorerWidgetModel extends DashboardEntity
{
@JsonSerialize(using = CustomMapSerializer.class, as = Map.class)
private Map<String, Object> timeSettings;
- private String pipelineId;
- private String measureName;
-
-
public DataExplorerWidgetModel() {
super();
this.baseAppearanceConfig = new HashMap<>();
@@ -97,22 +93,6 @@ public class DataExplorerWidgetModel extends DashboardEntity
{
this.dataConfig = dataConfig;
}
- public String getPipelineId() {
- return pipelineId;
- }
-
- public void setPipelineId(String pipelineId) {
- this.pipelineId = pipelineId;
- }
-
- public String getMeasureName() {
- return measureName;
- }
-
- public void setMeasureName(String measureName) {
- this.measureName = measureName;
- }
-
public Map<String, Object> getTimeSettings() {
return this.timeSettings;
}
diff --git
a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/CouchDbInstallationStep.java
b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/CouchDbInstallationStep.java
index e1e305e4a9..1e627973c6 100644
---
a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/CouchDbInstallationStep.java
+++
b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/CouchDbInstallationStep.java
@@ -19,6 +19,7 @@
package org.apache.streampipes.manager.setup;
import org.apache.streampipes.manager.setup.design.UserDesignDocument;
+import org.apache.streampipes.manager.setup.tasks.AddDataLakeMeasureViewTask;
import
org.apache.streampipes.manager.setup.tasks.AddDefaultPipelineTemplatesTask;
import org.apache.streampipes.manager.setup.tasks.CreateAssetLinkTypeTask;
import org.apache.streampipes.manager.setup.tasks.CreateDefaultAssetTask;
@@ -77,6 +78,7 @@ public class CouchDbInstallationStep extends InstallationStep
{
addUserView();
addNotificationView();
addPipelineView();
+ addDataLakeMeasureView();
}
private void addNotificationView() {
@@ -168,4 +170,8 @@ public class CouchDbInstallationStep extends
InstallationStep {
logFailure(PREPARING_USERS_TEXT, e);
}
}
+
+ private void addDataLakeMeasureView() {
+ new AddDataLakeMeasureViewTask().execute();
+ }
}
diff --git
a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/tasks/AddDataLakeMeasureViewTask.java
b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/tasks/AddDataLakeMeasureViewTask.java
new file mode 100644
index 0000000000..4ce055c6e7
--- /dev/null
+++
b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/tasks/AddDataLakeMeasureViewTask.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.manager.setup.tasks;
+
+import org.apache.streampipes.storage.couchdb.utils.Utils;
+
+import org.lightcouch.DesignDocument;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static
org.apache.streampipes.manager.setup.design.DesignDocumentUtils.prepareDocument;
+
+public class AddDataLakeMeasureViewTask implements InstallationTask {
+
+ public static final String MEASUREMENT_BY_NAME_VIEW = "_design/measurement";
+
+ public static final String VIEW_NAME = "by-measure-name";
+ public static final String MAP_FUNCTION = "function (doc) { if
(doc.measureName) { emit(doc.measureName, doc); } }";
+
+ @Override
+ public void execute() {
+ DesignDocument dataLakeDoc = prepareDocument(MEASUREMENT_BY_NAME_VIEW);
+ Map<String, DesignDocument.MapReduce> dataLakeMeasureViews = new
HashMap<>();
+
+ DesignDocument.MapReduce byNameFn = new DesignDocument.MapReduce();
+ byNameFn.setMap(MAP_FUNCTION);
+
+ dataLakeMeasureViews.put(VIEW_NAME, byNameFn);
+ dataLakeDoc.setViews(dataLakeMeasureViews);
+
Utils.getCouchDbGsonClient(Utils.DATA_LAKE_DB_NAME).design().synchronizeWithDb(dataLakeDoc);
+ }
+}
diff --git
a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/DataExplorerResourceManager.java
b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/DataExplorerResourceManager.java
index 38cca4a759..06edb30d5c 100644
---
a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/DataExplorerResourceManager.java
+++
b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/DataExplorerResourceManager.java
@@ -17,12 +17,43 @@
*/
package org.apache.streampipes.resource.management;
+import org.apache.streampipes.model.dashboard.CompositeDashboardModel;
import org.apache.streampipes.model.dashboard.DashboardModel;
+import org.apache.streampipes.model.datalake.DataExplorerWidgetModel;
+import org.apache.streampipes.storage.api.CRUDStorage;
+import org.apache.streampipes.storage.api.IDataLakeMeasureStorage;
import org.apache.streampipes.storage.management.StorageDispatcher;
+import java.util.List;
+import java.util.Map;
+
public class DataExplorerResourceManager extends
AbstractCRUDResourceManager<DashboardModel> {
+ private final CRUDStorage<DataExplorerWidgetModel> widgetStorage;
+ private final IDataLakeMeasureStorage dataLakeMeasureStorage;
+
public DataExplorerResourceManager() {
super(StorageDispatcher.INSTANCE.getNoSqlStore().getDataExplorerDashboardStorage(),
DashboardModel.class);
+ this.widgetStorage =
StorageDispatcher.INSTANCE.getNoSqlStore().getDataExplorerWidgetStorage();
+ this.dataLakeMeasureStorage =
StorageDispatcher.INSTANCE.getNoSqlStore().getDataLakeStorage();
+ }
+
+ public CompositeDashboardModel getCompositeDashboard(String dashboardId) {
+ var dashboard = db.getElementById(dashboardId);
+ var widgets = dashboard.getWidgets().stream().map(w ->
widgetStorage.getElementById(w.getId())).toList();
+ var dataLakeMeasures =
getMeasureNames(widgets).stream().map(dataLakeMeasureStorage::getByMeasureName).toList();
+
+ return new CompositeDashboardModel(dashboard, widgets, dataLakeMeasures);
+ }
+
+ private List<String> getMeasureNames(List<DataExplorerWidgetModel> widgets) {
+ return widgets.stream().map(DataExplorerWidgetModel::getDataConfig)
+ .map(dataConfig -> (List<?>) ((Map<?, ?>)
dataConfig).get("sourceConfigs"))
+ .filter(Map.class::isInstance)
+ .map(Map.class::cast)
+ .map(cfg -> cfg.get("measureName"))
+ .filter(String.class::isInstance)
+ .map(String.class::cast)
+ .toList();
}
}
diff --git
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DataLakeDashboardResource.java
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DataLakeDashboardResource.java
index 75eaded908..f97b7083a1 100644
---
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DataLakeDashboardResource.java
+++
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DataLakeDashboardResource.java
@@ -20,8 +20,9 @@ package org.apache.streampipes.rest.impl.dashboard;
import org.apache.streampipes.model.client.user.DefaultPrivilege;
+import org.apache.streampipes.model.dashboard.CompositeDashboardModel;
import org.apache.streampipes.model.dashboard.DashboardModel;
-import org.apache.streampipes.resource.management.AbstractCRUDResourceManager;
+import org.apache.streampipes.resource.management.DataExplorerResourceManager;
import
org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource;
import org.springframework.http.MediaType;
@@ -56,6 +57,12 @@ public class DataLakeDashboardResource extends
AbstractAuthGuardedRestResource {
return getResourceManager().find(dashboardId);
}
+ @GetMapping(path = "/{dashboardId}/composite", produces =
MediaType.APPLICATION_JSON_VALUE)
+ @PreAuthorize("this.hasReadAuthority() and hasPermission(#dashboardId,
'READ')")
+ public CompositeDashboardModel
getCompositeDashboardModel(@PathVariable("dashboardId") String dashboardId) {
+ return getResourceManager().getCompositeDashboard(dashboardId);
+ }
+
@PutMapping(path = "/{dashboardId}", produces =
MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("this.hasWriteAuthority() and
hasPermission(#dashboardModel.couchDbId, 'WRITE')")
public ResponseEntity<DashboardModel> modifyDashboard(@RequestBody
DashboardModel dashboardModel) {
@@ -77,7 +84,7 @@ public class DataLakeDashboardResource extends
AbstractAuthGuardedRestResource {
return ok();
}
- private AbstractCRUDResourceManager<DashboardModel> getResourceManager() {
+ private DataExplorerResourceManager getResourceManager() {
return getSpResourceManager().manageDataExplorer();
}
diff --git
a/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/migrations/AvailableMigrations.java
b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/migrations/AvailableMigrations.java
index e5e79b786c..b547059f59 100644
---
a/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/migrations/AvailableMigrations.java
+++
b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/migrations/AvailableMigrations.java
@@ -26,6 +26,7 @@ import
org.apache.streampipes.service.core.migrations.v090.UpdateUsernameViewMig
import org.apache.streampipes.service.core.migrations.v093.AdapterMigration;
import
org.apache.streampipes.service.core.migrations.v093.StoreEmailTemplatesMigration;
import
org.apache.streampipes.service.core.migrations.v095.MergeFilenamesAndRenameDuplicatesMigration;
+import
org.apache.streampipes.service.core.migrations.v0980.AddDataLakeMeasureViewMigration;
import
org.apache.streampipes.service.core.migrations.v0980.ModifyAssetLinkTypesMigration;
import
org.apache.streampipes.service.core.migrations.v0980.ModifyAssetLinksMigration;
import
org.apache.streampipes.service.core.migrations.v970.AddDataLakePipelineTemplateMigration;
@@ -56,7 +57,8 @@ public class AvailableMigrations {
new AddRolesToUserDbMigration(),
new AddDataLakePipelineTemplateMigration(),
new ModifyAssetLinksMigration(),
- new ModifyAssetLinkTypesMigration()
+ new ModifyAssetLinkTypesMigration(),
+ new AddDataLakeMeasureViewMigration()
);
}
}
diff --git
a/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/migrations/v0980/AddDataLakeMeasureViewMigration.java
b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/migrations/v0980/AddDataLakeMeasureViewMigration.java
new file mode 100644
index 0000000000..640f132c69
--- /dev/null
+++
b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/migrations/v0980/AddDataLakeMeasureViewMigration.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.service.core.migrations.v0980;
+
+import org.apache.streampipes.manager.setup.tasks.AddDataLakeMeasureViewTask;
+import org.apache.streampipes.service.core.migrations.Migration;
+import org.apache.streampipes.storage.couchdb.utils.Utils;
+
+import org.lightcouch.NoDocumentException;
+
+import java.io.IOException;
+
+public class AddDataLakeMeasureViewMigration implements Migration {
+
+ @Override
+ public boolean shouldExecute() {
+ try {
+ var designDoc = Utils
+ .getCouchDbGsonClient(Utils.DATA_LAKE_DB_NAME)
+ .design()
+ .getFromDb(AddDataLakeMeasureViewTask.MEASUREMENT_BY_NAME_VIEW);
+ var viewKey = AddDataLakeMeasureViewTask.VIEW_NAME;
+ var viewMapFunction = AddDataLakeMeasureViewTask.MAP_FUNCTION;
+ var views = designDoc.getViews();
+
+ if (views.containsKey(viewKey)) {
+ return !(views.get(viewKey).getMap().equals(viewMapFunction));
+ } else {
+ return true;
+ }
+ } catch (NoDocumentException e) {
+ return true;
+ }
+ }
+
+ @Override
+ public void executeMigration() throws IOException {
+ new AddDataLakeMeasureViewTask().execute();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Creating view for data lake measure database";
+ }
+}
diff --git
a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/DataExplorerResourceManager.java
b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataLakeMeasureStorage.java
similarity index 65%
copy from
streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/DataExplorerResourceManager.java
copy to
streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataLakeMeasureStorage.java
index 38cca4a759..cab2575714 100644
---
a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/DataExplorerResourceManager.java
+++
b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataLakeMeasureStorage.java
@@ -15,14 +15,12 @@
* limitations under the License.
*
*/
-package org.apache.streampipes.resource.management;
-import org.apache.streampipes.model.dashboard.DashboardModel;
-import org.apache.streampipes.storage.management.StorageDispatcher;
+package org.apache.streampipes.storage.api;
-public class DataExplorerResourceManager extends
AbstractCRUDResourceManager<DashboardModel> {
+import org.apache.streampipes.model.datalake.DataLakeMeasure;
- public DataExplorerResourceManager() {
-
super(StorageDispatcher.INSTANCE.getNoSqlStore().getDataExplorerDashboardStorage(),
DashboardModel.class);
- }
+public interface IDataLakeMeasureStorage extends CRUDStorage<DataLakeMeasure> {
+
+ DataLakeMeasure getByMeasureName(String measureName);
}
diff --git
a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java
b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java
index 742adf1409..ec330a4a7e 100644
---
a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java
+++
b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java
@@ -24,7 +24,6 @@ import org.apache.streampipes.model.client.user.Role;
import org.apache.streampipes.model.client.user.UserActivationToken;
import org.apache.streampipes.model.dashboard.DashboardModel;
import org.apache.streampipes.model.datalake.DataExplorerWidgetModel;
-import org.apache.streampipes.model.datalake.DataLakeMeasure;
import
org.apache.streampipes.model.extensions.configuration.SpServiceConfiguration;
import
org.apache.streampipes.model.extensions.svcdiscovery.SpServiceRegistration;
import org.apache.streampipes.model.file.FileMetadata;
@@ -48,7 +47,7 @@ public interface INoSqlStorage {
INotificationStorage getNotificationStorageApi();
- CRUDStorage<DataLakeMeasure> getDataLakeStorage();
+ IDataLakeMeasureStorage getDataLakeStorage();
CRUDStorage<FileMetadata> getFileMetadataStorage();
diff --git
a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java
b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java
index c6edb2cfcf..ea54cf6e0a 100644
---
a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java
+++
b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java
@@ -31,6 +31,7 @@ import org.apache.streampipes.model.file.FileMetadata;
import org.apache.streampipes.model.template.CompactPipelineTemplate;
import org.apache.streampipes.storage.api.CRUDStorage;
import org.apache.streampipes.storage.api.IAdapterStorage;
+import org.apache.streampipes.storage.api.IDataLakeMeasureStorage;
import org.apache.streampipes.storage.api.IDataProcessorStorage;
import org.apache.streampipes.storage.api.IDataSinkStorage;
import org.apache.streampipes.storage.api.IDataStreamStorage;
@@ -48,6 +49,7 @@ import org.apache.streampipes.storage.api.IUserStorage;
import
org.apache.streampipes.storage.couchdb.impl.AdapterDescriptionStorageImpl;
import org.apache.streampipes.storage.couchdb.impl.AdapterInstanceStorageImpl;
import
org.apache.streampipes.storage.couchdb.impl.CoreConfigurationStorageImpl;
+import org.apache.streampipes.storage.couchdb.impl.DataLakeMeasureStorage;
import org.apache.streampipes.storage.couchdb.impl.DataProcessorStorageImpl;
import org.apache.streampipes.storage.couchdb.impl.DataSinkStorageImpl;
import org.apache.streampipes.storage.couchdb.impl.DataStreamStorageImpl;
@@ -115,9 +117,9 @@ public enum CouchDbStorageManager implements INoSqlStorage {
}
@Override
- public CRUDStorage<DataLakeMeasure> getDataLakeStorage() {
- return new DefaultCrudStorage<>(
- () -> Utils.getCouchDbGsonClient("data-lake"),
+ public IDataLakeMeasureStorage getDataLakeStorage() {
+ return new DataLakeMeasureStorage(
+ () -> Utils.getCouchDbGsonClient(Utils.DATA_LAKE_DB_NAME),
DataLakeMeasure.class
);
}
diff --git
a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataLakeMeasureStorage.java
b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataLakeMeasureStorage.java
new file mode 100644
index 0000000000..38dec9498b
--- /dev/null
+++
b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataLakeMeasureStorage.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.storage.couchdb.impl;
+
+import org.apache.streampipes.model.datalake.DataLakeMeasure;
+import org.apache.streampipes.storage.api.IDataLakeMeasureStorage;
+
+import org.lightcouch.CouchDbClient;
+
+import java.util.List;
+import java.util.function.Supplier;
+
+public class DataLakeMeasureStorage extends
DefaultCrudStorage<DataLakeMeasure> implements IDataLakeMeasureStorage {
+
+ public static final String MEASUREMENT_BY_NAME_VIEW =
"measurement/by-measure-name";
+
+ public DataLakeMeasureStorage(Supplier<CouchDbClient> couchDbClientSupplier,
Class<DataLakeMeasure> clazz) {
+ super(couchDbClientSupplier, clazz);
+ }
+
+ @Override
+ public DataLakeMeasure getByMeasureName(String measureName) {
+ List<DataLakeMeasure> results = couchDbClientSupplier.get()
+ .view(MEASUREMENT_BY_NAME_VIEW)
+ .key(measureName)
+ .includeDocs(true)
+ .limit(1)
+ .query(DataLakeMeasure.class);
+
+ if (!results.isEmpty()) {
+ return results.get(0);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public List<DataLakeMeasure> findAll() {
+ return couchDbClientSupplier.get()
+ .view(MEASUREMENT_BY_NAME_VIEW)
+ .includeDocs(true)
+ .query(DataLakeMeasure.class);
+ }
+}
diff --git
a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java
b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java
index b6f9bf20ba..b98d8bafef 100644
---
a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java
+++
b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java
@@ -33,6 +33,7 @@ import org.lightcouch.CouchDbProperties;
public class Utils {
public static final String USER_DB_NAME = "users";
+ public static final String DATA_LAKE_DB_NAME = "data-lake";
public static CouchDbClient getCouchDbDataProcessorDescriptionClient() {
return getCouchDbGsonClient("data-processor");
diff --git
a/ui/projects/streampipes/platform-services/src/lib/apis/dashboard.service.ts
b/ui/projects/streampipes/platform-services/src/lib/apis/dashboard.service.ts
index 5e7753e257..4a40b03218 100644
---
a/ui/projects/streampipes/platform-services/src/lib/apis/dashboard.service.ts
+++
b/ui/projects/streampipes/platform-services/src/lib/apis/dashboard.service.ts
@@ -19,9 +19,11 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
-import { map } from 'rxjs/operators';
import { SharedDatalakeRestService } from './shared-dashboard.service';
-import { Dashboard } from '../model/dashboard/dashboard.model';
+import {
+ CompositeDashboard,
+ Dashboard,
+} from '../model/dashboard/dashboard.model';
@Injectable({
providedIn: 'root',
@@ -37,9 +39,13 @@ export class DashboardService {
}
getDashboard(dashboardId: string): Observable<Dashboard> {
- return this.http
- .get(`${this.dashboardUrl}/${dashboardId}`)
- .pipe(map(data => data as Dashboard));
+ return this.http.get<Dashboard>(`${this.dashboardUrl}/${dashboardId}`);
+ }
+
+ getCompositeDashboard(dashboardId: string): Observable<CompositeDashboard>
{
+ return this.http.get<CompositeDashboard>(
+ `${this.dashboardUrl}/${dashboardId}/composite`,
+ );
}
updateDashboard(dashboard: Dashboard): Observable<Dashboard> {
diff --git
a/ui/projects/streampipes/platform-services/src/lib/model/dashboard/dashboard.model.ts
b/ui/projects/streampipes/platform-services/src/lib/model/dashboard/dashboard.model.ts
index 134490d0ce..927d1a1946 100644
---
a/ui/projects/streampipes/platform-services/src/lib/model/dashboard/dashboard.model.ts
+++
b/ui/projects/streampipes/platform-services/src/lib/model/dashboard/dashboard.model.ts
@@ -18,7 +18,12 @@
import { GridsterConfig, GridsterItem } from 'angular-gridster2';
import { TimeSettings } from '../datalake/DateRange';
-import { ResourceMetadata } from '../gen/streampipes-model';
+import {
+ DashboardModel,
+ DataExplorerWidgetModel,
+ DataLakeMeasure,
+ ResourceMetadata,
+} from '../gen/streampipes-model';
// tslint:disable-next-line:no-empty-interface
export interface DashboardConfig extends GridsterConfig {}
@@ -49,3 +54,9 @@ export interface Dashboard {
metadata: ResourceMetadata;
rev?: string;
}
+
+export interface CompositeDashboard {
+ dashboard: Dashboard;
+ dataLakeMeasures: DataLakeMeasure[];
+ widgets: DataExplorerWidgetModel[];
+}
diff --git
a/ui/src/app/dashboard/components/chart-view/abstract-chart-view.directive.ts
b/ui/src/app/dashboard/components/chart-view/abstract-chart-view.directive.ts
index f75ab2f283..bf3adc6ad4 100644
---
a/ui/src/app/dashboard/components/chart-view/abstract-chart-view.directive.ts
+++
b/ui/src/app/dashboard/components/chart-view/abstract-chart-view.directive.ts
@@ -16,7 +16,7 @@
*
*/
-import { Directive, EventEmitter, Input, Output } from '@angular/core';
+import { Directive, EventEmitter, inject, Input, Output } from '@angular/core';
import {
ChartService,
Dashboard,
@@ -25,13 +25,19 @@ import {
TimeSettings,
} from '@streampipes/platform-services';
import { ResizeService } from
'../../../data-explorer-shared/services/resize.service';
-import { of, zip } from 'rxjs';
import { DataExplorerChartRegistry } from
'../../../data-explorer-shared/registry/data-explorer-chart-registry';
-import { catchError } from 'rxjs/operators';
@Directive()
export abstract class AbstractChartViewDirective {
- _dashboard: Dashboard;
+ protected resizeService = inject(ResizeService);
+ protected dataViewDataExplorerService = inject(ChartService);
+ protected widgetRegistryService = inject(DataExplorerChartRegistry);
+
+ @Input()
+ dashboard: Dashboard;
+
+ @Input()
+ widgets: DataExplorerWidgetModel[] = [];
@Input()
editMode: boolean;
@@ -61,39 +67,20 @@ export abstract class AbstractChartViewDirective {
@Output() startEditModeEmitter: EventEmitter<DataExplorerWidgetModel> =
new EventEmitter<DataExplorerWidgetModel>();
- constructor(
- protected resizeService: ResizeService,
- protected dataViewDataExplorerService: ChartService,
- protected widgetRegistryService: DataExplorerChartRegistry,
- ) {}
-
startEditMode(value: DataExplorerWidgetModel) {
this.startEditModeEmitter.emit(value);
this.currentlyConfiguredWidgetId = value.elementId;
}
- @Input() set dashboard(dashboard: Dashboard) {
- this._dashboard = dashboard;
- this.loadWidgetConfigs();
- }
-
- get dashboard() {
- return this._dashboard;
- }
-
loadWidgetConfigs() {
- const observables = this.dashboard.widgets.map(w =>
- this.dataViewDataExplorerService
- .getChart(w.id)
- .pipe(catchError(() => of(undefined))),
- );
- zip(...observables).subscribe(results => {
- results.forEach(r => {
- this.processWidget(r);
- this.onWidgetsAvailable();
- this.widgetsAvailable = true;
- });
+ this.dashboard.widgets.forEach(widgetConfig => {
+ const availableWidget = this.widgets.find(
+ w => w.elementId === widgetConfig.id,
+ );
+ this.processWidget(availableWidget);
});
+ this.onWidgetsAvailable();
+ this.widgetsAvailable = true;
}
loadWidgetConfig(widgetId: string, setCurrentlyConfigured?: boolean) {
diff --git
a/ui/src/app/dashboard/components/chart-view/grid-view/dashboard-grid-view.component.ts
b/ui/src/app/dashboard/components/chart-view/grid-view/dashboard-grid-view.component.ts
index 43f8a6a37c..481454a769 100644
---
a/ui/src/app/dashboard/components/chart-view/grid-view/dashboard-grid-view.component.ts
+++
b/ui/src/app/dashboard/components/chart-view/grid-view/dashboard-grid-view.component.ts
@@ -27,10 +27,7 @@ import {
import { GridsterItemComponent, GridType } from 'angular-gridster2';
import { GridsterInfo } from
'../../../../data-explorer-shared/models/gridster-info.model';
import { IDataViewDashboardConfig } from
'../../../../data-explorer-shared/models/dataview-dashboard.model';
-import { ResizeService } from
'../../../../data-explorer-shared/services/resize.service';
-import { ChartService } from '@streampipes/platform-services';
import { AbstractChartViewDirective } from '../abstract-chart-view.directive';
-import { DataExplorerChartRegistry } from
'../../../../data-explorer-shared/registry/data-explorer-chart-registry';
@Component({
selector: 'sp-dashboard-grid-view',
@@ -48,19 +45,8 @@ export class DashboardGridViewComponent
@ViewChildren(GridsterItemComponent)
gridsterItemComponents: QueryList<GridsterItemComponent>;
- constructor(
- protected resizeService: ResizeService,
- protected dataViewDataExplorerService: ChartService,
- protected widgetRegistryService: DataExplorerChartRegistry,
- ) {
- super(
- resizeService,
- dataViewDataExplorerService,
- widgetRegistryService,
- );
- }
-
ngOnInit(): void {
+ this.loadWidgetConfigs();
this.options = {
disablePushOnDrag: true,
draggable: { enabled: this.editMode },
diff --git
a/ui/src/app/dashboard/components/chart-view/slide-view/dashboard-slide-view.component.ts
b/ui/src/app/dashboard/components/chart-view/slide-view/dashboard-slide-view.component.ts
index d5169600c6..7d6dd7b283 100644
---
a/ui/src/app/dashboard/components/chart-view/slide-view/dashboard-slide-view.component.ts
+++
b/ui/src/app/dashboard/components/chart-view/slide-view/dashboard-slide-view.component.ts
@@ -16,16 +16,19 @@
*
*/
-import { AfterViewInit, Component, ElementRef, ViewChild } from
'@angular/core';
+import {
+ AfterViewInit,
+ Component,
+ ElementRef,
+ OnInit,
+ ViewChild,
+} from '@angular/core';
import { AbstractChartViewDirective } from '../abstract-chart-view.directive';
-import { ResizeService } from
'../../../../data-explorer-shared/services/resize.service';
import {
- ChartService,
DashboardItem,
DataExplorerWidgetModel,
DataLakeMeasure,
} from '@streampipes/platform-services';
-import { DataExplorerChartRegistry } from
'../../../../data-explorer-shared/registry/data-explorer-chart-registry';
@Component({
selector: 'sp-dashboard-slide-view',
@@ -35,7 +38,7 @@ import { DataExplorerChartRegistry } from
'../../../../data-explorer-shared/regi
})
export class DashboardSlideViewComponent
extends AbstractChartViewDirective
- implements AfterViewInit
+ implements OnInit, AfterViewInit
{
selectedWidgetIndex = 0;
@@ -49,16 +52,8 @@ export class DashboardSlideViewComponent
@ViewChild('slideViewOuter') slideViewOuter: ElementRef;
- constructor(
- protected resizeService: ResizeService,
- protected dataViewDataExplorerService: ChartService,
- protected widgetRegistryService: DataExplorerChartRegistry,
- ) {
- super(
- resizeService,
- dataViewDataExplorerService,
- widgetRegistryService,
- );
+ ngOnInit() {
+ this.loadWidgetConfigs();
}
selectWidget(index: number, widgetId: string): void {
diff --git
a/ui/src/app/dashboard/components/panel/dashboard-panel.component.html
b/ui/src/app/dashboard/components/panel/dashboard-panel.component.html
index ad1f0e154e..d2627f69c7 100644
--- a/ui/src/app/dashboard/components/panel/dashboard-panel.component.html
+++ b/ui/src/app/dashboard/components/panel/dashboard-panel.component.html
@@ -50,11 +50,13 @@
class="designer-panel"
>
<div fxLayout="column" fxFlex="100">
- <sp-dashboard-chart-selection-panel
- (addChartEmitter)="addChartToDashboard($event)"
- fxFlex="100"
- >
- </sp-dashboard-chart-selection-panel>
+ @if (editMode) {
+ <sp-dashboard-chart-selection-panel
+ (addChartEmitter)="addChartToDashboard($event)"
+ fxFlex="100"
+ >
+ </sp-dashboard-chart-selection-panel>
+ }
</div>
</mat-drawer>
<mat-drawer-content class="h-100 dashboard-grid">
@@ -77,6 +79,7 @@
*ngIf="dashboard.widgets.length > 0 && viewMode === 'grid'"
[editMode]="editMode"
[dashboard]="dashboard"
+ [widgets]="widgets"
[timeSettings]="timeSettings"
(deleteCallback)="removeChartFromDashboard($event)"
(startEditModeEmitter)="startEditMode($event)"
@@ -88,6 +91,7 @@
#dashboardSlide
[editMode]="editMode"
[dashboard]="dashboard"
+ [widgets]="widgets"
[timeSettings]="timeSettings"
(deleteCallback)="removeChartFromDashboard($event)"
(startEditModeEmitter)="startEditMode($event)"
diff --git a/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts
b/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts
index 5245ab3706..4931bc6417 100644
--- a/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts
+++ b/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts
@@ -63,6 +63,7 @@ export class DashboardPanelComponent
dashboardLoaded = false;
originalDashboard: Dashboard;
dashboard: Dashboard;
+ widgets: DataExplorerWidgetModel[] = [];
/**
* This is the date range (start, end) to view the data and is set in
data-explorer.ts
@@ -73,11 +74,8 @@ export class DashboardPanelComponent
editMode = false;
timeRangeVisible = true;
- @ViewChild('dashboardGrid')
- dashboardGrid: DashboardGridViewComponent;
-
- @ViewChild('dashboardSlide')
- dashboardSlide: DashboardSlideViewComponent;
+ _dashboardGrid: DashboardGridViewComponent;
+ _dashboardSlide: DashboardSlideViewComponent;
hasDataExplorerWritePrivileges = false;
@@ -133,11 +131,14 @@ export class DashboardPanelComponent
dashboardItem.x = 0;
dashboardItem.y = 0;
this.dashboard.widgets.push(dashboardItem);
- if (this.viewMode === 'grid') {
- this.dashboardGrid.loadWidgetConfig(dataViewElementId, true);
- } else {
- this.dashboardSlide.loadWidgetConfig(dataViewElementId, true);
- }
+ setTimeout(() => {
+ if (this.viewMode === 'grid') {
+ console.log(this.dashboardGrid);
+ this.dashboardGrid.loadWidgetConfig(dataViewElementId, true);
+ } else {
+ this.dashboardSlide.loadWidgetConfig(dataViewElementId, true);
+ }
+ });
}
setShouldShowConfirm(): boolean {
@@ -207,42 +208,49 @@ export class DashboardPanelComponent
}
getDashboard(dashboardId: string, startTime: number, endTime: number) {
- this.dashboardService.getDashboard(dashboardId).subscribe(dashboard =>
{
- this.dashboard = dashboard;
- this.originalDashboard = JSON.parse(JSON.stringify(dashboard));
- this.breadcrumbService.updateBreadcrumb(
- this.breadcrumbService.makeRoute(
- [SpDashboardRoutes.BASE],
- this.dashboard.name,
- ),
- );
- this.viewMode =
- this.dashboard.dashboardGeneralSettings.defaultViewMode ||
- 'grid';
- if (
- this.dashboard.dashboardGeneralSettings.globalTimeEnabled ===
- undefined
- ) {
- this.dashboard.dashboardGeneralSettings.globalTimeEnabled =
- true;
- }
- if (!this.dashboard.dashboardTimeSettings.startTime) {
- this.dashboard.dashboardTimeSettings =
- this.timeSelectionService.getDefaultTimeSettings();
- } else {
- this.timeSelectionService.updateTimeSettings(
- this.timeSelectionService.defaultQuickTimeSelections,
- this.dashboard.dashboardTimeSettings,
- new Date(),
+ this.dashboardService
+ .getCompositeDashboard(dashboardId)
+ .subscribe(compositeDashboard => {
+ this.dashboard = compositeDashboard.dashboard;
+ this.widgets = compositeDashboard.widgets;
+ this.originalDashboard = JSON.parse(
+ JSON.stringify(compositeDashboard.dashboard),
);
- }
- this.timeSettings =
- startTime && endTime
- ? this.overrideTime(+startTime, +endTime)
- : this.dashboard.dashboardTimeSettings;
- this.dashboardLoaded = true;
- this.modifyRefreshInterval(this.dashboard.dashboardLiveSettings);
- });
+ this.breadcrumbService.updateBreadcrumb(
+ this.breadcrumbService.makeRoute(
+ [SpDashboardRoutes.BASE],
+ this.dashboard.name,
+ ),
+ );
+ this.viewMode =
+ this.dashboard.dashboardGeneralSettings.defaultViewMode ||
+ 'grid';
+ if (
+ this.dashboard.dashboardGeneralSettings
+ .globalTimeEnabled === undefined
+ ) {
+ this.dashboard.dashboardGeneralSettings.globalTimeEnabled =
+ true;
+ }
+ if (!this.dashboard.dashboardTimeSettings.startTime) {
+ this.dashboard.dashboardTimeSettings =
+ this.timeSelectionService.getDefaultTimeSettings();
+ } else {
+ this.timeSelectionService.updateTimeSettings(
+ this.timeSelectionService.defaultQuickTimeSelections,
+ this.dashboard.dashboardTimeSettings,
+ new Date(),
+ );
+ }
+ this.timeSettings =
+ startTime && endTime
+ ? this.overrideTime(+startTime, +endTime)
+ : this.dashboard.dashboardTimeSettings;
+ this.dashboardLoaded = true;
+ this.modifyRefreshInterval(
+ this.dashboard.dashboardLiveSettings,
+ );
+ });
}
overrideTime(startTime: number, endTime: number): TimeSettings {
@@ -322,4 +330,26 @@ export class DashboardPanelComponent
)
.subscribe();
}
+
+ @ViewChild('dashboardGrid', { static: false })
+ set dashboardGrid(v: DashboardGridViewComponent) {
+ if (v) {
+ this._dashboardGrid = v;
+ }
+ }
+
+ get dashboardGrid(): DashboardGridViewComponent {
+ return this._dashboardGrid;
+ }
+
+ @ViewChild('dashboardSlide', { static: false })
+ set dashboardSlide(v: DashboardSlideViewComponent) {
+ if (v) {
+ this._dashboardSlide = v;
+ }
+ }
+
+ get dashboardSlide(): DashboardSlideViewComponent {
+ return this._dashboardSlide;
+ }
}
diff --git
a/ui/src/app/data-explorer-shared/components/chart-container/data-explorer-chart-container.component.ts
b/ui/src/app/data-explorer-shared/components/chart-container/data-explorer-chart-container.component.ts
index 373774462a..fb13faf5bb 100644
---
a/ui/src/app/data-explorer-shared/components/chart-container/data-explorer-chart-container.component.ts
+++
b/ui/src/app/data-explorer-shared/components/chart-container/data-explorer-chart-container.component.ts
@@ -31,7 +31,7 @@ import {
} from '@angular/core';
import { GridsterItemComponent } from 'angular-gridster2';
import {
- DashboardItem,
+ ClientDashboardItem,
DataExplorerWidgetModel,
DataLakeMeasure,
ExtendedTimeSettings,
@@ -70,7 +70,7 @@ export class DataExplorerChartContainerComponent
@ViewChild('timeSelectorMenu')
timeSelectorMenu: TimeRangeSelectorMenuComponent;
@Input()
- dashboardItem: DashboardItem;
+ dashboardItem: ClientDashboardItem;
@Input()
configuredWidget: DataExplorerWidgetModel;
diff --git
a/ui/src/app/data-explorer-shared/components/charts/base/base-data-explorer-widget.directive.ts
b/ui/src/app/data-explorer-shared/components/charts/base/base-data-explorer-widget.directive.ts
index 5db3fea62a..508dc62ff5 100644
---
a/ui/src/app/data-explorer-shared/components/charts/base/base-data-explorer-widget.directive.ts
+++
b/ui/src/app/data-explorer-shared/components/charts/base/base-data-explorer-widget.directive.ts
@@ -28,11 +28,10 @@ import {
import { GridsterItem, GridsterItemComponent } from 'angular-gridster2';
import { ChartConfigurationService } from
'../../../services/chart-configuration.service';
import {
- DashboardItem,
+ ClientDashboardItem,
DataExplorerDataConfig,
DataExplorerField,
DataExplorerWidgetModel,
- DatalakeRestService,
DataViewQueryGeneratorService,
SpLogMessage,
SpQueryResult,
@@ -80,7 +79,7 @@ export abstract class BaseDataExplorerWidgetDirective<
@Input()
gridMode = true;
- @Input() dataViewDashboardItem: DashboardItem;
+ @Input() dataViewDashboardItem: ClientDashboardItem;
@Input() dataExplorerWidget: T;
@Input()
@@ -110,8 +109,6 @@ export abstract class BaseDataExplorerWidgetDirective<
Observable<SpQueryResult>[]
>();
- // inject services to avoid constructor overload
- protected dataLakeRestService = inject(DatalakeRestService);
protected widgetConfigurationService = inject(ChartConfigurationService);
protected resizeService = inject(ResizeService);
protected dataViewQueryGeneratorService = inject(
diff --git
a/ui/src/app/data-explorer-shared/components/charts/image/image-widget.component.ts
b/ui/src/app/data-explorer-shared/components/charts/image/image-widget.component.ts
index 79875aae08..c66e0cbed2 100644
---
a/ui/src/app/data-explorer-shared/components/charts/image/image-widget.component.ts
+++
b/ui/src/app/data-explorer-shared/components/charts/image/image-widget.component.ts
@@ -16,11 +16,12 @@
*
*/
-import { Component, OnInit, ViewChild } from '@angular/core';
+import { Component, inject, OnInit, ViewChild } from '@angular/core';
import { MatSort } from '@angular/material/sort';
import { BaseDataExplorerWidgetDirective } from
'../base/base-data-explorer-widget.directive';
import {
DataExplorerField,
+ DatalakeRestService,
SpQueryResult,
} from '@streampipes/platform-services';
import { ImageWidgetModel } from './model/image-widget.model';
@@ -45,9 +46,8 @@ export class ImageWidgetComponent
canvasWidth;
imagePreviewHeight;
- constructor(private securePipe: SecurePipe) {
- super();
- }
+ private securePipe = inject(SecurePipe);
+ private dataLakeRestService = inject(DatalakeRestService);
ngOnInit(): void {
super.ngOnInit();
diff --git a/ui/src/app/data-explorer-shared/models/dataview-dashboard.model.ts
b/ui/src/app/data-explorer-shared/models/dataview-dashboard.model.ts
index ca0d5b9b62..57f4089b1b 100644
--- a/ui/src/app/data-explorer-shared/models/dataview-dashboard.model.ts
+++ b/ui/src/app/data-explorer-shared/models/dataview-dashboard.model.ts
@@ -22,7 +22,7 @@ import {
GridsterItemComponent,
} from 'angular-gridster2';
import {
- DashboardItem,
+ ClientDashboardItem,
DataExplorerField,
DataExplorerWidgetModel,
SpLogMessage,
@@ -50,7 +50,7 @@ export interface BaseWidgetData<T extends
DataExplorerWidgetModel> {
timeSettings: TimeSettings;
- dataViewDashboardItem: DashboardItem;
+ dataViewDashboardItem: ClientDashboardItem;
dataExplorerWidget: T;
previewMode: boolean;
gridMode: boolean;