Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

display error message on spinner when there is no connection #1864

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div>
<os-spinner *ngIf="spinnerText" [text]="spinnerText"></os-spinner>
<os-spinner *ngIf="!spinnerText"></os-spinner>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { GlobalSpinnerComponent } from './global-spinner.component';

xdescribe(`GlobalSpinnerComponent`, () => {
let component: GlobalSpinnerComponent;
let fixture: ComponentFixture<GlobalSpinnerComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [GlobalSpinnerComponent]
}).compileComponents();

fixture = TestBed.createComponent(GlobalSpinnerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it(`should create`, () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Component, Input } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { ConnectionStatusService } from 'src/app/site/services/connection-status.service';
import { LifecycleService } from 'src/app/site/services/lifecycle.service';
import { SpinnerComponent } from 'src/app/ui/modules/spinner/components/spinner/spinner.component';

@Component({
selector: `os-global-spinner`,
templateUrl: `./global-spinner.component.html`,
styleUrls: [`./global-spinner.component.scss`]
})
export class GlobalSpinnerComponent extends SpinnerComponent {
@Input()
public spinnerConfig: { text?: string };

public displayDetailedInformation = false;
public isOperatorReady = false;

public get spinnerText(): string {
let errorText = [];
if (this.displayDetailedInformation) {
if (this.connectionStatusService.isOffline()) {
errorText.push(
this.translate.instant(
`There seems to be a problem connecting to our services. Check your connection or try again later.`
)
);
if (this.connectionStatusService.getReason()) {
errorText.push(this.connectionStatusService.getReason());
}
}
}

return errorText.join(`\n`) || this.spinnerConfig?.text;
}

public constructor(
private lifecycleService: LifecycleService,
private connectionStatusService: ConnectionStatusService,
private translate: TranslateService
) {
super();

this.lifecycleService.booted.then(() => {
setTimeout(() => {
this.displayDetailedInformation = true;
console.log(
this.displayDetailedInformation,
this.connectionStatusService.isOffline(),
this.connectionStatusService.getReason()
);
}, 10000);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ import { NgModule } from '@angular/core';
import { OpenSlidesOverlayModule } from 'src/app/ui/modules/openslides-overlay';
import { SpinnerModule } from 'src/app/ui/modules/spinner';

import { OpenSlidesTranslationModule } from '../translations';
import { GlobalSpinnerComponent } from './components/global-spinner/global-spinner.component';

@NgModule({
declarations: [],
imports: [CommonModule, SpinnerModule, OpenSlidesOverlayModule]
declarations: [GlobalSpinnerComponent],
imports: [CommonModule, SpinnerModule, OpenSlidesTranslationModule.forChild(), OpenSlidesOverlayModule]
})
export class GlobalSpinnerModule {}
Original file line number Diff line number Diff line change
@@ -1,27 +1,35 @@
import { Injectable } from '@angular/core';
import { Router, RoutesRecognized } from '@angular/router';
import { combineLatest, filter, Subscription } from 'rxjs';
import { combineLatest, filter, startWith, Subscription } from 'rxjs';
import { ConnectionStatusService } from 'src/app/site/services/connection-status.service';
import { OpenSlidesStatusService } from 'src/app/site/services/openslides-status.service';
import { OperatorService } from 'src/app/site/services/operator.service';
import { OverlayInstance, OverlayService } from 'src/app/ui/modules/openslides-overlay';
import { SpinnerComponent } from 'src/app/ui/modules/spinner/components/spinner/spinner.component';

import { GlobalSpinnerComponent } from '../components/global-spinner/global-spinner.component';
import { SpinnerConfig } from '../definitions';
import { GlobalSpinnerModule } from '../global-spinner.module';

@Injectable({
providedIn: GlobalSpinnerModule
})
export class SpinnerService {
private overlayInstance: OverlayInstance<SpinnerComponent> | null = null;
public get isOffline(): boolean {
return this._isOffline;
}

private overlayInstance: OverlayInstance<GlobalSpinnerComponent> | null = null;

private isOperatorReady = false;
private isStable = false;
private isOffline = false;
private _isOffline = false;
private isOnLoginMask = false;
private isOnErrorPage = false;

private set isOffline(isOffline: boolean) {
this._isOffline = isOffline;
}

private isStableSubscription: Subscription | null = null;

public constructor(
Expand All @@ -32,11 +40,11 @@ export class SpinnerService {
private router: Router
) {}

public show(text?: string, config: SpinnerConfig = {}): OverlayInstance<SpinnerComponent> {
public show(text?: string, config: SpinnerConfig = {}): OverlayInstance<GlobalSpinnerComponent> {
if (this.overlayInstance) {
return this.overlayInstance; // Prevent multiple instances at the same time.
}
this.overlayInstance = this.overlay.open(SpinnerComponent, {
this.overlayInstance = this.overlay.open(GlobalSpinnerComponent, {
...config,
onCloseFn: () => (this.overlayInstance = null),
data: {
Expand Down Expand Up @@ -83,13 +91,16 @@ export class SpinnerService {
this.operator.isReadyObservable,
this.offlineService.isOfflineObservable,
this.openslidesStatus.isStableObservable,
this.router.events.pipe(filter(event => event instanceof RoutesRecognized))
this.router.events.pipe(filter(event => event instanceof RoutesRecognized)).pipe(startWith(null))
]).subscribe(([isReady, isOffline, isStable, event]) => {
this.isOperatorReady = isReady;
this.isOffline = isOffline;
this.isStable = isStable;
this.isOnLoginMask = (event as RoutesRecognized).url.includes(`login`);
this.isOnErrorPage = (event as RoutesRecognized).url.includes(`error`);
if (event) {
this.isOnLoginMask = (event as RoutesRecognized).url.includes(`login`);
this.isOnErrorPage = (event as RoutesRecognized).url.includes(`error`);
}

this.checkConnection();
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ export class AutoupdateCommunicationService {
if (this.autoupdateEndpointStatus === `unhealthy`) {
this.unhealtyTimeout = setTimeout(() => {
this.connectionStatusService.goOffline({
reason: `Autoupdate unhealthy`,
reason: this.translate.instant(`Autoupdate unhealthy`),
isOnlineFn: () => {
return this.autoupdateEndpointStatus === `healthy`;
}
Expand Down
4 changes: 4 additions & 0 deletions client/src/app/site/services/connection-status.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ export class ConnectionStatusService {
fromEvent(window, `offline`).subscribe(() => this.goOffline(DEFAULT_OFFLINE_REASON));
}

public getReason(): string {
return this._config?.reason || null;
}

public isOffline(): boolean {
return this._isOfflineSubject.value;
}
Expand Down
8 changes: 4 additions & 4 deletions client/src/app/site/services/openslides.service.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

import { AuthService } from './auth.service';
import { ConnectionStatusService } from './connection-status.service';
import { LifecycleService } from './lifecycle.service';
import { OpenSlidesRouterService } from './openslides-router.service';

const WHOAMI_FAILED = `WhoAmI failed`;

@Injectable({
providedIn: `root`
})
Expand All @@ -15,7 +14,8 @@ export class OpenSlidesService {
private offlineService: ConnectionStatusService,
private lifecycleService: LifecycleService,
private authService: AuthService,
private osRouter: OpenSlidesRouterService
private osRouter: OpenSlidesRouterService,
private translate: TranslateService
) {
this.lifecycleService.appLoaded.subscribe(() => this.bootup());
}
Expand All @@ -28,7 +28,7 @@ export class OpenSlidesService {
const online = await this.authService.doWhoAmIRequest();
if (!online) {
this.offlineService.goOffline({
reason: WHOAMI_FAILED,
reason: this.translate.instant(`WhoAmI failed`),
isOnlineFn: async () => this.authService.doWhoAmIRequest()
});
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
text-align: center;
color: white;
font-size: 1.4rem;
white-space: pre;
}

.spinner-component {
Expand Down