mirror of
				https://github.com/avatao-content/frontend-tutorial-framework
				synced 2025-11-04 13:12:55 +00:00 
			
		
		
		
	Use fix sidebar to instrument and control layout changes
This commit is contained in:
		@@ -2,7 +2,7 @@ import { NgModule } from '@angular/core';
 | 
			
		||||
import { RouterModule, Routes } from '@angular/router';
 | 
			
		||||
 | 
			
		||||
import { DashboardComponent } from './dashboard/dashboard.component';
 | 
			
		||||
import { WebideComponent } from './webide/webide.component';
 | 
			
		||||
import { IdeComponent } from './ide/ide.component';
 | 
			
		||||
import { TerminalComponent } from './terminal/terminal.component';
 | 
			
		||||
import { MessagesComponent } from './messages/messages.component';
 | 
			
		||||
import { TestmessengerComponent } from './testmessenger/testmessenger.component';
 | 
			
		||||
@@ -11,7 +11,7 @@ import { config } from './config';
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
  { path: '', redirectTo: '/dashboard', pathMatch: 'full'},
 | 
			
		||||
  { path: config.dashboard.route, component: DashboardComponent},
 | 
			
		||||
  { path: config.webide.route, component: WebideComponent },
 | 
			
		||||
  { path: config.ide.route, component: IdeComponent },
 | 
			
		||||
  { path: config.terminal.route, component: TerminalComponent },
 | 
			
		||||
  { path: config.messages.route, component: MessagesComponent },
 | 
			
		||||
  { path: config.testmessenger.route, component: TestmessengerComponent }
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ import { SidebarComponent } from './sidebar/sidebar.component';
 | 
			
		||||
import { LoginComponent } from './web/web.component';
 | 
			
		||||
import { MarkdownService } from './services/markdown.service';
 | 
			
		||||
import { TerminadoService } from './services/terminado.service';
 | 
			
		||||
import { WebideComponent } from './webide/webide.component';
 | 
			
		||||
import { IdeComponent } from './ide/ide.component';
 | 
			
		||||
import { MessagesComponent } from './messages/messages.component';
 | 
			
		||||
import { WebSocketService } from './services/websocket.service';
 | 
			
		||||
import { TerminalComponent } from './terminal/terminal.component';
 | 
			
		||||
@@ -30,7 +30,7 @@ import { DeploymentNotificationService } from './services/deployment-notificatio
 | 
			
		||||
    HeaderComponent,
 | 
			
		||||
    SidebarComponent,
 | 
			
		||||
    LoginComponent,
 | 
			
		||||
    WebideComponent,
 | 
			
		||||
    IdeComponent,
 | 
			
		||||
    MessagesComponent,
 | 
			
		||||
    TerminalComponent,
 | 
			
		||||
    DashboardComponent,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,24 +1,31 @@
 | 
			
		||||
