diff --git a/src/main.tsx b/src/main.tsx
index 67ba4971..b90671d4 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -20,6 +20,8 @@ const CellWidthPx = 8;
const RemotePtyRows = 8;
const RemotePtyCols = 80;
+const RemoteColors = ["red", "green", "yellow", "blue", "magenta", "cyan", "white", "orange"];
+
type InterObsValue = {
sessionid : string,
windowid : string,
@@ -850,6 +852,246 @@ class InfoRemoteShow extends React.Component<{}, {}> {
}
}
+@mobxReact.observer
+class InfoRemoteEdit extends React.Component<{}, {}> {
+ alias : mobx.IObservableValue;
+ hostName : mobx.IObservableValue;
+ userName : mobx.IObservableValue;
+ portStr : mobx.IObservableValue;
+ colorStr : mobx.IObservableValue;
+ connectMode : mobx.IObservableValue;
+ sudoBool : mobx.IObservableValue;
+ autoInstallBool : mobx.IObservableValue;
+
+ constructor(props) {
+ super(props);
+ this.resetForm();
+ }
+
+ resetForm() {
+ this.alias = mobx.observable.box("");
+ this.hostName = mobx.observable.box("");
+ this.userName = mobx.observable.box("");
+ this.portStr = mobx.observable.box("22");
+ this.colorStr = mobx.observable.box("");
+ this.connectMode = mobx.observable.box("startup");
+ this.sudoBool = mobx.observable.box(false);
+ this.autoInstallBool = mobx.observable.box(true);
+ }
+
+ @boundMethod
+ doCreateRemote() {
+ let cname = this.userName.get() + "@" + this.hostName.get();
+ let kwargs : Record = {};
+ if (this.alias.get() != "") {
+ kwargs["alias"] = this.alias.get();
+ }
+ if (this.sudoBool.get()) {
+ kwargs["sudo"] = "1";
+ }
+ if (this.portStr.get() != "22") {
+ kwargs["port"] = this.portStr.get();
+ }
+ if (this.colorStr.get() != "") {
+ kwargs["color"] = this.colorStr.get();
+ }
+ kwargs["connectmode"] = this.connectMode.get();
+ if (!this.autoInstallBool.get()) {
+ kwargs["autoinstall"] = "0";
+ }
+ kwargs["visual"] = "1";
+ kwargs["submit"] = "1";
+ console.log("create remote", cname, kwargs);
+ mobx.action(() => {
+ GlobalCommandRunner.createRemote(cname, kwargs);
+ this.resetForm();
+ })();
+ }
+
+ @boundMethod
+ doCancel() {
+ mobx.action(() => {
+ this.resetForm();
+ GlobalModel.inputModel.clearInfoMsg(true);
+ })();
+ }
+
+ @boundMethod
+ keyDownCreateRemote(e : any) {
+ if (e.code == "Enter") {
+ this.doCreateRemote();
+ }
+ }
+
+ @boundMethod
+ keyDownCancel(e : any) {
+ if (e.code == "Enter") {
+ this.doCancel();
+ }
+ }
+
+ @boundMethod
+ onChangeAlias(e : any) {
+ mobx.action(() => {
+ this.alias.set(e.target.value);
+ })();
+ }
+
+ @boundMethod
+ onChangeHostName(e : any) {
+ mobx.action(() => {
+ this.hostName.set(e.target.value);
+ })();
+ }
+
+ @boundMethod
+ onChangeUserName(e : any) {
+ mobx.action(() => {
+ this.userName.set(e.target.value);
+ })();
+ }
+
+ @boundMethod
+ onChangePortStr(e : any) {
+ let strVal = e.target.value;
+ let iVal = parseInt(strVal);
+ if (isNaN(iVal) || iVal < 0) {
+ iVal = 0;
+ }
+ mobx.action(() => {
+ this.portStr.set(String(iVal));
+ })();
+ }
+
+ @boundMethod
+ onChangeColorStr(e : any) {
+ mobx.action(() => {
+ this.colorStr.set(e.target.value);
+ })();
+ }
+
+ @boundMethod
+ onChangeConnectMode(e : any) {
+ mobx.action(() => {
+ this.connectMode.set(e.target.value);
+ })();
+ }
+
+ @boundMethod
+ onChangeSudo(e : any) {
+ mobx.action(() => {
+ this.sudoBool.set(e.target.checked);
+ })();
+ }
+
+ @boundMethod
+ onChangeAutoInstall(e : any) {
+ mobx.action(() => {
+ this.autoInstallBool.set(e.target.checked);
+ })();
+ }
+
+ render() {
+ let inputModel = GlobalModel.inputModel;
+ let infoMsg = inputModel.infoMsg.get();
+ if (infoMsg == null || !infoMsg.remoteedit) {
+ return null;
+ }
+ let redit = infoMsg.remoteedit;
+ if (!redit.remoteedit) {
+ return null;
+ }
+ if (!isBlank(redit.remoteid)) {
+ return (
+
+ visual editing of remotes not currently supported
+
+ );
+ }
+ let colorStr : string = null;
+ return (
+
+ );
+ }
+}
+
@mobxReact.observer
class InfoMsg extends React.Component<{}, {}> {
getAfterSlash(s : string) : string {
@@ -874,11 +1116,15 @@ class InfoMsg extends React.Component<{}, {}> {
let line : string = null;
let istr : string = null;
let idx : number = 0;
+ let titleStr = null;
+ if (infoMsg != null) {
+ titleStr = infoMsg.infotitle;
+ }
return (
- {infoMsg.infotitle}
+ {titleStr}
@@ -893,6 +1139,7 @@ class InfoMsg extends React.Component<{}, {}> {
+
0}>
@@ -1496,14 +1743,20 @@ class MainSideBar extends React.Component<{}, {}> {
@boundMethod
handleAddRemote() : void {
- mobx.action(() => {
- GlobalModel.addRemoteModalOpen.set(true);
- })();
+ GlobalCommandRunner.openCreateRemote();
}
render() {
let model = GlobalModel;
let activeSessionId = model.activeSessionId.get();
+ let activeWindow = model.getActiveWindow();
+ let activeRemoteId : string = null;
+ if (activeWindow != null) {
+ let rptr = activeWindow.curRemote.get();
+ if (rptr != null && !isBlank(rptr.remoteid)) {
+ activeRemoteId = rptr.remoteid;
+ }
+ }
let session : Session = null;
let remotes = model.remotes ?? [];
let remote : RemoteType = null;
@@ -1575,7 +1828,7 @@ class MainSideBar extends React.Component<{}, {}> {
- - this.clickRemote(remote)}>
+
- this.clickRemote(remote)}>
{this.remoteDisplayName(remote)}
diff --git a/src/model.ts b/src/model.ts
index 97ecfb65..674c55c7 100644
--- a/src/model.ts
+++ b/src/model.ts
@@ -1742,10 +1742,9 @@ class Model {
this.ws.watchScreen(curScreen.sessionId, curScreen.screenId);
}
- loadWindow(sessionId : string, windowId : string) : Window {
- let newWin = new Window(sessionId, windowId);
- this.windows.set(sessionId + "/" + windowId, newWin);
- let usp = new URLSearchParams({sessionid: sessionId, windowid: windowId});
+ _loadWindowAsync(newWin : Window) {
+ this.windows.set(newWin.sessionId + "/" + newWin.windowId, newWin);
+ let usp = new URLSearchParams({sessionid: newWin.sessionId, windowid: newWin.windowId});
let url = new URL(sprintf("http://localhost:8080/api/get-window?") + usp.toString());
fetch(url).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => {
if (data.data == null) {
@@ -1755,8 +1754,13 @@ class Model {
this.updateWindow(data.data, true);
return;
}).catch((err) => {
- this.errorHandler(sprintf("getting window=%s", windowId), err, false);
+ this.errorHandler(sprintf("getting window=%s", newWin.windowId), err, false);
});
+ }
+
+ loadWindow(sessionId : string, windowId : string) : Window {
+ let newWin = new Window(sessionId, windowId);
+ setTimeout(() => this._loadWindowAsync(newWin), 0);
return newWin;
}
@@ -1879,6 +1883,16 @@ class CommandRunner {
installCancelRemote(remoteid : string) {
GlobalModel.submitCommand("remote", "installcancel", null, {"nohist": "1", "remote": remoteid}, true);
}
+
+ createRemote(cname : string, kwargsArg : Record) {
+ let kwargs = Object.assign({}, kwargsArg);
+ kwargs["nohist"] = "1";
+ GlobalModel.submitCommand("remote", "new", [cname], kwargs, true);
+ }
+
+ openCreateRemote() : void {
+ GlobalModel.submitCommand("remote", "new", null, {"nohist": "1"}, true);
+ }
};
let GlobalModel : Model = null;
diff --git a/src/sh2.less b/src/sh2.less
index 95d642c7..c0b287e9 100644
--- a/src/sh2.less
+++ b/src/sh2.less
@@ -276,6 +276,10 @@ html, body, #main {
font-size: 10px;
}
+ &.is-active .small-text {
+ color: white;
+ }
+
.small-text {
color: #777;
font-size: 10px;
@@ -839,6 +843,11 @@ body .xterm .xterm-viewport {
color: #d3d7cf;
.mono-font(12px);
+ .info-remote-title {
+ font-weight: bold;
+ color: @term-cyan;
+ }
+
.remote-field {
display: flex;
flex-direction: row;
@@ -854,26 +863,87 @@ body .xterm .xterm-viewport {
flex-direction: row;
}
}
+
+ .remote-input-field {
+ display: flex;
+ flex-direction: row;
+ height: 25px;
+ align-items: center;
+
+ .remote-field-label {
+ white-space: pre;
+ width: 140px;
+ font-weight: bold;
+ color: @term-bright-white;
+ }
+
+ .remote-field-control {
+ &.text-control {
+ }
+
+ &.text-input {
+ input[type=text], input[type=number] {
+ background-color: black;
+ color: white;
+ width: 200px;
+ }
+ }
+
+ &.checkbox-input {
+ input[type=checkbox] {
+ position: relative;
+ top: 3px;
+ }
+ }
+
+ &.select-input {
+ select {
+ width: 200px;
+ background-color: black;
+ color: white;
+ }
+ }
+ }
+ }
}
.info-remote-showall {
color: #d3d7cf;
.mono-font(12px);
}
+ }
+}
- .text-button {
- .mono-font(12px, 600);
- color: @term-white;
- cursor: pointer;
+.text-button {
+ .mono-font(12px, 600);
+ color: @term-white;
+ cursor: pointer;
+ background-color: #171717;
+ outline: 2px solid #171717;
- &.connect-button {
- color: @term-green;
- }
+ &:hover, &:focus {
+ background-color: #333;
+ outline: 2px solid #333;
+ }
+
+ &.connect-button {
+ color: @term-green;
+ }
+
+ &.disconnect-button {
+ color: @term-red;
+ }
- &.disconnect-button {
- color: @term-red;
- }
- }
+ &.success-button {
+ color: @term-green;
+ }
+
+ &.error-button {
+ color: @term-red;
+ }
+
+ &.grey-button {
+ color: #666;
}
}
@@ -1138,7 +1208,7 @@ body .xterm .xterm-viewport {
top: 4px;
}
-.menu-list .remote-status .status-connecting {
+.menu-list .remote-status.status-connecting {
position: relative;
top: 0px;
font-size: 12px;
diff --git a/src/types.ts b/src/types.ts
index f45746bb..7431bdb1 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -90,6 +90,7 @@ type RemoteType = {
archived : boolean,
uname : string,
mshellversion : string,
+ needsmshellupgrade : boolean,
remove? : boolean,
};
@@ -279,6 +280,12 @@ type CmdLineUpdateType = {
insertpos : number,
};
+type RemoteEditType = {
+ remoteedit : boolean,
+ remoteid? : string,
+ errorstr? : string,
+};
+
type InfoType = {
infotitle? : string,
infomsg? : string,
@@ -288,6 +295,7 @@ type InfoType = {
infocompsmore? : boolean,
timeoutms? : number,
ptyremoteid? : string,
+ remoteedit? : RemoteEditType,
remoteshowall? : boolean,
};