checkpoint on remote:add/edit

This commit is contained in:
sawka
2022-09-30 14:57:23 -07:00
parent b981aafb1a
commit 0821e35a37
4 changed files with 367 additions and 22 deletions
+258 -5
View File
@@ -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<string>;
hostName : mobx.IObservableValue<string>;
userName : mobx.IObservableValue<string>;
portStr : mobx.IObservableValue<string>;
colorStr : mobx.IObservableValue<string>;
connectMode : mobx.IObservableValue<string>;
sudoBool : mobx.IObservableValue<boolean>;
autoInstallBool : mobx.IObservableValue<boolean>;
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<string, string> = {};
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 (
<div className="info-remote">
visual editing of remotes not currently supported
</div>
);
}
let colorStr : string = null;
return (
<form className="info-remote">
<div className="info-title">
<If condition={isBlank(redit.remoteid)}>
add new remote
</If>
<If condition={!isBlank(redit.remoteid)}>
edit remote
</If>
</div>
<div className="remote-input-field">
<div className="remote-field-label">type</div>
<div className="remote-field-control text-control">
ssh
</div>
</div>
<div className="remote-input-field">
<div className="remote-field-label">alias</div>
<div className="remote-field-control text-input">
<input type="text" onChange={this.onChangeAlias} value={this.alias.get()}/>
</div>
</div>
<div className="remote-input-field">
<div className="remote-field-label">hostname</div>
<div className="remote-field-control text-input">
<input type="text" onChange={this.onChangeHostName} value={this.hostName.get()}/>
</div>
</div>
<div className="remote-input-field">
<div className="remote-field-label">username</div>
<div className="remote-field-control text-input">
<input type="text" onChange={this.onChangeUserName} value={this.userName.get()}/>
</div>
</div>
<div className="remote-input-field">
<div className="remote-field-label">port</div>
<div className="remote-field-control text-input">
<input type="number" placeholder="22" onChange={this.onChangePortStr} value={this.portStr.get()}/>
</div>
</div>
<div className="remote-input-field">
<div className="remote-field-label">sudo</div>
<div className="remote-field-control checkbox-input">
<input type="checkbox" onChange={this.onChangeSudo} checked={this.sudoBool.get()}/>
</div>
</div>
<div className="remote-input-field">
<div className="remote-field-label">connectmode</div>
<div className="remote-field-control select-input">
<select onChange={this.onChangeConnectMode} value={this.connectMode.get()}>
<option>startup</option>
<option>auto</option>
<option>manual</option>
</select>
</div>
</div>
<div className="remote-input-field">
<div className="remote-field-label">autoinstall</div>
<div className="remote-field-control checkbox-input">
<input type="checkbox" onChange={this.onChangeAutoInstall} checked={this.autoInstallBool.get()}/>
</div>
</div>
<div className="remote-input-field">
<div className="remote-field-label">color</div>
<div className="remote-field-control select-input">
<select onChange={this.onChangeColorStr} value={this.colorStr.get()}>
<option value="">(default)</option>
<For each="colorStr" of={RemoteColors}>
<option key={colorStr} value={colorStr}>{colorStr}</option>
</For>
</select>
</div>
</div>
<div style={{marginTop: 15, marginBottom: 10}} className="remote-input-field">
<a tabIndex={0} style={{marginRight: 20}} onClick={this.doCreateRemote} onKeyDown={this.keyDownCreateRemote} className="text-button success-button">[create remote]</a>
{"|"}
<a tabIndex={0} style={{marginLeft: 20}} onClick={this.doCancel} onKeyDown={this.keyDownCancel} className="text-button grey-button">[cancel (ESC)]</a>
</div>
</form>
);
}
}
@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 (
<div className="cmd-input-info" style={{display: (infoShow ? "block" : "none")}}>
<If condition={infoMsg && infoMsg.infotitle != null}>
<div key="infotitle" className="info-title">
{infoMsg.infotitle}
{titleStr}
</div>
</If>
<If condition={infoMsg && infoMsg.infomsg != null}>
@@ -893,6 +1139,7 @@ class InfoMsg extends React.Component<{}, {}> {
</For>
</div>
</If>
<InfoRemoteEdit key="inforemoteedit"/>
<InfoRemoteShow key="inforemoteshow"/>
<InfoRemoteShowAll key="inforemoteshowall"/>
<If condition={infoMsg && infoMsg.infocomps != null && infoMsg.infocomps.length > 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<{}, {}> {
</p>
<ul className="menu-list remotes-menu-list">
<For each="remote" of={remotes}>
<li key={remote.remoteid} className="remote-menu-item"><a onClick={() => this.clickRemote(remote)}>
<li key={remote.remoteid} className={cn("remote-menu-item")}><a className={cn({"is-active": (remote.remoteid == activeRemoteId)})} onClick={() => this.clickRemote(remote)}>
<RemoteStatusLight status={remote.status}/>
{this.remoteDisplayName(remote)}
</a></li>
+19 -5
View File
@@ -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<string, string>) {
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;
+82 -12
View File
@@ -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;
+8
View File
@@ -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,
};