191 lines
6.2 KiB
TypeScript
191 lines
6.2 KiB
TypeScript
import { Component, OnDestroy, OnInit, ChangeDetectorRef, ElementRef, ViewChild } from '@angular/core';
|
|
import { DeploymentNotificationService } from '../services/deployment-notification.service';
|
|
import { Subscription, BehaviorSubject } from 'rxjs';
|
|
import { WebSocketService } from '../services/websocket.service';
|
|
import { WebSocketMessage } from '../message-types/websocket-message';
|
|
import { DashboardConfigService } from '../services/config.service';
|
|
import { HttpClient } from '@angular/common/http';
|
|
import { delay, retryWhen, tap } from 'rxjs/operators';
|
|
import { FSMUpdateService } from '../services/fsmupdate.service';
|
|
|
|
@Component({
|
|
selector: 'app-dashboard',
|
|
templateUrl: './dashboard.component.html',
|
|
styleUrls: ['./dashboard.component.scss']
|
|
})
|
|
export class DashboardComponent implements OnInit, OnDestroy {
|
|
deploying = false;
|
|
polling = new BehaviorSubject<boolean>(false);
|
|
deploymentNotificationSubscription: Subscription;
|
|
@ViewChild('webiframe', {static: false}) webiframe: ElementRef;
|
|
@ViewChild('tfwmessages', {static: false}) messages: ElementRef;
|
|
@ViewChild('urlbar', {static: false}) urlbar: ElementRef;
|
|
|
|
layout = this.configService.layout;
|
|
hideMessages = this.configService.hideMessages;
|
|
showUrlBar = this.configService.showUrlBar;
|
|
iframeUrl = this.configService.iframeUrl;
|
|
actualIframeUrl = this.iframeUrl.value;
|
|
terminalMenuItem = this.configService.terminalMenuItem;
|
|
iframeReloadSubscription: Subscription;
|
|
|
|
command_handlers = {
|
|
'dashboard.reloadFrontend': this.reloadFrontendHandlder.bind(this),
|
|
'dashboard.reloadIframe': this.reloadIframeHandler.bind(this)
|
|
};
|
|
|
|
constructor(private deploymentNotificationService: DeploymentNotificationService,
|
|
private webSocketService: WebSocketService,
|
|
private changeDetectorRef: ChangeDetectorRef,
|
|
private http: HttpClient,
|
|
private configService: DashboardConfigService,
|
|
private fsmUpdateService: FSMUpdateService) {}
|
|
|
|
ngOnInit() {
|
|
this.webSocketService.connect();
|
|
this.configService.init();
|
|
this.subscribeCheckSolution();
|
|
this.hideIframeUntilResponseOk();
|
|
this.subscribeResizeOnLayoutChange();
|
|
this.initCommandHandling();
|
|
this.initDeploymentNotifications();
|
|
this.sendReady();
|
|
}
|
|
|
|
subscribeCheckSolution() {
|
|
this.fsmUpdateService.init();
|
|
this.fsmUpdateService.in_accepted_state.subscribe(in_accepted_state => {
|
|
if (in_accepted_state) {
|
|
window.parent.postMessage('check solution', '*');
|
|
}
|
|
});
|
|
}
|
|
|
|
hideIframeUntilResponseOk() {
|
|
// TODO: hide iframe and show it after this whole deal...
|
|
this.reloadIframeWhenResponseOk();
|
|
}
|
|
|
|
subscribeResizeOnLayoutChange() {
|
|
this.configService.layout.subscribe(() => {
|
|
this.emitResizeEvent();
|
|
setTimeout(() => this.scrollMessagesToBottom(), 0);
|
|
});
|
|
}
|
|
|
|
initCommandHandling() {
|
|
this.webSocketService.observeControl<WebSocketMessage>('dashboard').subscribe(message => {
|
|
this.command_handlers[message.key](message);
|
|
this.changeDetectorRef.detectChanges();
|
|
});
|
|
}
|
|
|
|
initDeploymentNotifications() {
|
|
this.deploymentNotificationSubscription = this.deploymentNotificationService.deploying.subscribe(
|
|
(deploying) => {
|
|
this.deploying = deploying;
|
|
if (!deploying && this.configService.reloadIframeOnDeploy.value) {
|
|
this.reloadIframeWhenResponseOk();
|
|
}
|
|
});
|
|
}
|
|
|
|
sendReady() {
|
|
setTimeout(() => this.webSocketService.send({'key': 'frontend.ready'}));
|
|
}
|
|
|
|
reloadFrontendHandlder(message: WebSocketMessage) {
|
|
setTimeout(() => window.location.reload(), 2000);
|
|
}
|
|
|
|
reloadIframeHandler(message: WebSocketMessage) {
|
|
setTimeout(() => this.reloadIframeNoSubmit(), 200);
|
|
}
|
|
|
|
setLayout(layout: string) {
|
|
this.layout.next(layout);
|
|
}
|
|
|
|
emitResizeEvent() {
|
|
// We need to trigger a 'resize' event manually, otherwise editor stays collapsed
|
|
// editor 'resize' event listener requires a parameter of force=true
|
|
setTimeout(() => window.dispatchEvent(new Event('resize', {force: true} as any)), 0);
|
|
}
|
|
|
|
reloadIframe() {
|
|
setTimeout(() => {
|
|
this.webiframe.nativeElement.contentWindow.location.reload(true);
|
|
});
|
|
}
|
|
|
|
reloadIframeNoSubmit() {
|
|
// Sometimes it is needed to reload the iframe without resending the previous form data
|
|
setTimeout(() => {
|
|
this.webiframe.nativeElement.contentWindow.location = this.webiframe.nativeElement.contentWindow.location.href;
|
|
});
|
|
}
|
|
|
|
selectTerminalMenuItem(item: string) {
|
|
if (!item.match('(terminal|console)')) {
|
|
return;
|
|
}
|
|
this.terminalMenuItem.next(item);
|
|
}
|
|
|
|
scrollMessagesToBottom() {
|
|
const element = this.messages.nativeElement;
|
|
// This must be done in the Angular event loop to avoid messing up
|
|
// change detection (not in the template like ConsoleComponent does)
|
|
element.scrollTop = element.scrollHeight;
|
|
}
|
|
|
|
iframeLoad() {
|
|
if (this.webiframe && this.iframeUrl.value) {
|
|
const href = this.webiframe.nativeElement.contentWindow.frames.location.href;
|
|
const niceURL = href.match(/.*?\/\/.*?(\/.*)/)[1];
|
|
this.actualIframeUrl = niceURL;
|
|
}
|
|
}
|
|
|
|
changeIframeURL() {
|
|
const userGivenValue = this.urlbar.nativeElement.value.trim();
|
|
if (
|
|
userGivenValue === '/' ||
|
|
userGivenValue.startsWith('dashboard') ||
|
|
userGivenValue.startsWith('/dashboard')
|
|
) {
|
|
return;
|
|
}
|
|
this.webiframe.nativeElement.contentWindow.frames.location.href = this.urlbar.nativeElement.value;
|
|
}
|
|
|
|
reloadIframeWhenResponseOk() {
|
|
if (this.polling.value) {
|
|
this.iframeReloadSubscription.unsubscribe();
|
|
}
|
|
this.polling.next(true);
|
|
this.iframeReloadSubscription = this.http.get(this.actualIframeUrl, {observe: 'response'}).pipe(
|
|
retryWhen(errors =>
|
|
errors.pipe(
|
|
tap(
|
|
response => {
|
|
if (response.status === 200) {
|
|
this.iframeReloadSubscription.unsubscribe();
|
|
this.polling.next(false);
|
|
this.reloadIframe();
|
|
}}),
|
|
delay(1000)
|
|
))).subscribe();
|
|
}
|
|
|
|
ngOnDestroy() {
|
|
if (this.deploymentNotificationSubscription) {
|
|
this.deploymentNotificationSubscription.unsubscribe();
|
|
}
|
|
|
|
if (this.iframeReloadSubscription) {
|
|
this.iframeReloadSubscription.unsubscribe();
|
|
}
|
|
}
|
|
}
|