From 71c67a4cc2418ed187edd7dda1f8562f8d7b343a Mon Sep 17 00:00:00 2001 From: sawka Date: Thu, 16 Jun 2022 15:51:17 -0700 Subject: [PATCH] checkpoint, session, window, termmap --- src/main.tsx | 61 ++++++++++++++++++++++++++++++++++++++-------------- src/sh2.less | 8 ++----- src/sh2.ts | 4 +--- src/term.ts | 59 ++++++++++++++++++++++++++++++++++++-------------- 4 files changed, 91 insertions(+), 41 deletions(-) diff --git a/src/main.tsx b/src/main.tsx index 6c5f61516..97a66a5a0 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -7,9 +7,11 @@ import * as dayjs from 'dayjs' import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components"; import cn from "classnames" import {GlobalWS} from "./ws"; -import {TermWrap} from "./term"; +import {TermWrap, getOrCreateTermWrap} from "./term"; type LineType = { + sessionid : string, + windowid : string, lineid : number, ts : number, userid : string, @@ -20,9 +22,25 @@ type LineType = { isnew : boolean, }; +type SessionType = { + sessionid : string; + name : string; + windows : WindowType[]; +}; + +type WindowType = { + windowid : string; + name : string; + lines : LineType[]; +}; + +var GlobalUser = "sawka"; +var GSessionId = "47445c53-cfcf-4943-8339-2c04447f20a1"; +var GWindowId = "1"; + 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"}, + {sessionid: GSessionId, windowid: GWindowId, lineid: 1, userid: "sawka", ts: 1654631122000, linetype: "text", text: "hello"}, + {sessionid: GSessionId, windowid: GWindowId, lineid: 2, userid: "sawka", ts: 1654631125000, linetype: "text", text: "again"}, ]); function fetchJsonData(resp : any, ctErr : boolean) : Promise { @@ -101,12 +119,12 @@ class LineCmd extends React.Component<{line : LineType}, {}> { constructor(props) { super(props); - let {line, sessionid} = this.props; - this.termWrap = new TermWrap(sessionid, line.cmdid); + let {line} = this.props; + this.termWrap = new TermWrap(line.sessionid, line.cmdid, line.windowid, line.lineid); } componentDidMount() { - let {line, sessionid} = this.props; + let {line} = this.props; let termElem = document.getElementById(this.getId()); this.termWrap.connectToElem(termElem); this.termWrap.reloadTerminal(0); @@ -168,8 +186,8 @@ class LineCmd extends React.Component<{line : LineType}, {}> {
{line.userid}
{dayjs(line.ts).format("hh:mm:ss a")}
-
{line.cmdid} 0}>({termSize.rows}x{termSize.cols}) v{renderVersion}
-
> {this.singleLineCmdText(line.cmdtext)}
+
{line.cmdid} 0}>({termSize.rows}x{termSize.cols}) {this.termWrap.ptyPos} bytes, v{renderVersion}
+
> {this.singleLineCmdText(line.cmdtext)}
@@ -198,7 +216,7 @@ class Line extends React.Component<{line : LineType}, {}> { } @mobxReact.observer -class CmdInput extends React.Component<{line : LineType, sessionid : string}, {}> { +class CmdInput extends React.Component<{sessionid : string, windowid : string}, {}> { curLine : mobx.IObservableValue = mobx.observable("", {name: "command-line"}); @mobx.action @boundMethod @@ -223,12 +241,13 @@ class CmdInput extends React.Component<{line : LineType, sessionid : string}, {} @boundMethod doSubmitCmd() { + let {sessionid, windowid} = this.props; 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}; + let data = {sessionid: sessionid, windowid: windowid, command: commandStr, userid: GlobalUser}; fetch(url, {method: "post", body: JSON.stringify(data)}).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => { mobx.action(() => { let lines = GlobalLines.get(); @@ -269,36 +288,46 @@ class CmdInput extends React.Component<{line : LineType, sessionid : string}, {} } @mobxReact.observer -class SessionView extends React.Component<{sessionid : string}, {}> { +class SessionView extends React.Component<{session : SessionType}, {}> { render() { - let lines = GlobalLines.get(); + let session = this.props.session; + let window = session.windows[0]; + let lines = window.lines; return (
- +
- +
); } } @mobxReact.observer -class Main extends React.Component<{sessionid : string}, {}> { +class Main extends React.Component<{}, {}> { constructor(props : any) { super(props); } render() { + let windowLines = GlobalLines.get(); + let session : SessionType = { + sessionid: GSessionId, + name: "default", + windows: [ + {windowid: GWindowId, name: "default", lines: windowLines}, + ], + }; return (

ScriptHaus

- +
); } diff --git a/src/sh2.less b/src/sh2.less index 74dc28f13..a55906312 100644 --- a/src/sh2.less +++ b/src/sh2.less @@ -79,7 +79,7 @@ color: #777; } - .cmdid { + .metapart-mono { color: #777; margin-left: 8px; font-size: 0.75rem; @@ -89,11 +89,7 @@ } .cmdtext { - font-family: 'JetBrains Mono', monospace; - font-weight: 400; - font-size: 0.75rem; - margin-top: 5px; - margin-left: 8px; + color: black; overflow: hidden; } } diff --git a/src/sh2.ts b/src/sh2.ts index c602e8982..0d1d6012a 100644 --- a/src/sh2.ts +++ b/src/sh2.ts @@ -6,12 +6,10 @@ import {Main} from "./main"; import {GlobalWS} from "./ws"; let VERSION = __SHVERSION__; -let terminal = null; -let sessionId = "47445c53-cfcf-4943-8339-2c04447f20a1"; document.addEventListener("DOMContentLoaded", () => { GlobalWS.reconnect(); - let reactElem = React.createElement(Main, {sessionid: sessionId}, null); + let reactElem = React.createElement(Main, null, null); let elem = document.getElementById("main"); let root = createRoot(elem); root.render(reactElem); diff --git a/src/term.ts b/src/term.ts index 001a8dc8d..cd00e33fe 100644 --- a/src/term.ts +++ b/src/term.ts @@ -4,8 +4,23 @@ import {sprintf} from "sprintf-js"; import {boundMethod} from "autobind-decorator"; import {GlobalWS} from "./ws"; +// var TermMap : Record; +function getOrCreateTermWrap(sessionId : string, cmdId : string, windowId : string, lineid : number) : TermWrap { + let termKey = makeTermKey(sessionId, cmdId, windowId, lineid); + let termWrap = TermMap[termKey]; + if (termWrap != null) { + return termWrap; + } + termWrap = new TermWrap(sessionId, cmdId, windowId, lineid); + return termWrap; +} + +function makeTermKey(sessionId : string, cmdId : string, windowId : string, lineid : number) : string { + return sprintf("%s/%s/%s/%s", sessionId, cmdId, windowId, lineid); +} + function loadPtyOut(term : Terminal, sessionId : string, cmdId : string, delayMs : number, callback?: (number) => void) { term.clear() let url = sprintf("http://localhost:8080/api/ptyout?sessionid=%s&cmdid=%s", sessionId, cmdId); @@ -23,26 +38,24 @@ class TermWrap { terminal : Terminal; sessionId : string; cmdId : string; - ptyPos : number; - runPos : number; - runData : string; + windowId : string; + lineid : number; + ptyPos : number = 0; + runPos : number = 0; + runData : string = ""; renderVersion : mobx.IObservableValue = mobx.observable.box(1, {name: "renderVersion"}); isFocused : mobx.IObservableValue = mobx.observable.box(false, {name: "focus"}); - flexRows : boolean; - maxRows : number; - cols : number; - atRowMax : boolean; + flexRows : boolean = true; + maxRows : number = 25; + cols : number = 80; + atRowMax : boolean = false; + initialized : boolean = false; - constructor(sessionId : string, cmdId : string) { + constructor(sessionId : string, cmdId : string, windowId : string, lineid : number) { this.sessionId = sessionId; this.cmdId = cmdId; - this.ptyPos = 0; - this.runPos = 0; - this.runData = ""; - this.maxRows = 25; - this.cols = 80; - this.flexRows = true; - this.atRowMax = false; + this.windowId = windowId; + this.lineid = lineid; this.terminal = new Terminal({rows: 2, cols: 80}); TermMap[cmdId] = this; } @@ -51,6 +64,20 @@ class TermWrap { } + // datalen is passed because data could be utf-8 and data.length is not the actual *byte* length + updatePtyData(pos : number, data : string, datalen : number) { + if (pos != this.ptyPos) { + throw new Error(sprintf("invalid pty-update, data-pos[%d] does not match term-pos[%d]", pos, this.ptyPos)); + } + this.ptyPos += datalen; + term.write(data, () => { + mobx.action(() => { + this.resizeToContent(); + this.incRenderVersion(); + })(); + }); + } + resizeToContent() { if (this.atRowMax) { return; @@ -128,4 +155,4 @@ if (window.TermMap == null) { window.TermMap = TermMap; } -export {TermWrap, TermMap}; +export {TermWrap, TermMap, makeTermKey, getOrCreateTermWrap};