diff --git a/src/main.tsx b/src/main.tsx
index 737e0faf5..1ce310d52 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -9,7 +9,7 @@ import cn from "classnames"
import {TermWrap} from "./term";
import type {SessionDataType, LineType, CmdDataType, RemoteType} from "./types";
import localizedFormat from 'dayjs/plugin/localizedFormat';
-import {GlobalModel, Session, Cmd, Window} from "./model";
+import {GlobalModel, Session, Cmd, Window, Screen, ScreenWindow} from "./model";
dayjs.extend(localizedFormat)
@@ -340,7 +340,7 @@ class CmdInput extends React.Component<{}, {}> {
}
@mobxReact.observer
-class WindowView extends React.Component<{windowId : string}, {}> {
+class ScreenWindowView extends React.Component<{sw : ScreenWindow}, {}> {
mutObs : any;
scrollToBottom() {
@@ -352,11 +352,11 @@ class WindowView extends React.Component<{windowId : string}, {}> {
@boundMethod
scrollHandler(event : any) {
+ let {sw} = this.props;
let target = event.target;
let atBottom = (target.scrollTop + 30 > (target.scrollHeight - target.offsetHeight));
- let win = this.getWindow();
- if (win.shouldFollow.get() != atBottom) {
- mobx.action(() => win.shouldFollow.set(atBottom));
+ if (sw && sw.shouldFollow.get() != atBottom) {
+ mobx.action(() => sw.shouldFollow.set(atBottom));
}
// console.log("scroll-handler>", atBottom, target.scrollTop, target.scrollHeight);
}
@@ -376,42 +376,37 @@ class WindowView extends React.Component<{windowId : string}, {}> {
}
handleDomMutation(mutations, mutObs) {
- let win = this.getWindow();
- if (win && win.shouldFollow.get()) {
+ let {sw} = this.props;
+ if (sw && sw.shouldFollow.get()) {
setTimeout(() => this.scrollToBottom(), 0);
}
}
getWindow() : Window {
- let {windowId} = this.props;
- if (windowId == null) {
- return null;
- }
- let model = GlobalModel;
- let session = model.getActiveSession();
- if (session == null) {
- return null;
- }
- let win = session.getWindowById(windowId);
- return win;
+ let {sw} = this.props;
+ return GlobalModel.getWindowById(sw.sessionId, sw.windowId);
}
getLinesId() {
- let {windowId} = this.props;
- return "window-lines-" + windowId;
+ let {sw} = this.props;
+ return "window-lines-" + sw.windowId;
}
@boundMethod
handleTermResize(e : any) {
- let win = this.getWindow();
- if (win && win.shouldFollow.get()) {
+ let {sw} = this.props;
+ if (sw && sw.shouldFollow.get()) {
setTimeout(() => this.scrollToBottom(), 0);
}
}
+ getWindowViewStyle() : any {
+ return {width: "100%", height: "100%"};
+ }
+
renderError(message : string) {
return (
-
+
{message}
@@ -420,17 +415,18 @@ class WindowView extends React.Component<{windowId : string}, {}> {
}
render() {
- let win = this.getWindow();
- if (win == null) {
- return this.renderError("(no window)");
+ let {sw} = this.props;
+ if (sw == null) {
+ return this.renderError("(no screen window)");
}
+ let win = this.getWindow();
if (!win.linesLoaded.get()) {
return this.renderError("(loading)");
}
let idx = 0;
let line : LineType = null;
return (
-
+
@@ -441,6 +437,42 @@ class WindowView extends React.Component<{windowId : string}, {}> {
}
}
+@mobxReact.observer
+class ScreenView extends React.Component<{screen : Screen}, {}> {
+ render() {
+ let {screen} = this.props;
+ if (screen == null) {
+ return (
+
+ (no screen)
+
+ );
+ }
+ let sw = screen.getActiveSW();
+ return (
+
+
+
+ );
+ }
+}
+
+@mobxReact.observer
+class ScreenTabs extends React.Component<{}, {}> {
+ render() {
+ let model = GlobalModel;
+ let session = model.getActiveSession();
+ if (session == null) {
+ return null;
+ }
+ return (
+
+ tabs!
+
+ );
+ }
+}
+
@mobxReact.observer
class SessionView extends React.Component<{}, {}> {
render() {
@@ -449,10 +481,11 @@ class SessionView extends React.Component<{}, {}> {
if (session == null) {
return (no active session)
;
}
- let curWindowId = session.curWindowId.get();
+ let activeScreen = session.getActiveScreen();
return (
-
+
+
);
diff --git a/src/model.ts b/src/model.ts
index f48f45028..c3e139b88 100644
--- a/src/model.ts
+++ b/src/model.ts
@@ -4,7 +4,7 @@ import {boundMethod} from "autobind-decorator";
import {handleJsonFetchResponse} from "./util";
import {TermWrap} from "./term";
import {v4 as uuidv4} from "uuid";
-import type {SessionDataType, WindowDataType, LineType, RemoteType, HistoryItem, RemoteInstanceType, CmdDataType, FeCmdPacketType, TermOptsType, RemoteStateType} from "./types";
+import type {SessionDataType, WindowDataType, LineType, RemoteType, HistoryItem, RemoteInstanceType, CmdDataType, FeCmdPacketType, TermOptsType, RemoteStateType, ScreenDataType, ScreenWindowType, ScreenOptsType, LayoutType} from "./types";
import {WSControl} from "./ws";
var GlobalUser = "sawka";
@@ -26,6 +26,14 @@ function getApi() : ElectronApi {
return (window as any).api;
}
+// clean empty string
+function ces(s : string) {
+ if (s == "") {
+ return null;
+ }
+ return s;
+}
+
class Cmd {
sessionId : string;
windowId : string;
@@ -199,23 +207,90 @@ class Cmd {
}
};
+class Screen {
+ sessionId : string;
+ screenId : string;
+ opts : OV;
+ name : OV;
+ activeWindowId : OV;
+ windows : OArr;
+
+ constructor(sdata : ScreenDataType) {
+ this.sessionId = sdata.sessionid;
+ this.screenId = sdata.screenid;
+ this.name = mobx.observable.box(sdata.name);
+ this.opts = mobx.observable.box(sdata.screenopts);
+ this.activeWindowId = mobx.observable.box(ces(sdata.activewindowid));
+ let swArr : ScreenWindow[] = [];
+ let wins = sdata.windows || [];
+ for (let i=0; i;
+ layout : OV;
+ shouldFollow : OV = mobx.observable.box(true);
+
+ constructor(swdata : ScreenWindowType) {
+ this.sessionId = swdata.sessionid;
+ this.screenId = swdata.screenid;
+ this.windowId = swdata.windowid;
+ this.name = mobx.observable.box(swdata.name);
+ this.layout = mobx.observable.box(swdata.layout);
+ }
+
+ getWindow() : Window {
+ return GlobalModel.getWindowById(this.sessionId, this.windowId);
+ }
+}
+
+
class Window {
sessionId : string;
windowId : string;
- name : OV;
curRemote : OV;
loaded : OV = mobx.observable.box(false);
- lines : OArr = mobx.observable.array([]);
+ lines : OArr = mobx.observable.array([], {deep: false});
linesLoaded : OV = mobx.observable.box(false);
history : any[] = [];
cmds : Record = {};
- shouldFollow : OV = mobx.observable.box(true);
remoteInstances : OArr = mobx.observable.array([]);
constructor(wdata : WindowDataType) {
this.sessionId = wdata.sessionid;
this.windowId = wdata.windowid;
- this.name = mobx.observable.box(wdata.name);
this.curRemote = mobx.observable.box(wdata.curremote);
}
@@ -229,9 +304,6 @@ class Window {
updateWindow(win : WindowDataType, isActive : boolean) {
mobx.action(() => {
- if (!isBlank(win.name)) {
- this.name.set(win.name)
- }
if (!isBlank(win.curremote)) {
this.curRemote.set(win.curremote);
}
@@ -277,7 +349,7 @@ class Window {
let remote = GlobalModel.getRemoteByName(rname);
if (remote != null) {
return {riid: "", sessionid: this.sessionId, windowid: this.windowId, remoteid: remote.remoteid,
- name: rname, state: remote.defaultstate, sessionscope: false, version: 0};
+ name: rname, state: remote.defaultstate, sessionscope: false};
}
return null;
}
@@ -314,7 +386,8 @@ class Window {
class Session {
sessionId : string;
name : OV;
- curWindowId : OV;
+ activeScreenId : OV;
+ screens : OArr;
windows : OArr;
notifyNum : OV = mobx.observable.box(0);
remoteInstances : OArr = mobx.observable.array([]);
@@ -328,8 +401,15 @@ class Session {
let win = new Window(winData[i]);
wins.push(win);
}
- this.windows = mobx.observable.array(wins);
- this.curWindowId = mobx.observable.box((wins.length == 0 ? null : wins[0].windowId));
+ this.windows = mobx.observable.array(wins, {deep: false});
+ let screenData = sdata.screens || [];
+ let screens : Screen[] = [];
+ for (let i=0; i = mobx.observable.box(null);
sessionListLoaded : OV = mobx.observable.box(false);
- sessionList : OArr = mobx.observable.array([], {name: "SessionList"});
+ sessionList : OArr = mobx.observable.array([], {name: "SessionList", deep: false});
ws : WSControl;
remotes : OArr = mobx.observable.array([], {deep: false});
remotesLoaded : OV = mobx.observable.box(false);
@@ -442,12 +534,28 @@ class Model {
return null;
}
+ getWindowById(sessionId : string, windowId : string) : Window {
+ let session = this.getSessionById(sessionId);
+ if (session == null) {
+ return null;
+ }
+ return session.getWindowById(windowId);
+ }
+
getActiveWindow() : Window {
+ let screen = this.getActiveScreen();
+ if (screen == null) {
+ return null;
+ }
+ return screen.getActiveWindow();
+ }
+
+ getActiveScreen() : Screen {
let session = this.getActiveSession();
if (session == null) {
return null;
}
- return session.getActiveWindow();
+ return session.getActiveScreen();
}
addLineCmd(line : LineType, cmd : CmdDataType, interactive : boolean) {
@@ -592,6 +700,6 @@ if ((window as any).GlobalModal == null) {
}
GlobalModel = (window as any).GlobalModel;
-export {Model, Session, Window, GlobalModel, Cmd};
+export {Model, Session, Window, GlobalModel, Cmd, Screen, ScreenWindow};
diff --git a/src/sh2.less b/src/sh2.less
index bc5a99728..90d7a8fc9 100644
--- a/src/sh2.less
+++ b/src/sh2.less
@@ -17,12 +17,20 @@ html, body, #main {
flex-grow: 1;
display: flex;
flex-direction: column;
+ }
- .window-view {
- flex-grow: 1;
- display: flex;
- flex-direction: column;
- }
+ .screen-tabs {
+ height: 50px;
+ background-color: red;
+ }
+
+ .screen-view {
+ flex-grow: 1;
+ }
+
+ .window-view {
+ display: flex;
+ flex-direction: column;
}
}
}
diff --git a/src/types.ts b/src/types.ts
index b9719868f..cba9380cf 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -3,7 +3,10 @@ import * as mobx from "mobx";
type SessionDataType = {
sessionid : string,
name : string,
+ activescreenid : string,
windows : WindowDataType[],
+ screens : ScreenDataType[],
+ screenwindows : ScreenWindowType[],
cmds : CmdDataType[],
remove : boolean,
};
@@ -19,6 +22,41 @@ type LineType = {
cmdid : string,
};
+type ScreenOptsType = {
+ tabcolor? : string,
+}
+
+type ScreenDataType = {
+ sessionid : string,
+ screenid : string,
+ screenidx : number,
+ activewindowid : string,
+ name : string,
+ windows : ScreenWindowType[],
+ screenopts : ScreenOptsType,
+};
+
+type LayoutType = {
+ type : string,
+ parent? : string,
+ zindex? : number,
+ float? : boolean,
+ top? : string,
+ bottom? : string,
+ left? : string,
+ right? : string,
+ width? : string,
+ height? : string,
+};
+
+type ScreenWindowType = {
+ sessionid : string,
+ screenid : string,
+ windowid : string,
+ name : string,
+ layout : LayoutType,
+};
+
type RemoteType = {
remotetype : string,
remoteid : string,
@@ -40,19 +78,16 @@ type RemoteInstanceType = {
remoteid : string,
sessionscope : boolean,
state : RemoteStateType,
- version : number,
}
type WindowDataType = {
sessionid : string,
windowid : string,
- name : string,
curremote : string,
lines : LineType[],
history : HistoryItem[],
cmds : CmdDataType[],
remotes : RemoteInstanceType[],
- version : number,
remove : boolean,
};
@@ -78,7 +113,7 @@ type FeCmdPacketType = {
type TermOptsType = {
rows : number,
cols : number,
- flexrows : boolean,
+ flexrows? : boolean,
};
type CmdStartPacketType = {
@@ -112,4 +147,4 @@ type CmdDataType = {
usedrows : number,
};
-export type {SessionDataType, LineType, RemoteType, RemoteStateType, RemoteInstanceType, WindowDataType, HistoryItem, CmdRemoteStateType, FeCmdPacketType, TermOptsType, CmdStartPacketType, CmdDonePacketType, CmdDataType};
+export type {SessionDataType, LineType, RemoteType, RemoteStateType, RemoteInstanceType, WindowDataType, HistoryItem, CmdRemoteStateType, FeCmdPacketType, TermOptsType, CmdStartPacketType, CmdDonePacketType, CmdDataType, ScreenDataType, ScreenOptsType, ScreenWindowType, LayoutType};