209 lines
5.5 KiB
TypeScript
209 lines
5.5 KiB
TypeScript
import { ChangeDetectorRef, Component, EventEmitter, OnInit, Output } from '@angular/core';
|
|
|
|
import { WebSocketService } from '../services/websocket.service';
|
|
import { WebSocketMessage } from '../message-types/websocket-message';
|
|
import { IDEMessage } from '../message-types/ide-message';
|
|
import { ProcessManagerService } from '../services/processmanager.service';
|
|
import { DeploymentNotificationService } from '../services/deployment-notification.service';
|
|
import { config } from '../config';
|
|
import { LanguageMap } from './language-map';
|
|
import { filter, 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 = '';
|
|
code: string = config.ide.defaultCode;
|
|
|
|
codeState = CodeState.SAVED;
|
|
deployButtonState = DeployButtonState.DEPLOYED;
|
|
deployButtonText = config.ide.deployButtonText;
|
|
showDeployButton: boolean = config.ide.showDeployButton;
|
|
autosave = null;
|
|
|
|
editorOptions = {
|
|
theme: 'vs-dark',
|
|
language: config.ide.defaultLanguage,
|
|
glyphMargin: false,
|
|
minimap: {enabled: config.ide.showMiniMap}
|
|
};
|
|
|
|
@Output() newLogs = new EventEmitter<any>();
|
|
|
|
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 processManagerService: ProcessManagerService,
|
|
private deploymentNotificationService: DeploymentNotificationService) { }
|
|
|
|
ngOnInit() {
|
|
this.webSocketService.connect();
|
|
this.subscribeWS();
|
|
this.subscribeFirstLanguageDetection();
|
|
this.requestCode();
|
|
this.initProcessManagerService();
|
|
this.resetAutoSaveCountdown();
|
|
}
|
|
|
|
subscribeWS() {
|
|
this.webSocketService.observeKey<WebSocketMessage>('ide').subscribe(message => {
|
|
this.command_handlers[message.key](message);
|
|
this.changeDetectorRef.detectChanges();
|
|
});
|
|
}
|
|
|
|
subscribeFirstLanguageDetection() {
|
|
this.webSocketService.observeKey<IDEMessage>('ide.read').pipe(first()).subscribe(
|
|
() => this.autoDetectEditorLanguageIfEnabled(this.filename)
|
|
);
|
|
}
|
|
|
|
initProcessManagerService() {
|
|
this.processManagerService.init();
|
|
this.processManagerService.subscribeCallback(
|
|
config.ide.deployProcessName,
|
|
message => {
|
|
this.deploymentNotificationService.deploying.next(false);
|
|
this.newLogs.emit({
|
|
stdout: message.stdout,
|
|
stderr: message.stderr
|
|
});
|
|
}
|
|
);
|
|
|
|
this.processManagerService.subscribeSuccessCallback(
|
|
config.ide.deployProcessName,
|
|
message => this.setDeployButtonState(DeployButtonState.DEPLOYED)
|
|
);
|
|
|
|
this.processManagerService.subscribeErrorCallback(
|
|
config.ide.deployProcessName,
|
|
() => this.setDeployButtonState(DeployButtonState.FAILED)
|
|
);
|
|
}
|
|
|
|
reloadHandler(message: WebSocketMessage) {
|
|
this.requestCode();
|
|
}
|
|
|
|
readHandler(message: IDEMessage) {
|
|
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;
|
|
}
|
|
}
|
|
|
|
writeHandler(message: IDEMessage) {
|
|
this.setCodeState(CodeState.SAVED);
|
|
}
|
|
|
|
autoDetectEditorLanguageIfEnabled(filename: string) {
|
|
if (!config.ide.autoDetectFileLanguage) {
|
|
return;
|
|
}
|
|
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(); },
|
|
config.ide.autoSaveInterval
|
|
);
|
|
}
|
|
|
|
tabSwitchButtonHandler(file: string) {
|
|
if (this.codeState === CodeState.DIRTY) {
|
|
this.sendCodeContents();
|
|
}
|
|
this.filename = file;
|
|
this.requestCode();
|
|
this.autoDetectEditorLanguageIfEnabled(this.filename);
|
|
}
|
|
|
|
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.processManagerService.restartProcess(config.ide.deployProcessName);
|
|
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.sendJSON({
|
|
'key': 'ide.write',
|
|
'filename': this.filename,
|
|
'content': this.code
|
|
});
|
|
}
|
|
|
|
requestCode() {
|
|
this.webSocketService.sendJSON({
|
|
'key': 'ide.read',
|
|
'filename': this.filename
|
|
});
|
|
}
|
|
}
|