Fix manual and instumented layout changes (force event 'resize')
@@ -1,13 +1,16 @@
 | 
			
		||||
export const config = {
 | 
			
		||||
  dashboard: {
 | 
			
		||||
    route: 'dashboard',
 | 
			
		||||
    currentLayout: 'terminal-web',
 | 
			
		||||
    currentLayout: 'terminal-ide-web',
 | 
			
		||||
    enabledLayouts:  new Set([
 | 
			
		||||
      'terminal-ide-web',
 | 
			
		||||
      'terminal-web',
 | 
			
		||||
      'terminal-ide-vertical',
 | 
			
		||||
      'terminal-ide-horizontal',
 | 
			
		||||
      'terminal-only',
 | 
			
		||||
      'web-only',
 | 
			
		||||
      'ide-only'
 | 
			
		||||
      'terminal-web',
 | 
			
		||||
      'ide-web-vertical',
 | 
			
		||||
      'ide-only',
 | 
			
		||||
      'web-only'
 | 
			
		||||
      ]),
 | 
			
		||||
    allLayouts:  new Set([
 | 
			
		||||
      'terminal-ide-web',
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@
 | 
			
		||||
        <app-terminal></app-terminal>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="tfw-sidebar">
 | 
			
		||||
      <app-sidebar [layout]="layout"></app-sidebar>
 | 
			
		||||
      <app-sidebar (layoutChanged)="setLayout($event)" [layout]="layout"></app-sidebar>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="tfw-terminal-footer"></div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { Component, OnDestroy, OnInit, ChangeDetectorRef, ViewChild, AfterViewInit } from '@angular/core';
 | 
			
		||||
import { Component, OnDestroy, OnInit, ChangeDetectorRef } from '@angular/core';
 | 
			
		||||
import { DeploymentNotificationService } from '../services/deployment-notification.service';
 | 
			
		||||
import { Subscription } from 'rxjs/Subscription';
 | 
			
		||||
import { WebSocketService } from '../services/websocket.service';
 | 
			
		||||
@@ -11,16 +11,13 @@ import { SidebarComponent } from '../sidebar/sidebar.component';
 | 
			
		||||
  templateUrl: './dashboard.component.html',
 | 
			
		||||
  styleUrls: ['./dashboard.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit {
 | 
			
		||||
export class DashboardComponent implements OnInit, OnDestroy {
 | 
			
		||||
  deploying = false;
 | 
			
		||||
  deploymentNotificationSubscription: Subscription;
 | 
			
		||||
  enabledLayouts: Set<string> = config.dashboard.enabledLayouts;
 | 
			
		||||
  layout: string = config.dashboard.currentLayout ;
 | 
			
		||||
  layout: string = config.dashboard.currentLayout;
 | 
			
		||||
  command_handlers = {'layout': this.layoutHandler.bind(this)};
 | 
			
		||||
 | 
			
		||||
  @ViewChild(SidebarComponent)
 | 
			
		||||
  private sidebarComponent: SidebarComponent;
 | 
			
		||||
 | 
			
		||||
  constructor(private deploymentNotificationService: DeploymentNotificationService,
 | 
			
		||||
              private webSocketService: WebSocketService,
 | 
			
		||||
              private changeDetectorRef: ChangeDetectorRef) {}
 | 
			
		||||
@@ -36,19 +33,22 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit {
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngAfterViewInit() {
 | 
			
		||||
    this.layout = this.sidebarComponent.layout;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  layoutHandler(data: LayoutCommand) {
 | 
			
		||||
    if (this.enabledLayouts.has(data.layout)) {
 | 
			
		||||
      this.layout = data.layout;
 | 
			
		||||
      this.setLayout(data.layout);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      console.log('Invalid ide layout "' + data.layout + '" received!');
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setLayout(layout: string) {
 | 
			
		||||
    this.layout = layout;
 | 
			
		||||
    // We need to trigger a 'resize' event manually, otherwise ace editor stays collapsed
 | 
			
		||||
    // Ace editors 'resize' event listener requires a parameter of force=true
 | 
			
		||||
    setTimeout(() => window.dispatchEvent(new Event('resize', {force: true} as any)), 0);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnDestroy() {
 | 
			
		||||
    if (this.deploymentNotificationSubscription) {
 | 
			
		||||
      this.deploymentNotificationSubscription.unsubscribe();
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@ import { WebSocketService } from '../services/websocket.service';
 | 
			
		||||
import { ProcessManagerService } from '../services/processmanager.service';
 | 
			
		||||
import { DeploymentNotificationService } from '../services/deployment-notification.service';
 | 
			
		||||
import { config } from '../config';
 | 
			
		||||
import { element } from 'protractor';
 | 
			
		||||
 | 
			
		||||
const modelist = brace.acequire('ace/ext/modelist');
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { Component, Input, Output, OnInit } from '@angular/core';
 | 
			
		||||
import { Component, Input, Output, EventEmitter } from '@angular/core';
 | 
			
		||||
import { config } from '../config';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
@@ -7,14 +7,15 @@ import { config } from '../config';
 | 
			
		||||
  styleUrls: ['./sidebar.component.scss']
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export class SidebarComponent implements OnInit {
 | 
			
		||||
  @Input() @Output() layout: string;
 | 
			
		||||
export class SidebarComponent {
 | 
			
		||||
  @Input() layout: string;
 | 
			
		||||
  @Output() layoutChanged = new EventEmitter<string>();
 | 
			
		||||
  enabledLayouts: Set<string> = config.dashboard.enabledLayouts;
 | 
			
		||||
 | 
			
		||||
  constructor() {}
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setLayout(layout: string) {
 | 
			
		||||
    this.layout = layout;
 | 
			
		||||
    this.layoutChanged.emit(this.layout);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +0,0 @@
 | 
			
		||||
export interface SourceCode {
 | 
			
		||||
  filename: string;
 | 
			
		||||
  content?: string;
 | 
			
		||||
  files: string[];
 | 
			
		||||
  directory: string;
 | 
			
		||||
  command: string;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,44 +0,0 @@
 | 
			
		||||
<div class="tfw-grid-webide-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>
 | 
			
		||||
@@ -1,95 +0,0 @@
 | 
			
		||||
@import "../../assets/scss/variables.scss";
 | 
			
		||||
 | 
			
		||||
.tfw-grid-webide-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); }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,154 +0,0 @@
 | 
			
		||||
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-webide',
 | 
			
		||||
  templateUrl: './webide.component.html',
 | 
			
		||||
  styleUrls: ['./webide.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class WebideComponent implements OnInit {
 | 
			
		||||
  key_id = 'webide';
 | 
			
		||||
  filename = '';
 | 
			
		||||
  code: string = config.webide.defaultCode;
 | 
			
		||||
  language: string = config.webide.defaultLanguage;
 | 
			
		||||
  theme = 'cobalt';
 | 
			
		||||
  directory = '';
 | 
			
		||||
  files: string[];
 | 
			
		||||
  codeState = 'SAVED';
 | 
			
		||||
  deployButtonState = 'DEPLOYED';
 | 
			
		||||
  showDeployButton: boolean = config.webide.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.webide.deployProcessName, (event) => { this.setDeployButtonState('DEPLOYED'); });
 | 
			
		||||
    this.processManagerService.subscribeErrorCallback(config.webide.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.webide.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
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 6.4 KiB  | 
| 
		 Before Width: | Height: | Size: 6.8 KiB  | 
| 
		 Before Width: | Height: | Size: 7.0 KiB  | 
| 
		 Before Width: | Height: | Size: 12 KiB  | 
| 
		 Before Width: | Height: | Size: 7.9 KiB  | 
| 
		 Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB  | 
| 
		 Before Width: | Height: | Size: 7.8 KiB  | 
| 
		 Before Width: | Height: | Size: 13 KiB  | 
@@ -1 +0,0 @@
 | 
			
		||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 59"><defs><style>.cls-1{fill:#277eec;}</style></defs><title>terminalonly_active</title><path class="cls-1" d="M65.06,59H2.94C1.32,59,0,57.35,0,55.31V3.69C0,1.65,1.32,0,2.94,0H65.06C66.68,0,68,1.65,68,3.69V55.31C68,57.35,66.68,59,65.06,59ZM2.94,1.05A2.42,2.42,0,0,0,.84,3.69V55.31A2.42,2.42,0,0,0,2.94,58H65.06a2.42,2.42,0,0,0,2.1-2.64V3.69a2.42,2.42,0,0,0-2.1-2.64Z"/><path class="cls-1" d="M18.82,12.75a.16.16,0,0,1,.13.06l12,13.47a1.13,1.13,0,0,1,0,1.58L19,41.33a.18.18,0,0,1-.22,0,.1.1,0,0,1-.05-.17l12-13.47a.93.93,0,0,0,0-1.31L18.68,13a.1.1,0,0,1,.05-.17A.14.14,0,0,1,18.82,12.75Z"/><path class="cls-1" d="M18.82,41.76a.52.52,0,0,1-.27-.07.49.49,0,0,1-.26-.35l0-.18.15-.22,12-13.46a.57.57,0,0,0,0-.82L18.28,13.06v-.27a.53.53,0,0,1,.26-.35l.09,0,.18,0a.56.56,0,0,1,.41.18L31.22,26a1.52,1.52,0,0,1,0,2.08l-12,13.47A.54.54,0,0,1,18.82,41.76Zm-.15-.68h0Zm0-28Z"/><path class="cls-1" d="M18.82,41.63a.54.54,0,0,1-.21-.05.38.38,0,0,1-.19-.26.32.32,0,0,1,.09-.29l12-13.47a.71.71,0,0,0,0-1l-12-13.46a.34.34,0,0,1-.08-.29.38.38,0,0,1,.19-.26.44.44,0,0,1,.52.09l12,13.47a1.37,1.37,0,0,1,0,1.9l-12,13.47A.41.41,0,0,1,18.82,41.63Zm.05-.28h0Zm-.1-.18Zm.09-28.39h0Z"/><path class="cls-1" d="M18.82,42a.79.79,0,0,1-.38-.09.73.73,0,0,1-.39-.52.72.72,0,0,1,.18-.61l12-13.46a.33.33,0,0,0,0-.5l-12-13.47a.68.68,0,0,1-.18-.59.73.73,0,0,1,.39-.53.8.8,0,0,1,1,.17l12,13.47a1.76,1.76,0,0,1,0,2.4l-12,13.47A.77.77,0,0,1,18.82,42Zm0-29.1L30.77,26.33a1.06,1.06,0,0,1,0,1.48l-12,13.47,0,0h0l12-13.46a1,1,0,0,0,0-1.42Z"/><path class="cls-1" d="M44.35,41.93H30.14a.75.75,0,1,1,0-1.5H44.35a.75.75,0,0,1,0,1.5Z"/></svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 1.6 KiB  | 
| 
		 Before Width: | Height: | Size: 6.8 KiB  | 
| 
		 Before Width: | Height: | Size: 5.7 KiB  | 
@@ -46,7 +46,6 @@ $ide-web-vertical-layout: (
 | 
			
		||||
  '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),
 | 
			
		||||
@@ -74,7 +73,6 @@ $web-only-layout: (
 | 
			
		||||
  'sidebar': ($grid-columns-count,$grid-columns-count+1, 1,$grid-rows-count+1)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
$layouts: (
 | 
			
		||||
  'terminal-ide-web': $terminal-ide-web-layout,
 | 
			
		||||
  'terminal-web': $terminal-web-layout,
 | 
			
		||||
@@ -131,5 +129,3 @@ $layouts: (
 | 
			
		||||
    min-height: #{$rows-count / $grid-rows-count * 100}vh;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||