export const config = {
 | 
			
		||||
  dashboard: {
 | 
			
		||||
    'route': 'dashboard',
 | 
			
		||||
    'defaultLayout': 'vraw-open'
 | 
			
		||||
    route: 'dashboard',
 | 
			
		||||
    defaultLayout: 'terminal-ide-vertical',
 | 
			
		||||
    enabledLayouts: [
 | 
			
		||||
      'terminal-ide-vertical',
 | 
			
		||||
      'terminal-ide-horizontal',
 | 
			
		||||
      'terminal-only',
 | 
			
		||||
      'ide-only'
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
  },
 | 
			
		||||
  webide: {
 | 
			
		||||
    'route': 'webide',
 | 
			
		||||
    'autoSaveInterval': 444,
 | 
			
		||||
    'defaultCode': 'Loading your file...',
 | 
			
		||||
    'defaultLanguage': 'text',
 | 
			
		||||
    'deployProcessName': 'login',
 | 
			
		||||
    'showDeployButton': true
 | 
			
		||||
  ide: {
 | 
			
		||||
    route: 'ide',
 | 
			
		||||
    autoSaveInterval: 444,
 | 
			
		||||
    defaultCode: 'Loading your file...',
 | 
			
		||||
    defaultLanguage: 'text',
 | 
			
		||||
    deployProcessName: 'login',
 | 
			
		||||
    showDeployButton: true
 | 
			
		||||
  },
 | 
			
		||||
  terminal: {
 | 
			
		||||
    'route': 'shell'
 | 
			
		||||
    route: 'shell'
 | 
			
		||||
  },
 | 
			
		||||
  messages: {
 | 
			
		||||
    'route': 'messages',
 | 
			
		||||
    'showNextButton': false
 | 
			
		||||
    route: 'messages',
 | 
			
		||||
    showNextButton: false
 | 
			
		||||
  },
 | 
			
		||||
  testmessenger: {
 | 
			
		||||
    'route': 'testmessenger'
 | 
			
		||||
    route: 'testmessenger'
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
<div [attr.tfw-layout]="layout">
 | 
			
		||||
<div [attr.class]="layout">
 | 
			
		||||
  <div class="tfw-grid-main-components">
 | 
			
		||||
    <div class="tfw-header"><app-header></app-header></div>
 | 
			
		||||
    <div class="tfw-messages"><app-messages></app-messages></div>
 | 
			
		||||
@@ -10,7 +10,9 @@
 | 
			
		||||
                src="about:blank"></iframe>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="tfw-webide"><app-webide></app-webide></div>
 | 
			
		||||
    <div class="tfw-ide">
 | 
			
		||||
      <app-ide></app-ide>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="tfw-terminal">
 | 
			
		||||
        <app-terminal></app-terminal>
 | 
			
		||||
    </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,24 @@
 | 
			
		||||
@import "../../assets/scss/mixins/layout.scss";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@mixin set-tfw-web($layouts-key) {
 | 
			
		||||
 | 
			
		||||
  .tfw-web {
 | 
			
		||||
    .iframe-container {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      overflow: hidden;
 | 
			
		||||
      @include set-component-size($layouts-key, 'web');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .iframe {
 | 
			
		||||
      flex-grow: 1;
 | 
			
		||||
      border: none;
 | 
			
		||||
      margin: 0;
 | 
			
		||||
      padding: $small;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tfw-grid-main-components {
 | 
			
		||||
  display: grid;
 | 
			
		||||
  width: 100vw;
 | 
			
		||||
@@ -13,7 +31,9 @@
 | 
			
		||||
 | 
			
		||||
  .tfw-header,
 | 
			
		||||
  .tfw-messages {
 | 
			
		||||
    @if (str_slice($layout-key, 0, str_length('default')) == 'default') {
 | 
			
		||||
 | 
			
		||||
    // Check whether the layout contains a web component
 | 
			
		||||
    div[class*="web"] & {
 | 
			
		||||
      border: 2px solid $tao-gray-100;
 | 
			
		||||
      border-top: 0;
 | 
			
		||||
      border-left: 0;
 | 
			
		||||
@@ -31,51 +51,34 @@
 | 
			
		||||
    padding-top: $hair;
 | 
			
		||||
    background-color: $tao-gray-50;
 | 
			
		||||
    overflow-y: scroll;
 | 
			
		||||
    max-height: 55vmin;
 | 
			
		||||
 | 
			
		||||
    @if (str_slice($layout-key, 0, str_length('default')) != 'default') {
 | 
			
		||||
    div[class*="web"] & {
 | 
			
		||||
      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-ide {
 | 
			
		||||
    background-color: $tao-plum-900;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .tfw-sidebar {
 | 
			
		||||
    background-color: $tao-turqoise-800;
 | 
			
		||||
    background-color: $tao-turqoise-300;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    justify-content: flex-start;
 | 
			
		||||
    justify-content: space-between;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    padding-top: 75px;
 | 
			
		||||
    border-left: 1px solid $tao-plum-500;
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .tfw-terminal {
 | 
			
		||||
    overflow-y: hidden;
 | 
			
		||||
    border: 1px solid $tao-plum-100;
 | 
			
		||||
    border-bottom: 0;
 | 
			
		||||
    background-color: $tao-gray-800;
 | 
			
		||||
    @if (str_slice($layout-key, 0, str_length('vraw')) == 'vraw') {
 | 
			
		||||
      border-left: 0;
 | 
			
		||||
      border-top: 0;
 | 
			
		||||
 | 
			
		||||
    div[class*="web"] & {
 | 
			
		||||
      border-top: 1px solid $tao-plum-100;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -83,3 +86,39 @@
 | 
			
		||||
.deploy-blur {
 | 
			
		||||
  filter: blur(3px);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.terminal-ide-web {
 | 
			
		||||
  @include set-tfw-web('terminal-ide-web');
 | 
			
		||||
  @include position-grid-items(map_get($layouts, 'terminal-ide-web'),'.tfw-');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.terminal-web{
 | 
			
		||||
  @include set-tfw-web('terminal-web');
 | 
			
		||||
  @include position-grid-items(map_get($layouts,'terminal-web'),'.tfw-');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.terminal-ide-vertical {
 | 
			
		||||
  @include position-grid-items(map_get($layouts,'terminal-ide-vertical'),'.tfw-');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.terminal-ide-horizontal {
 | 
			
		||||
  @include position-grid-items(map_get($layouts,'terminal-ide-horizontal'),'.tfw-');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ide-web-vertical {
 | 
			
		||||
  @include set-tfw-web('ide-web-vertical');
 | 
			
		||||
  @include position-grid-items(map_get($layouts,'ide-web-vertical'),'.tfw-');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.terminal-only {
 | 
			
		||||
  @include position-grid-items(map_get($layouts,'terminal-only'),'.tfw-');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ide-only {
 | 
			
		||||
  @include position-grid-items(map_get($layouts,'ide-only'),'.tfw-');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.web-only {
 | 
			
		||||
  @include set-tfw-web('web-only');
 | 
			
		||||
  @include position-grid-items(map_get($layouts,'web-only'),'.tfw-');
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,8 +13,7 @@ import { config } from '../config';
 | 
			
		||||
export class DashboardComponent implements OnInit, OnDestroy {
 | 
			
		||||
  deploying = false;
 | 
			
		||||
  deploymentNotificationSubscription: Subscription;
 | 
			
		||||
  layout: string = config.dashboard.defaultLayout;
 | 
			
		||||
  layout = 'vraw-closed';
 | 
			
		||||
  layout: string = config.dashboard.defaultLayout ;
 | 
			
		||||
  command_handlers = {'layout': this.layoutHandler.bind(this)};
 | 
			
		||||
 | 
			
		||||
  constructor(private deploymentNotificationService: DeploymentNotificationService,
 | 
			
		||||
@@ -33,11 +32,11 @@ export class DashboardComponent implements OnInit, OnDestroy {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  layoutHandler(data: LayoutCommand) {
 | 
			
		||||
    if (data.layout.match('vraw-open|vraw-closed|hraw|default-open|default-closed')) {
 | 
			
		||||
    if (data.layout.match('terminal-ide-vertical|terminal-only|hraw|default-open|default-closed')) {
 | 
			
		||||
      this.layout = data.layout;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      console.log('Invalid webide layout "' + data.layout + '" received!');
 | 
			
		||||
      console.log('Invalid ide layout "' + data.layout + '" received!');
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										44
									
								
								src/app/ide/ide.component.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/app/ide/ide.component.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
<div class="tfw-grid-ide-statusbar">
 | 
			
		||||
  <div class="btn-group btn-group-sm flex-wrap tao-grid-center-left">
 | 
			
		||||
    <button *ngFor="let file of files"
 | 
			
		||||
            class="btn tfw-tab-btn"
 | 
			
		||||
            (click)="tabSwitchButtonHandler(file)"
 | 
			
		||||
            [class.active]="filename === file"
 | 
			
		||||
            [class.disabled]="filename === file"
 | 
			
		||||
            [disabled]="filename === file"
 | 
			
		||||
            [class.tao-tab-btn-saved]="filename === file && codeState === 'SAVED'">
 | 
			
		||||
      <span *ngIf="filename !== file">{{file}}</span>
 | 
			
		||||
      <span *ngIf="filename === file"
 | 
			
		||||
            [class.underline]="codeState === 'DIRTY'">{{file}}</span>
 | 
			
		||||
    </button>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div class="btn-group-sm tfw-deploy-btn-group">
 | 
			
		||||
    <button *ngIf="showDeployButton"
 | 
			
		||||
            type="submit"
 | 
			
		||||
            class="btn tfw-deploy-btn tao-grid-top-center"
 | 
			
		||||
            (click)="sendCodeIfDirty(); deployCode()"
 | 
			
		||||
            [disabled]="deployButtonState === 'DEPLOYING' || deployButtonState === 'DEPLOYED'"
 | 
			
		||||
            [class.deployed]="deployButtonState === 'DEPLOYED'"
 | 
			
		||||
            [class.deploy]="deployButtonState === 'DEPLOYING'"
 | 
			
		||||
            [class.disabled]="deployButtonState === 'DEPLOYING' || deployButtonState === 'DEPLOYED'"
 | 
			
		||||
            [class.failed]="deployButtonState === 'FAILED'"
 | 
			
		||||
    >
 | 
			
		||||
      <span *ngIf="deployButtonState === 'TODEPLOY'">Deploy</span>
 | 
			
		||||
      <span *ngIf="deployButtonState === 'DEPLOYED'">
 | 
			
		||||
        <img src="images/greentick_icon.svg"/>
 | 
			
		||||
        <span>Deployed</span>
 | 
			
		||||
      </span>
 | 
			
		||||
      <span *ngIf="deployButtonState === 'DEPLOYING'"><div class="loader"></div>Reloading app...</span>
 | 
			
		||||
      <span *ngIf="deployButtonState === 'FAILED'">Deployment failed. Retry</span></button>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<div (keyup)="setCodeState('DIRTY'); setDeployButtonState('TODEPLOY'); resetAutoSaveCountdown()"
 | 
			
		||||
  ace-editor
 | 
			
		||||
  [(text)]="code"
 | 
			
		||||
  [mode]="language"
 | 
			
		||||
  [theme]="theme"
 | 
			
		||||
  class="tfw-ace-editor"
 | 
			
		||||
>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										95
									
								
								src/app/ide/ide.component.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								src/app/ide/ide.component.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
			
		||||
@import "../../assets/scss/variables.scss";
 | 
			
		||||
 | 
			
		||||
.tfw-grid-ide-statusbar {
 | 
			
		||||
  display: grid;
 | 
			
		||||
  height: $tao-navbar-height;
 | 
			
		||||
  grid-template-columns: 8fr 1fr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tfw-ace-editor {
 | 
			
		||||
  height: calc(100% - 67px);
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.btn-group {
 | 
			
		||||
  padding-left: 34px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.underline {
 | 
			
		||||
  text-decoration: underline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tfw-tab-btn {
 | 
			
		||||
  background-color: white;
 | 
			
		||||
  border: 1px solid $tao-plum-900;
 | 
			
		||||
  border-left: 0;
 | 
			
		||||
  border-right: 0;
 | 
			
		||||
  border-radius: 100px;
 | 
			
		||||
  padding: 5px 19px;
 | 
			
		||||
  z-index: 200;
 | 
			
		||||
 | 
			
		||||
  .tfw-tab-btn-saved,
 | 
			
		||||
  .active,
 | 
			
		||||
  .disabled,
 | 
			
		||||
  &:disabled {
 | 
			
		||||
    background-color: $tao-plum-200;
 | 
			
		||||
    font-weight: 500;
 | 
			
		||||
    font-style: italic;
 | 
			
		||||
    color: black;
 | 
			
		||||
    border: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tfw-deploy-btn-group {
 | 
			
		||||
  margin: auto $tiny;
 | 
			
		||||
 | 
			
		||||
  .tfw-deploy-btn {
 | 
			
		||||
    background: $tao-bright-green-200;
 | 
			
		||||
    border-radius: 100px;
 | 
			
		||||
    padding: 6px 19px;
 | 
			
		||||
 | 
			
		||||
    img {
 | 
			
		||||
      position: relative;
 | 
			
		||||
      bottom: 1px;
 | 
			
		||||
      height: $small;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.failed {
 | 
			
		||||
      background-color: $tao-red-500;
 | 
			
		||||
      color:white;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:disabled,
 | 
			
		||||
    &.disabled,
 | 
			
		||||
    &.deployed,
 | 
			
		||||
    &.deploy
 | 
			
		||||
    {
 | 
			
		||||
      background-color: $tao-bright-green-100;
 | 
			
		||||
      color: black;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.deploy {
 | 
			
		||||
      background-color: $tao-warm-yellow-200;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    .loader {
 | 
			
		||||
      border: 2px solid $tao-warm-yellow-600;
 | 
			
		||||
      border-radius: 50%;
 | 
			
		||||
      border-top: 2px solid $tao-warm-yellow-200;
 | 
			
		||||
      width: 15px;
 | 
			
		||||
      height: 15px;
 | 
			
		||||
      animation: spin 2s linear infinite;
 | 
			
		||||
      display: inline-block;
 | 
			
		||||
      margin-right: 5px;
 | 
			
		||||
      position: relative;
 | 
			
		||||
      top: 2px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @keyframes spin {
 | 
			
		||||
      0% { transform: rotate(0deg); }
 | 
			
		||||
      100% { transform: rotate(360deg); }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										154
									
								
								src/app/ide/ide.component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								src/app/ide/ide.component.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,154 @@
 | 
			
		||||
import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
 | 
			
		||||
 | 
			
		||||
import * as brace from 'brace';
 | 
			
		||||
import 'brace/ext/modelist';
 | 
			
		||||
 | 
			
		||||
import 'brace/mode/c_cpp';
 | 
			
		||||
import 'brace/mode/csharp';
 | 
			
		||||
import 'brace/mode/java';
 | 
			
		||||
import 'brace/mode/javascript';
 | 
			
		||||
import 'brace/mode/json';
 | 
			
		||||
import 'brace/mode/python';
 | 
			
		||||
import 'brace/mode/sql';
 | 
			
		||||
 | 
			
		||||
import 'brace/theme/cobalt';
 | 
			
		||||
import { SourceCode } from './source-code';
 | 
			
		||||
import { WebSocketService } from '../services/websocket.service';
 | 
			
		||||
import { ProcessManagerService } from '../services/processmanager.service';
 | 
			
		||||
import { DeploymentNotificationService } from '../services/deployment-notification.service';
 | 
			
		||||
import { config } from '../config';
 | 
			
		||||
 | 
			
		||||
const modelist = brace.acequire('ace/ext/modelist');
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-ide',
 | 
			
		||||
  templateUrl: './ide.component.html',
 | 
			
		||||
  styleUrls: ['./ide.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class IdeComponent implements OnInit {
 | 
			
		||||
  key_id = 'webide';
 | 
			
		||||
  filename = '';
 | 
			
		||||
  code: string = config.ide.defaultCode;
 | 
			
		||||
  language: string = config.ide.defaultLanguage;
 | 
			
		||||
  theme = 'cobalt';
 | 
			
		||||
  directory = '';
 | 
			
		||||
  files: string[];
 | 
			
		||||
  codeState = 'SAVED';
 | 
			
		||||
  deployButtonState = 'DEPLOYED';
 | 
			
		||||
  showDeployButton: boolean = config.ide.showDeployButton;
 | 
			
		||||
  autosave = null;
 | 
			
		||||
  command_handlers = {'reload':    this.reloadHandler.bind(this),
 | 
			
		||||
                      'read':      this.readHandler.bind(this),
 | 
			
		||||
                      'select':    this.selectHandler.bind(this),
 | 
			
		||||
                      'write':     this.writeHandler.bind(this),
 | 
			
		||||
                      'selectdir': this.selectdirHandler.bind(this)};
 | 
			
		||||
 | 
			
		||||
  constructor(private webSocketService: WebSocketService,
 | 
			
		||||
              private changeDetectorRef: ChangeDetectorRef,
 | 
			
		||||
              private processManagerService: ProcessManagerService,
 | 
			
		||||
              private deploymentNotificationService: DeploymentNotificationService) { }
 | 
			
		||||
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
    this.webSocketService.connect();
 | 
			
		||||
    this.subscribeWS();
 | 
			
		||||
    this.requestCode();
 | 
			
		||||
    this.processManagerService.init();
 | 
			
		||||
    this.processManagerService.subscribeCallback(config.ide.deployProcessName, (event) => { this.setDeployButtonState('DEPLOYED'); });
 | 
			
		||||
    this.processManagerService.subscribeErrorCallback(config.ide.deployProcessName, (event) => { this.setDeployButtonState('FAILED'); });
 | 
			
		||||
    this.resetAutoSaveCountdown();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  subscribeWS() {
 | 
			
		||||
    this.webSocketService.observeKey<SourceCode>(this.key_id).subscribe((event) => {
 | 
			
		||||
      this.command_handlers[event.data.command](event.data);
 | 
			
		||||
      this.changeDetectorRef.detectChanges();
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  updateFileData(data: SourceCode) {
 | 
			
		||||
    this.filename = data.filename;
 | 
			
		||||
    this.directory = data.directory;
 | 
			
		||||
    this.code = (data.content != null) ? data.content : this.code;
 | 
			
		||||
    this.language = modelist.getModeForPath(this.filename).name;
 | 
			
		||||
    this.files = data.files;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  selectHandler(data: SourceCode) {
 | 
			
		||||
    this.updateFileData(data);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  reloadHandler(data: SourceCode) {
 | 
			
		||||
    this.requestCode();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  readHandler(data: SourceCode) {
 | 
			
		||||
    if (this.codeState === 'SAVED') {
 | 
			
		||||
      this.updateFileData(data);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  writeHandler() {
 | 
			
		||||
    this.setCodeState('SAVED');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  selectdirHandler(data: SourceCode) {
 | 
			
		||||
    this.updateFileData(data);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  resetAutoSaveCountdown() {
 | 
			
		||||
    if (this.autosave) {
 | 
			
		||||
      clearInterval(this.autosave);
 | 
			
		||||
    }
 | 
			
		||||
    this.autosave = setInterval(() => { this.sendCodeIfDirty(); }, config.ide.autoSaveInterval);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  tabSwitchButtonHandler(file) {
 | 
			
		||||
    if (this.codeState === 'DIRTY') {
 | 
			
		||||
      this.sendCodeContents();
 | 
			
		||||
    }
 | 
			
		||||
    this.selectCode(file);
 | 
			
		||||
    this.requestCode();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setCodeState(state: string) {
 | 
			
		||||
    if (state.match('SAVED|DIRTY')) {
 | 
			
		||||
      this.codeState = state;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setDeployButtonState(state: string) {
 | 
			
		||||
    this.deployButtonState = state;
 | 
			
		||||
    this.deploymentNotificationService.deploying.next(state === 'DEPLOYING' ? true : false);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  deployCode() {
 | 
			
		||||
    this.processManagerService.restartProcess('login');
 | 
			
		||||
    this.setDeployButtonState('DEPLOYING');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  sendCodeIfDirty() {
 | 
			
		||||
    if (this.codeState === 'DIRTY') {
 | 
			
		||||
      this.sendCodeContents();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  sendCodeContents() {
 | 
			
		||||
    this.webSocketService.send(this.key_id, {
 | 
			
		||||
      'command': 'write',
 | 
			
		||||
      'content': this.code
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  requestCode() {
 | 
			
		||||
    this.webSocketService.send(this.key_id, {
 | 
			
		||||
      'command': 'read'
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  selectCode(filename: string) {
 | 
			
		||||
    this.webSocketService.send(this.key_id, {
 | 
			
		||||
      'command': 'select',
 | 
			
		||||
      'filename': filename
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								src/app/ide/source-code.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/app/ide/source-code.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
export interface SourceCode {
 | 
			
		||||
  filename: string;
 | 
			
		||||
  content?: string;
 | 
			
		||||
  files: string[];
 | 
			
		||||
  directory: string;
 | 
			
		||||
  command: string;
 | 
			
		||||
}
 | 
			
		||||
@@ -1 +1,4 @@
 | 
			
		||||
<div> IDE </div>
 | 
			
		||||
<div class="tfw-ide-pin">
 | 
			
		||||
  <img src="images/IDE.svg">
 | 
			
		||||
  <img class="active" src="images/IDE_active.svg">
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,16 @@
 | 
			
		||||
@import "../../assets/scss/variables.scss";
 | 
			
		||||
@import "../../assets/scss/mixins/layout.scss";
 | 
			
		||||
 | 
			
		||||
.tfw-webide-pin{
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
img {
 | 
			
		||||
  width: 50px;
 | 
			
		||||
  height: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tfw-ide-pin {
 | 
			
		||||
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
 | 
			
		||||
  & .active {
 | 
			
		||||
    display: none;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								src/assets/images/IDE.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/assets/images/IDE.svg
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
		 After Width: | Height: | Size: 6.4 KiB  | 
							
								
								
									
										1
									
								
								src/assets/images/IDE_active.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/assets/images/IDE_active.svg
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
		 After Width: | Height: | Size: 6.8 KiB  | 
@@ -158,3 +158,6 @@ $font-size-h5:            floor(($font-size-base * 1.1));
 | 
			
		||||
 | 
			
		||||
$tao-navbar-height: 67px;
 | 
			
		||||
$company-logo-width: 130px;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,72 +1,102 @@
 | 
			
		||||
$grid-columns-count: 25;
 | 
			
		||||
$grid-rows-count: 25;
 | 
			
		||||
 | 
			
		||||
$layout-key: 'vraw-open';
 | 
			
		||||
 | 
			
		||||
$default-open-layout: (
 | 
			
		||||
$terminal-ide-web-layout: (
 | 
			
		||||
  'header': (1, 6, 1, 2),
 | 
			
		||||
  'messages': (1, 6, 2, 10),
 | 
			
		||||
  'webide': (15,$grid-columns-count+1, 1, $grid-rows-count+1),
 | 
			
		||||
  'terminal': (1, 15, 10, $grid-rows-count+1),
 | 
			
		||||
  'web': (6, 15, 1, 10),
 | 
			
		||||
  'sidebar': ()
 | 
			
		||||
  'messages': (1, 6, 2, 16),
 | 
			
		||||
  'ide': (15,$grid-columns-count, 1, $grid-rows-count+1),
 | 
			
		||||
  'terminal': (1, 15, 16, $grid-rows-count+1),
 | 
			
		||||
  'web': (6, 15, 1, 16),
 | 
			
		||||
  'sidebar': ($grid-columns-count,$grid-columns-count+1, 1,$grid-rows-count+1)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
$default-closed-layout: (
 | 
			
		||||
$terminal-web-layout: (
 | 
			
		||||
  'header': (1, 6, 1, 2),
 | 
			
		||||
  'messages': (1, 6, 2, 10),
 | 
			
		||||
  'webide': (16,$grid-columns-count+1, 1, $grid-rows-count+1),
 | 
			
		||||
  'terminal': (1, 16, 10, $grid-rows-count+1),
 | 
			
		||||
  'ide': (),
 | 
			
		||||
  'terminal': (15, $grid-columns-count, 10, $grid-rows-count+1),
 | 
			
		||||
  'web': (6, 15, 1, 10),
 | 
			
		||||
  'sidebar': ()
 | 
			
		||||
  'sidebar': ($grid-columns-count,$grid-columns-count+1, 1,$grid-rows-count+1)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
$vraw-open-layout: (
 | 
			
		||||
$terminal-ide-vertical-layout: (
 | 
			
		||||
  'header': (1, 6, 1, 2),
 | 
			
		||||
  'messages': (1, 6, 2,$grid-rows-count+1),
 | 
			
		||||
  'webide': (16, $grid-columns-count+1, 1,$grid-rows-count+1),
 | 
			
		||||
  'terminal': (6, 16, 1, $grid-rows-count+1),
 | 
			
		||||
  'ide': (15, $grid-columns-count, 1,$grid-rows-count+1),
 | 
			
		||||
  'terminal': (6, 15, 1, $grid-rows-count+1),
 | 
			
		||||
  'web': (),
 | 
			
		||||
  'sidebar': (),
 | 
			
		||||
  'sidebar': ($grid-columns-count,$grid-columns-count+1, 1,$grid-rows-count+1)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
$vraw-closed-layout: (
 | 
			
		||||
$terminal-ide-horizontal-layout: (
 | 
			
		||||
  'header': (1, 6, 1, 2),
 | 
			
		||||
  'messages': (1, 6, 2,$grid-rows-count+1),
 | 
			
		||||
  'webide': (),
 | 
			
		||||
  'ide': (6,$grid-columns-count, 1, 16),
 | 
			
		||||
  'terminal': (6, $grid-columns-count, 16, $grid-rows-count+1),
 | 
			
		||||
  'web': (),
 | 
			
		||||
  'sidebar': ($grid-columns-count,$grid-columns-count+1, 1,$grid-rows-count+1),
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
$ide-web-vertical-layout: (
 | 
			
		||||
  'header': (1, 6, 1, 2),
 | 
			
		||||
  'messages': (1, 6, 2, $grid-rows-count+1),
 | 
			
		||||
  'ide': (15, $grid-columns-count, 1,$grid-rows-count+1),
 | 
			
		||||
  'terminal': (),
 | 
			
		||||
  'web': (6, 15, 10, $grid-rows-count+1),
 | 
			
		||||
  'sidebar': ($grid-columns-count,$grid-columns-count+1, 1,$grid-rows-count+1)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
$terminal-only-layout: (
 | 
			
		||||
  'header': (1, 6, 1, 2),
 | 
			
		||||
  'messages': (1, 6, 2,$grid-rows-count+1),
 | 
			
		||||
  'ide': (),
 | 
			
		||||
  'terminal': (6, $grid-columns-count, 1,$grid-rows-count+1),
 | 
			
		||||
  'web': (),
 | 
			
		||||
  'sidebar': ($grid-columns-count,$grid-columns-count+1, 1,$grid-rows-count+1)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
$hraw-layout: (
 | 
			
		||||
  'header': (1, 4, 1,$grid-rows-count+1),
 | 
			
		||||
  'messages': (1, 4, 2,$grid-rows-count+1),
 | 
			
		||||
  'webide': (4,$grid-columns-count+1, 1, 10),
 | 
			
		||||
  'terminal': (4, $grid-columns-count+1, 10, $grid-rows-count+1),
 | 
			
		||||
$ide-only-layout: (
 | 
			
		||||
  'header': (1, 6, 1, 2),
 | 
			
		||||
  'messages': (1, 6, 2,$grid-rows-count+1),
 | 
			
		||||
  'ide': (6, $grid-columns-count,  1,$grid-rows-count+1),
 | 
			
		||||
  'terminal': (),
 | 
			
		||||
  'web': (),
 | 
			
		||||
  'sidebar': (),
 | 
			
		||||
  'sidebar': ($grid-columns-count,$grid-columns-count+1, 1,$grid-rows-count+1)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
$web-only-layout: (
 | 
			
		||||
  'header': (1, 6, 1, 2),
 | 
			
		||||
  'messages': (1, 6, 2,$grid-rows-count+1),
 | 
			
		||||
  'ide': (),
 | 
			
		||||
  'terminal': (),
 | 
			
		||||
  'web': (6, $grid-columns-count, 1,$grid-rows-count+1),
 | 
			
		||||
  'sidebar': ($grid-columns-count,$grid-columns-count+1, 1,$grid-rows-count+1)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
$layouts: (
 | 
			
		||||
  'default-open': $default-open-layout,
 | 
			
		||||
  'default-closed': $default-closed-layout,
 | 
			
		||||
  'vraw-open': $vraw-open-layout,
 | 
			
		||||
  'vraw-closed': $vraw-closed-layout,
 | 
			
		||||
  'hraw': $hraw-layout
 | 
			
		||||
  'terminal-ide-web': $terminal-ide-web-layout,
 | 
			
		||||
  'terminal-web': $terminal-web-layout,
 | 
			
		||||
  'terminal-ide-vertical': $terminal-ide-vertical-layout,
 | 
			
		||||
  'terminal-ide-horizontal': $terminal-ide-horizontal-layout,
 | 
			
		||||
  'ide-web-vertical': $ide-web-vertical-layout,
 | 
			
		||||
  'terminal-only': $terminal-only-layout,
 | 
			
		||||
  'ide-only': $ide-only-layout,
 | 
			
		||||
  'web-only': $web-only-layout
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@mixin set-layout($layout_key) {
 | 
			
		||||
  @if(index(map_keys($layouts), $layout_key)) {
 | 
			
		||||
    $layout: map_get($layouts, $layout_key)
 | 
			
		||||
@mixin set-layout($layouts-key) {
 | 
			
		||||
  @if(index(map_keys($layouts), $layouts-key)) {
 | 
			
		||||
    $layout: map_get($layouts, $layouts-key)
 | 
			
		||||
  }
 | 
			
		||||
  @else {
 | 
			
		||||
    @error 'Invalid layout value: "#{$layout_key}"'
 | 
			
		||||
    @error 'Invalid layout value: "#{$layouts-key}"'
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@function get-layout(){
 | 
			
		||||
  @return map_get($layouts, $layout_key);
 | 
			
		||||
@function get-layout($layouts-key){
 | 
			
		||||
  @return map_get($layouts, $layouts-key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@mixin position-grid-items($map, $sel) {
 | 
			
		||||
@@ -87,8 +117,8 @@ $layouts: (
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@mixin set-component-size($key) {
 | 
			
		||||
  $tfw-component: map_get(get-layout(), $key);
 | 
			
		||||
@mixin set-component-size($layouts-key, $layout-key) {
 | 
			
		||||
  $tfw-component: map_get(get-layout($layouts-key), $layout-key);
 | 
			
		||||
 | 
			
		||||
  @if (length($tfw-component) > 0) {
 | 
			
		||||
    $columns-count: nth($tfw-component,2) - nth($tfw-component,1);
 | 
			
		||||
@@ -100,22 +130,3 @@ $layouts: (
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[tfw-layout='vraw-open'] {
 | 
			
		||||
  @include position-grid-items(map_get($layouts,'vraw-open'),'.tfw-');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[tfw-layout='vraw-closed'] {
 | 
			
		||||
  @include position-grid-items(map_get($layouts,'vraw-closed'),'.tfw-');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[tfw-layout='hraw'] {
 | 
			
		||||
  @include position-grid-items(map_get($layouts,'hraw'),'.tfw-');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[tfw-layout='default-open'] {
 | 
			
		||||
  @include position-grid-items(map_get($layouts, 'default-open'),'.tfw-');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[tfw-layout='default-closed'] {
 | 
			
		||||
  @include position-grid-items(map_get($layouts,'default-closed'),'.tfw-');
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user