mirror of
				https://github.com/avatao-content/frontend-tutorial-framework
				synced 2025-11-04 12:12:55 +00:00 
			
		
		
		
	Merge branch 'frontend_fixes'
This commit is contained in:
		
							
								
								
									
										53
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								package.json
									
									
									
									
									
								
							@@ -9,38 +9,37 @@
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  "private": true,
 | 
					  "private": true,
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@angular/animations": "^6.0.2",
 | 
					    "@angular/animations": "^7.2.15",
 | 
				
			||||||
    "@angular/common": "^6.0.2",
 | 
					    "@angular/common": "^7.2.15",
 | 
				
			||||||
    "@angular/compiler": "^6.0.2",
 | 
					    "@angular/compiler": "^7.2.15",
 | 
				
			||||||
    "@angular/core": "^6.0.2",
 | 
					    "@angular/core": "^7.2.15",
 | 
				
			||||||
    "@angular/forms": "^6.0.2",
 | 
					    "@angular/forms": "^7.2.15",
 | 
				
			||||||
    "@angular/http": "^6.0.2",
 | 
					    "@angular/http": "^7.2.15",
 | 
				
			||||||
    "@angular/platform-browser": "^6.0.2",
 | 
					    "@angular/platform-browser": "^7.2.15",
 | 
				
			||||||
    "@angular/platform-browser-dynamic": "^6.0.2",
 | 
					    "@angular/platform-browser-dynamic": "^7.2.15",
 | 
				
			||||||
    "@angular/router": "^6.0.2",
 | 
					    "@angular/router": "^7.2.15",
 | 
				
			||||||
    "@ng-bootstrap/ng-bootstrap": "^2.0.0",
 | 
					    "@ng-bootstrap/ng-bootstrap": "^4.1.2",
 | 
				
			||||||
    "bootstrap": "^4.0.0",
 | 
					    "bootstrap": "^4.3.1",
 | 
				
			||||||
    "classlist.js": "^1.1.20150312",
 | 
					    "classlist.js": "^1.1.20150312",
 | 
				
			||||||
    "core-js": "^2.5.4",
 | 
					    "core-js": "^2.5.4",
 | 
				
			||||||
    "ngx-monaco-editor": "^6.0.0",
 | 
					    "ngx-monaco-editor": "^7.0.0",
 | 
				
			||||||
    "node-sass": "^4.7.2",
 | 
					    "node-sass": "^4.12.0",
 | 
				
			||||||
    "rxjs": "^6.0.0",
 | 
					    "rxjs": "^6.5.2",
 | 
				
			||||||
    "rxjs-compat": "^6.1.0",
 | 
					 | 
				
			||||||
    "rxjs-websockets": "^6.0.1",
 | 
					    "rxjs-websockets": "^6.0.1",
 | 
				
			||||||
    "showdown": "^1.8.5",
 | 
					    "showdown": "^1.8.5",
 | 
				
			||||||
    "xterm": "^3.4.1",
 | 
					    "xterm": "^3.13.0",
 | 
				
			||||||
    "zone.js": "^0.8.26"
 | 
					    "zone.js": "~0.8.26"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@angular-devkit/build-angular": "^0.6.3",
 | 
					    "@angular-devkit/build-angular": "^0.13.9",
 | 
				
			||||||
    "@angular/cli": "^6.0.3",
 | 
					    "@angular/cli": "^7.3.9",
 | 
				
			||||||
    "@angular/compiler-cli": "^6.0.2",
 | 
					    "@angular/compiler-cli": "^7.2.15",
 | 
				
			||||||
    "@angular/language-service": "^6.0.2",
 | 
					    "@angular/language-service": "^7.2.15",
 | 
				
			||||||
    "@types/node": "~8.9.4",
 | 
					    "@types/node": "^12.0.0",
 | 
				
			||||||
    "@types/showdown": "^1.7.2",
 | 
					    "@types/showdown": "^1.9.2",
 | 
				
			||||||
    "codelyzer": "~4.2.1",
 | 
					    "codelyzer": "~5.1.0",
 | 
				
			||||||
    "ts-node": "~5.0.1",
 | 
					    "ts-node": "^8.1.0",
 | 
				
			||||||
    "tslint": "^5.10.0",
 | 
					    "tslint": "^5.16.0",
 | 
				
			||||||
    "typescript": "~2.7.2"
 | 
					    "typescript": "3.1.6"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@ export const config = {
 | 
				
			|||||||
      'web-only'
 | 
					      'web-only'
 | 
				
			||||||
      ],
 | 
					      ],
 | 
				
			||||||
    iframeUrl: '/webservice',
 | 
					    iframeUrl: '/webservice',
 | 
				
			||||||
 | 
					    showUrlBar: false,
 | 
				
			||||||
    hideMessages: false
 | 
					    hideMessages: false
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  ide: {
 | 
					  ide: {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,15 +10,25 @@
 | 
				
			|||||||
      <app-messages (newMessageEvent)="scrollMessagesToBottom()"></app-messages>
 | 
					      <app-messages (newMessageEvent)="scrollMessagesToBottom()"></app-messages>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div class="tfw-web tao-grid-top-left"
 | 
					    <div class="tfw-web tao-grid-top-left"
 | 
				
			||||||
         [ngClass]="{'deploy-blur': deploying}">
 | 
					         [ngClass]="{'deploy-blur': deploying || polling}">
 | 
				
			||||||
         <app-web *ngIf="!iframeUrl"></app-web>
 | 
					         <app-web *ngIf="!iframeUrl"></app-web>
 | 
				
			||||||
 | 
					         <div *ngIf="showUrlBar" class="urlbar-container">
 | 
				
			||||||
 | 
					           <button class="refresh btn btn-sm rounded-circle" (click)="reloadIframe()">↻</button>
 | 
				
			||||||
 | 
					           <input type="text"
 | 
				
			||||||
 | 
					                  #urlbar
 | 
				
			||||||
 | 
					                  class="urlbar form-control"
 | 
				
			||||||
 | 
					                  value="{{actualIframeUrl}}"
 | 
				
			||||||
 | 
					                  (keyup.enter)="changeIframeURL()">
 | 
				
			||||||
 | 
					           <button class="go btn btn-sm rounded-circle" (click)="changeIframeURL()">⇨</button>
 | 
				
			||||||
 | 
					         </div>
 | 
				
			||||||
         <div *ngIf="iframeUrl" class="iframe-container">
 | 
					         <div *ngIf="iframeUrl" class="iframe-container">
 | 
				
			||||||
          <iframe class="iframe"
 | 
					            <iframe class="iframe"
 | 
				
			||||||
                  #webiframe
 | 
					                    #webiframe
 | 
				
			||||||
                  scrolling="yes"
 | 
					                    scrolling="yes"
 | 
				
			||||||
                  frameborder="0"
 | 
					                    frameborder="0"
 | 
				
			||||||
                  [src]="iframeUrl | safe">
 | 
					                    (load)="iframeLoad()"
 | 
				
			||||||
          </iframe>
 | 
					                    [src]="iframeUrl | safe">
 | 
				
			||||||
 | 
					            </iframe>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div class="tfw-ide">
 | 
					    <div class="tfw-ide">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,11 +3,13 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@import "../../assets/scss/variables.scss";
 | 
					@import "../../assets/scss/variables.scss";
 | 
				
			||||||
@import "../../assets/scss/mixins/layout.scss";
 | 
					@import "../../assets/scss/mixins/layout.scss";
 | 
				
			||||||
 | 
					@import "../../assets/scss/mixins/scrollbar";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@mixin set-tfw-web($layouts-key) {
 | 
					@mixin set-tfw-web($layouts-key) {
 | 
				
			||||||
  .tfw-web {
 | 
					  .tfw-web {
 | 
				
			||||||
    .iframe-container {
 | 
					    .iframe-container {
 | 
				
			||||||
      display: flex;
 | 
					      display: flex;
 | 
				
			||||||
 | 
					      flex-direction: column;
 | 
				
			||||||
      overflow: hidden;
 | 
					      overflow: hidden;
 | 
				
			||||||
      @include set-component-size($layouts-key, 'web');
 | 
					      @include set-component-size($layouts-key, 'web');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -18,6 +20,30 @@
 | 
				
			|||||||
      margin: 0;
 | 
					      margin: 0;
 | 
				
			||||||
      padding: 0;
 | 
					      padding: 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .urlbar-container {
 | 
				
			||||||
 | 
					      display: flex;
 | 
				
			||||||
 | 
					      height: 37px;
 | 
				
			||||||
 | 
					      background: #353535;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      .btn {
 | 
				
			||||||
 | 
					        background: #353535;
 | 
				
			||||||
 | 
					        color: white;
 | 
				
			||||||
 | 
					        align-self: center;
 | 
				
			||||||
 | 
					        margin: 5px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      .btn:hover{
 | 
				
			||||||
 | 
					        background: lighten(#353535, 10);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .urlbar {
 | 
				
			||||||
 | 
					      flex-grow: 1;
 | 
				
			||||||
 | 
					      height: 30px;
 | 
				
			||||||
 | 
					      align-self: center;
 | 
				
			||||||
 | 
					      border-radius: 15px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -46,6 +72,8 @@
 | 
				
			|||||||
    background-color: $tao-gray-50;
 | 
					    background-color: $tao-gray-50;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @include set-scrollbar-style('dark', '.tfw-messages');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .tfw-messages {
 | 
					  .tfw-messages {
 | 
				
			||||||
    padding: $space;
 | 
					    padding: $space;
 | 
				
			||||||
    padding-top: $hair;
 | 
					    padding-top: $hair;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,8 @@ import { config } from '../config';
 | 
				
			|||||||
import { ProcessLogService } from '../services/processlog.service';
 | 
					import { ProcessLogService } from '../services/processlog.service';
 | 
				
			||||||
import { LogMessage } from '../message-types/log-message';
 | 
					import { LogMessage } from '../message-types/log-message';
 | 
				
			||||||
import { CommandMessage } from '../message-types/command-message';
 | 
					import { CommandMessage } from '../message-types/command-message';
 | 
				
			||||||
 | 
					import { HttpClient } from '@angular/common/http';
 | 
				
			||||||
 | 
					import { delay, retryWhen, tap } from 'rxjs/operators';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-dashboard',
 | 
					  selector: 'app-dashboard',
 | 
				
			||||||
@@ -18,14 +20,19 @@ import { CommandMessage } from '../message-types/command-message';
 | 
				
			|||||||
})
 | 
					})
 | 
				
			||||||
export class DashboardComponent implements OnInit, OnDestroy {
 | 
					export class DashboardComponent implements OnInit, OnDestroy {
 | 
				
			||||||
  deploying = false;
 | 
					  deploying = false;
 | 
				
			||||||
 | 
					  polling = false;
 | 
				
			||||||
  deploymentNotificationSubscription: Subscription;
 | 
					  deploymentNotificationSubscription: Subscription;
 | 
				
			||||||
  @ViewChild('webiframe') webiframe: ElementRef;
 | 
					  @ViewChild('webiframe') webiframe: ElementRef;
 | 
				
			||||||
  @ViewChild('tfwmessages') messages: ElementRef;
 | 
					  @ViewChild('tfwmessages') messages: ElementRef;
 | 
				
			||||||
 | 
					  @ViewChild('urlbar') urlbar: ElementRef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  layout: string = config.dashboard.currentLayout;
 | 
					  layout: string = config.dashboard.currentLayout;
 | 
				
			||||||
  hideMessages: boolean = config.dashboard.hideMessages;
 | 
					  hideMessages: boolean = config.dashboard.hideMessages;
 | 
				
			||||||
  iframeUrl: string = config.dashboard.iframeUrl;
 | 
					  iframeUrl: string = config.dashboard.iframeUrl;
 | 
				
			||||||
 | 
					  showUrlBar = config.dashboard.showUrlBar;
 | 
				
			||||||
 | 
					  actualIframeUrl: string = this.iframeUrl;
 | 
				
			||||||
  selectedTerminalMenuItem: string = config.dashboard.terminalOrConsole;
 | 
					  selectedTerminalMenuItem: string = config.dashboard.terminalOrConsole;
 | 
				
			||||||
 | 
					  iframeReloadSubscription: Subscription;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  command_handlers = {
 | 
					  command_handlers = {
 | 
				
			||||||
    'layout':           this.layoutHandler.bind(this),
 | 
					    'layout':           this.layoutHandler.bind(this),
 | 
				
			||||||
@@ -38,7 +45,8 @@ export class DashboardComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
  constructor(private deploymentNotificationService: DeploymentNotificationService,
 | 
					  constructor(private deploymentNotificationService: DeploymentNotificationService,
 | 
				
			||||||
              private webSocketService: WebSocketService,
 | 
					              private webSocketService: WebSocketService,
 | 
				
			||||||
              private changeDetectorRef: ChangeDetectorRef,
 | 
					              private changeDetectorRef: ChangeDetectorRef,
 | 
				
			||||||
              private processLogService: ProcessLogService) {}
 | 
					              private processLogService: ProcessLogService,
 | 
				
			||||||
 | 
					              private http: HttpClient) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ngOnInit() {
 | 
					  ngOnInit() {
 | 
				
			||||||
    this.webSocketService.connect();
 | 
					    this.webSocketService.connect();
 | 
				
			||||||
@@ -60,7 +68,10 @@ export class DashboardComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
      (deploying) => {
 | 
					      (deploying) => {
 | 
				
			||||||
        this.deploying = deploying;
 | 
					        this.deploying = deploying;
 | 
				
			||||||
        if (!deploying && config.ide.reloadIframeOnDeploy) {
 | 
					        if (!deploying && config.ide.reloadIframeOnDeploy) {
 | 
				
			||||||
          this.reloadIframe();
 | 
					          if (this.polling) {
 | 
				
			||||||
 | 
					            this.iframeReloadSubscription.unsubscribe();
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          this.pollingServerForIframeReload();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -113,12 +124,6 @@ export class DashboardComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
    setTimeout(() => window.dispatchEvent(new Event('resize', {force: true} as any)), 0);
 | 
					    setTimeout(() => window.dispatchEvent(new Event('resize', {force: true} as any)), 0);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ngOnDestroy() {
 | 
					 | 
				
			||||||
    if (this.deploymentNotificationSubscription) {
 | 
					 | 
				
			||||||
      this.deploymentNotificationSubscription.unsubscribe();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  reloadIframe() {
 | 
					  reloadIframe() {
 | 
				
			||||||
    setTimeout(() => {
 | 
					    setTimeout(() => {
 | 
				
			||||||
      this.webiframe.nativeElement.contentWindow.location.reload(true);
 | 
					      this.webiframe.nativeElement.contentWindow.location.reload(true);
 | 
				
			||||||
@@ -152,4 +157,44 @@ export class DashboardComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
    // change detection (not in the template like ConsoleComponent does)
 | 
					    // change detection (not in the template like ConsoleComponent does)
 | 
				
			||||||
    element.scrollTop = element.scrollHeight;
 | 
					    element.scrollTop = element.scrollHeight;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  iframeLoad(): void {
 | 
				
			||||||
 | 
					    if (this.webiframe) {
 | 
				
			||||||
 | 
					      this.actualIframeUrl = this.webiframe.nativeElement.contentWindow.frames.location.pathname;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  changeIframeURL() {
 | 
				
			||||||
 | 
					    this.webiframe.nativeElement.contentWindow.frames.location.pathname = this.urlbar.nativeElement.value;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,6 +39,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<ngx-monaco-editor [(ngModel)]="code"
 | 
					<ngx-monaco-editor [(ngModel)]="code"
 | 
				
			||||||
                   class="tfw-ide-editor"
 | 
					                   class="tfw-ide-editor"
 | 
				
			||||||
                   (keyup)="editorWriteHanlder()"
 | 
					                   (ngModelChange)="editorWriteHanlder()"
 | 
				
			||||||
                   [options]="editorOptions"
 | 
					                   [options]="editorOptions"
 | 
				
			||||||
></ngx-monaco-editor>
 | 
					></ngx-monaco-editor>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,13 +4,12 @@
 | 
				
			|||||||
@import "../../assets/scss/variables.scss";
 | 
					@import "../../assets/scss/variables.scss";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.tfw-grid-ide-statusbar {
 | 
					.tfw-grid-ide-statusbar {
 | 
				
			||||||
  display: grid;
 | 
					  display: flex;
 | 
				
			||||||
  grid-template-columns: 8fr 1fr;
 | 
					 | 
				
			||||||
  background-color: #353535;
 | 
					  background-color: #353535;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.tfw-ide-editor {
 | 
					.tfw-ide-editor {
 | 
				
			||||||
  height: calc(100% - 67px);
 | 
					  height: calc(100% - 25px);
 | 
				
			||||||
  width: 100%;
 | 
					  width: 100%;
 | 
				
			||||||
  overflow: hidden;
 | 
					  overflow: hidden;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -38,12 +37,19 @@
 | 
				
			|||||||
.tfw-deploy-btn-group {
 | 
					.tfw-deploy-btn-group {
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  justify-content: flex-end;
 | 
					  justify-content: flex-end;
 | 
				
			||||||
 | 
					  flex-grow: 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .tfw-deploy-btn {
 | 
					  .tfw-deploy-btn {
 | 
				
			||||||
    background: $tao-bright-green-200;
 | 
					    background: $tao-bright-green-200;
 | 
				
			||||||
    padding: 0.3em 0.7em 0.7em 1.5em;
 | 
					    padding: 0.3em 0.7em 0.7em 1.5em;
 | 
				
			||||||
    border-radius: 0;
 | 
					    border-radius: 0 0 0 2.2em;
 | 
				
			||||||
    border-bottom-left-radius: 2.2em;
 | 
					    color: black;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &:first-child {
 | 
				
			||||||
 | 
					      display: flex;
 | 
				
			||||||
 | 
					      align-items: center;
 | 
				
			||||||
 | 
					      justify-content: center;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    img {
 | 
					    img {
 | 
				
			||||||
      padding-right: 0.5em;
 | 
					      padding-right: 0.5em;
 | 
				
			||||||
@@ -71,9 +77,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .loader {
 | 
					    .loader {
 | 
				
			||||||
      border: 2px solid $tao-warm-yellow-600;
 | 
					 | 
				
			||||||
      border-radius: 50%;
 | 
					      border-radius: 50%;
 | 
				
			||||||
      border-top: 2px solid $tao-warm-yellow-200;
 | 
					      border: 2px solid;
 | 
				
			||||||
      width: 15px;
 | 
					      width: 15px;
 | 
				
			||||||
      height: 15px;
 | 
					      height: 15px;
 | 
				
			||||||
      animation: spin 2s linear infinite;
 | 
					      animation: spin 2s linear infinite;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@
 | 
				
			|||||||
      <div class="tao-grid-center-left originator">{{message.originator}}</div>
 | 
					      <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 class="timestamp tao-grid-center-right">{{message.timestamp | date:'HH:mm:ss'}}</div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div [innerHtml]="message.message"></div>
 | 
					    <div class="tfw-grid-message-body" [innerHtml]="message.message"></div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  <div *ngIf="messageInQueue" class="tfw-grid-message jumping-circle-container">
 | 
					  <div *ngIf="messageInQueue" class="tfw-grid-message jumping-circle-container">
 | 
				
			||||||
      <div class="jumping-circle" id="jc1"></div>
 | 
					      <div class="jumping-circle" id="jc1"></div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@
 | 
				
			|||||||
// All Rights Reserved. See LICENSE file for details.
 | 
					// All Rights Reserved. See LICENSE file for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@import "../../assets/scss/variables.scss";
 | 
					@import "../../assets/scss/variables.scss";
 | 
				
			||||||
 | 
					@import "../../assets/scss/mixins/layout";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.tfw-next-button {
 | 
					.tfw-next-button {
 | 
				
			||||||
  text-align: center;
 | 
					  text-align: center;
 | 
				
			||||||
@@ -84,3 +85,7 @@
 | 
				
			|||||||
    opacity: 0.37;
 | 
					    opacity: 0.37;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.tfw-grid-message-body {
 | 
				
			||||||
 | 
					  @include word-break()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,10 @@
 | 
				
			|||||||
@import "../../app/dashboard/dashboard.component.scss";
 | 
					@import "../../app/dashboard/dashboard.component.scss";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					::ng-deep .xterm .xterm-viewport {
 | 
				
			||||||
 | 
					  overflow-y: auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.tfw-xterm {
 | 
					.tfw-xterm {
 | 
				
			||||||
  max-height: 100%;
 | 
					  max-height: 100%;
 | 
				
			||||||
  height: 100%;
 | 
					  height: 100%;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								src/assets/images/favicon.ico
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/assets/images/favicon.ico
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 15 KiB  | 
@@ -1,79 +1,79 @@
 | 
				
			|||||||
// Copyright (C) 2018 Avatao.com Innovative Learning Kft.
 | 
					// Copyright (C) 2018 Avatao.com Innovative Learning Kft.
 | 
				
			||||||
// All Rights Reserved. See LICENSE file for details.
 | 
					// All Rights Reserved. See LICENSE file for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$grid-columns-count: 25;
 | 
					$grid-columns-count: 100;
 | 
				
			||||||
$grid-rows-count: 25;
 | 
					$grid-rows-count: 30;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$terminal-ide-web-layout: (
 | 
					$terminal-ide-web-layout: (
 | 
				
			||||||
  'header': (1, 6, 1, 2),
 | 
					  'header': (0, 20, 0, 4),
 | 
				
			||||||
  'messages': (1, 6, 2, 16),
 | 
					  'messages': (0, 20, 4, 60),
 | 
				
			||||||
  'ide': (15,$grid-columns-count, 1, $grid-rows-count+1),
 | 
					  'ide': (56, 96, 0, 100),
 | 
				
			||||||
  'terminal': (1, 15, 16, $grid-rows-count+1),
 | 
					  'terminal': (0, 56, 60, 100),
 | 
				
			||||||
  'web': (6, 15, 1, 16),
 | 
					  'web': (20, 56, 0, 60),
 | 
				
			||||||
  'sidebar': ($grid-columns-count,$grid-columns-count+1, 1,$grid-rows-count+1)
 | 
					  'sidebar': (96, 100, 0, 100)
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$terminal-web-layout: (
 | 
					$terminal-web-layout: (
 | 
				
			||||||
  'header': (1, 6, 1, 2),
 | 
					  'header': (0, 20, 0, 4),
 | 
				
			||||||
  'messages': (1, 6, 2, $grid-columns-count+1),
 | 
					  'messages': (0, 20, 2, 100),
 | 
				
			||||||
  'ide': (),
 | 
					  'ide': (),
 | 
				
			||||||
  'terminal': (15, $grid-columns-count, 1, $grid-rows-count+1),
 | 
					  'terminal': (56, 96, 0, 100),
 | 
				
			||||||
  'web': (6, 15, 1, $grid-rows-count+1),
 | 
					  'web': (20, 56, 0, 100),
 | 
				
			||||||
  'sidebar': ($grid-columns-count,$grid-columns-count+1, 1,$grid-rows-count+1)
 | 
					  'sidebar': (96, 100, 0, 100)
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$terminal-ide-vertical-layout: (
 | 
					$terminal-ide-vertical-layout: (
 | 
				
			||||||
  'header': (1, 6, 1, 2),
 | 
					  'header': (0, 20, 0, 4),
 | 
				
			||||||
  'messages': (1, 6, 2,$grid-rows-count+1),
 | 
					  'messages': (0, 20, 2, 100),
 | 
				
			||||||
  'ide': (15, $grid-columns-count, 1,$grid-rows-count+1),
 | 
					  'ide': (56, 96, 0, 100),
 | 
				
			||||||
  'terminal': (6, 15, 1, $grid-rows-count+1),
 | 
					  'terminal': (20, 56, 0, 100),
 | 
				
			||||||
  'web': (),
 | 
					  'web': (),
 | 
				
			||||||
  'sidebar': ($grid-columns-count,$grid-columns-count+1, 1,$grid-rows-count+1)
 | 
					  'sidebar': (96, 100, 0, 100)
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$terminal-ide-horizontal-layout: (
 | 
					$terminal-ide-horizontal-layout: (
 | 
				
			||||||
  'header': (1, 6, 1, 2),
 | 
					  'header': (0, 20, 0, 4),
 | 
				
			||||||
  'messages': (1, 6, 2,$grid-rows-count+1),
 | 
					  'messages': (0, 20, 2, 100),
 | 
				
			||||||
  'ide': (6,$grid-columns-count, 1, 16),
 | 
					  'ide': (20, 96, 0, 60),
 | 
				
			||||||
  'terminal': (6, $grid-columns-count, 16, $grid-rows-count+1),
 | 
					  'terminal': (20, 96, 60, 100),
 | 
				
			||||||
  'web': (),
 | 
					  'web': (),
 | 
				
			||||||
  'sidebar': ($grid-columns-count,$grid-columns-count+1, 1,$grid-rows-count+1),
 | 
					  'sidebar': (96, 100, 0, 100)
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$ide-web-vertical-layout: (
 | 
					$ide-web-vertical-layout: (
 | 
				
			||||||
  'header': (1, 6, 1, 2),
 | 
					  'header': (0, 20, 0, 4),
 | 
				
			||||||
  'messages': (1, 6, 2, $grid-rows-count+1),
 | 
					  'messages': (0, 20, 4, 100),
 | 
				
			||||||
  'ide': (15, $grid-columns-count, 1,$grid-rows-count+1),
 | 
					  'ide': (56, 96, 0, 100),
 | 
				
			||||||
  'terminal': (),
 | 
					  'terminal': (),
 | 
				
			||||||
  'web': (6, 15, 1, $grid-rows-count+1),
 | 
					  'web': (20, 56, 0, 100),
 | 
				
			||||||
  'sidebar': ($grid-columns-count,$grid-columns-count+1, 1,$grid-rows-count+1)
 | 
					  'sidebar': (96, 100, 0, 100)
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$terminal-only-layout: (
 | 
					$terminal-only-layout: (
 | 
				
			||||||
  'header': (1, 6, 1, 2),
 | 
					  'header': (0, 20, 0, 4),
 | 
				
			||||||
  'messages': (1, 6, 2,$grid-rows-count+1),
 | 
					  'messages': (0, 20, 4, 100),
 | 
				
			||||||
  'ide': (),
 | 
					  'ide': (),
 | 
				
			||||||
  'terminal': (6, $grid-columns-count, 1,$grid-rows-count+1),
 | 
					  'terminal': (20, 96, 0, 100),
 | 
				
			||||||
  'web': (),
 | 
					  'web': (),
 | 
				
			||||||
  'sidebar': ($grid-columns-count,$grid-columns-count+1, 1,$grid-rows-count+1)
 | 
					  'sidebar': (96, 100, 0, 100)
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$ide-only-layout: (
 | 
					$ide-only-layout: (
 | 
				
			||||||
  'header': (1, 6, 1, 2),
 | 
					  'header': (0, 20, 0, 4),
 | 
				
			||||||
  'messages': (1, 6, 2,$grid-rows-count+1),
 | 
					  'messages': (0, 20, 4, 100),
 | 
				
			||||||
  'ide': (6, $grid-columns-count,  1,$grid-rows-count+1),
 | 
					  'ide': (20, 96, 0, 100),
 | 
				
			||||||
  'terminal': (),
 | 
					  'terminal': (),
 | 
				
			||||||
  'web': (),
 | 
					  'web': (),
 | 
				
			||||||
  'sidebar': ($grid-columns-count,$grid-columns-count+1, 1,$grid-rows-count+1)
 | 
					  'sidebar': (96, 100, 0, 100)
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$web-only-layout: (
 | 
					$web-only-layout: (
 | 
				
			||||||
  'header': (1, 6, 1, 2),
 | 
					  'header': (0, 20, 0, 4),
 | 
				
			||||||
  'messages': (1, 6, 2,$grid-rows-count+1),
 | 
					  'messages': (0, 20, 4, 100),
 | 
				
			||||||
  'ide': (),
 | 
					  'ide': (),
 | 
				
			||||||
  'terminal': (),
 | 
					  'terminal': (),
 | 
				
			||||||
  'web': (6, $grid-columns-count, 1,$grid-rows-count+1),
 | 
					  'web': (20, 96, 0, 100),
 | 
				
			||||||
  'sidebar': ($grid-columns-count,$grid-columns-count+1, 1,$grid-rows-count+1)
 | 
					  'sidebar': (96, 100, 0, 100)
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$layouts: (
 | 
					$layouts: (
 | 
				
			||||||
@@ -111,6 +111,10 @@ $layouts: (
 | 
				
			|||||||
  @return map_get($layouts, $layouts-key);
 | 
					  @return map_get($layouts, $layouts-key);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@function convert-ratio($ratio, $max) {
 | 
				
			||||||
 | 
					  @return round(($ratio * $max) / 100) + 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@mixin position-grid-items($map, $sel) {
 | 
					@mixin position-grid-items($map, $sel) {
 | 
				
			||||||
  $sel: if($sel == '' and &, &, $sel);
 | 
					  $sel: if($sel == '' and &, &, $sel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -120,11 +124,18 @@ $layouts: (
 | 
				
			|||||||
        @include hide-component();
 | 
					        @include hide-component();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      @else {
 | 
					      @else {
 | 
				
			||||||
        grid-column-start: nth($v, 1);
 | 
					        grid-column-start: convert-ratio(nth($v, 1), $grid-columns-count);
 | 
				
			||||||
        grid-column-end: nth($v, 2);
 | 
					        grid-column-end: convert-ratio(nth($v, 2), $grid-columns-count);
 | 
				
			||||||
        grid-row-start: nth($v, 3);
 | 
					        grid-row-start: convert-ratio(nth($v, 3), $grid-rows-count);
 | 
				
			||||||
        grid-row-end: nth($v, 4);
 | 
					        grid-row-end: convert-ratio(nth($v, 4), $grid-rows-count);
 | 
				
			||||||
 | 
					        max-width: calc(100vw / #{$grid-columns-count} * (#{convert-ratio(nth($v, 2), $grid-columns-count)} - #{convert-ratio(nth($v, 1), $grid-columns-count)}));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      /* A hack for Chrome, without this there is a white 1px strip on the left of the terminal */
 | 
				
			||||||
 | 
					      /* You have been warned: don't try to understand this */
 | 
				
			||||||
 | 
					      @if($sel == 'terminal-ide-web' & & $k == 'terminal') {
 | 
				
			||||||
 | 
					        transform: translateX(-1px);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      /* End of hack */
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -133,10 +144,18 @@ $layouts: (
 | 
				
			|||||||
  $tfw-component: map_get(get-layout($layouts-key), $layout-key);
 | 
					  $tfw-component: map_get(get-layout($layouts-key), $layout-key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @if (length($tfw-component) > 0) {
 | 
					  @if (length($tfw-component) > 0) {
 | 
				
			||||||
    $columns-count: nth($tfw-component,2) - nth($tfw-component,1);
 | 
					    $columns-count: convert-ratio(nth($tfw-component,2), $grid-columns-count) - convert-ratio(nth($tfw-component,1), $grid-columns-count);
 | 
				
			||||||
    $rows-count: nth($tfw-component,4) - nth($tfw-component,3);
 | 
					    $rows-count: convert-ratio(nth($tfw-component,4), $grid-columns-count) - convert-ratio(nth($tfw-component,3), $grid-columns-count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    min-width: #{$columns-count / $grid-columns-count * 100}vw;
 | 
					    min-width: #{$columns-count / $grid-columns-count * 100}vw;
 | 
				
			||||||
    min-height: #{$rows-count / $grid-rows-count * 100}vh;
 | 
					    min-height: #{$rows-count / $grid-rows-count * 100}vh;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@mixin word-break() {
 | 
				
			||||||
 | 
					  /* For Firefox */
 | 
				
			||||||
 | 
					  white-space: pre-wrap;
 | 
				
			||||||
 | 
					  word-break: break-all;
 | 
				
			||||||
 | 
					  /* For Chrome and IE */
 | 
				
			||||||
 | 
					  word-wrap: break-word;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,17 +1,36 @@
 | 
				
			|||||||
@mixin set-scrollbar-style() {
 | 
					@mixin set-scrollbar-style($style, $selctor) {
 | 
				
			||||||
  ::-webkit-scrollbar-track
 | 
					  ::-webkit-scrollbar {
 | 
				
			||||||
  {
 | 
					    width: 3px !important;
 | 
				
			||||||
    background-color: #F5F5F5;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ::-webkit-scrollbar
 | 
					  #{$selctor}::-webkit-scrollbar-track {
 | 
				
			||||||
  {
 | 
					    border-radius: 10px !important;
 | 
				
			||||||
    width: 4px;
 | 
					    width: 3px !important;
 | 
				
			||||||
    background-color: #F5F5F5;
 | 
					    @if ($style == 'light') {
 | 
				
			||||||
 | 
					      background: #8a8a8a !important;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    } @else if ($style == 'dark') {
 | 
				
			||||||
 | 
					      background: white !important;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ::-webkit-scrollbar-thumb
 | 
					  #{$selctor}::-webkit-scrollbar-thumb {
 | 
				
			||||||
  {
 | 
					    @if ($style == 'dark') {
 | 
				
			||||||
    background-color: gray;
 | 
					      background: #8a8a8a !important;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    } @else if ($style == 'light') {
 | 
				
			||||||
 | 
					      background: white !important;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    border-radius: 10px !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #{$selctor}::-webkit-scrollbar-thumb:hover {
 | 
				
			||||||
 | 
					    @if ($style == 'dark') {
 | 
				
			||||||
 | 
					      background: #424242 !important;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    } @else if ($style == 'light') {
 | 
				
			||||||
 | 
					      background: #9d9d9d !important;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    cursor: pointer !important;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,4 +8,5 @@ body, html {
 | 
				
			|||||||
  height: 100vh;
 | 
					  height: 100vh;
 | 
				
			||||||
  width: 100vw;
 | 
					  width: 100vw;
 | 
				
			||||||
  overflow: hidden;
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					  @include set-scrollbar-style('light', '');
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,16 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "extends": "../tsconfig.json",
 | 
					  "extends": "../tsconfig.json",
 | 
				
			||||||
  "compilerOptions": {
 | 
					  "compilerOptions": {
 | 
				
			||||||
 | 
					    "paths": {
 | 
				
			||||||
 | 
					      "*": [
 | 
				
			||||||
 | 
					        "types/*"
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "outDir": "../out-tsc/app",
 | 
					    "outDir": "../out-tsc/app",
 | 
				
			||||||
    "baseUrl": "./",
 | 
					    "baseUrl": "./",
 | 
				
			||||||
    "module": "es2015",
 | 
					    "module": "esNext",
 | 
				
			||||||
    "types": []
 | 
					    "types": [],
 | 
				
			||||||
 | 
					    "resolveJsonModule": true
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "exclude": [
 | 
					  "exclude": [
 | 
				
			||||||
    "test.ts",
 | 
					    "test.ts",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@
 | 
				
			|||||||
    "emitDecoratorMetadata": true,
 | 
					    "emitDecoratorMetadata": true,
 | 
				
			||||||
    "experimentalDecorators": true,
 | 
					    "experimentalDecorators": true,
 | 
				
			||||||
    "target": "es5",
 | 
					    "target": "es5",
 | 
				
			||||||
 | 
					    "module": "esNext",
 | 
				
			||||||
    "typeRoots": [
 | 
					    "typeRoots": [
 | 
				
			||||||
      "node_modules/@types"
 | 
					      "node_modules/@types"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user