mirror of
				https://github.com/avatao-content/frontend-tutorial-framework
				synced 2025-11-04 04:52:55 +00:00 
			
		
		
		
	@@ -9,7 +9,7 @@ import { AceEditorModule } from 'ng2-ace-editor';
 | 
				
			|||||||
import { AppComponent } from './app.component';
 | 
					import { AppComponent } from './app.component';
 | 
				
			||||||
import { DashboardComponent } from './dashboard/dashboard.component';
 | 
					import { DashboardComponent } from './dashboard/dashboard.component';
 | 
				
			||||||
import { HeaderComponent } from './header/header.component';
 | 
					import { HeaderComponent } from './header/header.component';
 | 
				
			||||||
import { LoginComponent } from './login/login.component';
 | 
					import { LoginComponent } from './web/web.component';
 | 
				
			||||||
import { MarkdownService } from './services/markdown.service';
 | 
					import { MarkdownService } from './services/markdown.service';
 | 
				
			||||||
import { TerminadoService } from './services/terminado.service';
 | 
					import { TerminadoService } from './services/terminado.service';
 | 
				
			||||||
import { WebideComponent } from './webide/webide.component';
 | 
					import { WebideComponent } from './webide/webide.component';
 | 
				
			||||||
@@ -20,6 +20,7 @@ import { FSMUpdateService } from './services/fsmupdate.service';
 | 
				
			|||||||
import { ProcessManagerService } from './services/processmanager.service';
 | 
					import { ProcessManagerService } from './services/processmanager.service';
 | 
				
			||||||
import { AppRoutingModule } from './app-routing.module';
 | 
					import { AppRoutingModule } from './app-routing.module';
 | 
				
			||||||
