2018-05-11 16:00:26 +00:00
|
|
|
// Copyright (C) 2018 Avatao.com Innovative Learning Kft.
|
|
|
|
// All Rights Reserved. See LICENSE file for details.
|
|
|
|
|
2018-05-17 13:58:08 +00:00
|
|
|
import { Component, OnDestroy, OnInit, ChangeDetectorRef, ElementRef, ViewChild } from '@angular/core';
|
2018-03-14 15:50:37 +00:00
|
|
|
import { DeploymentNotificationService } from '../services/deployment-notification.service';
|
2018-05-18 12:53:45 +00:00
|
|
|
import { Subscription } from 'rxjs';
|
2018-03-20 14:52:40 +00:00
|
|
|
import { WebSocketService } from '../services/websocket.service';
|
2019-08-07 08:28:38 +00:00
|
|
|
import { WebSocketMessage } from '../message-types/websocket-message';
|
2019-08-08 12:44:40 +00:00
|
|
|
import { HideMessagesMessage, LayoutMessage, TerminalMenuItemMessage } from '../message-types/dashboard-messages';
|
2018-03-21 15:32:56 +00:00
|
|
|
import { config } from '../config';
|
2018-05-29 14:48:45 +00:00
|
|
|
import { ProcessLogService } from '../services/processlog.service';
|
2018-06-02 15:31:51 +00:00
|
|
|
import { LogMessage } from '../message-types/log-message';
|
2019-05-13 11:57:08 +00:00
|
|
|
import { HttpClient } from '@angular/common/http';
|
|
|
|
import { delay, retryWhen, tap } from 'rxjs/operators';
|
2018-02-16 10:19:52 +00:00
|
|
|
|
|
|
|
@Component({
|
|
|
|
selector: 'app-dashboard',
|
|
|
|
templateUrl: './dashboard.component.html',
|
|
|
|
styleUrls: ['./dashboard.component.scss']
|
|
|
|
})
|
2018-04-20 09:09:47 +00:00
|
|
|
export class DashboardComponent implements OnInit, OnDestroy {
|
2018-03-12 14:03:38 +00:00
|
|
|
deploying = false;
|
2019-01-22 12:57:43 +00:00
|
|
|
polling = false;
|
2018-03-12 14:03:38 +00:00
|
|
|
deploymentNotificationSubscription: Subscription;
|
2019-08-12 12:45:21 +00:00
|
|
|
@ViewChild('webiframe', {static: true}) webiframe: ElementRef;
|
|
|
|
@ViewChild('tfwmessages', {static: true}) messages: ElementRef;
|
|
|
|
@ViewChild('urlbar', {static: true}) urlbar: ElementRef;
|
2018-05-31 12:18:13 +00:00
|
|
|
|
2018-04-20 09:09:47 +00:00
|
|
|
layout: string = config.dashboard.currentLayout;
|
2018-05-31 12:18:13 +00:00
|
|
|
hideMessages: boolean = config.dashboard.hideMessages;
|
2018-04-25 09:48:15 +00:00
|
|
|
iframeUrl: string = config.dashboard.iframeUrl;
|
2019-06-25 09:12:18 +00:00
|
|
|
showUrlBar = config.dashboard.showUrlBar;
|
2019-01-21 16:24:02 +00:00
|
|
|
actualIframeUrl: string = this.iframeUrl;
|
2018-05-31 12:18:13 +00:00
|
|
|
selectedTerminalMenuItem: string = config.dashboard.terminalOrConsole;
|
2019-01-22 12:57:43 +00:00
|
|
|
iframeReloadSubscription: Subscription;
|
2018-05-25 11:33:37 +00:00
|
|
|
|
2018-06-19 12:26:12 +00:00
|
|
|
command_handlers = {
|
2019-08-07 08:28:38 +00:00
|
|
|
'dashboard.layout': this.layoutHandler.bind(this),
|
|
|
|
'dashboard.hideMessages': this.hideMessagesHandler.bind(this),
|
|
|
|
'dashboard.terminalMenuItem': this.terminalMenuItemHandler.bind(this),
|
|
|
|
'dashboard.reloadFrontend': this.reloadFrontendHandlder.bind(this),
|
|
|
|
'dashboard.reloadIframe': this.reloadIframeHandler.bind(this)
|
2018-06-19 12:26:12 +00:00
|
|
|
};
|
2018-03-12 14:03:38 +00:00
|
|
|
|
2018-03-20 14:52:40 +00:00
|
|
|
constructor(private deploymentNotificationService: DeploymentNotificationService,
|
|
|
|
private webSocketService: WebSocketService,
|
2018-05-29 14:48:45 +00:00
|
|
|
private changeDetectorRef: ChangeDetectorRef,
|
2019-01-22 12:57:43 +00:00
|
|
|
private processLogService: ProcessLogService,
|
|
|
|
private http: HttpClient) {}
|
2018-03-12 14:03:38 +00:00
|
|
|
|
|
|
|
ngOnInit() {
|
2018-03-20 14:52:40 +00:00
|
|
|
this.webSocketService.connect();
|
2018-05-17 14:03:35 +00:00
|
|
|
this.initCommandHandling();
|
2018-05-17 14:04:30 +00:00
|
|
|
this.initDeploymentNotifications();
|
2018-07-20 07:24:28 +00:00
|
|
|
this.recoverIfNeeded();
|
2018-08-03 15:09:45 +00:00
|
|
|
this.triggerFirstFSMStepIfNeeded();
|
2018-03-12 14:03:38 +00:00
|
|
|
}
|
|
|
|
|
2018-05-17 14:03:35 +00:00
|
|
|
initCommandHandling() {
|
2019-08-08 14:18:26 +00:00
|
|
|
this.webSocketService.observeKey<WebSocketMessage>('dashboard').subscribe(message => {
|
2019-08-08 12:44:40 +00:00
|
|
|
this.command_handlers[message.key](message);
|
2018-05-17 14:03:35 +00:00
|
|
|
this.changeDetectorRef.detectChanges();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-05-17 14:04:30 +00:00
|
|
|
initDeploymentNotifications() {
|
|
|
|
this.deploymentNotificationSubscription = this.deploymentNotificationService.deploying.subscribe(
|
|
|
|
(deploying) => {
|
|
|
|
this.deploying = deploying;
|
2018-05-27 17:10:22 +00:00
|
|
|
if (!deploying && config.ide.reloadIframeOnDeploy) {
|
2019-01-22 12:57:43 +00:00
|
|
|
if (this.polling) {
|
|
|
|
this.iframeReloadSubscription.unsubscribe();
|
|
|
|
}
|
|
|
|
this.pollingServerForIframeReload();
|
2018-05-17 14:04:30 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-05-30 13:31:47 +00:00
|
|
|
triggerFirstFSMStepIfNeeded() {
|
|
|
|
if (config.dashboard.triggerFirstFSMStep) {
|
|
|
|
setTimeout(() => {
|
|
|
|
this.webSocketService.sendJSON({
|
2019-08-07 08:28:38 +00:00
|
|
|
'key': 'fsm.step',
|
|
|
|
'trigger': config.dashboard.triggerFirstFSMStep
|
2018-05-30 13:31:47 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-20 07:24:28 +00:00
|
|
|
recoverIfNeeded() {
|
|
|
|
if (config.dashboard.recoverAfterPageReload) {
|
|
|
|
setTimeout(() => this.webSocketService.sendJSON({'key': 'recover'}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-08 12:44:40 +00:00
|
|
|
layoutHandler(message: LayoutMessage) {
|
|
|
|
if (config.dashboard.enabledLayouts.includes(message.value)) {
|
|
|
|
this.setLayout(message.value);
|
2018-04-20 12:36:06 +00:00
|
|
|
} else {
|
2019-08-08 12:44:40 +00:00
|
|
|
console.log('Invalid ide layout "' + message.value + '" received!');
|
2018-03-20 14:52:40 +00:00
|
|
|
}
|
2018-05-27 14:45:52 +00:00
|
|
|
}
|
|
|
|
|
2019-08-08 12:44:40 +00:00
|
|
|
hideMessagesHandler(message: HideMessagesMessage) {
|
|
|
|
this.hideMessages = message.value;
|
2018-03-20 14:52:40 +00:00
|
|
|
}
|
|
|
|
|
2019-08-08 12:44:40 +00:00
|
|
|
terminalMenuItemHandler(message: TerminalMenuItemMessage) {
|
|
|
|
this.selectTerminalMenuItem(message.value);
|
2018-05-27 14:57:29 +00:00
|
|
|
}
|
|
|
|
|
2019-08-08 12:44:40 +00:00
|
|
|
reloadFrontendHandlder(message: WebSocketMessage) {
|
2018-04-20 12:50:43 +00:00
|
|
|
setTimeout(() => window.location.reload(), 2000);
|
|
|
|
}
|
|
|
|
|
2019-08-08 12:44:40 +00:00
|
|
|
reloadIframeHandler(message: WebSocketMessage) {
|
2019-02-24 00:11:54 +00:00
|
|
|
setTimeout(() => this.reloadIframeNoSubmit(), 200);
|
|
|
|
}
|
|
|
|
|
2018-04-20 09:09:47 +00:00
|
|
|
setLayout(layout: string) {
|
|
|
|
this.layout = layout;
|
2018-06-12 17:09:11 +00:00
|
|
|
// We need to trigger a 'resize' event manually, otherwise editor stays collapsed
|
|
|
|
// editor 'resize' event listener requires a parameter of force=true
|
2018-04-20 09:09:47 +00:00
|
|
|
setTimeout(() => window.dispatchEvent(new Event('resize', {force: true} as any)), 0);
|
|
|
|
}
|
|
|
|
|
2018-05-17 13:58:08 +00:00
|
|
|
reloadIframe() {
|
|
|
|
setTimeout(() => {
|
|
|
|
this.webiframe.nativeElement.contentWindow.location.reload(true);
|
|
|
|
});
|
|
|
|
}
|
2018-05-25 13:45:56 +00:00
|
|
|
|
2019-02-24 00:11:54 +00:00
|
|
|
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;
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-05-25 13:45:56 +00:00
|
|
|
selectTerminalMenuItem(item: string) {
|
|
|
|
if (!item.match('(terminal|console)')) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.selectedTerminalMenuItem = item;
|
|
|
|
}
|
2018-05-27 17:02:18 +00:00
|
|
|
|
2018-05-30 12:19:19 +00:00
|
|
|
setConsoleContentIfNoLiveLogs(logs: LogMessage) {
|
2018-05-30 09:14:48 +00:00
|
|
|
this.processLogService.emitNewLogsIfNoLiveLogs(logs);
|
2018-05-29 15:56:16 +00:00
|
|
|
if (config.ide.showConsoleOnDeploy) {
|
|
|
|
this.selectTerminalMenuItem('console');
|
2018-05-27 17:09:15 +00:00
|
|
|
}
|
2018-05-27 17:02:18 +00:00
|
|
|
}
|
2018-06-26 12:13:29 +00:00
|
|
|
|
|
|
|
scrollMessagesToBottom(): void {
|
|
|
|
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;
|
|
|
|
}
|
2019-01-21 15:49:44 +00:00
|
|
|
|
|
|
|
iframeLoad(): void {
|
2019-01-21 16:24:02 +00:00
|
|
|
if (this.webiframe) {
|
2019-07-10 07:21:23 +00:00
|
|
|
const href = this.webiframe.nativeElement.contentWindow.frames.location.href;
|
|
|
|
const niceURL = href.match(/.*?\/\/.*?(\/.*)/)[1];
|
|
|
|
this.actualIframeUrl = niceURL;
|
2019-01-21 16:24:02 +00:00
|
|
|
}
|
2019-01-21 15:49:44 +00:00
|
|
|
}
|
2019-01-21 16:00:13 +00:00
|
|
|
|
|
|
|
changeIframeURL() {
|
2019-07-10 07:21:23 +00:00
|
|
|
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;
|
2019-01-21 16:00:13 +00:00
|
|
|
}
|
2019-01-22 12:57:43 +00:00
|
|
|
|
|
|
|
pollingServerForIframeReload() {
|
|
|
|
this.polling = 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 = false;
|
|
|
|
this.reloadIframe();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
),
|
|
|
|
delay(1000)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
).subscribe();
|
|
|
|
}
|
|
|
|
|
|
|
|
ngOnDestroy() {
|
|
|
|
if (this.deploymentNotificationSubscription) {
|
|
|
|
this.deploymentNotificationSubscription.unsubscribe();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.iframeReloadSubscription) {
|
|
|
|
this.iframeReloadSubscription.unsubscribe();
|
|
|
|
}
|
|
|
|
}
|
2018-02-16 10:19:52 +00:00
|
|
|
}
|