import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { WebSocketService } from '../services/websocket.service'; import { WebSocketMessage } from '../message-types/websocket-message'; import { IDEMessage } from '../message-types/ide-message'; import { DeployMessage } from '../message-types/deploy-message'; import { DeploymentNotificationService } from '../services/deployment-notification.service'; import { IdeConfigService } from '../services/config.service'; import { LanguageMap } from './language-map'; import { first } from 'rxjs/operators'; enum DeployButtonState { DEPLOYED, DEPLOYING, FAILED, TODEPLOY } enum CodeState { SAVED, DIRTY } @Component({ selector: 'app-ide', templateUrl: './ide.component.html', styleUrls: ['./ide.component.scss'] }) export class IdeComponent implements OnInit { CodeState = CodeState; DeployButtonState = DeployButtonState; files: string[]; filename = ''; lastFilename = ''; reloadFile = false; code = 'Loading your file...'; codeState = CodeState.SAVED; deployButtonState = DeployButtonState.DEPLOYED; deployButtonText = this.configService.deployButtonText; showDeployButton = this.configService.showDeployButton; autosave = null; editorOptions = { theme: 'vs-dark', language: 'text', glyphMargin: false, minimap: {enabled: false} }; command_handlers = { 'ide.reload': this.reloadHandler.bind(this), 'ide.read': this.readHandler.bind(this), 'ide.write': this.writeHandler.bind(this), }; constructor(private webSocketService: WebSocketService, private changeDetectorRef: ChangeDetectorRef, private deploymentNotificationService: DeploymentNotificationService, private configService: IdeConfigService) {} ngOnInit() { this.webSocketService.connect(); this.configService.init(); this.subscribeWS(); this.subscribeFirstLanguageDetection(); this.requestCode(); this.resetAutoSaveCountdown(); } subscribeWS() { this.webSocketService.observeControl('ide').subscribe(message => { this.command_handlers[message.key](message); this.changeDetectorRef.detectChanges(); }); this.webSocketService.observeControl('deploy.finish').subscribe( message => this.deployHandler(message) ); } subscribeFirstLanguageDetection() { this.webSocketService.observeControl('ide.read').pipe(first()).subscribe( () => this.autoDetectEditorLanguage(this.filename) ); } reloadHandler(message: WebSocketMessage) { if (!this.reloadFile) { this.reloadFile = true; this.requestCode(); } } readHandler(message: IDEMessage) { if (!this.reloadFile && message.reload) { return; } this.reloadFile = false; if (this.codeState === CodeState.SAVED) { if (this.filename !== message.filename) { this.filename = message.filename; } this.code = (message.content != null) ? message.content : this.code; this.files = message.files; if (this.lastFilename !== this.filename) { this.autoDetectEditorLanguage(this.filename); } this.lastFilename = this.filename; } } writeHandler(message: IDEMessage) { this.setCodeState(CodeState.SAVED); } deployHandler(message: DeployMessage) { if ('error' in message) { this.setDeployButtonState(DeployButtonState.FAILED); } else { this.setDeployButtonState(DeployButtonState.DEPLOYED); } this.deploymentNotificationService.deploying.next(false); } autoDetectEditorLanguage(filename: string) { const extension = filename.substr(filename.lastIndexOf('.') + 1); let language = LanguageMap[extension]; language = (language === undefined) ? 'text' : language; this.setEditorLanguage(language); } setEditorLanguage(lang: string) { this.editorOptions = Object.assign( {}, this.editorOptions, { language: lang } ); } resetAutoSaveCountdown() { if (this.autosave) { clearInterval(this.autosave); } this.autosave = setInterval( () => { this.sendCodeIfDirty(); }, this.configService.autoSaveInterval.value ); } tabSwitchButtonHandler(file: string) { if (this.codeState === CodeState.DIRTY) { this.sendCodeContents(); } this.filename = file; this.requestCode(); } editorWriteHandler() { this.setCodeState(CodeState.DIRTY); this.setDeployButtonState(DeployButtonState.TODEPLOY); this.resetAutoSaveCountdown(); } setCodeState(state: CodeState) { this.codeState = state; } setDeployButtonState(state: DeployButtonState) { this.deployButtonState = state; } deployCode() { this.webSocketService.send({'key': 'deploy.start'}); this.setDeployButtonState(DeployButtonState.DEPLOYING); this.deploymentNotificationService.deploying.next(true); } sendCodeIfDirty() { if (this.codeState === CodeState.DIRTY) { this.sendCodeContents(); } } pathBasename(path: string) { return path.split('/').reverse()[0]; } sendCodeContents() { this.webSocketService.send({ 'key': 'ide.write', 'filename': this.filename, 'content': this.code }); } requestCode() { this.webSocketService.send({ 'key': 'ide.read', 'filename': this.filename, 'reload': this.reloadFile }); } }