This is an automated email from the ASF dual-hosted git repository.
riemer pushed a commit to branch
2396-should-prevent-multiple-clicks-on-tutorial-button
in repository https://gitbox.apache.org/repos/asf/streampipes.git
The following commit(s) were added to
refs/heads/2396-should-prevent-multiple-clicks-on-tutorial-button by this push:
new f04f555f3 fix(#2396): Disable tutorial button, fix subscription cleanup
f04f555f3 is described below
commit f04f555f3c0ad888491230fe2b18ece1ef19787d
Author: Dominik Riemer <[email protected]>
AuthorDate: Mon Jan 8 20:25:38 2024 +0100
fix(#2396): Disable tutorial button, fix subscription cleanup
---
.../existing-adapters.component.html | 4 +-
.../existing-adapters.component.ts | 53 +++++++++----------
ui/src/app/home/home.component.ts | 28 +++++-----
ui/src/app/pipelines/pipelines.component.html | 1 +
ui/src/app/pipelines/pipelines.component.ts | 60 +++++++++++++++-------
ui/src/app/services/tour/shepherd.service.ts | 26 ++++++++--
6 files changed, 107 insertions(+), 65 deletions(-)
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 b3beb2826..4e5cfefc8 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
@@ -66,11 +66,13 @@
>
<button
mat-icon-button
+ color="accent"
id="startAdapterTutorial3"
(click)="startAdapterTutorial()"
matTooltip="Tutorial: Generic Adapter"
+ [disabled]="tutorialActive"
>
- <mat-icon color="accent">school</mat-icon>
+ <mat-icon>school</mat-icon>
</button>
</div>
<button
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 d46dbaf33..c10f7729f 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
@@ -16,18 +16,16 @@
*
*/
-import { Component, OnInit, ViewChild } from '@angular/core';
+import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import {
AdapterDescription,
AdapterMonitoringService,
AdapterService,
PipelineElementService,
- PipelineService,
SpLogMessage,
SpMetricsEntry,
} from '@streampipes/platform-services';
import { MatTableDataSource } from '@angular/material/table';
-import { ConnectService } from '../../services/connect.service';
import {
CurrentUserService,
DialogRef,
@@ -47,7 +45,7 @@ import { Router } from '@angular/router';
import { AdapterFilterSettingsModel } from
'../../model/adapter-filter-settings.model';
import { AdapterFilterPipe } from '../../filter/adapter-filter.pipe';
import { SpConnectRoutes } from '../../connect.routes';
-import { zip } from 'rxjs';
+import { Subscription, zip } from 'rxjs';
import { RestApi } from '../../../services/rest-api.service';
import { ShepherdService } from '../../../services/tour/shepherd.service';
@@ -56,7 +54,7 @@ import { ShepherdService } from
'../../../services/tour/shepherd.service';
templateUrl: './existing-adapters.component.html',
styleUrls: ['./existing-adapters.component.scss'],
})
-export class ExistingAdaptersComponent implements OnInit {
+export class ExistingAdaptersComponent implements OnInit, OnDestroy {
existingAdapters: AdapterDescription[] = [];
filteredAdapters: AdapterDescription[] = [];
@@ -82,13 +80,16 @@ export class ExistingAdaptersComponent implements OnInit {
isAdmin = false;
adapterMetrics: Record<string, SpMetricsEntry> = {};
+ tutorialActive = false;
+
+ userSubscription: Subscription;
+ tutorialActiveSubscription: Subscription;
constructor(
private adapterService: AdapterService,
private dialogService: DialogService,
private currentUserService: CurrentUserService,
private pipelineElementService: PipelineElementService,
- private pipelineService: PipelineService,
private router: Router,
private restApi: RestApi,
private adapterFilter: AdapterFilterPipe,
@@ -101,10 +102,16 @@ export class ExistingAdaptersComponent implements OnInit {
this.breadcrumbService.updateBreadcrumb(
this.breadcrumbService.getRootLink(SpConnectRoutes.BASE),
);
- this.currentUserService.user$.subscribe(user => {
- this.isAdmin = user.roles.indexOf(UserRole.ROLE_ADMIN) > -1;
- this.getAdaptersRunning();
- });
+ this.userSubscription = this.currentUserService.user$.subscribe(
+ user => {
+ this.isAdmin = user.roles.indexOf(UserRole.ROLE_ADMIN) > -1;
+ this.getAdaptersRunning();
+ },
+ );
+ this.tutorialActiveSubscription =
+ this.shepherdService.tutorialActive$.subscribe(tutorialActive => {
+ this.tutorialActive = tutorialActive;
+ });
}
startAdapter(adapter: AdapterDescription) {
@@ -225,28 +232,11 @@ export class ExistingAdaptersComponent implements OnInit {
}
/**
- * Start edit mode when adapter is not used within a pipeline, otherwise
shows warning dialog
+ * Start edit mode
* @param adapter
*/
editAdapter(adapter: AdapterDescription) {
- this.pipelineService
- .getPipelinesContainingElementId(
- adapter.correspondingDataStreamElementId,
- )
- .subscribe(effectedPipelines => {
- // if (effectedPipelines.length > 0) {
- // this.dialogService.open(CanNotEditAdapterDialog, {
- // panelType: PanelType.STANDARD_PANEL,
- // title: 'No edit possible',
- // width: '50vw',
- // data: {
- // pipelines: effectedPipelines,
- // },
- // });
- // } else {
- this.router.navigate(['connect', 'edit', adapter.elementId]);
- //}
- });
+ this.router.navigate(['connect', 'edit', adapter.elementId]);
}
deleteAdapter(adapter: AdapterDescription): void {
@@ -331,4 +321,9 @@ export class ExistingAdaptersComponent implements OnInit {
'metrics',
]);
}
+
+ ngOnDestroy() {
+ this.userSubscription?.unsubscribe();
+ this.tutorialActiveSubscription?.unsubscribe();
+ }
}
diff --git a/ui/src/app/home/home.component.ts
b/ui/src/app/home/home.component.ts
index 158993a3a..6670c28a6 100644
--- a/ui/src/app/home/home.component.ts
+++ b/ui/src/app/home/home.component.ts
@@ -39,6 +39,7 @@ import {
PipelineService,
} from '@streampipes/platform-services';
import { zip } from 'rxjs';
+import { UserInfo } from
'../../../projects/streampipes/platform-services/src/lib/model/gen/streampipes-model';
@Component({
templateUrl: './home.component.html',
@@ -62,6 +63,7 @@ export class HomeComponent implements OnInit {
missingElementsForTutorial: any = [];
isTutorialOpen = false;
+ currentUser: UserInfo;
constructor(
private homeService: HomeService,
@@ -79,18 +81,19 @@ export class HomeComponent implements OnInit {
}
ngOnInit() {
- this.currentUserService.user$.subscribe(userInfo => {
- const isAdmin = userInfo.roles.indexOf(UserRole.ROLE_ADMIN) > -1;
- this.showStatus =
- isAdmin ||
- userInfo.roles.indexOf(UserRole.ROLE_PIPELINE_ADMIN) > -1;
- if (isAdmin) {
- this.loadResources();
- }
- });
+ this.currentUser = this.currentUserService.getCurrentUser();
+ const isAdmin = this.hasRole(UserRole.ROLE_ADMIN);
+ this.showStatus = isAdmin ||
this.hasRole(UserRole.ROLE_PIPELINE_ADMIN);
+ if (isAdmin) {
+ this.loadResources();
+ }
this.breadcrumbService.updateBreadcrumb([]);
}
+ hasRole(role: UserRole): boolean {
+ return this.currentUser.roles.indexOf(role) > -1;
+ }
+
openLink(link) {
if (link.link.newWindow) {
window.open(link.link.value);
@@ -100,8 +103,7 @@ export class HomeComponent implements OnInit {
}
checkForTutorial() {
- const currentUser = this.currentUserService.getCurrentUser();
- if (currentUser.showTutorial) {
+ if (this.currentUser.showTutorial) {
if (this.requiredPipelineElementsForTourPresent()) {
this.isTutorialOpen = true;
const dialogRef = this.dialogService.open(
@@ -110,7 +112,7 @@ export class HomeComponent implements OnInit {
panelType: PanelType.STANDARD_PANEL,
title: 'Welcome to ' + this.appConstants.APP_NAME,
data: {
- userInfo: currentUser,
+ userInfo: this.currentUser,
},
},
);
@@ -125,7 +127,7 @@ export class HomeComponent implements OnInit {
startTutorial() {
if (this.requiredPipelineElementsForTourPresent()) {
- this.router.navigate(['connect']).then(next => {
+ this.router.navigate(['connect']).then(() => {
this.shepherdService.startAdapterTour();
});
} else {
diff --git a/ui/src/app/pipelines/pipelines.component.html
b/ui/src/app/pipelines/pipelines.component.html
index 9f1851d6f..f8feda339 100644
--- a/ui/src/app/pipelines/pipelines.component.html
+++ b/ui/src/app/pipelines/pipelines.component.html
@@ -88,6 +88,7 @@
color="accent"
(click)="startPipelineTour()"
[matTooltip]="'Tutorial'"
+ [disabled]="tutorialActive"
style="margin-right: 5px"
>
<i class="material-icons"> school </i>
diff --git a/ui/src/app/pipelines/pipelines.component.ts
b/ui/src/app/pipelines/pipelines.component.ts
index 99adc8f1b..e87d8f02f 100644
--- a/ui/src/app/pipelines/pipelines.component.ts
+++ b/ui/src/app/pipelines/pipelines.component.ts
@@ -17,7 +17,7 @@
*/
import * as FileSaver from 'file-saver';
-import { Component, OnInit } from '@angular/core';
+import { Component, OnDestroy, OnInit } from '@angular/core';
import {
FunctionId,
FunctionsService,
@@ -41,13 +41,14 @@ import { UserPrivilege } from
'../_enums/user-privilege.enum';
import { SpPipelineRoutes } from './pipelines.routes';
import { UserRole } from '../_enums/user-role.enum';
import { ShepherdService } from '../services/tour/shepherd.service';
+import { Subscription } from 'rxjs';
@Component({
selector: 'sp-pipelines',
templateUrl: './pipelines.component.html',
styleUrls: ['./pipelines.component.scss'],
})
-export class PipelinesComponent implements OnInit {
+export class PipelinesComponent implements OnInit, OnDestroy {
pipeline: Pipeline;
pipelines: Pipeline[] = [];
systemPipelines: Pipeline[] = [];
@@ -67,6 +68,12 @@ export class PipelinesComponent implements OnInit {
functionsReady = false;
isAdminRole = false;
+ tutorialActive = false;
+
+ activatedRouteSubscription: Subscription;
+ tutorialActiveSubscription: Subscription;
+ userSubscription: Subscription;
+
constructor(
private pipelineService: PipelineService,
private dialogService: DialogService,
@@ -87,23 +94,32 @@ export class PipelinesComponent implements OnInit {
this.breadcrumbService.updateBreadcrumb(
this.breadcrumbService.getRootLink(SpPipelineRoutes.BASE),
);
- this.currentUserService.user$.subscribe(user => {
- this.hasPipelineWritePrivileges = this.authService.hasRole(
- UserPrivilege.PRIVILEGE_WRITE_PIPELINE,
- );
- this.isAdminRole = this.authService.hasRole(UserRole.ROLE_ADMIN);
- });
- this.activatedRoute.queryParams.subscribe(params => {
- if (params['pipeline']) {
- this.pipelineIdToStart = params['pipeline'];
- }
- if (params.startTutorial) {
- this.startPipelineTour();
- }
- this.getPipelineCategories();
- this.getPipelines();
- this.getFunctions();
- });
+ this.userSubscription = this.currentUserService.user$.subscribe(
+ user => {
+ this.hasPipelineWritePrivileges = this.authService.hasRole(
+ UserPrivilege.PRIVILEGE_WRITE_PIPELINE,
+ );
+ this.isAdminRole = this.authService.hasRole(
+ UserRole.ROLE_ADMIN,
+ );
+ },
+ );
+ this.activatedRouteSubscription =
+ this.activatedRoute.queryParams.subscribe(params => {
+ if (params['pipeline']) {
+ this.pipelineIdToStart = params['pipeline'];
+ }
+ if (params.startTutorial) {
+ this.startPipelineTour();
+ }
+ this.getPipelineCategories();
+ this.getPipelines();
+ this.getFunctions();
+ });
+ this.tutorialActiveSubscription =
+ this.shepherdService.tutorialActive$.subscribe(tutorialActive => {
+ this.tutorialActive = tutorialActive;
+ });
}
setSelectedTab(index) {
@@ -243,4 +259,10 @@ export class PipelinesComponent implements OnInit {
this.shepherdService.trigger('pipeline-new-button-clicked'),
);
}
+
+ ngOnDestroy() {
+ this.activatedRouteSubscription?.unsubscribe();
+ this.userSubscription?.unsubscribe();
+ this.tutorialActiveSubscription?.unsubscribe();
+ }
}
diff --git a/ui/src/app/services/tour/shepherd.service.ts
b/ui/src/app/services/tour/shepherd.service.ts
index 3eeeb263f..069c33f5d 100644
--- a/ui/src/app/services/tour/shepherd.service.ts
+++ b/ui/src/app/services/tour/shepherd.service.ts
@@ -21,6 +21,7 @@ import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { TourProviderService } from './tour-provider.service';
import Step from 'shepherd.js/src/types/step';
+import { BehaviorSubject } from 'rxjs';
import StepOptions = Step.StepOptions;
@Injectable({ providedIn: 'root' })
@@ -28,6 +29,9 @@ export class ShepherdService {
currentTour: Shepherd.Tour;
currentTourSettings: any;
timeWaitMillis: number;
+ tutorialActive = false;
+
+ public tutorialActive$ = new BehaviorSubject(false);
constructor(
private router: Router,
@@ -38,12 +42,22 @@ export class ShepherdService {
makeTour(currentTourSettings) {
const tour = new Shepherd.Tour({
- confirmCancel: true,
- confirmCancelMessage: 'Do you really want to cancel the tour?',
+ confirmCancel: () => {
+ return new Promise(resolve => {
+ const exit = window.confirm(
+ 'Do you really want to cancel the tour?',
+ );
+ if (exit) {
+ resolve(true);
+ this.changeTutorialStatus(false);
+ } else {
+ resolve(false);
+ }
+ });
+ },
defaultStepOptions: {
classes: 'shadow-md bg-purple-dark',
scrollTo: true,
- // showCancelLink: true
},
});
@@ -101,6 +115,7 @@ export class ShepherdService {
this.currentTourSettings = tourSettings;
this.currentTour = this.makeTour(this.currentTourSettings);
this.currentTour.start();
+ this.changeTutorialStatus(true);
}
makeCancelButton(tour) {
@@ -198,4 +213,9 @@ export class ShepherdService {
getTimeWaitMillis() {
return this.tourProviderService.getTime();
}
+
+ changeTutorialStatus(tutorialActive: boolean): void {
+ this.tutorialActive = tutorialActive;
+ this.tutorialActive$.next(tutorialActive);
+ }
}