import { TestmessengerComponent } from './testmessenger/testmessenger.component';
 | 
					import { TestmessengerComponent } from './testmessenger/testmessenger.component';
 | 
				
			||||||
 | 
					import { DeploymentNotificationService } from './services/deployment-notification.service';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@NgModule({
 | 
					@NgModule({
 | 
				
			||||||
@@ -46,7 +47,8 @@ import { TestmessengerComponent } from './testmessenger/testmessenger.component'
 | 
				
			|||||||
    WebSocketService,
 | 
					    WebSocketService,
 | 
				
			||||||
    TerminadoService,
 | 
					    TerminadoService,
 | 
				
			||||||
    FSMUpdateService,
 | 
					    FSMUpdateService,
 | 
				
			||||||
    ProcessManagerService
 | 
					    ProcessManagerService,
 | 
				
			||||||
 | 
					    DeploymentNotificationService
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  bootstrap: [
 | 
					  bootstrap: [
 | 
				
			||||||
    AppComponent
 | 
					    AppComponent
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,17 @@
 | 
				
			|||||||
<app-header></app-header>
 | 
					 | 
				
			||||||
<div class="tfw-grid-main-components">
 | 
					<div class="tfw-grid-main-components">
 | 
				
			||||||
 | 
					  <div class="tfw-header"><app-header></app-header></div>
 | 
				
			||||||
  <div class="tfw-messages"><app-messages></app-messages></div>
 | 
					  <div class="tfw-messages"><app-messages></app-messages></div>
 | 
				
			||||||
  <div class="tfw-web tao-grid-top-left"><app-login></app-login></div>
 | 
					  <div class="tfw-web tao-grid-top-left"
 | 
				
			||||||
  <div class="tfw-webide"><app-webide></app-webide></div>
 | 
					       [ngClass]="{ 'deploy-blur': deploying }">
 | 
				
			||||||
  <div class="tfw-terminal"><app-terminal></app-terminal></div>
 | 
					    <div class="iframe-container">
 | 
				
			||||||
 | 
					      <iframe class="iframe"
 | 
				
			||||||
 | 
					              scrolling="yes" frameborder="0"
 | 
				
			||||||
 | 
					              src="about:blank"></iframe>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					  <div class="tfw-webide"><app-webide></app-webide></div>
 | 
				
			||||||
 | 
					  <div class="tfw-terminal">
 | 
				
			||||||
 | 
					      <app-terminal></app-terminal>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					  <div class="tfw-terminal-footer"></div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,72 +1,60 @@
 | 
				
			|||||||
$space: 24px;
 | 
					@import "../../assets/scss/variables.scss";
 | 
				
			||||||
 | 
					@import "../../assets/scss/mixins/layout.scss";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$tao-plum-900: #272F4C;
 | 
					 | 
				
			||||||
$tao-gray-50:  #FAFAFA;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
$tao-navbar-height: 67px;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
$layout-template: "default";  // Change this to switch template
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
$default-layout: (
 | 
					 | 
				
			||||||
  'messages': (1, 2, 1, 4),
 | 
					 | 
				
			||||||
  'webide': (4, -1, 1, -1),
 | 
					 | 
				
			||||||
  'terminal': (1, 4, 4, -1),
 | 
					 | 
				
			||||||
  'web': (2, 4, 1, 4)
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
$raw-layout: (
 | 
					 | 
				
			||||||
  'messages': (1, 2, 1, -1),
 | 
					 | 
				
			||||||
  'webide': (4, -1, 1, -1),
 | 
					 | 
				
			||||||
  'terminal': (2, 4, 1, -1),
 | 
					 | 
				
			||||||
  'web': (),
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
$layout: (
 | 
					 | 
				
			||||||
  "default": $default-layout,
 | 
					 | 
				
			||||||
  "raw": $raw-layout
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@mixin position-grid-items($map, $sel) {
 | 
					 | 
				
			||||||
  $sel: if($sel == '' and &, &, $sel);
 | 
					 | 
				
			||||||
  @debug $sel;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  #{$sel} {
 | 
					 | 
				
			||||||
    @each $k, $v in $map {
 | 
					 | 
				
			||||||
      @at-root #{$sel}#{$k} {
 | 
					 | 
				
			||||||
        @if (length($v) == 0) {
 | 
					 | 
				
			||||||
          display: none
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        @else {
 | 
					 | 
				
			||||||
          grid-column-start: nth($v, 1);
 | 
					 | 
				
			||||||
          grid-column-end: nth($v, 2);
 | 
					 | 
				
			||||||
          grid-row-start: nth($v, 3);
 | 
					 | 
				
			||||||
          grid-row-end: nth($v, 4);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
.tfw-grid-main-components {
 | 
					.tfw-grid-main-components {
 | 
				
			||||||
  overflow-y: hidden;
 | 
					 | 
				
			||||||
  display: grid;
 | 
					  display: grid;
 | 
				
			||||||
  padding-top: $tao-navbar-height;
 | 
					 | 
				
			||||||
  width: 100vw;
 | 
					  width: 100vw;
 | 
				
			||||||
  height: 100vh;
 | 
					  height: 100vh;
 | 
				
			||||||
  justify-content: center;
 | 
					  justify-content: center;
 | 
				
			||||||
  align-content: center;
 | 
					  align-content: center;
 | 
				
			||||||
  grid-template-columns: repeat(5, 1fr);
 | 
					  grid-template-columns: repeat($grid-columns-count, 1fr);
 | 
				
			||||||
  grid-template-rows: repeat(5, 1fr);
 | 
					  grid-template-rows: repeat($grid-rows-count, 1fr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @include position-grid-items(map_get($layout,$layout-template),'.tfw-');
 | 
					  @include position-grid-items(map_get($layout,$layout-template),'.tfw-');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .tfw-web {
 | 
					  .tfw-header,
 | 
				
			||||||
    padding: $space;
 | 
					  .tfw-messages {
 | 
				
			||||||
 | 
					    @if ($layout-template == 'default') {
 | 
				
			||||||
 | 
					      border: 2px solid $tao-gray-100;
 | 
				
			||||||
 | 
					      border-top: 0;
 | 
				
			||||||
 | 
					      border-left: 0;
 | 
				
			||||||
 | 
					      border-bottom: 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .tfw-header {
 | 
				
			||||||
 | 
					    padding: $small;
 | 
				
			||||||
 | 
					    background-color: $tao-gray-50;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .tfw-messages {
 | 
					  .tfw-messages {
 | 
				
			||||||
    padding: $space;
 | 
					    padding: $space;
 | 
				
			||||||
 | 
					    padding-top: $hair;
 | 
				
			||||||
    background-color: $tao-gray-50;
 | 
					    background-color: $tao-gray-50;
 | 
				
			||||||
 | 
					    overflow-y: scroll;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @if ($layout-template != 'default') {
 | 
				
			||||||
 | 
					      max-height: 95vmin;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    @else {
 | 
				
			||||||
 | 
					      max-height: 55vmin;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .tfw-web {
 | 
				
			||||||
 | 
					    .iframe-container {
 | 
				
			||||||
 | 
					      display: flex;
 | 
				
			||||||
 | 
					      overflow: hidden;
 | 
				
			||||||
 | 
					      @include set-component-size('web');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .iframe {
 | 
				
			||||||
 | 
					      flex-grow: 1;
 | 
				
			||||||
 | 
					      border: none;
 | 
				
			||||||
 | 
					      margin: 0;
 | 
				
			||||||
 | 
					      padding: $small;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .tfw-webide {
 | 
					  .tfw-webide {
 | 
				
			||||||
@@ -74,6 +62,18 @@ $layout: (
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .tfw-terminal {
 | 
					  .tfw-terminal {
 | 
				
			||||||
 | 
					    overflow-y: hidden;
 | 
				
			||||||
 | 
					    border: 1px solid $tao-plum-100;
 | 
				
			||||||
 | 
					    border-bottom: 0;
 | 
				
			||||||
 | 
					    background-color: $tao-gray-800;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @if ($layout-template != 'vraw') {
 | 
				
			||||||
 | 
					      border-left: 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.deploy-blur {
 | 
				
			||||||
 | 
					  filter: blur(3px);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,28 @@
 | 
				
			|||||||
import { Component } from '@angular/core';
 | 
					import { Component, OnDestroy, OnInit } from '@angular/core';
 | 
				
			||||||
 | 
					import { DeploymentNotificationService } from '../services/deployment-notification.service';
 | 
				
			||||||
 | 
					import { Subscription } from 'rxjs/Subscription';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-dashboard',
 | 
					  selector: 'app-dashboard',
 | 
				
			||||||
  templateUrl: './dashboard.component.html',
 | 
					  templateUrl: './dashboard.component.html',
 | 
				
			||||||
  styleUrls: ['./dashboard.component.scss']
 | 
					  styleUrls: ['./dashboard.component.scss']
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
export class DashboardComponent {
 | 
					export class DashboardComponent implements OnInit, OnDestroy {
 | 
				
			||||||
  constructor() {}
 | 
					
 | 
				
			||||||
 | 
					  deploying = false;
 | 
				
			||||||
 | 
					  deploymentNotificationSubscription: Subscription;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor(private deploymentNotificationService: DeploymentNotificationService) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ngOnInit() {
 | 
				
			||||||
 | 
					    this.deploymentNotificationSubscription = this.deploymentNotificationService.deploying.subscribe(
 | 
				
			||||||
 | 
					      (deploying) => this.deploying = deploying
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ngOnDestroy() {
 | 
				
			||||||
 | 
					    if (this.deploymentNotificationSubscription) {
 | 
				
			||||||
 | 
					      this.deploymentNotificationSubscription.unsubscribe();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,4 @@
 | 
				
			|||||||
<nav class="navbar navbar-default navbar-expand-md navbar-light tfw-navbar fixed-top">
 | 
					<div class="tfw-grid-navbar tao-grid-center-center">
 | 
				
			||||||
  <div class="tfw-grid-navbar">
 | 
					 | 
				
			||||||
<!--    <ul class="navbar-nav tao-grid-center-right">
 | 
					 | 
				
			||||||
      <li class="nav-item tao-header-title">an</li>
 | 
					 | 
				
			||||||
    </ul>-->
 | 
					 | 
				
			||||||
  <img src="images/avatao_logo.svg" routerLink="/" class="tao-grid-center-left tfw-company-logo" alt="">
 | 
					  <img src="images/avatao_logo.svg" routerLink="/" class="tao-grid-center-left tfw-company-logo" alt="">
 | 
				
			||||||
    <ul class="navbar-nav">
 | 
					  <span class="tfw-header-title">Tutorials</span>
 | 
				
			||||||
      <li class="nav-item tfw-header-title">Tutorials</li>
 | 
					 | 
				
			||||||
    </ul>
 | 
					 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
</nav>
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,24 +1,10 @@
 | 
				
			|||||||
$tao-blue-500: #277EEC;
 | 
					@import "../../assets/scss/variables.scss";
 | 
				
			||||||
$font-size-base: 14px;
 | 
					 | 
				
			||||||
$font-size-h3: floor(($font-size-base * 1.3));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
$tao-navbar-height: 67px;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
$company-logo-width: 130px;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
.tfw-header-title {
 | 
					.tfw-header-title {
 | 
				
			||||||
  color: $tao-blue-500;
 | 
					  color: $tao-blue-500;
 | 
				
			||||||
  font-size: $font-size-h3;
 | 
					  font-size: $font-size-h3;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.tfw-navbar {
 | 
					 | 
				
			||||||
  background-color: rgba(255, 255, 255, 0.96);
 | 
					 | 
				
			||||||
  min-height: $tao-navbar-height;
 | 
					 | 
				
			||||||
  box-shadow: 0px 1px 6px 0px #888;
 | 
					 | 
				
			||||||
  margin-bottom: 12px;
 | 
					 | 
				
			||||||
  border: 1px solid #e7e7e7;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.tfw-grid-navbar {
 | 
					.tfw-grid-navbar {
 | 
				
			||||||
  display: grid;
 | 
					  display: grid;
 | 
				
			||||||
  grid-template-columns: $company-logo-width 1fr;
 | 
					  grid-template-columns: $company-logo-width 1fr;
 | 
				
			||||||
@@ -31,29 +17,3 @@ $company-logo-width: 130px;
 | 
				
			|||||||
  width: $company-logo-width;
 | 
					  width: $company-logo-width;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.tfw-company-logo-mobile {
 | 
					 | 
				
			||||||
  display: none;
 | 
					 | 
				
			||||||
  width: 130px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@media (max-width: 767px) {
 | 
					 | 
				
			||||||
  .tfw-grid-navbar {
 | 
					 | 
				
			||||||
    grid-template-columns: 1fr;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .tfw-company-logo {
 | 
					 | 
				
			||||||
    display: none;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .tfw-company-logo-mobile {
 | 
					 | 
				
			||||||
    display: block;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .tfw-navbar-links {
 | 
					 | 
				
			||||||
    justify-self: left !important;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.jumbotron {
 | 
					 | 
				
			||||||
  padding: 2vh;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,8 @@
 | 
				
			|||||||
<div class="tfw-messages-main">
 | 
					<div class="tfw-messages-main">
 | 
				
			||||||
  <h5>Instructions</h5>
 | 
					  <div class="tfw-grid-messages-header">
 | 
				
			||||||
 | 
					    <div class="tao-grid-top-left"><span>Instructions</span></div>
 | 
				
			||||||
 | 
					    <div class="tao-grid-center-right"><button class="tao-btn-rainbow">Next</button></div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
  <div class="tfw-grid-message" *ngFor="let message of messages.slice().reverse()">
 | 
					  <div class="tfw-grid-message" *ngFor="let message of messages.slice().reverse()">
 | 
				
			||||||
    <div class="tfw-grid-message-header">
 | 
					    <div class="tfw-grid-message-header">
 | 
				
			||||||
      <img class="tao-grid-center-left" src="images/avataobot.svg"/>
 | 
					      <img class="tao-grid-center-left" src="images/avataobot.svg"/>
 | 
				
			||||||
@@ -9,3 +12,4 @@
 | 
				
			|||||||
    <div [innerHtml]="message.message"></div>
 | 
					    <div [innerHtml]="message.message"></div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,30 +1,23 @@
 | 
				
			|||||||
$space: 24px;
 | 
					@import "../../assets/scss/variables.scss";
 | 
				
			||||||
 | 
					 | 
				
			||||||
$small: 0.75 * $space;
 | 
					 | 
				
			||||||
$tiny: 0.5 * $space;
 | 
					 | 
				
			||||||
$hair: 0.25 * $space;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
$tao-blue-500: #277EEC;
 | 
					 | 
				
			||||||
$tao-gray-100: #F2F2F2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
$tao-panel-border-radius-sm:	 8px;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
$font-size-tiny:          12px;
 | 
					 | 
				
			||||||
$font-size-base:          14px;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
.tfw-messages-main {
 | 
					.tfw-messages-main {
 | 
				
			||||||
  max-height: 50vmin;
 | 
					 | 
				
			||||||
  overflow-y: scroll;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  h5 {
 | 
					
 | 
				
			||||||
 | 
					  .tfw-grid-messages-header {
 | 
				
			||||||
 | 
					    display: grid;
 | 
				
			||||||
 | 
					    grid-template-columns: 1fr 1fr;
 | 
				
			||||||
    margin-bottom: $small;
 | 
					    margin-bottom: $small;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    span {
 | 
				
			||||||
      color: $tao-blue-500;
 | 
					      color: $tao-blue-500;
 | 
				
			||||||
      font-weight: 500;
 | 
					      font-weight: 500;
 | 
				
			||||||
 | 
					      font-size: $font-size-h3;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.tfw-grid-message {
 | 
					.tfw-grid-message {
 | 
				
			||||||
  display: grid;
 | 
					  display: grid;
 | 
				
			||||||
  grid-template-rows: 1fr auto;
 | 
					  grid-template-rows: 1fr auto;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								src/app/services/deployment-notification.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/app/services/deployment-notification.service.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					import { Injectable } from '@angular/core';
 | 
				
			||||||
 | 
					import { Subject } from 'rxjs/Subject';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Injectable()
 | 
				
			||||||
 | 
					export class DeploymentNotificationService {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  deploying: Subject<boolean> = new Subject<boolean>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor() { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -11,7 +11,32 @@ export class TerminadoService {
 | 
				
			|||||||
  constructor() {
 | 
					  constructor() {
 | 
				
			||||||
    Terminal.applyAddon(fit);
 | 
					    Terminal.applyAddon(fit);
 | 
				
			||||||
    Terminal.applyAddon(terminado);
 | 
					    Terminal.applyAddon(terminado);
 | 
				
			||||||
    this.xterm = new Terminal();
 | 
					    this.xterm = new Terminal({
 | 
				
			||||||
 | 
					      theme: {
 | 
				
			||||||
 | 
					        foreground: '#ffffff',
 | 
				
			||||||
 | 
					        background: '#0C0C0C',                  // $tao-gray-800
 | 
				
			||||||
 | 
					        cursor: '#ffffff',
 | 
				
			||||||
 | 
					        selection: 'rgba(255, 255, 255, 0.3)',
 | 
				
			||||||
 | 
					        black: '#000000',
 | 
				
			||||||
 | 
					        red: '#FF5252',                         // $tao-red-500
 | 
				
			||||||
 | 
					        brightRed: '#FF7171',                   // $tao-red-400
 | 
				
			||||||
 | 
					        green: '#2fd19f',                       // $tao-bright-green-500
 | 
				
			||||||
 | 
					        brightGreen: '#2fd19f',                 // $tao-bright-green-500
 | 
				
			||||||
 | 
					        brightYellow: '#FFD283',                // $tao-warm-yellow-300
 | 
				
			||||||
 | 
					        yellow: '#FFB83B',                      // $tao-warm-yellow-500
 | 
				
			||||||
 | 
					        magenta: '#FF8FC6',                     // $tao-pink-200
 | 
				
			||||||
 | 
					        brightMagenta: '#FF8FC6',               // $tao-pink-200
 | 
				
			||||||
 | 
					        cyan: '#277EEC',                        // $tao-blue-500
 | 
				
			||||||
 | 
					        blue: '#277EEC',                        // $tao-blue-500
 | 
				
			||||||
 | 
					        brightCyan: '#42B7DF',                  // $tao-sky-400
 | 
				
			||||||
 | 
					        brightBlue: '#19A7D8',                  // $tao-sky-500
 | 
				
			||||||
 | 
					        white: '#FAFAFA',                       // $tao-gray-50
 | 
				
			||||||
 | 
					        brightBlack: '#808080',
 | 
				
			||||||
 | 
					        brightWhite: '#ffffff'
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      fontSize: 14
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const wsproto = (location.protocol === 'https:') ? 'wss://' : 'ws://';
 | 
					    const wsproto = (location.protocol === 'https:') ? 'wss://' : 'ws://';
 | 
				
			||||||
    this.ws = new WebSocket(wsproto + window.location.host + '/terminal');
 | 
					    this.ws = new WebSocket(wsproto + window.location.host + '/terminal');
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +1 @@
 | 
				
			|||||||
<div #xterm class="tfw-xterm mt-3 mb-3" (window:resize)="fit()"></div>
 | 
					  <div #xterm class="tfw-xterm" (window:resize)="fit()"></div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					@import "../../assets/scss/mixins/layout.scss";
 | 
				
			||||||
 | 
					@import "../../app/dashboard/dashboard.component.scss";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.tfw-xterm {
 | 
				
			||||||
 | 
					  max-height: 100%;
 | 
				
			||||||
 | 
					  height: 100%;
 | 
				
			||||||
 | 
					  min-height: 100%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,4 @@
 | 
				
			|||||||
 | 
					<!--
 | 
				
			||||||
<div>
 | 
					<div>
 | 
				
			||||||
  <h1>Login page</h1>
 | 
					  <h1>Login page</h1>
 | 
				
			||||||
  <form #loginForm="ngForm" (submit)="onSubmit()" [hidden]="submitted">
 | 
					  <form #loginForm="ngForm" (submit)="onSubmit()" [hidden]="submitted">
 | 
				
			||||||
@@ -23,7 +24,7 @@
 | 
				
			|||||||
        [(ngModel)]="model.password"
 | 
					        [(ngModel)]="model.password"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <button type="submit" class="btn btn-primary">Submit</button>
 | 
					    <button type="submit" class="btn tao-btn-primary">Submit</button>
 | 
				
			||||||
  </form>
 | 
					  </form>
 | 
				
			||||||
  <div [hidden]="!submitted">
 | 
					  <div [hidden]="!submitted">
 | 
				
			||||||
    <p>
 | 
					    <p>
 | 
				
			||||||
@@ -31,6 +32,8 @@
 | 
				
			|||||||
      You <em><span *ngIf="!is_admin">don't </span>have</em> admin privileges.
 | 
					      You <em><span *ngIf="!is_admin">don't </span>have</em> admin privileges.
 | 
				
			||||||
    </p>
 | 
					    </p>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					-->
 | 
				
			||||||
 | 
					<div class="iframe-container">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					 | 
				
			||||||
@@ -1,21 +1,25 @@
 | 
				
			|||||||
import { HttpClient } from '@angular/common/http';
 | 
					import { HttpClient } from '@angular/common/http';
 | 
				
			||||||
import { Component, OnInit } from '@angular/core';
 | 
					import { Component, OnDestroy, OnInit } from '@angular/core';
 | 
				
			||||||
import { Observable } from 'rxjs/Observable';
 | 
					import { Observable } from 'rxjs/Observable';
 | 
				
			||||||
import { Login } from './login';
 | 
					import { Login } from './web';
 | 
				
			||||||
 | 
					import { DeploymentNotificationService } from '../services/deployment-notification.service';
 | 
				
			||||||
 | 
					import { Subscription } from 'rxjs/Subscription';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-login',
 | 
					  selector: 'app-web',
 | 
				
			||||||
  templateUrl: './login.component.html',
 | 
					  templateUrl: './web.component.html',
 | 
				
			||||||
  styleUrls: ['./login.component.scss']
 | 
					  styleUrls: ['./web.component.scss']
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
export class LoginComponent implements OnInit {
 | 
					export class LoginComponent {
 | 
				
			||||||
  model = new Login('', '');
 | 
					  model = new Login('', '');
 | 
				
			||||||
  submitted = false;
 | 
					  submitted = false;
 | 
				
			||||||
  is_admin: boolean;
 | 
					  is_admin: boolean;
 | 
				
			||||||
  logged_in_email: string;
 | 
					  logged_in_email: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    private http: HttpClient
 | 
					    private http: HttpClient
 | 
				
			||||||
  ) {}
 | 
					  ) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  onSubmit() {
 | 
					  onSubmit() {
 | 
				
			||||||
    this.postLogin(this.model).subscribe(
 | 
					    this.postLogin(this.model).subscribe(
 | 
				
			||||||
      res => {
 | 
					      res => {
 | 
				
			||||||
@@ -27,8 +31,6 @@ export class LoginComponent implements OnInit {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  postLogin(login: Login): Observable<any> {
 | 
					  postLogin(login: Login): Observable<any> {
 | 
				
			||||||
    return this.http.post<Login>('/login', login);
 | 
					    return this.http.post<Login>('/web', login);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  ngOnInit() {}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
<div class="tfw-grid-container">
 | 
					<div class="tfw-grid-webide-statusbar">
 | 
				
			||||||
  <div class="btn-group btn-group-sm flex-wrap tao-grid-center-left">
 | 
					  <div class="btn-group btn-group-sm flex-wrap tao-grid-center-left">
 | 
				
			||||||
    <button *ngFor="let file of files"
 | 
					    <button *ngFor="let file of files"
 | 
				
			||||||
            class="btn tfw-tab-btn"
 | 
					            class="btn tfw-tab-btn"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,24 +1,12 @@
 | 
				
			|||||||
$space: 24px;
 | 
					@import "../../assets/scss/variables.scss";
 | 
				
			||||||
$small: 0.75 * $space;
 | 
					.tfw-grid-webide-statusbar {
 | 
				
			||||||
 | 
					 | 
				
			||||||
$tao-bright-green-100: #c5f2e4;
 | 
					 | 
				
			||||||
$tao-bright-green-200: #a0ead3;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
$tao-warm-yellow-200: #FFE0A9;
 | 
					 | 
				
			||||||
$tao-warm-yellow-600: #E59C3C;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
$tao-plum-200: #BEC7F3;
 | 
					 | 
				
			||||||
$tao-plum-900: #272F4C;
 | 
					 | 
				
			||||||
$tao-red-500: #FF5252;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.tfw-grid-container {
 | 
					 | 
				
			||||||
  display: grid;
 | 
					  display: grid;
 | 
				
			||||||
 | 
					  height: $tao-navbar-height;
 | 
				
			||||||
  grid-template-columns: 8fr 1fr;
 | 
					  grid-template-columns: 8fr 1fr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.tfw-ace-editor {
 | 
					.tfw-ace-editor {
 | 
				
			||||||
  height: 100%;
 | 
					  height: calc(100% - 67px);
 | 
				
			||||||
  width: 100%;
 | 
					  width: 100%;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -40,12 +28,15 @@ $tao-red-500: #FF5252;
 | 
				
			|||||||
  .disabled,
 | 
					  .disabled,
 | 
				
			||||||
  &:disabled {
 | 
					  &:disabled {
 | 
				
			||||||
    background-color: $tao-plum-200;
 | 
					    background-color: $tao-plum-200;
 | 
				
			||||||
 | 
					    font-weight: 500;
 | 
				
			||||||
 | 
					    font-style: italic;
 | 
				
			||||||
    color: black;
 | 
					    color: black;
 | 
				
			||||||
 | 
					    border: 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.tfw-deploy-btn-group {
 | 
					.tfw-deploy-btn-group {
 | 
				
			||||||
  margin: $small;
 | 
					  margin: auto $tiny;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .tfw-deploy-btn {
 | 
					  .tfw-deploy-btn {
 | 
				
			||||||
    background: $tao-bright-green-200;
 | 
					    background: $tao-bright-green-200;
 | 
				
			||||||
@@ -97,4 +88,3 @@ $tao-red-500: #FF5252;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,7 @@ import 'brace/theme/cobalt';
 | 
				
			|||||||
import { SourceCode } from './source-code';
 | 
					import { SourceCode } from './source-code';
 | 
				
			||||||
import { WebSocketService } from '../services/websocket.service';
 | 
					import { WebSocketService } from '../services/websocket.service';
 | 
				
			||||||
import { ProcessManagerService } from '../services/processmanager.service';
 | 
					import { ProcessManagerService } from '../services/processmanager.service';
 | 
				
			||||||
 | 
					import { DeploymentNotificationService } from '../services/deployment-notification.service';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const modelist = brace.acequire('ace/ext/modelist');
 | 
					const modelist = brace.acequire('ace/ext/modelist');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -45,7 +46,8 @@ export class WebideComponent implements OnInit {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  constructor(private webSocketService: WebSocketService,
 | 
					  constructor(private webSocketService: WebSocketService,
 | 
				
			||||||
              private changeDetectorRef: ChangeDetectorRef,
 | 
					              private changeDetectorRef: ChangeDetectorRef,
 | 
				
			||||||
              private processManagerService: ProcessManagerService) { }
 | 
					              private processManagerService: ProcessManagerService,
 | 
				
			||||||
 | 
					              private deploymentNotificationService: DeploymentNotificationService) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ngOnInit() {
 | 
					  ngOnInit() {
 | 
				
			||||||
    this.webSocketService.connect();
 | 
					    this.webSocketService.connect();
 | 
				
			||||||
@@ -116,11 +118,12 @@ export class WebideComponent implements OnInit {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  setDeployButtonState(state: string) {
 | 
					  setDeployButtonState(state: string) {
 | 
				
			||||||
    this.deployButtonState = state;
 | 
					    this.deployButtonState = state;
 | 
				
			||||||
 | 
					    this.deploymentNotificationService.deploying.next(state === 'DEPLOYING' ? true : false);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  deployCode() {
 | 
					  deployCode() {
 | 
				
			||||||
    this.processManagerService.restartProcess('login');
 | 
					    this.processManagerService.restartProcess('login');
 | 
				
			||||||
    this.deployButtonState = 'DEPLOYING';
 | 
					    this.setDeployButtonState('DEPLOYING');
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  sendCodeIfDirty() {
 | 
					  sendCodeIfDirty() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,3 @@
 | 
				
			|||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@import
 | 
					@import
 | 
				
			||||||
  'variables',
 | 
					  'variables',
 | 
				
			||||||
  'grid';
 | 
					  'grid';
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -156,5 +156,9 @@ $font-size-h4:            floor(($font-size-base * 1.2));
 | 
				
			|||||||
$font-size-h5:            floor(($font-size-base * 1.1));
 | 
					$font-size-h5:            floor(($font-size-base * 1.1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
$tao-navbar-height: 67px;
 | 
					$tao-navbar-height: 67px;
 | 
				
			||||||
 | 
					$company-logo-width: 130px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Change this to switch template. Options: 'default', 'vraw', 'hraw'
 | 
				
			||||||
 | 
					$layout-template: 'default';
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										62
									
								
								src/assets/scss/mixins/_layout.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/assets/scss/mixins/_layout.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					$grid-columns-count: 5;
 | 
				
			||||||
 | 
					$grid-rows-count: 15;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$default-layout: (
 | 
				
			||||||
 | 
					  'header': (1, 2, 1, 2),
 | 
				
			||||||
 | 
					  'messages': (1, 2, 2, 10),
 | 
				
			||||||
 | 
					  'webide': (4,$grid-rows-count+1, 1, $grid-rows-count+1),
 | 
				
			||||||
 | 
					  'terminal': (1, 4, 10, $grid-rows-count+1),
 | 
				
			||||||
 | 
					  'web': (2, 4, 1, 10)
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$vraw-layout: (
 | 
				
			||||||
 | 
					  'header': (1, 2, 1, 2),
 | 
				
			||||||
 | 
					  'messages': (1, 2, 2,$grid-rows-count+1),
 | 
				
			||||||
 | 
					  'webide': (4,$grid-rows-count+1, 1,$grid-rows-count+1),
 | 
				
			||||||
 | 
					  'terminal': (2, 4, 1,$grid-rows-count+1),
 | 
				
			||||||
 | 
					  'web': (),
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$hraw-layout: (
 | 
				
			||||||
 | 
					  'header': (1, 2, 1,$grid-rows-count+1),
 | 
				
			||||||
 | 
					  'messages': (1, 2, 2,$grid-rows-count+1),
 | 
				
			||||||
 | 
					  'webide': (2,$grid-rows-count+1, 1, 10),
 | 
				
			||||||
 | 
					  'terminal': (2, $grid-rows-count+1, 10, $grid-rows-count+1),
 | 
				
			||||||
 | 
					  'web': (),
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$layout: (
 | 
				
			||||||
 | 
					  'default': $default-layout,
 | 
				
			||||||
 | 
					  'vraw': $vraw-layout,
 | 
				
			||||||
 | 
					  'hraw': $hraw-layout
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@mixin position-grid-items($map, $sel) {
 | 
				
			||||||
 | 
					  $sel: if($sel == '' and &, &, $sel);
 | 
				
			||||||
 | 
					  @debug $sel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #{$sel} {
 | 
				
			||||||
 | 
					    @each $k, $v in $map {
 | 
				
			||||||
 | 
					      @at-root #{$sel}#{$k} {
 | 
				
			||||||
 | 
					        @if (length($v) == 0) {
 | 
				
			||||||
 | 
					          display: none
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        @else {
 | 
				
			||||||
 | 
					          grid-column-start: nth($v, 1);
 | 
				
			||||||
 | 
					          grid-column-end: nth($v, 2);
 | 
				
			||||||
 | 
					          grid-row-start: nth($v, 3);
 | 
				
			||||||
 | 
					          grid-row-end: nth($v, 4);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@mixin set-component-size($key) {
 | 
				
			||||||
 | 
					  $columns-count: nth(map_get($default-layout, $key),2) - nth(map_get($default-layout, $key),1);
 | 
				
			||||||
 | 
					  $rows-count: nth(map_get($default-layout, $key),4) - nth(map_get($default-layout, $key),3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  min-width: #{$columns-count / $grid-columns-count * 100}vw;
 | 
				
			||||||
 | 
					  min-height: #{$rows-count / $grid-rows-count * 100}vh;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -24,11 +24,18 @@
 | 
				
			|||||||
    padding: 8px 24px;
 | 
					    padding: 8px 24px;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &:hover {
 | 
					  &:hover
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    background: initial;
 | 
				
			||||||
    background-color: transparent;
 | 
					    background-color: transparent;
 | 
				
			||||||
    color: $tao-blue-500;
 | 
					    color: $tao-blue-500;
 | 
				
			||||||
    box-shadow: inset 0 0 0 1px $tao-blue-500;
 | 
					    box-shadow: inset 0 0 0 1px $tao-blue-500;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &:active {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.tao-btn-rainbow {
 | 
					.tao-btn-rainbow {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user