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 bfa9c9dbe9 feat: Add feature card to adapter page (#4196)
bfa9c9dbe9 is described below
commit bfa9c9dbe9d20950873bcd73ab1a251094678406
Author: Dominik Riemer <[email protected]>
AuthorDate: Tue Feb 24 12:30:27 2026 +0100
feat: Add feature card to adapter page (#4196)
---
ui/deployment/feature-cards.yml | 4 +
.../live-preview-table.component.html | 52 ++++----
.../live-preview-table.component.scss | 9 ++
.../live-preview-table.component.ts | 21 ++--
.../pipeline-element-runtime-info.component.html | 1 +
.../pipeline-element-runtime-info.component.scss | 17 ---
.../pipeline-element-runtime-info.component.ts | 4 +-
.../connect-feature-card.component.html | 116 +++++++++++++++++
.../connect-feature-card.component.scss | 99 +++++++++++++++
.../connect-feature-card.component.ts | 138 +++++++++++++++++++++
.../existing-adapters.component.html | 2 +
11 files changed, 410 insertions(+), 53 deletions(-)
diff --git a/ui/deployment/feature-cards.yml b/ui/deployment/feature-cards.yml
index 27b4dded52..8265f5adff 100644
--- a/ui/deployment/feature-cards.yml
+++ b/ui/deployment/feature-cards.yml
@@ -29,3 +29,7 @@
componentPath:
'./dataset/components/dataset-feature-card/dataset-feature-card.component'
componentName: DatasetFeatureCardComponent
moduleName: spDatasets
+- id: adapter
+ componentPath:
'./connect/components/connect-feature-card/connect-feature-card.component'
+ componentName: ConnectFeatureCardComponent
+ moduleName: spConnect
diff --git
a/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/live-preview-table/live-preview-table.component.html
b/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/live-preview-table/live-preview-table.component.html
index 8c119527db..0b595ebf3c 100644
---
a/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/live-preview-table/live-preview-table.component.html
+++
b/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/live-preview-table/live-preview-table.component.html
@@ -20,7 +20,7 @@
@if (showTitle) {
<p>{{ 'Here is a preview of your data:' | translate }}</p>
}
- <table mat-table [dataSource]="runtimeInfo">
+ <table mat-table [dataSource]="runtimeInfo" [class.compact]="compact">
<ng-container matColumnDef="runtimeName">
<th mat-header-cell *matHeaderCellDef>
<strong>{{ 'Runtime Name' | translate }}</strong>
@@ -30,32 +30,34 @@
</td>
</ng-container>
- <ng-container matColumnDef="label">
- <th mat-header-cell *matHeaderCellDef>
- <strong>{{ 'Field Name' | translate }}</strong>
- </th>
- <td mat-cell *matCellDef="let element">
- {{ element.label }}
- </td>
- </ng-container>
+ @if (!compact) {
+ <ng-container matColumnDef="label">
+ <th mat-header-cell *matHeaderCellDef>
+ <strong>{{ 'Field Name' | translate }}</strong>
+ </th>
+ <td mat-cell *matCellDef="let element">
+ {{ element.label }}
+ </td>
+ </ng-container>
- <ng-container matColumnDef="description">
- <th mat-header-cell *matHeaderCellDef>
- <strong>{{ 'Description' | translate }}</strong>
- </th>
- <td mat-cell *matCellDef="let element">
- {{ element.description }}
- </td>
- </ng-container>
+ <ng-container matColumnDef="description">
+ <th mat-header-cell *matHeaderCellDef>
+ <strong>{{ 'Description' | translate }}</strong>
+ </th>
+ <td mat-cell *matCellDef="let element">
+ {{ element.description }}
+ </td>
+ </ng-container>
- <ng-container matColumnDef="runtimeType">
- <th mat-header-cell *matHeaderCellDef>
- <strong>{{ 'Type' | translate }}</strong>
- </th>
- <td mat-cell *matCellDef="let element">
- {{ element.runtimeType }}
- </td>
- </ng-container>
+ <ng-container matColumnDef="runtimeType">
+ <th mat-header-cell *matHeaderCellDef>
+ <strong>{{ 'Type' | translate }}</strong>
+ </th>
+ <td mat-cell *matCellDef="let element">
+ {{ element.runtimeType }}
+ </td>
+ </ng-container>
+ }
<ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef>
diff --git
a/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/live-preview-table/live-preview-table.component.scss
b/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/live-preview-table/live-preview-table.component.scss
index b6f18bbb57..c5e5de49e4 100644
---
a/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/live-preview-table/live-preview-table.component.scss
+++
b/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/live-preview-table/live-preview-table.component.scss
@@ -41,3 +41,12 @@
text-align: center;
background: #ffe7ad;
}
+
+.mat-mdc-table.compact {
+ --mat-table-row-item-container-height: 36px;
+
+ .mat-mdc-header-cell,
+ .mat-mdc-cell {
+ font-size: var(--font-size-xs);
+ }
+}
diff --git
a/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/live-preview-table/live-preview-table.component.ts
b/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/live-preview-table/live-preview-table.component.ts
index 88d4a8417d..fcafa4fd49 100644
---
a/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/live-preview-table/live-preview-table.component.ts
+++
b/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/live-preview-table/live-preview-table.component.ts
@@ -16,7 +16,7 @@
*
*/
-import { Component, Input } from '@angular/core';
+import { Component, Input, OnInit } from '@angular/core';
import { EventSchema } from '@streampipes/platform-services';
import { RuntimeInfo } from '../pipeline-element-runtime-info.model';
import {
@@ -53,7 +53,7 @@ import { TranslatePipe } from '@ngx-translate/core';
TranslatePipe,
],
})
-export class LivePreviewTableComponent {
+export class LivePreviewTableComponent implements OnInit {
@Input()
eventSchema: EventSchema;
@@ -63,13 +63,14 @@ export class LivePreviewTableComponent {
@Input()
showTitle = true;
- displayedColumns: string[] = [
- 'runtimeName',
- 'label',
- 'description',
- 'runtimeType',
- 'value',
- ];
+ @Input()
+ compact = false;
+
+ displayedColumns: string[] = [];
- constructor() {}
+ ngOnInit() {
+ this.displayedColumns = this.compact
+ ? ['runtimeName', 'value']
+ : ['runtimeName', 'label', 'description', 'runtimeType', 'value'];
+ }
}
diff --git
a/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/pipeline-element-runtime-info.component.html
b/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/pipeline-element-runtime-info.component.html
index 8432e1835c..222e7436fb 100644
---
a/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/pipeline-element-runtime-info.component.html
+++
b/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/pipeline-element-runtime-info.component.html
@@ -18,6 +18,7 @@
@if (runtimeInfo) {
<sp-live-preview-table
+ [compact]="compact"
[showTitle]="showTitle"
[eventSchema]="streamDescription.eventSchema"
[runtimeInfo]="runtimeInfo"
diff --git
a/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/pipeline-element-runtime-info.component.scss
b/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/pipeline-element-runtime-info.component.scss
deleted file mode 100644
index 13cbc4aacb..0000000000
---
a/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/pipeline-element-runtime-info.component.scss
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * 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.
- *
- */
diff --git
a/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/pipeline-element-runtime-info.component.ts
b/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/pipeline-element-runtime-info.component.ts
index 59c4d0cbfb..8acab3c382 100644
---
a/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/pipeline-element-runtime-info.component.ts
+++
b/ui/projects/streampipes/shared-ui/src/lib/components/pipeline-element-runtime-info/pipeline-element-runtime-info.component.ts
@@ -38,7 +38,6 @@ import { LivePreviewErrorComponent } from
'./live-preview-error/live-preview-err
@Component({
selector: 'sp-pipeline-element-runtime-info',
templateUrl: './pipeline-element-runtime-info.component.html',
- styleUrls: ['./pipeline-element-runtime-info.component.scss'],
imports: [LivePreviewTableComponent, LivePreviewErrorComponent],
})
export class PipelineElementRuntimeInfoComponent implements OnInit, OnDestroy {
@@ -48,6 +47,9 @@ export class PipelineElementRuntimeInfoComponent implements
OnInit, OnDestroy {
@Input()
showTitle = true;
+ @Input()
+ compact = false;
+
runtimeData: { runtimeName: string; value: any }[];
runtimeInfo: RuntimeInfo[];
timer: any;
diff --git
a/ui/src/app/connect/components/connect-feature-card/connect-feature-card.component.html
b/ui/src/app/connect/components/connect-feature-card/connect-feature-card.component.html
new file mode 100644
index 0000000000..1e6c4ca372
--- /dev/null
+++
b/ui/src/app/connect/components/connect-feature-card/connect-feature-card.component.html
@@ -0,0 +1,116 @@
+<!--
+ ~ 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.
+ ~
+ -->
+
+@if (adapter) {
+ <div fxFlexFill fxLayout="column" class="feature-card-outer">
+ <sp-feature-card-header
+ [title]="adapter.name"
+ [description]="adapter.description"
+ [icon]="assetLinkType?.linkIcon"
+ [iconColor]="assetLinkType?.linkColor"
+ [detailsLink]="assetLinkType?.navPaths"
+ (close)="onClose?.()"
+ (onDetailsClick)="navigateToAdapter()"
+ >
+ </sp-feature-card-header>
+
+ <div class="feature-card-meta-card meta-card">
+ <sp-feature-card-meta-section [label]="'Status' | translate">
+ <div
+ class="feature-card-meta-box"
+ fxLayout="row"
+ fxLayoutAlign="start center"
+ fxLayoutGap="0.75rem"
+ >
+ <mat-icon class="feature-card-meta-icon">
+ {{ adapter.running ? 'play_circle' : 'pause_circle' }}
+ </mat-icon>
+ <div>
+ <div class="feature-card-meta-field-label">
+ {{ 'Adapter status' | translate }}
+ </div>
+ <sp-label
+ class="mt-xs"
+ textCase="uppercase"
+ [tone]="getStatusTone()"
+ size="small"
+ variant="soft"
+ >
+ {{ getStatusLabel() | translate }}
+ </sp-label>
+ </div>
+ </div>
+ </sp-feature-card-meta-section>
+
+ <div class="feature-card-meta-section__label">
+ {{ 'Preview info' | translate }}
+ </div>
+ <div class="adapter-info-table" fxLayout="column">
+ <div class="adapter-info-row">
+ <span class="adapter-info-key">{{
+ 'Created' | translate
+ }}</span>
+ <span class="adapter-info-value">{{
+ formatDate(adapter.createdAt)
+ }}</span>
+ </div>
+
+ <div class="adapter-info-row">
+ <span class="adapter-info-key">{{
+ 'Output stream' | translate
+ }}</span>
+ <span class="adapter-info-value">{{
+ getOutputStreamName()
+ }}</span>
+ </div>
+
+ <div class="adapter-info-row">
+ <span class="adapter-info-key">{{
+ 'Schema fields' | translate
+ }}</span>
+ <span class="adapter-info-value">{{
+ getFieldCount()
+ }}</span>
+ </div>
+ </div>
+ </div>
+
+ <div fxFlex fxLayout="column" class="feature-preview-wrapper">
+ <div class="adapter-live-preview">
+ <div class="feature-card-meta-section__label">
+ {{ 'Live preview' | translate }}
+ </div>
+
+ <div class="adapter-live-preview__content">
+ @if (streamDescription) {
+ <sp-pipeline-element-runtime-info
+ [compact]="true"
+ [showTitle]="false"
+ [streamDescription]="streamDescription"
+ >
+ </sp-pipeline-element-runtime-info>
+ } @else {
+ <span class="adapter-preview-empty">{{
+ 'No live preview available.' | translate
+ }}</span>
+ }
+ </div>
+ </div>
+ </div>
+ </div>
+}
diff --git
a/ui/src/app/connect/components/connect-feature-card/connect-feature-card.component.scss
b/ui/src/app/connect/components/connect-feature-card/connect-feature-card.component.scss
new file mode 100644
index 0000000000..93dec1fe3e
--- /dev/null
+++
b/ui/src/app/connect/components/connect-feature-card/connect-feature-card.component.scss
@@ -0,0 +1,99 @@
+/*!
+ * 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.
+ *
+ */
+
+:host {
+ width: 100%;
+ height: 100%;
+}
+
+.meta-card {
+ display: flex;
+ flex-direction: column;
+}
+
+.adapter-info-table {
+ gap: 0.25rem;
+}
+
+.adapter-info-row {
+ display: grid;
+ grid-template-columns: minmax(7rem, 38%) minmax(0, 1fr);
+ gap: 0.75rem;
+ align-items: start;
+ padding: 0.5rem 0.625rem;
+ border-radius: 0.375rem;
+ border: 1px solid transparent;
+}
+
+.adapter-info-row:nth-child(odd) {
+ background: var(--color-bg-1);
+ border-color: color-mix(in srgb, var(--color-bg-3) 45%, transparent);
+}
+
+.adapter-info-row:nth-child(even) {
+ background: var(--color-bg-0);
+ border-color: color-mix(in srgb, var(--color-bg-3) 65%, transparent);
+}
+
+.adapter-info-key {
+ font-size: var(--text-xs, 0.75rem);
+ font-weight: 600;
+ opacity: 0.78;
+ line-height: 1.2;
+ word-break: break-word;
+ text-transform: capitalize;
+ letter-spacing: 0.03em;
+ padding-top: 0.125rem;
+}
+
+.adapter-info-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;
+}
+
+.adapter-live-preview {
+ display: flex;
+ flex-direction: column;
+ flex: 1 1 auto;
+ min-height: 0;
+ gap: 0.5rem;
+}
+
+.adapter-live-preview__content {
+ flex: 1 1 auto;
+ min-height: 0;
+ overflow: auto;
+ border: 1px solid var(--color-bg-3);
+ border-radius: 0.5rem;
+ padding: 0.25rem;
+}
+
+.adapter-preview-empty {
+ display: block;
+ padding: 0.5rem;
+}
+
+.adapter-live-preview__content > sp-pipeline-element-runtime-info {
+ display: block;
+}
diff --git
a/ui/src/app/connect/components/connect-feature-card/connect-feature-card.component.ts
b/ui/src/app/connect/components/connect-feature-card/connect-feature-card.component.ts
new file mode 100644
index 0000000000..6caa979090
--- /dev/null
+++
b/ui/src/app/connect/components/connect-feature-card/connect-feature-card.component.ts
@@ -0,0 +1,138 @@
+/*
+ * 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, inject, Input, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { FlexFillDirective } from '@ngbracket/ngx-layout';
+import {
+ FlexDirective,
+ LayoutAlignDirective,
+ LayoutDirective,
+ LayoutGapDirective,
+} from '@ngbracket/ngx-layout/flex';
+import { MatIcon } from '@angular/material/icon';
+import { TranslatePipe } from '@ngx-translate/core';
+import { forkJoin } from 'rxjs';
+import {
+ AdapterDescription,
+ AdapterService,
+ AssetConstants,
+ AssetLinkType,
+ GenericStorageService,
+ PipelineElementService,
+ SpDataStream,
+} from '@streampipes/platform-services';
+import {
+ DateFormatService,
+ FeatureCardHeaderComponent,
+ FeatureCardMetaSectionComponent,
+ PipelineElementRuntimeInfoComponent,
+ SpLabelComponent,
+} from '@streampipes/shared-ui';
+
+@Component({
+ selector: 'sp-connect-feature-card',
+ templateUrl: './connect-feature-card.component.html',
+ styleUrls: ['./connect-feature-card.component.scss'],
+ imports: [
+ FlexFillDirective,
+ FlexDirective,
+ LayoutDirective,
+ LayoutAlignDirective,
+ LayoutGapDirective,
+ MatIcon,
+ TranslatePipe,
+ FeatureCardHeaderComponent,
+ FeatureCardMetaSectionComponent,
+ SpLabelComponent,
+ PipelineElementRuntimeInfoComponent,
+ ],
+})
+export class ConnectFeatureCardComponent implements OnInit {
+ @Input()
+ resourceId: string;
+
+ @Input()
+ onClose?: () => void;
+
+ adapter: AdapterDescription;
+ assetLinkType: AssetLinkType;
+ streamDescription: SpDataStream;
+
+ private adapterService = inject(AdapterService);
+ private genericStorageService = inject(GenericStorageService);
+ private pipelineElementService = inject(PipelineElementService);
+ private dateFormatService = inject(DateFormatService);
+ private router = inject(Router);
+
+ ngOnInit(): void {
+ forkJoin([
+ this.adapterService.getAdapter(this.resourceId),
+ this.genericStorageService.getAllDocuments(
+ AssetConstants.ASSET_LINK_TYPES_DOC_NAME,
+ ),
+ ]).subscribe(([adapter, assetLinkTypes]) => {
+ this.adapter = adapter;
+ this.assetLinkType = assetLinkTypes.find(
+ link => link.linkType === 'adapter',
+ );
+
+ if (adapter?.correspondingDataStreamElementId) {
+ this.pipelineElementService
+ .getDataStreamByElementId(
+ adapter.correspondingDataStreamElementId,
+ )
+ .subscribe(stream => {
+ this.streamDescription = stream;
+ });
+ }
+ });
+ }
+
+ formatDate(timestamp?: number): string {
+ return this.dateFormatService.formatDate(timestamp);
+ }
+
+ getFieldCount(): number {
+ return (
+ this.streamDescription?.eventSchema?.eventProperties?.length ?? 0
+ );
+ }
+
+ getOutputStreamName(): string {
+ return (
+ this.streamDescription?.name ||
+ this.adapter?.dataStream?.name ||
+ this.adapter?.correspondingDataStreamElementId ||
+ '–'
+ );
+ }
+
+ getStatusLabel(): string {
+ return this.adapter?.running ? 'Running' : 'Stopped';
+ }
+
+ getStatusTone(): 'success' | 'error' {
+ return this.adapter?.running ? 'success' : 'error';
+ }
+
+ navigateToAdapter(): void {
+ this.onClose?.();
+ this.router.navigate(['connect', 'details', this.resourceId, 'data']);
+ }
+}
diff --git
a/ui/src/app/connect/components/existing-adapters/existing-adapters.component.html
b/ui/src/app/connect/components/existing-adapters/existing-adapters.component.html
index d4369bfba1..c389dcb574 100644
---
a/ui/src/app/connect/components/existing-adapters/existing-adapters.component.html
+++
b/ui/src/app/connect/components/existing-adapters/existing-adapters.component.html
@@ -95,6 +95,8 @@
<div fxFlex="100" fxLayout="row" fxLayoutAlign="center start">
<sp-table
fxFlex="100"
+ featureCardId="adapter"
+ resourceIdKey="elementId"
[columns]="displayedColumns"
[dataSource]="dataSource"
[showActionsMenu]="true"