This is an automated email from the ASF dual-hosted git repository. riemer pushed a commit to branch improve-dataset-feature-card in repository https://gitbox.apache.org/repos/asf/streampipes.git
commit e2597d306ceee315f50cc2d7d25086086f2f5330 Author: Dominik Riemer <[email protected]> AuthorDate: Mon Feb 23 10:17:25 2026 +0100 style: Improve layout of dataset feature card preview --- .../dataset-feature-card.component.html | 25 +++++----- .../dataset-feature-card.component.scss | 53 +++++++++++++++++++++- .../dataset-feature-card.component.ts | 43 +++++++++++++++--- 3 files changed, 103 insertions(+), 18 deletions(-) diff --git a/ui/src/app/dataset/components/dataset-feature-card/dataset-feature-card.component.html b/ui/src/app/dataset/components/dataset-feature-card/dataset-feature-card.component.html index d5904bcc4a..fba5358311 100644 --- a/ui/src/app/dataset/components/dataset-feature-card/dataset-feature-card.component.html +++ b/ui/src/app/dataset/components/dataset-feature-card/dataset-feature-card.component.html @@ -50,7 +50,7 @@ size="small" variant="soft" > - {{ (lastEventTs | date: 'short') || '-' }} + {{ formatDate(lastEventTs) }} </sp-label> </div> </div> @@ -61,26 +61,29 @@ </div> <div class="dataset-preview-inner"> @if (dataPreview && dataPreview.total > 0) { - <div fxLayout="column"> + <div class="dataset-preview-table" fxLayout="column"> @for ( header of dataPreview.headers; let i = $index; track $index ) { - <div fxLayout="row" fxFlex="100"> - <span class="text-sm" fxFlex="70">{{ - header - }}</span> - <span class="text-sm font-bold" fxFlex="30"> + <div class="dataset-preview-row"> + <span class="dataset-preview-key"> + {{ header }} + </span> + <span class="dataset-preview-value"> {{ - dataPreview.allDataSeries[0].rows[0][i] - }}</span - > + formatPreviewValue( + header, + previewRow[i] + ) + }} + </span> </div> } </div> } @else { - <span class="text-sm">{{ + <span class="text-sm dataset-preview-empty">{{ 'No data available.' | translate }}</span> } diff --git a/ui/src/app/dataset/components/dataset-feature-card/dataset-feature-card.component.scss b/ui/src/app/dataset/components/dataset-feature-card/dataset-feature-card.component.scss index f224c48e64..62796fa7a5 100644 --- a/ui/src/app/dataset/components/dataset-feature-card/dataset-feature-card.component.scss +++ b/ui/src/app/dataset/components/dataset-feature-card/dataset-feature-card.component.scss @@ -22,8 +22,59 @@ } .dataset-preview-inner { - overflow-y: scroll; + overflow-y: auto; min-height: 0; + padding: 0.25rem; +} + +.dataset-preview-table { + gap: 0.25rem; +} + +.dataset-preview-row { + display: grid; + grid-template-columns: minmax(6.5rem, 38%) minmax(0, 1fr); + gap: 0.75rem; + align-items: start; + padding: 0.5rem 0.625rem; + border-radius: 0.375rem; + border: 1px solid transparent; +} + +.dataset-preview-row:nth-child(odd) { + background: var(--color-bg-1); + border-color: color-mix(in srgb, var(--color-bg-3) 45%, transparent); +} + +.dataset-preview-row:nth-child(even) { + background: var(--color-bg-0); + border-color: color-mix(in srgb, var(--color-bg-3) 65%, transparent); +} + +.dataset-preview-key { + font-size: var(--text-xs, 0.75rem); + opacity: 0.78; + line-height: 1.2; + word-break: break-word; + text-transform: capitalize; + letter-spacing: 0.03em; + padding-top: 0.125rem; +} + +.dataset-preview-value { + min-width: 0; + font-size: var(--text-sm, 0.85rem); + font-weight: var(--font-weight-bold); + line-height: 1.3; + overflow-wrap: anywhere; + border-left: 1px solid var(--color-bg-3); + padding-left: 0.75rem; + opacity: 0.95; +} + +.dataset-preview-empty { + display: block; + padding: 0.5rem; } .meta-card { diff --git a/ui/src/app/dataset/components/dataset-feature-card/dataset-feature-card.component.ts b/ui/src/app/dataset/components/dataset-feature-card/dataset-feature-card.component.ts index a9703fd3bf..a0bd276574 100644 --- a/ui/src/app/dataset/components/dataset-feature-card/dataset-feature-card.component.ts +++ b/ui/src/app/dataset/components/dataset-feature-card/dataset-feature-card.component.ts @@ -19,6 +19,7 @@ import { Component, inject, Input, OnInit } from '@angular/core'; import { FlexFillDirective } from '@ngbracket/ngx-layout'; import { + DateFormatService, FeatureCardHeaderComponent, FeatureCardMetaSectionComponent, SpLabelComponent, @@ -34,9 +35,7 @@ import { import { forkJoin } from 'rxjs'; import { TranslatePipe } from '@ngx-translate/core'; import { MatIcon } from '@angular/material/icon'; -import { DatePipe } from '@angular/common'; import { - FlexDirective, LayoutAlignDirective, LayoutDirective, LayoutGapDirective, @@ -48,13 +47,11 @@ import { styleUrls: ['./dataset-feature-card.component.scss'], imports: [ FlexFillDirective, - FlexDirective, LayoutDirective, TranslatePipe, LayoutAlignDirective, LayoutGapDirective, MatIcon, - DatePipe, FeatureCardHeaderComponent, FeatureCardMetaSectionComponent, SpLabelComponent, @@ -70,10 +67,12 @@ export class DatasetFeatureCardComponent implements OnInit { dataset: DataLakeMeasure; assetLinkType: AssetLinkType; dataPreview: SpQueryResult; - lastEventTs: number; + lastEventTs: number | undefined; + previewRow: unknown[] = []; private datalakeRestService = inject(DatalakeRestService); private genericStorageService = inject(GenericStorageService); + private dateFormatService = inject(DateFormatService); ngOnInit() { forkJoin([ @@ -103,10 +102,42 @@ export class DatasetFeatureCardComponent implements OnInit { .subscribe(res => { this.dataPreview = res; if (res.total > 0) { - this.lastEventTs = res.allDataSeries[0].rows[0][0]; + this.previewRow = res.allDataSeries?.[0]?.rows?.[0] ?? []; + this.lastEventTs = Number(this.previewRow[0]); + } else { + this.previewRow = []; + this.lastEventTs = undefined; } }); } + formatDate(timestamp?: number): string { + return this.dateFormatService.formatDate(timestamp); + } + + formatPreviewValue(header: string, value: unknown): string { + if (value === null || value === undefined || value === '') { + return '–'; + } + + if (this.isTimestampField(header)) { + return this.dateFormatService.formatDate(Number(value)); + } + + if (typeof value === 'object') { + try { + return JSON.stringify(value); + } catch { + return String(value); + } + } + + return String(value); + } + + private isTimestampField(header: string): boolean { + return 'time' === header; + } + navigateToChartView(): void {} }
