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 52b4ebbabb feat: Add ResourceMetadata model (#3556)
52b4ebbabb is described below

commit 52b4ebbabbe02cc7a1eccd7a52d98badde4bbfdc
Author: Dominik Riemer <[email protected]>
AuthorDate: Tue Apr 22 10:40:17 2025 +0200

    feat: Add ResourceMetadata model (#3556)
    
    * feat: Add ResourceMetadata model
    
    * feat: Add metadata to data explorer and dashboard overview
    
    * Fix pulsar container version
    
    ---------
    
    Co-authored-by: Marcelfrueh <[email protected]>
---
 .../apache/streampipes/model/ResourceMetadata.java | 41 ++++++++++++++++++
 .../apache/streampipes/model/api/SpResource.java   | 26 +++++++++++
 .../model/dashboard/DashboardEntity.java           | 11 ++++-
 .../model/dashboard/DashboardModel.java            | 11 ++++-
 ui/deployment/i18n/de.json                         |  4 ++
 ui/deployment/i18n/en.json                         |  4 ++
 .../src/lib/model/dashboard/dashboard.model.ts     |  2 +
 .../src/lib/model/gen/streampipes-model.ts         | 32 ++++++++++++--
 .../src/lib/services/date-format.service.ts        | 38 ++++++++++++++++
 .../streampipes/shared-ui/src/public-api.ts        |  1 +
 .../dashboard-overview-table.component.html        | 50 ++++++++++++++++++++++
 .../dashboard-overview-table.component.ts          | 15 ++++++-
 .../overview/dashboard-overview.component.ts       |  4 ++
 .../edit-dashboard-dialog.component.ts             |  1 +
 .../data-explorer-chart-view.component.ts          |  5 +++
 .../data-explorer-overview-table.component.html    | 50 ++++++++++++++++++++++
 .../data-explorer-overview-table.component.ts      | 13 +++++-
 17 files changed, 300 insertions(+), 8 deletions(-)

diff --git 
a/streampipes-model/src/main/java/org/apache/streampipes/model/ResourceMetadata.java
 
b/streampipes-model/src/main/java/org/apache/streampipes/model/ResourceMetadata.java
new file mode 100644
index 0000000000..02c78e4eb4
--- /dev/null
+++ 
b/streampipes-model/src/main/java/org/apache/streampipes/model/ResourceMetadata.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.model;
+
+public class ResourceMetadata {
+
+  private long createdAtEpochMs;
+  private long lastModifiedEpochMs;
+
+  public long getCreatedAtEpochMs() {
+    return createdAtEpochMs;
+  }
+
+  public void setCreatedAtEpochMs(long createdAtEpochMs) {
+    this.createdAtEpochMs = createdAtEpochMs;
+  }
+
+  public long getLastModifiedEpochMs() {
+    return lastModifiedEpochMs;
+  }
+
+  public void setLastModifiedEpochMs(long lastModifiedEpochMs) {
+    this.lastModifiedEpochMs = lastModifiedEpochMs;
+  }
+}
diff --git 
a/streampipes-model/src/main/java/org/apache/streampipes/model/api/SpResource.java
 
b/streampipes-model/src/main/java/org/apache/streampipes/model/api/SpResource.java
new file mode 100644
index 0000000000..e7fdc2df95
--- /dev/null
+++ 
b/streampipes-model/src/main/java/org/apache/streampipes/model/api/SpResource.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.model.api;
+
+import org.apache.streampipes.model.ResourceMetadata;
+
+public interface SpResource {
+
+  ResourceMetadata getMetadata();
+}
diff --git 
a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardEntity.java
 
b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardEntity.java
index b990e99966..d1e77bcfd8 100644
--- 
a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardEntity.java
+++ 
b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardEntity.java
@@ -18,6 +18,8 @@
 
 package org.apache.streampipes.model.dashboard;
 
+import org.apache.streampipes.model.ResourceMetadata;
+import org.apache.streampipes.model.api.SpResource;
 import org.apache.streampipes.model.datalake.DataExplorerWidgetModel;
 import org.apache.streampipes.model.shared.api.Storable;
 
@@ -28,7 +30,7 @@ import com.google.gson.annotations.SerializedName;
 @JsonSubTypes({
     @JsonSubTypes.Type(DataExplorerWidgetModel.class)
 })
-public abstract class DashboardEntity implements Storable {
+public abstract class DashboardEntity implements Storable, SpResource {
 
   @JsonAlias("_id")
   @SerializedName("_id")
@@ -38,6 +40,8 @@ public abstract class DashboardEntity implements Storable {
   @SerializedName("_rev")
   private String rev;
 
+  private ResourceMetadata metadata;
+
   public DashboardEntity() {
     super();
   }
@@ -61,4 +65,9 @@ public abstract class DashboardEntity implements Storable {
   public void setElementId(String elementId) {
     this.elementId = elementId;
   }
+
+  @Override
+  public ResourceMetadata getMetadata() {
+    return metadata;
+  }
 }
diff --git 
a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardModel.java
 
b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardModel.java
index cf9ee00ea2..2d1108c0d0 100644
--- 
a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardModel.java
+++ 
b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardModel.java
@@ -18,6 +18,8 @@
 
 package org.apache.streampipes.model.dashboard;
 
+import org.apache.streampipes.model.ResourceMetadata;
+import org.apache.streampipes.model.api.SpResource;
 import org.apache.streampipes.model.shared.annotation.TsModel;
 import org.apache.streampipes.model.shared.api.Storable;
 
@@ -29,7 +31,7 @@ import java.util.List;
 import java.util.Map;
 
 @TsModel
-public class DashboardModel implements Storable {
+public class DashboardModel implements Storable, SpResource {
 
   @JsonAlias("_id")
   @SerializedName("_id")
@@ -50,6 +52,8 @@ public class DashboardModel implements Storable {
 
   private List<DashboardItem> widgets;
 
+  private ResourceMetadata metadata;
+
   public DashboardModel() {
     this.dashboardTimeSettings = new HashMap<>();
     this.dashboardGeneralSettings = new HashMap<>();
@@ -143,4 +147,9 @@ public class DashboardModel implements Storable {
   public void setDashboardLiveSettings(Map<String, Object> 
dashboardLiveSettings) {
     this.dashboardLiveSettings = dashboardLiveSettings;
   }
+
+  @Override
+  public ResourceMetadata getMetadata() {
+    return metadata;
+  }
 }
diff --git a/ui/deployment/i18n/de.json b/ui/deployment/i18n/de.json
index 3625f8fe7b..5352dd885b 100644
--- a/ui/deployment/i18n/de.json
+++ b/ui/deployment/i18n/de.json
@@ -150,6 +150,7 @@
   "Charts": "Diagramme",
   "New chart": "Neues Diagramm",
   "Chart": "Diagramm",
+  "Created": "Erstellt",
   "Show chart": "Diagramm anzeigen",
   "Edit chart": "Diagramm bearbeiten",
   "Manage permissions": "Berechtigungen verwalten",
@@ -200,6 +201,9 @@
   "Mode": "Modus",
   "Count": "Anzahl",
   "Sum": "Summe",
+  "Median": "Median",
+  "Standard deviation": "Standardabweichung",
+  "Spread": "Spanne",
   "Unit": "Einheit",
   "Background": "Hintergrund",
   "Text": "Text",
diff --git a/ui/deployment/i18n/en.json b/ui/deployment/i18n/en.json
index d61d859016..9264e48626 100644
--- a/ui/deployment/i18n/en.json
+++ b/ui/deployment/i18n/en.json
@@ -150,6 +150,7 @@
   "Charts": null,
   "New chart": null,
   "Chart": null,
+  "Created": null,
   "Show chart": null,
   "Edit chart": null,
   "Manage permissions": null,
@@ -200,6 +201,9 @@
   "Mode": null,
   "Count": null,
   "Sum": null,
+  "Median": null,
+  "Standard deviation": null,
+  "Spread": null,
   "Unit": null,
   "Background": null,
   "Text": null,
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 532a19b2d4..134490d0ce 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,6 +18,7 @@
 
 import { GridsterConfig, GridsterItem } from 'angular-gridster2';
 import { TimeSettings } from '../datalake/DateRange';
+import { ResourceMetadata } from '../gen/streampipes-model';
 
 // tslint:disable-next-line:no-empty-interface
 export interface DashboardConfig extends GridsterConfig {}
@@ -45,5 +46,6 @@ export interface Dashboard {
     dashboardGeneralSettings?: any;
     dashboardLiveSettings: DashboardLiveSettings;
     elementId?: string;
+    metadata: ResourceMetadata;
     rev?: string;
 }
diff --git 
a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
 
b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
index 157c3538f5..d8d6f02e56 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,7 +20,7 @@
 /* tslint:disable */
 /* eslint-disable */
 // @ts-nocheck
-// Generated using typescript-generator version 3.2.1263 on 2025-03-10 
14:35:15.
+// Generated using typescript-generator version 3.2.1263 on 2025-04-04 
12:37:31.
 
 export class NamedStreamPipesEntity implements Storable {
     '@class':
@@ -1096,8 +1096,9 @@ export class CustomTransformOutputStrategy extends 
OutputStrategy {
     }
 }
 
-export class DashboardEntity implements Storable {
+export class DashboardEntity implements Storable, SpResource {
     elementId: string;
+    metadata: ResourceMetadata;
     rev: string;
 
     static fromData(
@@ -1109,6 +1110,7 @@ export class DashboardEntity implements Storable {
         }
         const instance = target || new DashboardEntity();
         instance.elementId = data.elementId;
+        instance.metadata = ResourceMetadata.fromData(data.metadata);
         instance.rev = data.rev;
         return instance;
     }
@@ -1150,7 +1152,7 @@ export class DashboardItem {
     }
 }
 
-export class DashboardModel implements Storable {
+export class DashboardModel implements Storable, SpResource {
     couchDbId: string;
     dashboardGeneralSettings: { [index: string]: any };
     dashboardLiveSettings: { [index: string]: any };
@@ -1159,6 +1161,7 @@ export class DashboardModel implements Storable {
     displayHeader: boolean;
     elementId: string;
     id: string;
+    metadata: ResourceMetadata;
     name: string;
     rev: string;
     widgets: DashboardItem[];
@@ -1185,6 +1188,7 @@ export class DashboardModel implements Storable {
         instance.displayHeader = data.displayHeader;
         instance.elementId = data.elementId;
         instance.id = data.id;
+        instance.metadata = ResourceMetadata.fromData(data.metadata);
         instance.name = data.name;
         instance.rev = data.rev;
         instance.widgets = __getCopyArrayFn(DashboardItem.fromData)(
@@ -3255,6 +3259,24 @@ export class RenameRuleDescription extends 
SchemaTransformationRuleDescription {
     }
 }
 
+export class ResourceMetadata {
+    createdAtEpochMs: number;
+    lastModifiedEpochMs: number;
+
+    static fromData(
+        data: ResourceMetadata,
+        target?: ResourceMetadata,
+    ): ResourceMetadata {
+        if (!data) {
+            return data;
+        }
+        const instance = target || new ResourceMetadata();
+        instance.createdAtEpochMs = data.createdAtEpochMs;
+        instance.lastModifiedEpochMs = data.lastModifiedEpochMs;
+        return instance;
+    }
+}
+
 export class RuntimeOptionsRequest {
     '@class':
         | 'org.apache.streampipes.model.runtime.RuntimeOptionsRequest'
@@ -3674,6 +3696,10 @@ export class SpQueryResult {
     }
 }
 
+export interface SpResource {
+    metadata: ResourceMetadata;
+}
+
 export class SpServiceConfiguration implements Storable {
     configs: ConfigItem[];
     elementId: string;
diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/services/date-format.service.ts 
b/ui/projects/streampipes/shared-ui/src/lib/services/date-format.service.ts
new file mode 100644
index 0000000000..539fdf14f7
--- /dev/null
+++ b/ui/projects/streampipes/shared-ui/src/lib/services/date-format.service.ts
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+import { Injectable } from '@angular/core';
+import { TranslateService } from '@ngx-translate/core';
+
+@Injectable({
+    providedIn: 'root',
+})
+export class DateFormatService {
+    constructor(private translateService: TranslateService) {}
+
+    formatDate(timestamp?: number): string {
+        if (!timestamp) {
+            return '–';
+        }
+
+        const currentLang = this.translateService.currentLang;
+        return new Intl.DateTimeFormat(currentLang, {
+            dateStyle: 'medium',
+            timeStyle: 'short',
+        }).format(new Date(timestamp));
+    }
+}
diff --git a/ui/projects/streampipes/shared-ui/src/public-api.ts 
b/ui/projects/streampipes/shared-ui/src/public-api.ts
index cbf05ab894..233e9d90a7 100644
--- a/ui/projects/streampipes/shared-ui/src/public-api.ts
+++ b/ui/projects/streampipes/shared-ui/src/public-api.ts
@@ -57,3 +57,4 @@ export * from './lib/services/echarts-toolbox.service';
 export * from './lib/services/colorization.service';
 export * from './lib/services/time-selection.service';
 export * from './lib/components/asset-browser/asset-browser.service';
+export * from './lib/services/date-format.service';
diff --git 
a/ui/src/app/dashboard/components/overview/dashboard-overview-table/dashboard-overview-table.component.html
 
b/ui/src/app/dashboard/components/overview/dashboard-overview-table/dashboard-overview-table.component.html
index 0f256d57ef..ff0e0525df 100644
--- 
a/ui/src/app/dashboard/components/overview/dashboard-overview-table/dashboard-overview-table.component.html
+++ 
b/ui/src/app/dashboard/components/overview/dashboard-overview-table/dashboard-overview-table.component.html
@@ -52,6 +52,56 @@
                 </td>
             </ng-container>
 
+            <ng-container matColumnDef="lastModified">
+                <th
+                    fxFlex="60"
+                    fxLayoutAlign="start center"
+                    mat-header-cell
+                    *matHeaderCellDef
+                >
+                    {{ 'Last modified' | translate }}
+                </th>
+                <td
+                    fxFlex="60"
+                    fxLayoutAlign="center start"
+                    mat-cell
+                    *matCellDef="let element"
+                    fxLayout="column"
+                >
+                    <div *ngIf="element.metadata">
+                        {{
+                            this.formatDate(
+                                element.metadata.lastModifiedEpochMs
+                            )
+                        }}
+                    </div>
+                    <div *ngIf="!element.metadata">–</div>
+                </td>
+            </ng-container>
+
+            <ng-container matColumnDef="createdAt">
+                <th
+                    fxFlex="60"
+                    fxLayoutAlign="start center"
+                    mat-header-cell
+                    *matHeaderCellDef
+                >
+                    {{ 'Created' | translate }}
+                </th>
+                <td
+                    fxFlex="60"
+                    fxLayoutAlign="center start"
+                    mat-cell
+                    *matCellDef="let element"
+                    fxLayout="column"
+                >
+                    <div *ngIf="element.metadata">
+                        {{ this.formatDate(element.metadata.createdAtEpochMs) 
}}
+                    </div>
+                    <div *ngIf="!element.metadata">–</div>
+                </td>
+            </ng-container>
+
             <ng-container matColumnDef="actions">
                 <th
                     fxFlex="40"
diff --git 
a/ui/src/app/dashboard/components/overview/dashboard-overview-table/dashboard-overview-table.component.ts
 
b/ui/src/app/dashboard/components/overview/dashboard-overview-table/dashboard-overview-table.component.ts
index d30057d1fa..d623b3e95f 100644
--- 
a/ui/src/app/dashboard/components/overview/dashboard-overview-table/dashboard-overview-table.component.ts
+++ 
b/ui/src/app/dashboard/components/overview/dashboard-overview-table/dashboard-overview-table.component.ts
@@ -31,6 +31,7 @@ import { MatDialog } from '@angular/material/dialog';
 import { DataExplorerDashboardService } from 
'../../../services/dashboard.service';
 import { DataExplorerSharedService } from 
'../../../../data-explorer-shared/services/data-explorer-shared.service';
 import { TranslateService } from '@ngx-translate/core';
+import { DateFormatService } from '@streampipes/shared-ui';
 
 @Component({
     selector: 'sp-dashboard-overview-table',
@@ -57,13 +58,19 @@ export class DashboardOverviewTableComponent extends 
SpDataExplorerOverviewDirec
         authService: AuthService,
         currentUserService: CurrentUserService,
         private dialog: MatDialog,
-        private translateService: TranslateService,
+        protected translateService: TranslateService,
+        protected dateFormatService: DateFormatService,
     ) {
         super(dialogService, authService, currentUserService, routingService);
     }
 
     afterInit(): void {
-        this.displayedColumns = ['name', 'actions'];
+        this.displayedColumns = [
+            'name',
+            'lastModified',
+            'createdAt',
+            'actions',
+        ];
         this.getDashboards();
     }
 
@@ -146,4 +153,8 @@ export class DashboardOverviewTableComponent extends 
SpDataExplorerOverviewDirec
         }
         this.dataSource.data = this.filteredDashboards;
     }
+
+    formatDate(timestamp?: number): string {
+        return this.dateFormatService.formatDate(timestamp);
+    }
 }
diff --git 
a/ui/src/app/dashboard/components/overview/dashboard-overview.component.ts 
b/ui/src/app/dashboard/components/overview/dashboard-overview.component.ts
index 562b9a47e2..527315c75c 100644
--- a/ui/src/app/dashboard/components/overview/dashboard-overview.component.ts
+++ b/ui/src/app/dashboard/components/overview/dashboard-overview.component.ts
@@ -78,6 +78,10 @@ export class DashboardOverviewComponent implements OnInit {
                 refreshIntervalInSeconds: 10,
                 label: this.translateService.instant('Off'),
             },
+            metadata: {
+                createdAtEpochMs: Date.now(),
+                lastModifiedEpochMs: Date.now(),
+            },
         };
 
         this.openDashboardModificationDialog(true, dataViewDashboard);
diff --git 
a/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.ts
 
b/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.ts
index a99645f2d1..45a4eacd7d 100644
--- 
a/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.ts
+++ 
b/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.ts
@@ -51,6 +51,7 @@ export class EditDashboardDialogComponent implements OnInit {
     }
 
     onSave(): void {
+        this.dashboard.metadata.lastModifiedEpochMs = Date.now();
         if (this.createMode) {
             this.dashboardService
                 .saveDashboard(this.dashboard)
diff --git 
a/ui/src/app/data-explorer/components/chart-view/data-explorer-chart-view.component.ts
 
b/ui/src/app/data-explorer/components/chart-view/data-explorer-chart-view.component.ts
index 5e2f01d849..5690b66998 100644
--- 
a/ui/src/app/data-explorer/components/chart-view/data-explorer-chart-view.component.ts
+++ 
b/ui/src/app/data-explorer/components/chart-view/data-explorer-chart-view.component.ts
@@ -147,11 +147,16 @@ export class DataExplorerChartViewComponent
         this.dataView.dataConfig.ignoreMissingValues = false;
         this.dataView.baseAppearanceConfig.backgroundColor = '#FFFFFF';
         this.dataView.baseAppearanceConfig.textColor = '#3e3e3e';
+        this.dataView.metadata = {
+            createdAtEpochMs: Date.now(),
+            lastModifiedEpochMs: Date.now(),
+        };
         this.dataView = { ...this.dataView };
     }
 
     saveDataView(): void {
         this.dataView.timeSettings = this.timeSettings;
+        this.dataView.metadata.lastModifiedEpochMs = Date.now();
         const observable =
             this.dataView.elementId !== undefined
                 ? this.dataViewService.updateChart(this.dataView)
diff --git 
a/ui/src/app/data-explorer/components/overview/data-explorer-overview-table/data-explorer-overview-table.component.html
 
b/ui/src/app/data-explorer/components/overview/data-explorer-overview-table/data-explorer-overview-table.component.html
index c45176bd5e..0f6581437f 100644
--- 
a/ui/src/app/data-explorer/components/overview/data-explorer-overview-table/data-explorer-overview-table.component.html
+++ 
b/ui/src/app/data-explorer/components/overview/data-explorer-overview-table/data-explorer-overview-table.component.html
@@ -46,6 +46,56 @@
                 </td>
             </ng-container>
 
+            <ng-container matColumnDef="lastModified">
+                <th
+                    fxFlex="60"
+                    fxLayoutAlign="start center"
+                    mat-header-cell
+                    *matHeaderCellDef
+                >
+                    {{ 'Last modified' | translate }}
+                </th>
+                <td
+                    fxFlex="60"
+                    fxLayoutAlign="center start"
+                    mat-cell
+                    *matCellDef="let element"
+                    fxLayout="column"
+                >
+                    <div *ngIf="element.metadata">
+                        {{
+                            this.formatDate(
+                                element.metadata.lastModifiedEpochMs
+                            )
+                        }}
+                    </div>
+                    <div *ngIf="!element.metadata">–</div>
+                </td>
+            </ng-container>
+
+            <ng-container matColumnDef="createdAt">
+                <th
+                    fxFlex="60"
+                    fxLayoutAlign="start center"
+                    mat-header-cell
+                    *matHeaderCellDef
+                >
+                    {{ 'Created' | translate }}
+                </th>
+                <td
+                    fxFlex="60"
+                    fxLayoutAlign="center start"
+                    mat-cell
+                    *matCellDef="let element"
+                    fxLayout="column"
+                >
+                    <div *ngIf="element.metadata">
+                        {{ this.formatDate(element.metadata.createdAtEpochMs) 
}}
+                    </div>
+                    <div *ngIf="!element.metadata">–</div>
+                </td>
+            </ng-container>
+
             <ng-container matColumnDef="actions">
                 <th
                     fxFlex="40"
diff --git 
a/ui/src/app/data-explorer/components/overview/data-explorer-overview-table/data-explorer-overview-table.component.ts
 
b/ui/src/app/data-explorer/components/overview/data-explorer-overview-table/data-explorer-overview-table.component.ts
index 62b6cad499..c8b9d12733 100644
--- 
a/ui/src/app/data-explorer/components/overview/data-explorer-overview-table/data-explorer-overview-table.component.ts
+++ 
b/ui/src/app/data-explorer/components/overview/data-explorer-overview-table/data-explorer-overview-table.component.ts
@@ -26,6 +26,7 @@ import {
 import {
     ConfirmDialogComponent,
     CurrentUserService,
+    DateFormatService,
     DialogService,
 } from '@streampipes/shared-ui';
 import { AuthService } from '../../../../services/auth.service';
@@ -57,12 +58,18 @@ export class SpDataExplorerDataViewOverviewComponent 
extends SpDataExplorerOverv
         routingService: DataExplorerRoutingService,
         private dialog: MatDialog,
         private translateService: TranslateService,
+        protected dateFormatService: DateFormatService,
     ) {
         super(dialogService, authService, currentUserService, routingService);
     }
 
     afterInit(): void {
-        this.displayedColumns = ['name', 'actions'];
+        this.displayedColumns = [
+            'name',
+            'lastModified',
+            'createdAt',
+            'actions',
+        ];
         this.getDataViews();
     }
 
@@ -134,4 +141,8 @@ export class SpDataExplorerDataViewOverviewComponent 
extends SpDataExplorerOverv
         }
         this.dataSource.data = this.filteredCharts;
     }
+
+    formatDate(timestamp?: number): string {
+        return this.dateFormatService.formatDate(timestamp);
+    }
 }

Reply via email to