From df3b7a3bb0307c1fef4291a3aab7e110172469d4 Mon Sep 17 00:00:00 2001 From: sawka Date: Mon, 13 Jun 2022 11:12:39 -0700 Subject: [PATCH] run commands via run-command --- src/main.tsx | 110 ++++++++++++++++++++++++++++++++++++++++++--------- src/sh2.less | 4 +- src/sh2.ts | 3 +- 3 files changed, 95 insertions(+), 22 deletions(-) diff --git a/src/main.tsx b/src/main.tsx index 66cdd0c3..ce89dc70 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -16,8 +16,47 @@ type LineType = { text : string, cmdid : string, cmdtext : string, + isnew : boolean, }; +var GlobalLines = mobx.observable.box([ + {lineid: 1, userid: "sawka", ts: 1654631122000, linetype: "text", text: "hello"}, + {lineid: 2, userid: "sawka", ts: 1654631125000, linetype: "text", text: "again"}, +]); + +function fetchJsonData(resp : any, ctErr : boolean) : Promise { + let contentType = resp.headers.get("Content-Type"); + if (contentType != null && contentType.startsWith("application/json")) { + return resp.text().then((textData) => { + try { + return JSON.parse(textData); + } + catch (err) { + let errMsg = sprintf("Unparseable JSON: " + err.message); + let rtnErr = new Error(errMsg); + throw rtnErr; + } + }); + } + if (ctErr) { + throw new Error("non-json content-type"); + } +} + +function handleJsonFetchResponse(url : URL, resp : any) : Promise { + if (!resp.ok) { + let errData = fetchJsonData(resp, false); + if (errData && errData["error"]) { + throw new Error(errData["error"]) + } + let errMsg = sprintf("Bad status code response from fetch '%s': %d %s", url.toString(), resp.status, resp.statusText); + let rtnErr = new Error(errMsg); + throw rtnErr; + } + let rtnData = fetchJsonData(resp, true); + return rtnData; +} + @mobxReact.observer class LineMeta extends React.Component<{line : LineType}, {}> { render() { @@ -56,6 +95,7 @@ class LineText extends React.Component<{line : LineType}, {}> { } function loadPtyOut(term : Terminal, sessionId : string, cmdId : string) { + term.clear() let url = sprintf("http://localhost:8080/api/ptyout?sessionid=%s&cmdid=%s", sessionId, cmdId); fetch(url).then((resp) => { if (!resp.ok) { @@ -63,7 +103,6 @@ function loadPtyOut(term : Terminal, sessionId : string, cmdId : string) { } return resp.text() }).then((resptext) => { - console.log(resptext); term.write(resptext); }); } @@ -75,11 +114,10 @@ class LineCmd extends React.Component<{line : LineType}, {}> { componentDidMount() { let {line, sessionid} = this.props; - console.log("load terminal", sessionid, line.cmdid); this.terminal = new Terminal(); - this.terminal.open(document.getElementById(this.getId())); + let termElem = document.getElementById(this.getId()); + this.terminal.open(termElem); loadPtyOut(this.terminal, sessionid, line.cmdid); - console.log(this.terminal, this.terminal.element); this.terminal.textarea.addEventListener("focus", () => { mobx.action(() => { this.focus.set(true); @@ -90,19 +128,37 @@ class LineCmd extends React.Component<{line : LineType}, {}> { this.focus.set(false); })(); }); + if (line.isnew) { + setTimeout(() => { + let lineElem = document.getElementById("line-" + this.getId()); + lineElem.scrollIntoView({block: "end"}); + mobx.action(() => { + line.isnew = false; + })(); + }, 100); + setTimeout(() => { + loadPtyOut(this.terminal, sessionid, line.cmdid); + }, 1000); + } } getId() : string { let {line} = this.props; return "cmd-" + line.lineid + "-" + line.cmdid; } + + @boundMethod + doRefresh() { + let {line, sessionid} = this.props; + loadPtyOut(this.terminal, sessionid, line.cmdid); + } render() { let {line} = this.props; let lineid = line.lineid.toString(); let running = false; return ( -
+
= 5}, {"running": running})}> {lineid}
@@ -116,6 +172,9 @@ class LineCmd extends React.Component<{line : LineType}, {}> {
+
+
Refresh
+
); } @@ -136,7 +195,7 @@ class Line extends React.Component<{line : LineType}, {}> { } @mobxReact.observer -class CmdInput extends React.Component<{line : LineType}, {}> { +class CmdInput extends React.Component<{line : LineType, sessionid : string}, {}> { curLine : mobx.IObservableValue = mobx.observable("", {name: "command-line"}); @mobx.action @boundMethod @@ -144,13 +203,11 @@ class CmdInput extends React.Component<{line : LineType}, {}> { mobx.action(() => { let ctrlMod = e.getModifierState("Control") || e.getModifierState("Meta") || e.getModifierState("Shift"); if (e.code == "Enter" && !ctrlMod) { - let cmdLine = this.curLine.get(); - this.curLine.set(""); - console.log("START COMMAND", cmdLine); e.preventDefault(); + setTimeout(() => this.doSubmitCmd(), 0); return; } - console.log(e.code, e.keyCode, e.key, event.which, ctrlMod, e); + // console.log(e.code, e.keyCode, e.key, event.which, ctrlMod, e); })(); } @@ -160,6 +217,26 @@ class CmdInput extends React.Component<{line : LineType}, {}> { this.curLine.set(e.target.value); })(); } + + @boundMethod + doSubmitCmd() { + let commandStr = this.curLine.get(); + mobx.action(() => { + this.curLine.set(""); + })(); + let url = sprintf("http://localhost:8080/api/run-command"); + let data = {sessionid: this.props.sessionid, command: commandStr}; + fetch(url, {method: "post", body: JSON.stringify(data)}).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => { + console.log("got success data", data); + mobx.action(() => { + let lines = GlobalLines.get(); + data.data.line.isnew = true; + lines.push(data.data.line); + })(); + }).catch((err) => { + console.log("error calling run-command", err) + }); + } render() { return ( @@ -177,7 +254,7 @@ class CmdInput extends React.Component<{line : LineType}, {}> {
-
+
@@ -192,13 +269,8 @@ class CmdInput extends React.Component<{line : LineType}, {}> { @mobxReact.observer class Main extends React.Component<{sessionid : string}, {}> { render() { - let lines = [ - {lineid: 1, userid: "sawka", ts: 1654631122000, linetype: "text", text: "hello"}, - {lineid: 2, userid: "sawka", ts: 1654631125000, linetype: "text", text: "again"}, - {lineid: 3, userid: "sawka", ts: 1654631125000, linetype: "??", text: "again"}, - {lineid: 4, userid: "sawka", ts: 1654631125000, linetype: "cmd", cmdid: "47445c53-cfcf-4943-8339-2c04447f20a1", cmdtext: "ls -l"}, - {lineid: 5, userid: "sawka", ts: 1654631135000, linetype: "cmd", cmdid: "792a66ab-577c-4fe1-88f4-862703bdb42d", cmdtext: "ls -l | grep go"}, - ]; + let lines = GlobalLines.get(); + console.log("main-lines", mobx.toJS(lines)); return (

@@ -210,7 +282,7 @@ class Main extends React.Component<{sessionid : string}, {}> {

- +
); } diff --git a/src/sh2.less b/src/sh2.less index 7042bc4f..49efebae 100644 --- a/src/sh2.less +++ b/src/sh2.less @@ -96,10 +96,10 @@ .terminal-wrapper { background-color: #000; - padding: 5px; - width: calc(100% - 8px); + padding: 5px 15px 5px 5px; margin-right: 8px; margin-top: 2px; + align-self: flex-start; &.focus { outline: 3px solid blue; diff --git a/src/sh2.ts b/src/sh2.ts index e0118a47..1f9756ee 100644 --- a/src/sh2.ts +++ b/src/sh2.ts @@ -6,9 +6,10 @@ import {Main} from "./main"; let VERSION = __SHVERSION__; let terminal = null; +let sessionId = "47445c53-cfcf-4943-8339-2c04447f20a1"; document.addEventListener("DOMContentLoaded", () => { - let reactElem = React.createElement(Main, {sessionid: "AQ45MM"}, null); + let reactElem = React.createElement(Main, {sessionid: sessionId}, null); let elem = document.getElementById("main"); let root = createRoot(elem); root.render(reactElem);