frontend-tutorial-framework/src/app/dashboard/dashboard.component.ts

165 lines
5.5 KiB
TypeScript

import { Component, OnDestroy, OnInit, ChangeDetectorRef, ElementRef, ViewChild } from '@angular/core';
import { DeploymentNotificationService } from '../services/deployment-notification.service';
import { Subscription } from 'rxjs';
import { WebSocketService } from '../services/websocket.service';
import { WebSocketMessage } from '../message-types/websocket-message';
import { DashboardConfigService, ConfigReadyService } from '../services/config.service';
import { HttpClient } from '@angular/common/http';
import { FSMUpdateService } from '../services/fsmupdate.service';
import { MessagesComponent } from '../messages/messages.component';
import { StatusCodePoller } from './statuscodepoller';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss']
})
export class DashboardComponent implements OnInit, OnDestroy {
deploying = false;
deploymentNotificationSubscription: Subscription;
@ViewChild('webiframe', {static: false}) webiframe: ElementRef;
@ViewChild(MessagesComponent, {static: false}) messages: MessagesComponent;
@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;
iframeReloadPoller: StatusCodePoller;
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 configReadyService: ConfigReadyService,
private configService: DashboardConfigService,
private fsmUpdateService: FSMUpdateService) {}
ngOnInit() {
this.webSocketService.connect();
this.configService.init();
this.subscribeCheckSolution();
this.iframeReloadPoller = new StatusCodePoller(this.iframeUrl, this.http);
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() {
this.iframeReloadPoller.ok.subscribe(() => this.reloadIframe());
this.configReadyService.configDone.subscribe(() =>
this.iframeReloadPoller.start()
);
}
subscribeResizeOnLayoutChange() {
this.configService.layout.subscribe(() => {
this.emitResizeEvent();
setTimeout(() => this.messages.scrollToBottom(), 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.iframeReloadPoller.start();
}
});
}
sendReady() {
setTimeout(() => this.webSocketService.send({'key': 'frontend.ready'}));
}
reloadFrontendHandlder(message: WebSocketMessage) {
setTimeout(() => window.location.reload(), 2000);
}
reloadIframeHandler(message: WebSocketMessage) {
this.iframeReloadPoller.ok.subscribe(() => this.reloadIframe());
this.iframeReloadPoller.start();
}
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.frames.location.href = this.iframeUrl.value;
});
}
selectTerminalMenuItem(item: string) {
if (!item.match('(terminal|console)')) {
return;
}
this.terminalMenuItem.next(item);
}
iframeLoad() {
if (this.webiframe && this.iframeUrl.value) {
const href = this.webiframe.nativeElement.contentWindow.frames.location.href;
const match = href.match(/.*?\/\/.*?(\/.*)/);
if (match !== null) {
// iframes on Firefox can have an about:blank
// contentWindow after firing a (load) event
const niceURL = match[1];
this.actualIframeUrl = niceURL;
}
}
}
changeIframeURL() {
const userGivenValue = this.urlbar.nativeElement.value.trim();
if (
userGivenValue === '/' ||
userGivenValue.startsWith('dashboard') ||
userGivenValue.startsWith('/dashboard')
) {
return;
}
this.iframeUrl.next(this.urlbar.nativeElement.value);
}
ngOnDestroy() {
if (this.deploymentNotificationSubscription) {
this.deploymentNotificationSubscription.unsubscribe();
}
this.iframeReloadPoller.stop();
}
}