Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8545c48be | ||
|
|
031a9916a0 | ||
|
|
68f9a2c57d | ||
|
|
f2720c218b | ||
|
|
f7a2182ba6 | ||
|
|
f17fe18cef | ||
|
|
a3993e8b87 | ||
|
|
abf7d8ced8 | ||
|
|
b45f624ab3 |
@@ -17,7 +17,7 @@ import { TerminalComponent } from './terminal/terminal.component';
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { TestmessengerComponent } from './testmessenger/testmessenger.component';
|
||||
import { DeploymentNotificationService } from './services/deployment-notification.service';
|
||||
import { SafePipe } from './pipes/safe.pipe';
|
||||
import { SafePipe, SafeHtmlPipe } from './pipes/safe.pipe';
|
||||
import { ConsoleComponent } from './console/console.component';
|
||||
import { MonacoEditorModule } from 'ngx-monaco-editor';
|
||||
import {
|
||||
@@ -41,6 +41,7 @@ import { LoaderComponent } from './loader/loader.component';
|
||||
DashboardComponent,
|
||||
TestmessengerComponent,
|
||||
SafePipe,
|
||||
SafeHtmlPipe,
|
||||
ConsoleComponent,
|
||||
LoaderComponent
|
||||
],
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<app-messages></app-messages>
|
||||
</div>
|
||||
<div class="tfw-web tao-grid-top-left"
|
||||
[ngClass]="{'deploy-blur': deploying || (polling | async)}">
|
||||
[ngClass]="{'deploy-blur': deploying || (iframeReloadPoller.isPolling | async)}">
|
||||
<div *ngIf="iframeUrl | async" class="iframe-container">
|
||||
<div *ngIf="showUrlBar | async" class="urlbar-container">
|
||||
<button class="refresh btn btn-sm rounded-circle" (click)="reloadIframe()">↻</button>
|
||||
@@ -18,6 +18,7 @@
|
||||
</div>
|
||||
<iframe class="iframe"
|
||||
#webiframe
|
||||
name="webiframe"
|
||||
scrolling="yes"
|
||||
frameborder="0"
|
||||
(load)="iframeLoad()"
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Component, OnDestroy, OnInit, ChangeDetectorRef, ElementRef, ViewChild } from '@angular/core';
|
||||
import { DeploymentNotificationService } from '../services/deployment-notification.service';
|
||||
import { Subscription, BehaviorSubject } from 'rxjs';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { WebSocketService } from '../services/websocket.service';
|
||||
import { WebSocketMessage } from '../message-types/websocket-message';
|
||||
import { DashboardConfigService } from '../services/config.service';
|
||||
import { DashboardConfigService, ConfigReadyService } from '../services/config.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { delay, retryWhen, tap } from 'rxjs/operators';
|
||||
import { FSMUpdateService } from '../services/fsmupdate.service';
|
||||
import { MessagesComponent } from '../messages/messages.component';
|
||||
import { StatusCodePoller } from './statuscodepoller';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dashboard',
|
||||
@@ -16,7 +16,6 @@ import { MessagesComponent } from '../messages/messages.component';
|
||||
})
|
||||
export class DashboardComponent implements OnInit, OnDestroy {
|
||||
deploying = false;
|
||||
polling = new BehaviorSubject<boolean>(false);
|
||||
deploymentNotificationSubscription: Subscription;
|
||||
@ViewChild('webiframe', {static: false}) webiframe: ElementRef;
|
||||
@ViewChild(MessagesComponent, {static: false}) messages: MessagesComponent;
|
||||
@@ -28,7 +27,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
||||
iframeUrl = this.configService.iframeUrl;
|
||||
actualIframeUrl = this.iframeUrl.value;
|
||||
terminalMenuItem = this.configService.terminalMenuItem;
|
||||
iframeReloadSubscription: Subscription;
|
||||
iframeReloadPoller: StatusCodePoller;
|
||||
|
||||
command_handlers = {
|
||||
'dashboard.reloadFrontend': this.reloadFrontendHandlder.bind(this),
|
||||
@@ -39,6 +38,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
||||
private webSocketService: WebSocketService,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private http: HttpClient,
|
||||
private configReadyService: ConfigReadyService,
|
||||
private configService: DashboardConfigService,
|
||||
private fsmUpdateService: FSMUpdateService) {}
|
||||
|
||||
@@ -46,6 +46,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
||||
this.webSocketService.connect();
|
||||
this.configService.init();
|
||||
this.subscribeCheckSolution();
|
||||
this.iframeReloadPoller = new StatusCodePoller(this.iframeUrl, this.http);
|
||||
this.hideIframeUntilResponseOk();
|
||||
this.subscribeResizeOnLayoutChange();
|
||||
this.initCommandHandling();
|
||||
@@ -63,8 +64,10 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
hideIframeUntilResponseOk() {
|
||||
// TODO: hide iframe and show it after this whole deal...
|
||||
this.reloadIframeWhenResponseOk();
|
||||
this.iframeReloadPoller.ok.subscribe(() => this.reloadIframe());
|
||||
this.configReadyService.configDone.subscribe(() =>
|
||||
this.iframeReloadPoller.start()
|
||||
);
|
||||
}
|
||||
|
||||
subscribeResizeOnLayoutChange() {
|
||||
@@ -86,7 +89,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
||||
(deploying) => {
|
||||
this.deploying = deploying;
|
||||
if (!deploying && this.configService.reloadIframeOnDeploy.value) {
|
||||
this.reloadIframeWhenResponseOk();
|
||||
this.iframeReloadPoller.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -151,36 +154,10 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
||||
this.iframeUrl.next(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 (this.iframeUrl.value === '') {
|
||||
this.iframeReloadSubscription.unsubscribe();
|
||||
this.polling.next(false);
|
||||
}
|
||||
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();
|
||||
}
|
||||
this.iframeReloadPoller.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Subject, Subscription, BehaviorSubject } from 'rxjs';
|
||||
import { retryWhen, delay, tap, skip } from 'rxjs/operators';
|
||||
|
||||
export class StatusCodePoller {
|
||||
http: HttpClient;
|
||||
url: BehaviorSubject<string>;
|
||||
pollFreq: number;
|
||||
okCode: number;
|
||||
stopOnOk: boolean;
|
||||
|
||||
pollSubscription: Subscription;
|
||||
urlSubscription: Subscription;
|
||||
poll = new Subject<any>();
|
||||
ok = new Subject<any>();
|
||||
isPolling = new BehaviorSubject<boolean>(false);
|
||||
|
||||
constructor(
|
||||
url: BehaviorSubject<string>, http: HttpClient,
|
||||
pollFreq = 1000, okCode = 200,
|
||||
stopOnOk = true
|
||||
) {
|
||||
this.url = url;
|
||||
this.http = http;
|
||||
this.pollFreq = pollFreq;
|
||||
this.okCode = okCode;
|
||||
this.stopOnOk = stopOnOk;
|
||||
}
|
||||
|
||||
start() {
|
||||
this.stop();
|
||||
if (this.url.value === '') {
|
||||
return;
|
||||
}
|
||||
this.urlSubscription = this.url.pipe(skip(1)).subscribe(() => this.stop());
|
||||
this.isPolling.next(true);
|
||||
this.pollSubscription = this.http.get(this.url.value, {observe: 'response'}).pipe(
|
||||
retryWhen(errors =>
|
||||
errors.pipe(
|
||||
tap(
|
||||
response => {
|
||||
this.poll.next(response);
|
||||
if (response.status === this.okCode) {
|
||||
if (this.stopOnOk) {
|
||||
this.stop();
|
||||
}
|
||||
this.ok.next(response);
|
||||
}
|
||||
}),
|
||||
delay(this.pollFreq)
|
||||
))).subscribe();
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.isPolling.next(false);
|
||||
if (this.pollSubscription) {
|
||||
this.pollSubscription.unsubscribe();
|
||||
}
|
||||
if (this.urlSubscription) {
|
||||
this.urlSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,8 @@
|
||||
|
||||
.loader {
|
||||
border-radius: 50%;
|
||||
border: 2px solid;
|
||||
border: 2px solid $tao-warm-yellow-600;
|
||||
border-top: 2px solid $tao-warm-yellow-200;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
animation: spin 2s linear infinite;
|
||||
|
||||
@@ -30,5 +30,7 @@ export const LanguageMap: { [extension: string]: string; } = {
|
||||
css: 'css',
|
||||
less: 'less',
|
||||
scss: 'scss',
|
||||
sh: 'shell'
|
||||
sh: 'shell',
|
||||
kt: 'kotlin',
|
||||
kts: 'kotlin'
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ export interface MessageData {
|
||||
originator?: string;
|
||||
timestamp?: Date;
|
||||
typing?: boolean;
|
||||
command?: any;
|
||||
message: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
<div class="tfw-messages-main">
|
||||
<div class="tfw-grid-message"
|
||||
*ngFor="let message of messages.slice(); let last = last"
|
||||
[class.highlighted-message]="last">
|
||||
[class.highlighted-message]="last"
|
||||
(click)="sendMessageCommand(message)">
|
||||
<div class="tfw-grid-message-header">
|
||||
<img class="tao-grid-center-left" src="images/avataobot.svg"/>
|
||||
<div class="tao-grid-center-left originator">{{message.originator}}</div>
|
||||
<div class="timestamp tao-grid-center-right">{{message.timestamp | date:'HH:mm:ss'}}</div>
|
||||
</div>
|
||||
<div class="tfw-grid-message-body" [innerHtml]="message.message"></div>
|
||||
<div class="tfw-grid-message-body" [innerHtml]="message.message | safeHtml"></div>
|
||||
</div>
|
||||
<div *ngIf="showTypingIndicator" class="tfw-grid-message jumping-circle-container">
|
||||
<div *ngIf="showTypingIndicator"
|
||||
class="tfw-grid-message jumping-circle-container"
|
||||
(click)="drainMessageQueue()">
|
||||
<div class="jumping-circle" id="jc1"></div>
|
||||
<div class="jumping-circle" id="jc2"></div>
|
||||
<div class="jumping-circle" id="jc3"></div>
|
||||
|
||||
@@ -59,4 +59,16 @@ export class MessagesComponent implements OnInit {
|
||||
convertMarkdownToHTML(text: string) {
|
||||
return this.markdownService.convertToHtml(text);
|
||||
}
|
||||
|
||||
drainMessageQueue() {
|
||||
this.websocketService.send({
|
||||
'key': 'message.queue.drain'
|
||||
});
|
||||
}
|
||||
|
||||
sendMessageCommand(message: MessageData) {
|
||||
if ('command' in message) {
|
||||
this.websocketService.send(message.command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,3 +11,14 @@ export class SafePipe implements PipeTransform {
|
||||
return this.sanitizer.bypassSecurityTrustResourceUrl(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Pipe({
|
||||
name: 'safeHtml'
|
||||
})
|
||||
export class SafeHtmlPipe implements PipeTransform {
|
||||
constructor(private sanitized: DomSanitizer) {}
|
||||
|
||||
transform(value) {
|
||||
return this.sanitized.bypassSecurityTrustHtml(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ export class DashboardConfigService extends ConfigServiceBase {
|
||||
|
||||
layout = new BehaviorSubject<string>('terminal-ide-web');
|
||||
hideMessages = new BehaviorSubject<boolean>(false);
|
||||
iframeUrl = new BehaviorSubject<string>('/webservice');
|
||||
iframeUrl = new BehaviorSubject<string>('');
|
||||
showUrlBar = new BehaviorSubject<boolean>(false);
|
||||
terminalMenuItem = new BehaviorSubject<string>('terminal');
|
||||
reloadIframeOnDeploy = new BehaviorSubject<boolean>(false);
|
||||
|
||||
Reference in New Issue
Block a user