This is an automated email from the ASF dual-hosted git repository.
tenthe 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 e071909262 1358 harmonize resource creation workflow for connect
(#4707)
e071909262 is described below
commit e071909262bc5b1000f503df086d85bf09637f9c
Author: Jacqueline Höllig <[email protected]>
AuthorDate: Thu Jul 23 22:55:06 2026 +0200
1358 harmonize resource creation workflow for connect (#4707)
Co-authored-by: Philipp Zehnder <[email protected]>
---
ui/deployment/i18n/de.json | 5 +-
ui/deployment/i18n/en.json | 5 +-
ui/deployment/i18n/pl.json | 5 +-
.../object-manage-dialog.component.html | 1 -
.../object-manage-dialog.component.ts | 24 ++-
.../adapter-configuration.component.html | 36 ++++-
.../adapter-configuration.component.ts | 121 ++++++++++++++
.../start-adapter-configuration.component.html | 179 ++++++++++-----------
.../start-adapter-configuration.component.ts | 13 +-
.../existing-adapters.component.html | 16 +-
.../existing-adapters.component.ts | 106 +++++++++---
.../adapter-code-dialog.component.html | 37 +++++
.../adapter-code-dialog.component.ts | 50 ++++++
.../adapter-started-dialog.component.html | 27 ++--
.../adapter-started-dialog.component.ts | 32 +++-
15 files changed, 499 insertions(+), 158 deletions(-)
diff --git a/ui/deployment/i18n/de.json b/ui/deployment/i18n/de.json
index 76a652ae74..e60235e3e3 100644
--- a/ui/deployment/i18n/de.json
+++ b/ui/deployment/i18n/de.json
@@ -644,6 +644,7 @@
"Mail Template": "Mail-Vorlage",
"Make available to all users with appropriate role": "Allen Benutzern mit
entsprechender Rolle zur Verfügung stellen",
"Manage": "Verwalten",
+ "Manage Adapter ": "Adapter verwalten ",
"Manage Asset ": "Asset verwalten ",
"Manage Chart ": "Diagramm verwalten",
"Manage Dashboard ": "Dashboard verwalten",
@@ -656,7 +657,6 @@
"Manage datasets": "Datensätze verwalten",
"Manage links": "Verwalten von Links",
"Manage permissions": "Berechtigungen verwalten",
- "Manage permissions for adapter ": "Berechtigungen für Adapter verwalten",
"Manage permissions for dataset ": "Berechtigungen für Datensatz verwalten",
"Manage permissions for pipeline element {{name}}": "Berechtigungen für
Pipeline-Element {{name}} verwalten",
"Manage pipeline": "Pipeline verwalten",
@@ -1001,9 +1001,8 @@
"Show Last Seen Timestamp": "Letzten Zeitstempel anzeigen",
"Show Pointer": "Zeiger anzeigen",
"Show Value in Traffic Light": "Wert anzeigen",
+ "Show as Code": "Code anzeigen",
"Show asset": "Asset anzeigen",
- "Show code": "Code anzeigen",
- "Show code to programmatically deploy this adapter over the API": "Code
anzeigen, um diesen Adapter programmatisch über die API einzusetzen",
"Show delta indicator": "Delta-Indikator anzeigen",
"Show details": "Details anzeigen",
"Show documentation": "Dokumentation anzeigen",
diff --git a/ui/deployment/i18n/en.json b/ui/deployment/i18n/en.json
index f0b7ebadf8..198792fa61 100644
--- a/ui/deployment/i18n/en.json
+++ b/ui/deployment/i18n/en.json
@@ -644,6 +644,7 @@
"Mail Template": null,
"Make available to all users with appropriate role": null,
"Manage": null,
+ "Manage Adapter ": null,
"Manage Asset ": null,
"Manage Chart ": null,
"Manage Dashboard ": null,
@@ -656,7 +657,6 @@
"Manage datasets": null,
"Manage links": null,
"Manage permissions": null,
- "Manage permissions for adapter ": null,
"Manage permissions for dataset ": null,
"Manage permissions for pipeline element {{name}}": "Manage permissions for
pipeline element {{name}}",
"Manage pipeline": null,
@@ -1001,9 +1001,8 @@
"Show Last Seen Timestamp": null,
"Show Pointer": null,
"Show Value in Traffic Light": null,
+ "Show as Code": null,
"Show asset": null,
- "Show code": null,
- "Show code to programmatically deploy this adapter over the API": null,
"Show delta indicator": null,
"Show details": null,
"Show documentation": null,
diff --git a/ui/deployment/i18n/pl.json b/ui/deployment/i18n/pl.json
index dab204a19c..00b80f0417 100644
--- a/ui/deployment/i18n/pl.json
+++ b/ui/deployment/i18n/pl.json
@@ -644,6 +644,7 @@
"Mail Template": "Szablon wiadomości",
"Make available to all users with appropriate role": "Udostępnij wszystkim
użytkownikom z odpowiednią rolą",
"Manage": "Zarządzanie",
+ "Manage Adapter ": "Zarządzaj adapterem ",
"Manage Asset ": "Zarządzanie aktywami ",
"Manage Chart ": "Zarządzaj wykresem",
"Manage Dashboard ": "Zarządzaj pulpitem nawigacyjnym",
@@ -656,7 +657,6 @@
"Manage datasets": "Zarządzaj zestawami danych",
"Manage links": "Zarządzaj linkami",
"Manage permissions": "Zarządzaj uprawnieniami",
- "Manage permissions for adapter ": "Zarządzaj uprawnieniami dla adaptera ",
"Manage permissions for dataset ": "Zarządzaj uprawnieniami dla zbioru
danych ",
"Manage permissions for pipeline element {{name}}": "Zarządzaj uprawnieniami
dla elementu strumienia {{name}}",
"Manage pipeline": "Zarządzaj procesem",
@@ -1001,9 +1001,8 @@
"Show Last Seen Timestamp": "Pokaż znacznik czasu ostatniego wystąpienia",
"Show Pointer": "Pokaż wskaźnik",
"Show Value in Traffic Light": "Pokaż wartość na sygnalizatorze",
+ "Show as Code": "Pokaż jako kod",
"Show asset": "Pokaż zasób",
- "Show code": "Pokaż kod",
- "Show code to programmatically deploy this adapter over the API": "Pokaż kod
do programowego wdrożenia tego adaptera przez API",
"Show delta indicator": "Pokaż wskaźnik zmiany",
"Show details": "Pokaż szczegóły",
"Show documentation": "Pokaż dokumentację",
diff --git
a/ui/projects/streampipes/shared-ui/src/lib/dialog/object-manage-dialog/object-manage-dialog.component.html
b/ui/projects/streampipes/shared-ui/src/lib/dialog/object-manage-dialog/object-manage-dialog.component.html
index ae3483a221..1d35f625b8 100644
---
a/ui/projects/streampipes/shared-ui/src/lib/dialog/object-manage-dialog/object-manage-dialog.component.html
+++
b/ui/projects/streampipes/shared-ui/src/lib/dialog/object-manage-dialog/object-manage-dialog.component.html
@@ -26,7 +26,6 @@
} @else if (!permissionDenied || createMode) {
<div class="sp-dialog-content">
<div fxFlex="100" fxLayout="column" class="p-15">
- <h4>{{ headerTitle }}</h4>
<form [formGroup]="parentForm" fxFlex="100" fxLayout="column">
@if (showResourceSection) {
<sp-split-section
diff --git
a/ui/projects/streampipes/shared-ui/src/lib/dialog/object-manage-dialog/object-manage-dialog.component.ts
b/ui/projects/streampipes/shared-ui/src/lib/dialog/object-manage-dialog/object-manage-dialog.component.ts
index 37d3e09722..9f2e97be27 100644
---
a/ui/projects/streampipes/shared-ui/src/lib/dialog/object-manage-dialog/object-manage-dialog.component.ts
+++
b/ui/projects/streampipes/shared-ui/src/lib/dialog/object-manage-dialog/object-manage-dialog.component.ts
@@ -398,8 +398,10 @@ export class ObjectManageDialogComponent<
return;
}
- await this.saveImmediately(result);
- this.close(true);
+ const saved = await this.saveImmediately(result);
+ if (saved) {
+ this.close(true);
+ }
}
close(result?: ObjectManageDialogResult<TResource> | boolean) {
@@ -433,9 +435,13 @@ export class ObjectManageDialogComponent<
private async saveImmediately(
result: ObjectManageDialogResult<TResource>,
- ): Promise<void> {
+ ): Promise<boolean> {
this.touchResource(result.resource);
- await this.saveResource(result.resource);
+ const saved = await this.saveResource(result.resource);
+ if (!saved) {
+ return false;
+ }
+
if (result.permission) {
await firstValueFrom(
this.permissionsService.updatePermission(result.permission),
@@ -450,6 +456,8 @@ export class ObjectManageDialogComponent<
result.originalAssets,
);
}
+
+ return true;
}
private createLinkageData(resource: TResource): LinkageData[] {
@@ -480,17 +488,17 @@ export class ObjectManageDialogComponent<
);
}
- private async saveResource(resource: TResource): Promise<void> {
+ private async saveResource(resource: TResource): Promise<boolean> {
const saveResource = this.resourceConfig.saveResource;
if (!saveResource) {
- return;
+ return true;
}
const saveResult = saveResource(resource);
if (isObservable(saveResult)) {
- await firstValueFrom(saveResult);
+ return (await firstValueFrom(saveResult)) !== false;
} else {
- await saveResult;
+ return (await saveResult) !== false;
}
}
diff --git
a/ui/src/app/connect/components/adapter-configuration/adapter-configuration.component.html
b/ui/src/app/connect/components/adapter-configuration/adapter-configuration.component.html
index 6379c07b41..991936ae86 100644
---
a/ui/src/app/connect/components/adapter-configuration/adapter-configuration.component.html
+++
b/ui/src/app/connect/components/adapter-configuration/adapter-configuration.component.html
@@ -21,7 +21,36 @@
[showBackLink]="true"
[backLinkTarget]="['connect']"
>
- <div nav fxFlex="100" fxLayout="row" fxLayoutAlign="end center"></div>
+ <div nav fxFlex="100" fxLayout="row" fxLayoutAlign="end center">
+ @if (isEditMode) {
+ <button
+ mat-icon-button
+ [matMenuTriggerFor]="optMenu"
+ [attr.aria-label]="'Options' | translate"
+ data-cy="options-adapter"
+ >
+ <mat-icon>more_vert</mat-icon>
+ </button>
+ <mat-menu #optMenu="matMenu">
+ <button
+ mat-menu-item
+ (click)="manageAdapter()"
+ data-cy="manage-adapter-btn"
+ >
+ <mat-icon>settings</mat-icon>
+ <span>{{ 'Manage' | translate }}</span>
+ </button>
+ <button
+ mat-menu-item
+ (click)="deleteAdapter()"
+ data-cy="delete-adapter-btn"
+ >
+ <mat-icon>clear</mat-icon>
+ <span>{{ 'Delete' | translate }}</span>
+ </button>
+ </mat-menu>
+ }
+ </div>
@let adapterConfigurationState = state();
@if (adapterConfigurationState) {
@if (adapterConfigurationState.adapterDescription) {
@@ -97,6 +126,11 @@
adapterDescription.dataStream.eventSchema
"
[isEditMode]="isEditMode"
+ [permission]="pendingPermission"
+ [selectedAssets]="pendingSelectedAssets"
+ [deselectedAssets]="pendingDeselectedAssets"
+ [originalAssets]="pendingOriginalAssets"
+ [addToAssets]="shouldAddToAssets"
(cancelEmitter)="navigateToAdapterCatalog()"
(goBackEmitter)="goBack()"
(adapterStartedEmitter)="adapterWasStarted()"
diff --git
a/ui/src/app/connect/components/adapter-configuration/adapter-configuration.component.ts
b/ui/src/app/connect/components/adapter-configuration/adapter-configuration.component.ts
index e8947198e8..90e5c338da 100644
---
a/ui/src/app/connect/components/adapter-configuration/adapter-configuration.component.ts
+++
b/ui/src/app/connect/components/adapter-configuration/adapter-configuration.component.ts
@@ -31,6 +31,11 @@ import { Router } from '@angular/router';
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import { AdapterConfigurationStateService } from
'./adapter-configuration-state-service/adapter-configuration-state.service';
import {
+ DialogService,
+ ObjectManageDialogComponent,
+ ObjectManageDialogResourceConfig,
+ ObjectManageDialogResult,
+ PanelType,
SpBasicHeaderTitleComponent,
SpBasicViewComponent,
} from '@streampipes/shared-ui';
@@ -43,6 +48,10 @@ import { AdapterSettingsComponent } from
'./adapter-settings/adapter-settings.co
import { ConfigureSchemaComponent } from
'./configure-schema/configure-schema.component';
import { ConfigureFieldsComponent } from
'./configure-fields/configure-fields.component';
import { StartAdapterConfigurationComponent } from
'./start-adapter-configuration/start-adapter-configuration.component';
+import { MatIconButton } from '@angular/material/button';
+import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu';
+import { MatIcon } from '@angular/material/icon';
+import { DeleteAdapterDialogComponent } from
'../../dialog/delete-adapter-dialog/delete-adapter-dialog.component';
@Component({
selector: 'sp-adapter-configuration',
@@ -54,6 +63,11 @@ import { StartAdapterConfigurationComponent } from
'./start-adapter-configuratio
LayoutDirective,
LayoutAlignDirective,
SpBasicHeaderTitleComponent,
+ MatIconButton,
+ MatMenuTrigger,
+ MatMenu,
+ MatMenuItem,
+ MatIcon,
MatStepper,
MatStep,
MatStepLabel,
@@ -69,6 +83,7 @@ export class AdapterConfigurationComponent implements OnInit,
OnDestroy {
private router = inject(Router);
private translate = inject(TranslateService);
private stateService = inject(AdapterConfigurationStateService);
+ private dialogService = inject(DialogService);
@Input() adapterDescription: AdapterDescription;
@@ -82,6 +97,7 @@ export class AdapterConfigurationComponent implements OnInit,
OnDestroy {
myStepper: MatStepper;
pageTitle = '';
+ private pendingManageAdapterResult?:
ObjectManageDialogResult<AdapterDescription>;
ngOnInit() {
this.pageTitle = this.isEditMode
@@ -116,6 +132,111 @@ export class AdapterConfigurationComponent implements
OnInit, OnDestroy {
this.router.navigate(['connect']).then();
}
+ manageAdapter(): void {
+ const currentAdapter =
+ this.state().adapterDescription ?? this.adapterDescription;
+ const pendingManageResult = this.pendingManageAdapterResult;
+
+ if (!currentAdapter) {
+ return;
+ }
+
+ const resourceConfig:
ObjectManageDialogResourceConfig<AdapterDescription> =
+ {
+ resourceLabel: 'Adapter',
+ nameLabel: 'Adapter name',
+ descriptionLabel: 'Adapter description',
+ nameProperty: 'name',
+ assetLinkType: 'adapter',
+ assetLinkCheckboxLabel:
+ 'Add the current adapter to an existing asset',
+ };
+
+ const dialogRef = this.dialogService.open(ObjectManageDialogComponent,
{
+ panelType: PanelType.SLIDE_IN_PANEL,
+ title: this.translate.instant('Manage'),
+ width: '50vw',
+ data: {
+ objectInstanceId:
+ currentAdapter.correspondingDataStreamElementId,
+ resource: { ...currentAdapter },
+ saveMode: 'deferred',
+ resourceConfig,
+ selectedAssets: pendingManageResult?.selectedAssets ?? [],
+ deselectedAssets: pendingManageResult?.deselectedAssets ?? [],
+ originalAssets: pendingManageResult?.originalAssets ?? [],
+ addToAssets: pendingManageResult?.addToAssets ?? true,
+ headerTitle:
+ this.translate.instant('Manage Adapter ') +
+ (currentAdapter.name ?? ''),
+ },
+ });
+
+ dialogRef.afterClosed().subscribe(result => {
+ if (result && typeof result !== 'boolean') {
+ this.pendingManageAdapterResult = result;
+ Object.assign(
+ currentAdapter,
+ result.resource as AdapterDescription,
+ );
+ this.adapterDescription = currentAdapter;
+ this.displayName = currentAdapter.name;
+ this.pageTitle =
+ this.translate.instant('Edit adapter: ') +
this.displayName;
+ }
+ });
+ }
+
+ deleteAdapter(): void {
+ const currentAdapter =
+ this.state().adapterDescription ?? this.adapterDescription;
+
+ if (!currentAdapter) {
+ return;
+ }
+
+ const dialogRef = this.dialogService.open(
+ DeleteAdapterDialogComponent,
+ {
+ panelType: PanelType.STANDARD_PANEL,
+ title: this.translate.instant('Delete Adapter'),
+ width: '70vw',
+ data: {
+ adapter: currentAdapter,
+ },
+ },
+ );
+
+ dialogRef.afterClosed().subscribe(refresh => {
+ if (refresh) {
+ this.stateService.reset();
+ this.router.navigate(['connect'], {
+ state: { omitConfirm: true },
+ });
+ }
+ });
+ }
+
+ get pendingPermission() {
+ return this.pendingManageAdapterResult?.permission;
+ }
+
+ get pendingSelectedAssets() {
+ return this.pendingManageAdapterResult?.selectedAssets ?? [];
+ }
+
+ get pendingDeselectedAssets() {
+ return this.pendingManageAdapterResult?.deselectedAssets ?? [];
+ }
+
+ get pendingOriginalAssets() {
+ return this.pendingManageAdapterResult?.originalAssets ?? [];
+ }
+
+ get shouldAddToAssets() {
+ return this.pendingManageAdapterResult?.addToAssets ?? true;
+ }
+
ngOnDestroy() {
this.stateService.reset();
}
diff --git
a/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.html
b/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.html
index f12efdc35e..abaea8d027 100644
---
a/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.html
+++
b/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.html
@@ -17,83 +17,89 @@
-->
<div [formGroup]="startAdapterForm" fxLayout="column" fxFlex="100">
- <sp-basic-inner-panel
- [panelTitle]="'Adapter settings' | translate"
- outerMargin="20px 0px 10px 0px"
- >
- <div fxFlex="100">
- <div fxLayoutAlign="center" fxLayout="column" fxFlex="100">
- <sp-form-field [level]="2" [label]="'Name' | translate">
- <mat-form-field color="accent">
- <input
- formControlName="adapterName"
- matInput
- id="input-AdapterName"
- [placeholder]="'Name' | translate"
- data-cy="sp-adapter-name"
- required
- (blur)="triggerTutorialAdapterNameAssigned()"
- />
- @if (
- startAdapterForm
- .get('adapterName')
- .hasError('invalidName')
- ) {
- <mat-error>
- Name can only contain letters, numbers, special
- characters (including umlauts), punctuation,
- symbols, and spaces.
- </mat-error>
- }
- @if (
- startAdapterForm
- .get('adapterName')
- .hasError('leadingOrTrailingWhitespace')
- ) {
- <mat-error>
- Name cannot start or end with a space.
- </mat-error>
- }
- @if (
- startAdapterForm
- .get('adapterName')
- .hasError('required') ||
- startAdapterForm
- .get('adapterName')
- .hasError('whiteSpaceOnly')
- ) {
- <mat-error> Adapter name is required. </mat-error>
- }
- @if (
- startAdapterForm
- .get('adapterName')
- .hasError('minlength') ||
- startAdapterForm
- .get('adapterName')
- .hasError('maxlength')
- ) {
- <mat-error>
- Adapter name must have between 3 and 40
- characters.
- </mat-error>
- }
- </mat-form-field>
- </sp-form-field>
- <sp-form-field [level]="2" [label]="'Description' | translate">
- <mat-form-field color="accent">
- <input
- matInput
- id="input-AdapterDescription"
- [ngModelOptions]="{ standalone: true }"
- [placeholder]="'Description' | translate"
- [(ngModel)]="adapterDescription.description"
- />
- </mat-form-field>
- </sp-form-field>
+ @if (!isEditMode) {
+ <sp-basic-inner-panel
+ [panelTitle]="'Adapter settings' | translate"
+ outerMargin="20px 0px 10px 0px"
+ >
+ <div fxFlex="100">
+ <div fxLayoutAlign="center" fxLayout="column" fxFlex="100">
+ <sp-form-field [level]="2" [label]="'Name' | translate">
+ <mat-form-field color="accent">
+ <input
+ formControlName="adapterName"
+ matInput
+ id="input-AdapterName"
+ [placeholder]="'Name' | translate"
+ data-cy="sp-adapter-name"
+ required
+ (blur)="triggerTutorialAdapterNameAssigned()"
+ />
+ @if (
+ startAdapterForm
+ .get('adapterName')
+ .hasError('invalidName')
+ ) {
+ <mat-error>
+ Name can only contain letters, numbers,
+ special characters (including umlauts),
+ punctuation, symbols, and spaces.
+ </mat-error>
+ }
+ @if (
+ startAdapterForm
+ .get('adapterName')
+ .hasError('leadingOrTrailingWhitespace')
+ ) {
+ <mat-error>
+ Name cannot start or end with a space.
+ </mat-error>
+ }
+ @if (
+ startAdapterForm
+ .get('adapterName')
+ .hasError('required') ||
+ startAdapterForm
+ .get('adapterName')
+ .hasError('whiteSpaceOnly')
+ ) {
+ <mat-error>
+ Adapter name is required.
+ </mat-error>
+ }
+ @if (
+ startAdapterForm
+ .get('adapterName')
+ .hasError('minlength') ||
+ startAdapterForm
+ .get('adapterName')
+ .hasError('maxlength')
+ ) {
+ <mat-error>
+ Adapter name must have between 3 and 40
+ characters.
+ </mat-error>
+ }
+ </mat-form-field>
+ </sp-form-field>
+ <sp-form-field
+ [level]="2"
+ [label]="'Description' | translate"
+ >
+ <mat-form-field color="accent">
+ <input
+ matInput
+ id="input-AdapterDescription"
+ [ngModelOptions]="{ standalone: true }"
+ [placeholder]="'Description' | translate"
+ [(ngModel)]="adapterDescription.description"
+ />
+ </mat-form-field>
+ </sp-form-field>
+ </div>
</div>
- </div>
- </sp-basic-inner-panel>
-
+ </sp-basic-inner-panel>
+ }
<div fxFlex="100" fxLayout="column">
@if (!isEditMode) {
<sp-adapter-options-panel
@@ -107,7 +113,7 @@
</sp-adapter-options-panel>
}
- @if (isAssetAdmin) {
+ @if (isAssetAdmin && !isEditMode) {
<sp-adapter-options-panel
[optionTitle]="'Add to Asset' | translate"
[optionDescription]="
@@ -282,25 +288,6 @@
</sp-adapter-options-panel>
}
}
-
- <sp-adapter-options-panel
- [optionTitle]="'Show code' | translate"
- [optionDescription]="
- 'Show code to programmatically deploy this adapter over the
API'
- | translate
- "
- optionIcon="code"
- dataCy="show-code-checkbox"
- (optionSelectedEmitter)="showCode = $event"
- >
- @if (showCode) {
- <sp-adapter-code-panel
- [adapterDescription]="adapterDescription"
- class="w-100"
- >
- </sp-adapter-code-panel>
- }
- </sp-adapter-options-panel>
</div>
<div fxLayoutAlign="end" style="margin-top: 10px">
diff --git
a/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.ts
b/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.ts
index 24410d2e15..32569e903e 100644
---
a/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.ts
+++
b/ui/src/app/connect/components/adapter-configuration/start-adapter-configuration/start-adapter-configuration.component.ts
@@ -26,6 +26,7 @@ import {
import {
AdapterDescription,
EventSchema,
+ Permission,
ReduceEventRateRule,
RemoveDuplicateRule,
SpAssetTreeNode,
@@ -64,7 +65,6 @@ import { MatInput } from '@angular/material/input';
import { SpAdapterOptionsPanelComponent } from
'./adapter-options-panel/adapter-options-panel.component';
import { MatOption, MatSelect } from '@angular/material/select';
import { MatTooltip } from '@angular/material/tooltip';
-import { AdapterCodePanelComponent } from
'../../adapter-code-panel/adapter-code-panel.component';
import { MatButton } from '@angular/material/button';
@Component({
@@ -87,7 +87,6 @@ import { MatButton } from '@angular/material/button';
MatSelect,
MatOption,
MatTooltip,
- AdapterCodePanelComponent,
MatButton,
TranslatePipe,
TimestampPipe,
@@ -109,6 +108,8 @@ export class StartAdapterConfigurationComponent implements
OnInit {
@Input() eventSchema: EventSchema;
@Input() isEditMode: boolean;
+ @Input() permission?: Permission;
+ @Input() addToAssets = true;
/**
* Cancels the adapter configuration process
@@ -146,9 +147,9 @@ export class StartAdapterConfigurationComponent implements
OnInit {
startAdapterNow = true;
showCode = false;
showAsset = false;
- selectedAssets = [];
- deselectedAssets = [];
- originalAssets = [];
+ @Input() selectedAssets: SpAssetTreeNode[] = [];
+ @Input() deselectedAssets: SpAssetTreeNode[] = [];
+ @Input() originalAssets: SpAssetTreeNode[] = [];
isAssetAdmin = false;
isPipelineAdmin = false;
@@ -202,6 +203,8 @@ export class StartAdapterConfigurationComponent implements
OnInit {
data: {
adapter: this.adapterDescription,
editMode: true,
+ permission: this.permission,
+ addToAssets: this.addToAssets,
selectedAssets: this.selectedAssets,
deselectedAssets: this.deselectedAssets,
originalAssets: this.originalAssets,
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 935b295329..489ceb39ce 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
@@ -252,6 +252,14 @@
<mat-icon>visibility</mat-icon>
<span>{{ 'Show' | translate }}</span>
</button>
+ <button
+ mat-menu-item
+ data-cy="show-adapter-code"
+ (click)="showCodeDialog(element)"
+ >
+ <mat-icon>code</mat-icon>
+ <span>{{ 'Code' | translate }}</span>
+ </button>
<button
mat-menu-item
data-cy="edit-adapter"
@@ -262,11 +270,11 @@
</button>
<button
mat-menu-item
- data-cy="open-manage-permissions"
- (click)="showPermissionsDialog(element)"
+ data-cy="open-manage-adapter"
+ (click)="showManageDialog(element)"
>
- <mat-icon>share</mat-icon>
- <span>{{ 'Manage permissions' | translate }}</span>
+ <mat-icon>settings</mat-icon>
+ <span>{{ 'Manage' | translate }}</span>
</button>
<button
mat-menu-item
diff --git
a/ui/src/app/connect/components/existing-adapters/existing-adapters.component.ts
b/ui/src/app/connect/components/existing-adapters/existing-adapters.component.ts
index ff39d474de..5808e77d53 100644
---
a/ui/src/app/connect/components/existing-adapters/existing-adapters.component.ts
+++
b/ui/src/app/connect/components/existing-adapters/existing-adapters.component.ts
@@ -18,6 +18,7 @@
import { Component, inject, OnDestroy, OnInit, ViewChild } from
'@angular/core';
import {
+ AdapterDescription,
AdapterMonitoringService,
AdapterService,
AdapterSummaryDto,
@@ -37,7 +38,8 @@ import {
CurrentUserService,
DialogRef,
DialogService,
- ObjectPermissionDialogComponent,
+ ObjectManageDialogComponent,
+ ObjectManageDialogResourceConfig,
PanelType,
SpAssetBrowserService,
SpBasicHeaderTitleComponent,
@@ -51,8 +53,10 @@ import {
SpTableActionsDirective,
SpTableComponent,
} from '@streampipes/shared-ui';
+import { AdapterCodeDialogComponent } from
'../../dialog/adapter-code-dialog/adapter-code-dialog.component';
import { DeleteAdapterDialogComponent } from
'../../dialog/delete-adapter-dialog/delete-adapter-dialog.component';
import { AllAdapterActionsComponent } from
'../../dialog/start-all-adapters/all-adapter-actions-dialog.component';
+import { AdapterStartedDialog } from
'../../dialog/adapter-started/adapter-started-dialog.component';
import { MatSort, MatSortHeader } from '@angular/material/sort';
import { Router } from '@angular/router';
import { SpConnectRoutes } from '../../connect.breadcrumb';
@@ -322,30 +326,94 @@ export class ExistingAdaptersComponent implements OnInit,
OnDestroy {
}
}
- showPermissionsDialog(adapter: AdapterSummaryDto): void {
- const dialogRef = this.dialogService.open(
- ObjectPermissionDialogComponent,
- {
- panelType: PanelType.SLIDE_IN_PANEL,
- title: this.translate.instant('Manage permissions'),
- width: '50vw',
+ showManageDialog(adapter: AdapterSummaryDto): void {
+ this.adapterService
+ .getAdapter(adapter.elementId)
+ .subscribe(fullAdapter => {
+ const resourceConfig:
ObjectManageDialogResourceConfig<AdapterDescription> =
+ {
+ resourceLabel: 'Adapter',
+ nameLabel: 'Adapter name',
+ descriptionLabel: 'Adapter description',
+ nameProperty: 'name',
+ assetLinkType: 'adapter',
+ assetLinkCheckboxLabel:
+ 'Add the current adapter to an existing asset',
+ saveResource: resource =>
+ this.updateManagedAdapter(
+ fullAdapter.name,
+ resource,
+ ),
+ };
+
+ const dialogRef = this.dialogService.open(
+ ObjectManageDialogComponent,
+ {
+ panelType: PanelType.SLIDE_IN_PANEL,
+ title: this.translate.instant('Manage'),
+ width: '50vw',
+ data: {
+ objectInstanceId:
+ fullAdapter.correspondingDataStreamElementId,
+ resource: { ...fullAdapter },
+ saveMode: 'immediate',
+ resourceConfig,
+ headerTitle:
+ this.translate.instant('Manage Adapter ') +
+ adapter.name,
+ },
+ },
+ );
+
+ dialogRef.afterClosed().subscribe(refresh => {
+ if (refresh) {
+ this.getAdaptersRunning();
+ }
+ });
+ });
+ }
+
+ private updateManagedAdapter(
+ originalName: string,
+ updatedAdapter: AdapterDescription,
+ ) {
+ if (originalName === updatedAdapter.name) {
+ return this.adapterService.updateAdapter(updatedAdapter);
+ }
+
+ return new Promise<boolean>(resolve => {
+ const dialogRef = this.dialogService.open(AdapterStartedDialog, {
+ panelType: PanelType.STANDARD_PANEL,
+ title: this.translate.instant('Edit adapter'),
+ width: '70vw',
data: {
- objectInstanceId: adapter.correspondingDataStreamElementId,
- headerTitle:
- this.translate.instant(
- 'Manage permissions for adapter ',
- ) + adapter.name,
+ adapter: updatedAdapter,
+ editMode: true,
+ addToAssets: false,
},
- },
- );
+ });
- dialogRef.afterClosed().subscribe(refresh => {
- if (refresh) {
- this.getAdaptersRunning();
- }
+ dialogRef.afterClosed().subscribe(result => {
+ resolve(result === 'Confirm');
+ });
});
}
+ showCodeDialog(adapter: AdapterSummaryDto): void {
+ this.adapterService
+ .getAdapter(adapter.elementId)
+ .subscribe(fullAdapter => {
+ this.dialogService.open(AdapterCodeDialogComponent, {
+ panelType: PanelType.SLIDE_IN_PANEL,
+ title: this.translate.instant('Show as Code'),
+ width: '50vw',
+ data: {
+ adapter: fullAdapter,
+ },
+ });
+ });
+ }
+
/**
* Start edit mode
* @param adapter
diff --git
a/ui/src/app/connect/dialog/adapter-code-dialog/adapter-code-dialog.component.html
b/ui/src/app/connect/dialog/adapter-code-dialog/adapter-code-dialog.component.html
new file mode 100644
index 0000000000..8bcce8d4d0
--- /dev/null
+++
b/ui/src/app/connect/dialog/adapter-code-dialog/adapter-code-dialog.component.html
@@ -0,0 +1,37 @@
+<!--
+~ Licensed to the Apache Software Foundation (ASF) under one or more
+~ contributor license agreements. See the NOTICE file distributed with
+~ this work for additional information regarding copyright ownership.
+~ The ASF licenses this file to You under the Apache License, Version 2.0
+~ (the "License"); you may not use this file except in compliance with
+~ the License. You may obtain a copy of the License at
+~
+~ http://www.apache.org/licenses/LICENSE-2.0
+~
+~ Unless required by applicable law or agreed to in writing, software
+~ distributed under the License is distributed on an "AS IS" BASIS,
+~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~ See the License for the specific language governing permissions and
+~ limitations under the License.
+~
+-->
+
+<div class="sp-dialog-container">
+ <div class="sp-dialog-content">
+ <div fxFlex="100" fxLayout="column" class="p-10">
+ @if (adapter) {
+ <sp-adapter-code-panel
+ [adapterDescription]="adapter"
+ maxHeight="none"
+ >
+ </sp-adapter-code-panel>
+ }
+ </div>
+ </div>
+ <mat-divider></mat-divider>
+ <div class="sp-dialog-actions">
+ <button mat-button mat-flat-button class="mat-basic" (click)="close()">
+ {{ 'Close' | translate }}
+ </button>
+ </div>
+</div>
diff --git
a/ui/src/app/connect/dialog/adapter-code-dialog/adapter-code-dialog.component.ts
b/ui/src/app/connect/dialog/adapter-code-dialog/adapter-code-dialog.component.ts
new file mode 100644
index 0000000000..02dc65397e
--- /dev/null
+++
b/ui/src/app/connect/dialog/adapter-code-dialog/adapter-code-dialog.component.ts
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { Component, Input, inject } from '@angular/core';
+import { AdapterDescription } from '@streampipes/platform-services';
+import { DialogRef } from '@streampipes/shared-ui';
+import { FlexDirective, LayoutDirective } from '@ngbracket/ngx-layout/flex';
+import { AdapterCodePanelComponent } from
'../../components/adapter-code-panel/adapter-code-panel.component';
+import { MatDivider } from '@angular/material/divider';
+import { MatButton } from '@angular/material/button';
+import { TranslatePipe } from '@ngx-translate/core';
+
+@Component({
+ selector: 'sp-adapter-code-dialog',
+ templateUrl: './adapter-code-dialog.component.html',
+ imports: [
+ FlexDirective,
+ LayoutDirective,
+ AdapterCodePanelComponent,
+ MatDivider,
+ MatButton,
+ TranslatePipe,
+ ],
+})
+export class AdapterCodeDialogComponent {
+ private dialogRef =
+ inject<DialogRef<AdapterCodeDialogComponent>>(DialogRef);
+
+ @Input()
+ adapter: AdapterDescription;
+
+ close(): void {
+ this.dialogRef.close();
+ }
+}
diff --git
a/ui/src/app/connect/dialog/adapter-started/adapter-started-dialog.component.html
b/ui/src/app/connect/dialog/adapter-started/adapter-started-dialog.component.html
index 8ab08b408f..1ae3beb014 100644
---
a/ui/src/app/connect/dialog/adapter-started/adapter-started-dialog.component.html
+++
b/ui/src/app/connect/dialog/adapter-started/adapter-started-dialog.component.html
@@ -78,14 +78,23 @@
{{ 'Keep editing' | translate }}
</button>
}
- <button
- id="confirm_adapter_started_button"
- class="mat-basic"
- mat-flat-button
- data-cy="close-adapter-started-dialog-button"
- (click)="onCloseConfirm()"
- >
- {{ 'Close' | translate }}
- </button>
+ @if (
+ !(
+ adapterUpdatePreflight &&
+ editMode &&
+ !adapterInstalled &&
+ !loading
+ )
+ ) {
+ <button
+ id="confirm_adapter_started_button"
+ class="mat-basic"
+ mat-flat-button
+ data-cy="close-adapter-started-dialog-button"
+ (click)="onCloseConfirm()"
+ >
+ {{ 'Close' | translate }}
+ </button>
+ }
</div>
</div>
diff --git
a/ui/src/app/connect/dialog/adapter-started/adapter-started-dialog.component.ts
b/ui/src/app/connect/dialog/adapter-started/adapter-started-dialog.component.ts
index 79b4fe9992..dc2d7db4ab 100644
---
a/ui/src/app/connect/dialog/adapter-started/adapter-started-dialog.component.ts
+++
b/ui/src/app/connect/dialog/adapter-started/adapter-started-dialog.component.ts
@@ -35,7 +35,9 @@ import {
ErrorMessage,
LinkageData,
Message,
+ Permission,
PipelineOperationStatus,
+ PermissionsService,
PipelineTemplateService,
PipelineUpdateInfo,
SpAssetTreeNode,
@@ -84,6 +86,7 @@ export class AdapterStartedDialog implements OnInit {
private compactPipelineService = inject(CompactPipelineService);
private assetSaveService = inject(AssetSaveService);
private dataLakeService = inject(DatalakeRestService);
+ private permissionsService = inject(PermissionsService);
adapterInstalled = false;
@@ -100,6 +103,8 @@ export class AdapterStartedDialog implements OnInit {
@Input() selectedAssets: SpAssetTreeNode[];
@Input() deselectedAssets: SpAssetTreeNode[];
@Input() originalAssets: SpAssetTreeNode[];
+ @Input() permission?: Permission;
+ @Input() addToAssets = true;
/**
* Indicates if a pipeline to store the adapter events should be started
@@ -185,8 +190,9 @@ export class AdapterStartedDialog implements OnInit {
this.loading = true;
this.adapterService.updateAdapter(this.adapter).subscribe({
- next: status => {
+ next: async status => {
if (status.success) {
+ await this.persistManageMetadata();
this.onAdapterReady(
`Adapter ${this.adapter.name} was successfully updated
and is available in the pipeline editor.`,
);
@@ -195,8 +201,6 @@ export class AdapterStartedDialog implements OnInit {
this.onAdapterFailure(errorLogMessage);
}
-
- this.addToAsset();
},
error: error => {
this.onAdapterFailure(error.error);
@@ -334,7 +338,9 @@ export class AdapterStartedDialog implements OnInit {
linkageData = this.createLinkageData(this.adapter);
}
- await this.saveAssets(linkageData);
+ if (this.addToAssets) {
+ await this.saveAssets(linkageData);
+ }
this.setSuccessMessage();
} catch (err) {
@@ -398,18 +404,32 @@ export class AdapterStartedDialog implements OnInit {
}
private setSuccessMessage(): void {
- if (this.selectedAssets.length > 0) {
+ if (this.addToAssets && this.selectedAssets.length > 0) {
this.addToAssetText = this.translateService.instant(
'Your Assets were successfully added.',
);
}
- if (this.deselectedAssets && this.deselectedAssets.length > 0) {
+ if (
+ this.addToAssets &&
+ this.deselectedAssets &&
+ this.deselectedAssets.length > 0
+ ) {
this.deletedFromAssetText = this.translateService.instant(
'Your Assets were successfully deleted.',
);
}
}
+ private async persistManageMetadata(): Promise<void> {
+ if (this.permission) {
+ await firstValueFrom(
+ this.permissionsService.updatePermission(this.permission),
+ );
+ }
+
+ await this.addToAsset();
+ }
+
private formatWithAnd(list: string[]): string {
if (list.length === 1) return list[0];
const lastItem = list.pop();