This is an automated email from the ASF dual-hosted git repository.
dominikriemer 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 c0127c93d7 feat: Improve home screen loading behaviour (#4555)
c0127c93d7 is described below
commit c0127c93d764d148da4b15acec29cb8e10a14d82
Author: Dominik Riemer <[email protected]>
AuthorDate: Sat Jun 13 14:06:46 2026 +0200
feat: Improve home screen loading behaviour (#4555)
---
ui/deployment/modules.yml | 8 +-
.../registration-allowed.can-activate.guard.ts | 6 +-
.../restore-password-allowed.can-activate.guard.ts | 8 +-
.../guards/terms.can-activate-children.guard.ts | 6 +-
ui/src/app/help/help.component.ts | 6 +-
ui/src/app/home/components/status.component.ts | 2 +-
.../welcome-tour/welcome-tour.component.html | 45 +++++--
.../welcome-tour/welcome-tour.component.scss | 10 ++
.../dialog/welcome-tour/welcome-tour.component.ts | 127 +++++++++++++++++-
ui/src/app/home/home.component.ts | 148 +++------------------
.../login/components/base-login-page.directive.ts | 4 +-
.../services/login-settings.service.ts} | 50 ++++---
ui/src/app/login/services/login.service.ts | 16 +--
13 files changed, 233 insertions(+), 203 deletions(-)
diff --git a/ui/deployment/modules.yml b/ui/deployment/modules.yml
index f8a7b05de1..429c018463 100644
--- a/ui/deployment/modules.yml
+++ b/ui/deployment/modules.yml
@@ -59,7 +59,7 @@ spConnect:
createLinks: "['connect', 'catalog']"
title: 'Adapters'
createTitle: 'New adapter'
- dataFns: '[this.adapterService.getAdapters()]'
+ dataFns: '[this.adapterService.getAdapterSummary()]'
viewRoles: '[UserPrivilege.PRIVILEGE_READ_ADAPTER,
UserPrivilege.PRIVILEGE_WRITE_ADAPTER]'
createRoles: '[UserPrivilege.PRIVILEGE_WRITE_ADAPTER]'
category: 'management'
@@ -78,7 +78,7 @@ spPipelines:
createLinks: "['pipelines', 'create']"
title: 'Pipelines'
createTitle: 'New pipeline'
- dataFns: '[this.pipelineService.getPipelines()]'
+ dataFns: '[this.pipelineService.getPipelineSummary()]'
viewRoles: '[UserPrivilege.PRIVILEGE_READ_PIPELINE,
UserPrivilege.PRIVILEGE_WRITE_PIPELINE]'
createRoles: '[UserPrivilege.PRIVILEGE_WRITE_PIPELINE]'
category: 'analytics'
@@ -107,7 +107,7 @@ spDashboard:
createLinks: "['dashboard']"
title: 'Dashboards'
createTitle: 'New dashboard'
- dataFns: '[this.dashboardService.getDashboards()]'
+ dataFns: '[this.dashboardService.getDashboardSummary()]'
viewRoles: '[UserPrivilege.PRIVILEGE_READ_DASHBOARD,
UserPrivilege.PRIVILEGE_WRITE_DASHBOARD]'
createRoles: '[UserPrivilege.PRIVILEGE_WRITE_DASHBOARD]'
category: 'visualization'
@@ -127,7 +127,7 @@ spChart:
createLinks: "['chart']"
title: 'Charts'
createTitle: 'New chart'
- dataFns: '[this.chartService.getAllCharts()]'
+ dataFns: '[this.chartService.getChartSummary()]'
viewRoles: '[UserPrivilege.PRIVILEGE_READ_DATA_EXPLORER_VIEW,
UserPrivilege.PRIVILEGE_WRITE_DATA_EXPLORER_VIEW]'
createRoles: '[UserPrivilege.PRIVILEGE_WRITE_DATA_EXPLORER_VIEW]'
category: 'visualization'
diff --git
a/ui/src/app/core/setup/guards/registration-allowed.can-activate.guard.ts
b/ui/src/app/core/setup/guards/registration-allowed.can-activate.guard.ts
index ccccc288e5..2b7f1e86ae 100644
--- a/ui/src/app/core/setup/guards/registration-allowed.can-activate.guard.ts
+++ b/ui/src/app/core/setup/guards/registration-allowed.can-activate.guard.ts
@@ -23,14 +23,14 @@ import {
RouterStateSnapshot,
UrlTree,
} from '@angular/router';
-import { LoginService } from '../../../login/services/login.service';
+import { LoginSettingsService } from
'../../../login/services/login-settings.service';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class RegistrationAllowedCanActivateGuard {
private router = inject(Router);
- private loginService = inject(LoginService);
+ private loginSettingsService = inject(LoginSettingsService);
canActivate(
_route: ActivatedRouteSnapshot,
@@ -40,7 +40,7 @@ export class RegistrationAllowedCanActivateGuard {
| Promise<boolean | UrlTree>
| boolean
| UrlTree {
- return this.loginService.fetchLoginSettings().pipe(
+ return this.loginSettingsService.getSettings().pipe(
map(config => {
return config.allowSelfRegistration
? true
diff --git
a/ui/src/app/core/setup/guards/restore-password-allowed.can-activate.guard.ts
b/ui/src/app/core/setup/guards/restore-password-allowed.can-activate.guard.ts
index e7f51df072..66c1060aef 100644
---
a/ui/src/app/core/setup/guards/restore-password-allowed.can-activate.guard.ts
+++
b/ui/src/app/core/setup/guards/restore-password-allowed.can-activate.guard.ts
@@ -23,14 +23,14 @@ import {
RouterStateSnapshot,
UrlTree,
} from '@angular/router';
-import { LoginService } from '../../../login/services/login.service';
+import { LoginSettingsService } from
'../../../login/services/login-settings.service';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class RestorePasswordAllowedCanActivateGuard {
private router = inject(Router);
- private loginService = inject(LoginService);
+ private loginSettingsService = inject(LoginSettingsService);
canActivate(
_route: ActivatedRouteSnapshot,
@@ -40,8 +40,8 @@ export class RestorePasswordAllowedCanActivateGuard {
| Promise<boolean | UrlTree>
| boolean
| UrlTree {
- return this.loginService
- .fetchLoginSettings()
+ return this.loginSettingsService
+ .getSettings()
.pipe(
map(config =>
config.allowPasswordRecovery
diff --git a/ui/src/app/core/setup/guards/terms.can-activate-children.guard.ts
b/ui/src/app/core/setup/guards/terms.can-activate-children.guard.ts
index 7eaf577d50..deb2e4e2f0 100644
--- a/ui/src/app/core/setup/guards/terms.can-activate-children.guard.ts
+++ b/ui/src/app/core/setup/guards/terms.can-activate-children.guard.ts
@@ -26,7 +26,7 @@ import {
RouterStateSnapshot,
} from '@angular/router';
import { CurrentUserService } from '@streampipes/shared-ui';
-import { LoginService } from '../../../login/services/login.service';
+import { LoginSettingsService } from
'../../../login/services/login-settings.service';
import { of, take } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
@@ -37,7 +37,7 @@ export class TermsCanActivateChildrenGuard implements
CanActivateChild {
state: RouterStateSnapshot,
): MaybeAsync<GuardResult> {
const currentUser = this.currentUserService.getCurrentUser();
- return this.loginService.fetchLoginSettings().pipe(
+ return this.loginSettingsService.getSettings().pipe(
take(1),
map(settings => {
const needsAck =
@@ -56,7 +56,7 @@ export class TermsCanActivateChildrenGuard implements
CanActivateChild {
}
private currentUserService = inject(CurrentUserService);
- private loginService = inject(LoginService);
+ private loginSettingsService = inject(LoginSettingsService);
private router = inject(Router);
}
diff --git a/ui/src/app/help/help.component.ts
b/ui/src/app/help/help.component.ts
index f85d009b64..214e696ad6 100644
--- a/ui/src/app/help/help.component.ts
+++ b/ui/src/app/help/help.component.ts
@@ -27,7 +27,7 @@ import {
LayoutDirective,
} from '@ngbracket/ngx-layout/flex';
import { MatTab, MatTabGroup } from '@angular/material/tabs';
-import { LoginService } from '../login/services/login.service';
+import { LoginSettingsService } from
'../login/services/login-settings.service';
import { InfoTabComponent } from './components/info/info.component';
import { DocumentationTabComponent } from
'./components/documentation/documentation.component';
import { ShortcutsTabComponent } from
'./components/shortcuts/shortcuts.component';
@@ -52,7 +52,7 @@ import { TranslatePipe, TranslateService } from
'@ngx-translate/core';
})
export class HelpComponent implements OnInit {
private breadcrumbService = inject(SpBreadcrumbService);
- private loginService = inject(LoginService);
+ private loginSettingsService = inject(LoginSettingsService);
private translateService = inject(TranslateService);
selectedIndex = 0;
@@ -67,7 +67,7 @@ export class HelpComponent implements OnInit {
this.breadcrumbService.updateBreadcrumb([
{ label: this.translateService.instant('Help') },
]);
- this.loginService.fetchLoginSettings().subscribe(res => {
+ this.loginSettingsService.getSettings().subscribe(res => {
this.documentationLink = res.linkSettings?.documentationUrl || '';
this.showDocumentationTab =
!!res.linkSettings?.showDocumentationLinkInProfileMenu &&
diff --git a/ui/src/app/home/components/status.component.ts
b/ui/src/app/home/components/status.component.ts
index 58872ec0cf..5143929bd0 100644
--- a/ui/src/app/home/components/status.component.ts
+++ b/ui/src/app/home/components/status.component.ts
@@ -55,7 +55,7 @@ export class StatusComponent implements OnInit {
zip(this.statusBox.dataFns).subscribe(res => {
let totalLength = 0;
res.forEach(response => {
- totalLength += response.length;
+ totalLength += response.totalCount;
});
this.resourceCount = totalLength;
diff --git a/ui/src/app/home/dialog/welcome-tour/welcome-tour.component.html
b/ui/src/app/home/dialog/welcome-tour/welcome-tour.component.html
index 150983d1a9..90c028bd2c 100644
--- a/ui/src/app/home/dialog/welcome-tour/welcome-tour.component.html
+++ b/ui/src/app/home/dialog/welcome-tour/welcome-tour.component.html
@@ -24,12 +24,6 @@
><h3>Thank you for using {{ appConstants.APP_NAME }}.</h3></b
>
</div>
- <div>
- <img
- src="assets/img/sp-pipeline-white-small.png"
- style="margin-left: auto; margin-right: auto; display: block"
- />
- </div>
<div fxFlex="100" fxLayoutAlign="center center" fxLayout="column">
<div fxFlex="100" fxLayoutAlign="center center" fxLayout="column">
<b
@@ -40,15 +34,38 @@
If you are using {{ appConstants.APP_NAME }} for the first
time, we recommend taking the interactive tour!
</p>
+ @if (loadingTutorialResources) {
+ <div
+ class="tutorial-status"
+ fxLayout="row"
+ fxLayoutAlign="center center"
+ fxLayoutGap="10px"
+ >
+ <mat-spinner [diameter]="20"></mat-spinner>
+ <span>Checking tutorial pipeline elements...</span>
+ </div>
+ }
+ @if (showMissingElementsHint) {
+ <sp-alert-banner
+ type="info"
+ title="Missing Elements for Tutorial"
+ description="The tutorial needs additional pipeline
elements.
+ Install the missing extensions (Settings -> Extensions)
and reopen the tour."
+ >
+ </sp-alert-banner>
+ }
</div>
- <button
- mat-button
- mat-flat-button
- color="accent"
- (click)="close(true)"
- >
- Start Tour
- </button>
+ @if (!loadingTutorialResources && !showMissingElementsHint) {
+ <button
+ mat-button
+ mat-flat-button
+ color="accent"
+ [disabled]="loadingTutorialResources"
+ (click)="startTutorial()"
+ >
+ Start Tour
+ </button>
+ }
</div>
</div>
<mat-divider></mat-divider>
diff --git a/ui/src/app/home/dialog/welcome-tour/welcome-tour.component.scss
b/ui/src/app/home/dialog/welcome-tour/welcome-tour.component.scss
index c6405f3d58..a06a4f52eb 100644
--- a/ui/src/app/home/dialog/welcome-tour/welcome-tour.component.scss
+++ b/ui/src/app/home/dialog/welcome-tour/welcome-tour.component.scss
@@ -38,3 +38,13 @@
border-color: transparent;
}
}
+
+.tutorial-status {
+ margin-top: 0.5rem;
+}
+
+.tutorial-hint {
+ margin: 0.5rem 0 0;
+ text-align: center;
+ max-width: 28rem;
+}
diff --git a/ui/src/app/home/dialog/welcome-tour/welcome-tour.component.ts
b/ui/src/app/home/dialog/welcome-tour/welcome-tour.component.ts
index 60fe452a98..8e57d2e7f4 100644
--- a/ui/src/app/home/dialog/welcome-tour/welcome-tour.component.ts
+++ b/ui/src/app/home/dialog/welcome-tour/welcome-tour.component.ts
@@ -16,11 +16,23 @@
*
*/
-import { DialogRef } from '@streampipes/shared-ui';
+import {
+ DialogRef,
+ DialogService,
+ PanelType,
+ SpAlertBannerComponent,
+} from '@streampipes/shared-ui';
import { Component, Input, OnInit, inject } from '@angular/core';
import { AppConstants } from '../../../services/app.constants';
import { AuthService } from '../../../services/auth.service';
-import { UserAccount, UserInfo } from '@streampipes/platform-services';
+import {
+ AdapterDescription,
+ AdapterService,
+ NamedStreamPipesEntity,
+ PipelineElementService,
+ UserAccount,
+ UserInfo,
+} from '@streampipes/platform-services';
import { ProfileService } from '../../../profile/profile.service';
import {
FlexDirective,
@@ -29,6 +41,10 @@ import {
} from '@ngbracket/ngx-layout/flex';
import { MatButton } from '@angular/material/button';
import { MatDivider } from '@angular/material/divider';
+import { MatProgressSpinner } from '@angular/material/progress-spinner';
+import { MissingElementsForTutorialComponent } from
'../../../editor/dialog/missing-elements-for-tutorial/missing-elements-for-tutorial.component';
+import { forkJoin } from 'rxjs';
+import { LayoutGapDirective } from '@ngbracket/ngx-layout';
@Component({
selector: 'sp-welcome-tour',
@@ -40,18 +56,36 @@ import { MatDivider } from '@angular/material/divider';
LayoutAlignDirective,
MatButton,
MatDivider,
+ MatProgressSpinner,
+ LayoutGapDirective,
+ SpAlertBannerComponent,
],
})
export class WelcomeTourComponent implements OnInit {
+ private static readonly REQUIRED_ADAPTER_FOR_TUTORIAL_APP_ID =
+ 'org.apache.streampipes.connect.iiot.adapters.simulator.machine';
+ private static readonly REQUIRED_PROCESSOR_FOR_TUTORIAL_APP_ID =
+ 'org.apache.streampipes.processors.filters.jvm.numericalfilter';
+ private static readonly REQUIRED_SINK_FOR_TUTORIAL_APP_ID =
+ 'org.apache.streampipes.sinks.internal.jvm.datalake';
+
private authService = inject(AuthService);
private dialogRef = inject<DialogRef<WelcomeTourComponent>>(DialogRef);
private profileService = inject(ProfileService);
+ private dialogService = inject(DialogService);
+ private adapterService = inject(AdapterService);
+ private pipelineElementService = inject(PipelineElementService);
appConstants = inject(AppConstants);
@Input()
userInfo: UserInfo;
currentUser: UserAccount;
+ availablePipelineElements: NamedStreamPipesEntity[] = [];
+ availableAdapters: AdapterDescription[] = [];
+ missingElementsForTutorial = [];
+ tutorialAvailable = false;
+ loadingTutorialResources = true;
ngOnInit(): void {
this.profileService
@@ -59,6 +93,24 @@ export class WelcomeTourComponent implements OnInit {
.subscribe(data => {
this.currentUser = data;
});
+
+ forkJoin([
+ this.adapterService.getAdapterDescriptions(),
+ this.pipelineElementService.getDataStreams(),
+ this.pipelineElementService.getDataProcessors(),
+ this.pipelineElementService.getDataSinks(),
+ ]).subscribe(res => {
+ this.availableAdapters = res[0];
+ this.availablePipelineElements = []
+ .concat(...res[1])
+ .concat(...res[2])
+ .concat(...res[3]);
+ this.missingElementsForTutorial =
+ this.getMissingElementsForTutorial();
+ this.tutorialAvailable =
+ this.missingElementsForTutorial.length === 0;
+ this.loadingTutorialResources = false;
+ });
}
hideTourForever() {
@@ -71,7 +123,78 @@ export class WelcomeTourComponent implements OnInit {
});
}
+ startTutorial() {
+ if (this.loadingTutorialResources) {
+ return;
+ }
+
+ if (this.tutorialAvailable) {
+ this.close(true);
+ } else {
+ this.dialogService.open(MissingElementsForTutorialComponent, {
+ panelType: PanelType.STANDARD_PANEL,
+ title: 'Tutorial requires pipeline elements',
+ data: {
+ missingElementsForTutorial:
this.missingElementsForTutorial,
+ },
+ });
+ }
+ }
+
close(startTutorial = false) {
this.dialogRef.close(startTutorial);
}
+
+ get showMissingElementsHint() {
+ return !this.loadingTutorialResources && !this.tutorialAvailable;
+ }
+
+ private getMissingElementsForTutorial() {
+ const missingElements = [];
+
+ if (
+ !this.requiredPeForTourPresent(
+ this.availableAdapters,
+ WelcomeTourComponent.REQUIRED_ADAPTER_FOR_TUTORIAL_APP_ID,
+ )
+ ) {
+ missingElements.push({
+ name: 'Machine Data Simulator',
+ appId:
WelcomeTourComponent.REQUIRED_ADAPTER_FOR_TUTORIAL_APP_ID,
+ });
+ }
+
+ if (
+ !this.requiredPeForTourPresent(
+ this.availablePipelineElements,
+ WelcomeTourComponent.REQUIRED_PROCESSOR_FOR_TUTORIAL_APP_ID,
+ )
+ ) {
+ missingElements.push({
+ name: 'Numerical Filter',
+ appId:
WelcomeTourComponent.REQUIRED_PROCESSOR_FOR_TUTORIAL_APP_ID,
+ });
+ }
+
+ if (
+ !this.requiredPeForTourPresent(
+ this.availablePipelineElements,
+ WelcomeTourComponent.REQUIRED_SINK_FOR_TUTORIAL_APP_ID,
+ )
+ ) {
+ missingElements.push({
+ name: 'Dashboard Sink',
+ appId: WelcomeTourComponent.REQUIRED_SINK_FOR_TUTORIAL_APP_ID,
+ });
+ }
+
+ return missingElements;
+ }
+
+ private requiredPeForTourPresent(
+ list: Array<{ appId: string }>,
+ appId: string,
+ ) {
+ return list?.some(el => el.appId === appId);
+ }
}
diff --git a/ui/src/app/home/home.component.ts
b/ui/src/app/home/home.component.ts
index 5a625422db..a73f4303aa 100644
--- a/ui/src/app/home/home.component.ts
+++ b/ui/src/app/home/home.component.ts
@@ -31,12 +31,9 @@ import {
SplitSectionComponent,
} from '@streampipes/shared-ui';
import { UserRole } from '../core/auth/user-role.enum';
-import { MissingElementsForTutorialComponent } from
'../editor/dialog/missing-elements-for-tutorial/missing-elements-for-tutorial.component';
import { WelcomeTourComponent } from
'./dialog/welcome-tour/welcome-tour.component';
import { ShepherdService } from '../services/tour/shepherd.service';
import {
- AdapterDescription,
- AdapterService,
AssetConstants,
AssetLinkType,
AssetManagementService,
@@ -44,12 +41,10 @@ import {
GenericStorageService,
LocationConfig,
LocationConfigService,
- NamedStreamPipesEntity,
- PipelineElementService,
SpAssetModel,
UserInfo,
} from '@streampipes/platform-services';
-import { forkJoin, Subscription, zip } from 'rxjs';
+import { forkJoin, Subscription } from 'rxjs';
import { StatusBox } from './models/home.model';
import {
FlexDirective,
@@ -92,9 +87,6 @@ export class HomeComponent implements OnInit, OnDestroy {
serviceLinks = [];
showStatus = false;
- availablePipelineElements: NamedStreamPipesEntity[] = [];
- availableAdapters: AdapterDescription[] = [];
-
statusBoxes: StatusBox[] = [];
locationConfig: LocationConfig;
assets: SpAssetModel[] = [];
@@ -102,14 +94,6 @@ export class HomeComponent implements OnInit, OnDestroy {
sites: Record<string, AssetSiteDesc> = {};
assetLinkTypes: Record<string, AssetLinkType> = {};
- requiredAdapterForTutorialAppId: any =
- 'org.apache.streampipes.connect.iiot.adapters.simulator.machine';
- requiredProcessorForTutorialAppId: any =
- 'org.apache.streampipes.processors.filters.jvm.numericalfilter';
- requiredSinkForTutorialAppId: any =
- 'org.apache.streampipes.sinks.internal.jvm.datalake';
- missingElementsForTutorial: any = [];
-
isTutorialOpen = false;
currentUser: UserInfo;
selectedView = signal<string>('table');
@@ -122,8 +106,6 @@ export class HomeComponent implements OnInit, OnDestroy {
private breadcrumbService = inject(SpBreadcrumbService);
private dialogService = inject(DialogService);
private shepherdService = inject(ShepherdService);
- private pipelineElementService = inject(PipelineElementService);
- private adapterService = inject(AdapterService);
private genericStorageService = inject(GenericStorageService);
private locationService = inject(LocationConfigService);
private assetService = inject(AssetManagementService);
@@ -175,8 +157,10 @@ export class HomeComponent implements OnInit, OnDestroy {
this.contentLoaded = true;
this.showStatus = true;
});
- if (isAdmin) {
- this.loadResources();
+ console.log(isAdmin);
+ console.log(this.currentUser.showTutorial);
+ if (isAdmin && this.currentUser.showTutorial) {
+ this.checkForTutorial();
}
this.breadcrumbService.updateBreadcrumb([]);
}
@@ -199,115 +183,27 @@ export class HomeComponent implements OnInit, OnDestroy {
}
checkForTutorial() {
- if (this.currentUser.showTutorial) {
- if (this.requiredPipelineElementsForTourPresent()) {
- this.isTutorialOpen = true;
- const dialogRef = this.dialogService.open(
- WelcomeTourComponent,
- {
- panelType: PanelType.STANDARD_PANEL,
- title: 'Welcome to ' + this.appConstants.APP_NAME,
- data: {
- userInfo: this.currentUser,
- },
- },
- );
- dialogRef.afterClosed().subscribe(startTutorial => {
- if (startTutorial) {
- this.startTutorial();
- }
- });
+ this.isTutorialOpen = true;
+ const dialogRef = this.dialogService.open(WelcomeTourComponent, {
+ panelType: PanelType.STANDARD_PANEL,
+ title: 'Welcome to ' + this.appConstants.APP_NAME,
+ data: {
+ userInfo: this.currentUser,
+ },
+ });
+ dialogRef.afterClosed().subscribe(startTutorial => {
+ if (startTutorial) {
+ this.startTutorial();
+ } else {
+ this.isTutorialOpen = false;
}
- }
+ });
}
startTutorial() {
- if (this.requiredPipelineElementsForTourPresent()) {
- this.router.navigate(['connect']).then(() => {
- this.shepherdService.startAdapterTour();
- });
- } else {
- this.missingElementsForTutorial = [];
- if (!this.requiredAdapterForTutorialAppId()) {
- this.missingElementsForTutorial.push({
- name: 'Machine Data Simulator',
- appId: this.requiredAdapterForTutorialAppId,
- });
- }
- if (!this.requiredProcessorForTourPresent()) {
- this.missingElementsForTutorial.push({
- name: 'Numerical Filter',
- appId: this.requiredProcessorForTutorialAppId,
- });
- }
- if (!this.requiredSinkForTourPresent()) {
- this.missingElementsForTutorial.push({
- name: 'Dashboard Sink',
- appId: this.requiredSinkForTutorialAppId,
- });
- }
-
- this.dialogService.open(MissingElementsForTutorialComponent, {
- panelType: PanelType.STANDARD_PANEL,
- title: 'Tutorial requires pipeline elements',
- data: {
- missingElementsForTutorial:
this.missingElementsForTutorial,
- },
- });
- }
- }
-
- requiredPipelineElementsForTourPresent() {
- return (
- this.requiredAdapterForTourPresent() &&
- this.requiredProcessorForTourPresent() &&
- this.requiredSinkForTourPresent()
- );
- }
-
- requiredAdapterForTourPresent() {
- return this.requiredPeForTourPresent(
- this.availableAdapters,
- this.requiredAdapterForTutorialAppId,
- );
- }
-
- requiredProcessorForTourPresent() {
- return this.requiredPeForTourPresent(
- this.availablePipelineElements,
- this.requiredProcessorForTutorialAppId,
- );
- }
-
- requiredSinkForTourPresent() {
- return this.requiredPeForTourPresent(
- this.availablePipelineElements,
- this.requiredSinkForTutorialAppId,
- );
- }
-
- requiredPeForTourPresent(list: NamedStreamPipesEntity[], appId: string) {
- return (
- list &&
- list.some(el => {
- return el.appId === appId;
- })
- );
- }
-
- loadResources(): void {
- zip(
- this.adapterService.getAdapterDescriptions(),
- this.pipelineElementService.getDataStreams(),
- this.pipelineElementService.getDataProcessors(),
- this.pipelineElementService.getDataSinks(),
- ).subscribe(res => {
- this.availableAdapters = res[0];
- this.availablePipelineElements = this.availablePipelineElements
- .concat(...res[1])
- .concat(...res[2])
- .concat(...res[3]);
- this.checkForTutorial();
+ this.router.navigate(['connect']).then(() => {
+ this.shepherdService.startAdapterTour();
+ this.isTutorialOpen = false;
});
}
diff --git a/ui/src/app/login/components/base-login-page.directive.ts
b/ui/src/app/login/components/base-login-page.directive.ts
index ef15cb926f..87228dbc98 100644
--- a/ui/src/app/login/components/base-login-page.directive.ts
+++ b/ui/src/app/login/components/base-login-page.directive.ts
@@ -18,6 +18,7 @@
import { Directive, inject, OnInit } from '@angular/core';
import { LoginService } from '../services/login.service';
+import { LoginSettingsService } from '../services/login-settings.service';
import { LoginModel } from './login/login.model';
@Directive()
@@ -26,9 +27,10 @@ export abstract class BaseLoginPageDirective implements
OnInit {
protected configReady = false;
protected loginService = inject(LoginService);
+ protected loginSettingsService = inject(LoginSettingsService);
ngOnInit(): void {
- this.loginService.fetchLoginSettings().subscribe(result => {
+ this.loginSettingsService.getSettings().subscribe(result => {
this.loginSettings = result;
this.configReady = true;
this.onSettingsAvailable();
diff --git
a/ui/src/app/core/setup/guards/registration-allowed.can-activate.guard.ts
b/ui/src/app/login/services/login-settings.service.ts
similarity index 51%
copy from
ui/src/app/core/setup/guards/registration-allowed.can-activate.guard.ts
copy to ui/src/app/login/services/login-settings.service.ts
index ccccc288e5..347a74399b 100644
--- a/ui/src/app/core/setup/guards/registration-allowed.can-activate.guard.ts
+++ b/ui/src/app/login/services/login-settings.service.ts
@@ -17,35 +17,31 @@
*/
import { Injectable, inject } from '@angular/core';
-import {
- ActivatedRouteSnapshot,
- Router,
- RouterStateSnapshot,
- UrlTree,
-} from '@angular/router';
-import { LoginService } from '../../../login/services/login.service';
-import { Observable } from 'rxjs';
-import { map } from 'rxjs/operators';
+import { HttpClient } from '@angular/common/http';
+import { PlatformServicesCommons } from '@streampipes/platform-services';
+import { Observable, shareReplay } from 'rxjs';
+import { LoginModel } from '../components/login/login.model';
@Injectable({ providedIn: 'root' })
-export class RegistrationAllowedCanActivateGuard {
- private router = inject(Router);
- private loginService = inject(LoginService);
+export class LoginSettingsService {
+ private http = inject(HttpClient);
+ private platformServicesCommons = inject(PlatformServicesCommons);
- canActivate(
- _route: ActivatedRouteSnapshot,
- _state: RouterStateSnapshot,
- ):
- | Observable<boolean | UrlTree>
- | Promise<boolean | UrlTree>
- | boolean
- | UrlTree {
- return this.loginService.fetchLoginSettings().pipe(
- map(config => {
- return config.allowSelfRegistration
- ? true
- : this.router.parseUrl('register');
- }),
- );
+ private settings$?: Observable<LoginModel>;
+
+ getSettings(): Observable<LoginModel> {
+ if (!this.settings$) {
+ this.settings$ = this.http
+ .get<LoginModel>(
+
`${this.platformServicesCommons.apiBasePath}/auth/settings`,
+ )
+ .pipe(shareReplay(1));
+ }
+
+ return this.settings$;
+ }
+
+ invalidateCache(): void {
+ this.settings$ = undefined;
}
}
diff --git a/ui/src/app/login/services/login.service.ts
b/ui/src/app/login/services/login.service.ts
index d5b17f1df1..95a886acff 100644
--- a/ui/src/app/login/services/login.service.ts
+++ b/ui/src/app/login/services/login.service.ts
@@ -19,8 +19,7 @@
import { Injectable, inject } from '@angular/core';
import { HttpClient, HttpContext } from '@angular/common/http';
import { PlatformServicesCommons } from '@streampipes/platform-services';
-import { Observable, shareReplay } from 'rxjs';
-import { LoginModel } from '../components/login/login.model';
+import { Observable } from 'rxjs';
import { RegistrationModel } from '../components/register/registration.model';
import { NGX_LOADING_BAR_IGNORED } from '@ngx-loading-bar/http-client';
@@ -29,19 +28,6 @@ export class LoginService {
private http = inject(HttpClient);
private platformServicesCommons = inject(PlatformServicesCommons);
- private settings$?: Observable<LoginModel>;
-
- fetchLoginSettings(): Observable<LoginModel> {
- if (!this.settings$) {
- this.settings$ = this.http
- .get<LoginModel>(
-
`${this.platformServicesCommons.apiBasePath}/auth/settings`,
- )
- .pipe(shareReplay({ bufferSize: 1, refCount: true }));
- }
- return this.settings$;
- }
-
login(credentials): Observable<any> {
return this.http.post(
this.platformServicesCommons.apiBasePath + '/auth/login',