cleanup old connections code, more cleanup on the connection flows

This commit is contained in:
sawka
2023-04-03 21:33:03 -07:00
parent b731763746
commit c1b4b7eb63
3 changed files with 155 additions and 870 deletions
+1 -710
View File
File diff suppressed because it is too large Load Diff
+2 -100
View File
@@ -962,10 +962,6 @@ class InputModel {
infoMsg : OV<InfoType> = mobx.observable.box(null);
infoTimeoutId : any = null;
remoteTermWrap : TermWrap;
remoteTermWrapFocus : OV<boolean> = mobx.observable.box(false, {name: "remoteTermWrapFocus"});
showNoInputMsg : OV<boolean> = mobx.observable.box(false);
showNoInputTimeoutId : any = null;
inputMode : OV<null | "comment" | "global"> = mobx.observable.box(null);
// cursor
@@ -982,34 +978,12 @@ class InputModel {
});
}
setRemoteTermWrapFocus(focus : boolean) : void {
mobx.action(() => {
this.remoteTermWrapFocus.set(focus);
})();
}
setInputMode(inputMode : null | "comment" | "global") : void {
mobx.action(() => {
this.inputMode.set(inputMode);
})();
}
setShowNoInputMsg(val : boolean) {
mobx.action(() => {
if (this.showNoInputTimeoutId != null) {
clearTimeout(this.showNoInputTimeoutId);
this.showNoInputTimeoutId = null;
}
if (val) {
this.showNoInputMsg.set(true);
this.showNoInputTimeoutId = setTimeout(() => this.setShowNoInputMsg(false), 2000);
}
else {
this.showNoInputMsg.set(false);
}
})();
}
onInputFocus(isFocused : boolean) : void {
mobx.action(() => {
if (isFocused) {
@@ -1075,14 +1049,6 @@ class InputModel {
}
}
getPtyRemoteId() : string {
let info = this.infoMsg.get();
if (info == null || isBlank(info.ptyremoteid)) {
return null;
}
return info.ptyremoteid;
}
hasFocus() : boolean {
let mainInputElem = document.getElementById("main-cmd-input");
if (document.activeElement == mainInputElem) {
@@ -1404,7 +1370,6 @@ class InputModel {
this._clearInfoTimeout();
mobx.action(() => {
this.infoMsg.set(info);
this.syncTermWrap();
if (info == null) {
this.infoShow.set(false);
}
@@ -1452,7 +1417,6 @@ class InputModel {
this.infoShow.set(false);
if (setNull) {
this.infoMsg.set(null);
this.syncTermWrap();
}
})();
}
@@ -1525,62 +1489,10 @@ class InputModel {
this.resetHistory();
this.dropModHistory(false);
this.infoMsg.set(null);
this.syncTermWrap();
this._clearInfoTimeout();
})();
}
termKeyHandler(remoteId : string, event : any, termWrap : TermWrap) : void {
let remote = GlobalModel.getRemote(remoteId);
if (remote == null) {
return;
}
if (remote.status != "connecting" && remote.installstatus != "connecting") {
this.setShowNoInputMsg(true);
return;
}
let inputPacket : RemoteInputPacketType = {
type: "remoteinput",
remoteid: remoteId,
inputdata64: btoa(event.key),
};
GlobalModel.sendInputPacket(inputPacket);
}
syncTermWrap() : void {
let infoMsg = this.infoMsg.get();
let remoteId = (infoMsg == null ? null : infoMsg.ptyremoteid);
let curTermRemoteId = (this.remoteTermWrap == null ? null : this.remoteTermWrap.getContextRemoteId());
if (remoteId == curTermRemoteId) {
return;
}
if (this.remoteTermWrap != null) {
this.remoteTermWrap.dispose();
this.remoteTermWrap = null;
}
if (remoteId != null) {
let elem = document.getElementById("term-remote");
if (elem == null) {
console.log("ERROR null term-remote element");
}
else {
let termOpts = {rows: RemotePtyRows, cols: RemotePtyCols, flexrows: false, maxptysize: 64*1024};
this.remoteTermWrap = new TermWrap(elem, {
termContext: {remoteId: remoteId},
usedRows: RemotePtyRows,
termOpts: termOpts,
winSize: null,
keyHandler: (e, termWrap) => { this.termKeyHandler(remoteId, e, termWrap)},
focusHandler: this.setRemoteTermWrapFocus.bind(this),
isRunning: true,
fontSize: GlobalModel.termFontSize.get(),
ptyDataSource: getTermPtyData,
onUpdateContentHeight: null,
});
}
}
}
getCurLine() : string {
let model = GlobalModel;
let hidx = this.historyIndex.get();
@@ -2314,6 +2226,7 @@ class RemotesModalModel {
deSelectRemote() : void {
mobx.action(() => {
this.selectedRemoteId.set(null);
this.remoteEdit.set(null);
})();
}
@@ -2886,24 +2799,13 @@ class Model {
if (isBlank(ptyMsg.remoteid)) {
// regular update
this.updatePtyData(ptyMsg);
return;
}
else {
// remote update
let ptyData = base64ToArray(ptyMsg.ptydata64);
// new remote term
this.remotesModalModel.receiveData(ptyMsg.remoteid, ptyMsg.ptypos, ptyData);
// old remote term
let activeRemoteId = this.inputModel.getPtyRemoteId();
if (activeRemoteId != ptyMsg.remoteid || this.inputModel.remoteTermWrap == null) {
return;
}
this.inputModel.remoteTermWrap.receiveData(ptyMsg.ptypos, ptyData);
return;
}
return;
}
let update : ModelUpdateType = genUpdate;
if ("screens" in update) {
+152 -60
View File
@@ -34,6 +34,17 @@ function getRemoteTitle(remote : RemoteType) {
return remote.remotecanonicalname;
}
function isStrEq(s1 : string, s2 : string) {
if (util.isBlank(s1) && util.isBlank(s2)) {
return true;
}
return s1 == s2;
}
function isBoolEq(b1 : boolean, b2 : boolean) {
return (!!b1) == (!!b2);
}
@mobxReact.observer
class AuthModeDropdown extends React.Component<{tempVal : OV<string>}, {}> {
active : OV<boolean> = mobx.observable.box(false, {name: "AuthModeDropdown-active"});
@@ -131,6 +142,7 @@ class CreateRemote extends React.Component<{model : RemotesModalModel, remoteEdi
tempManualMode : OV<boolean>;
tempPassword : OV<string>;
tempKeyFile : OV<string>;
tempAutoInstall : OV<boolean>;
errorStr : OV<string>;
constructor(props : any) {
@@ -143,9 +155,21 @@ class CreateRemote extends React.Component<{model : RemotesModalModel, remoteEdi
this.tempConnectMode = mobx.observable.box("auto", {name: "CreateRemote-connectMode"});
this.tempKeyFile = mobx.observable.box("", {name: "CreateRemote-keystr"});
this.tempPassword = mobx.observable.box("", {name: "CreateRemote-password"});
this.tempAutoInstall = mobx.observable.box(true, {name: "CreateRemote-autoinstall"});
this.errorStr = mobx.observable.box(remoteEdit.errorstr, {name: "CreateRemote-errorStr"});
}
remoteCName() : string {
let hostName = this.tempHostName.get();
if (hostName == "") {
return "[no host]";
}
if (hostName.indexOf("@") == -1) {
hostName = "[no user]@" + hostName;
}
return hostName;
}
getErrorStr() : string {
if (this.errorStr.get() != null) {
return this.errorStr.get();
@@ -190,7 +214,7 @@ class CreateRemote extends React.Component<{model : RemotesModalModel, remoteEdi
kwargs["password"] = ""
}
kwargs["connectmode"] = this.tempConnectMode.get();
kwargs["autoinstall"] = "1";
kwargs["autoinstall"] = (this.tempAutoInstall.get() ? "1" : "0");
kwargs["visual"] = "1";
kwargs["submit"] = "1";
GlobalCommandRunner.createRemote(cname, kwargs);
@@ -230,13 +254,20 @@ class CreateRemote extends React.Component<{model : RemotesModalModel, remoteEdi
this.tempHostName.set(e.target.value);
})();
}
@boundMethod
handleChangeAutoInstall(val : boolean) : void {
mobx.action(() => {
this.tempAutoInstall.set(val);
})();
}
render() {
let {model, remote, remoteEdit} = this.props;
let {model, remoteEdit} = this.props;
let authMode = this.tempAuthMode.get();
return (
<div className="remote-detail create-remote">
<div className="title is-5">Create New Remote</div>
<div className="title is-5">Create New Connection</div>
<div className="settings-field mt-3">
<div className="settings-label">
<div>user@host</div>
@@ -304,11 +335,11 @@ class CreateRemote extends React.Component<{model : RemotesModalModel, remoteEdi
<div className="settings-field" style={{marginTop: 10}}>
<div className="settings-label">
{authMode == "password" ? "SSH Password" : "Key Passphrase"}
</div>
<div className="settings-input">
<input type="password" placeholder="password" onFocus={this.onFocusPassword} onChange={this.handleChangePassword} value={this.tempPassword.get()} maxLength={400}/>
</div>
</div>
</div>
<div className="settings-input">
<input type="password" placeholder="password" onChange={this.handleChangePassword} value={this.tempPassword.get()} maxLength={400}/>
</div>
</div>
</If>
<div className="settings-field align-top" style={{marginTop: 10}}>
<div className="settings-label">
@@ -326,6 +357,18 @@ class CreateRemote extends React.Component<{model : RemotesModalModel, remoteEdi
<div className="raw-input"><div className="raw-input"><ConnectModeDropdown tempVal={this.tempConnectMode}/></div></div>
</div>
</div>
<div className="settings-field" style={{marginTop: 10}}>
<div className="settings-label">
<div>Auto Install</div>
<div className="flex-spacer"/>
<InfoMessage width={350}>
If selected, will try to auto-install the mshell client if it is not installed or out of date.
</InfoMessage>
</div>
<div className="settings-input">
<Toggle checked={this.tempAutoInstall.get()} onChange={this.handleChangeAutoInstall}/>
</div>
</div>
<If condition={!util.isBlank(this.getErrorStr())}>
<div className="remoteedit-error">
Error: {this.getErrorStr()}
@@ -350,6 +393,7 @@ class EditRemoteSettings extends React.Component<{model : RemotesModalModel, rem
tempManualMode : OV<boolean>;
tempPassword : OV<string>;
tempKeyFile : OV<string>;
tempAutoInstall : OV<boolean>;
constructor(props : any) {
super(props);
@@ -359,6 +403,36 @@ class EditRemoteSettings extends React.Component<{model : RemotesModalModel, rem
this.tempConnectMode = mobx.observable.box(remote.connectmode, {name: "EditRemoteSettings-connectMode"});
this.tempKeyFile = mobx.observable.box(remoteEdit.keystr ?? "", {name: "EditRemoteSettings-keystr"});
this.tempPassword = mobx.observable.box(remoteEdit.haspassword ? PasswordUnchangedSentinel : "", {name: "EditRemoteSettings-password"});
this.tempAutoInstall = mobx.observable.box(!!remote.autoinstall, {name: "EditRemoteSettings-autoinstall"});
}
componentDidUpdate() {
let {remote} = this.props;
if (remote == null || remote.archived) {
this.props.model.deSelectRemote();
}
}
@boundMethod
clickArchive() : void {
let {remote} = this.props;
if (remote.status == "connected") {
GlobalModel.showAlert({message: "Cannot archived a connected remote. Disconnect and try again."});
return;
}
let prtn = GlobalModel.showAlert({message: "Are you sure you want to archive this connection?", confirm: true});
prtn.then((confirm) => {
if (!confirm) {
return;
}
GlobalCommandRunner.archiveRemote(remote.remoteid);
});
}
@boundMethod
clickForceInstall() : void {
let {remote} = this.props;
GlobalCommandRunner.installRemote(remote.remoteid);
}
@boundMethod
@@ -382,6 +456,13 @@ class EditRemoteSettings extends React.Component<{model : RemotesModalModel, rem
})();
}
@boundMethod
handleChangeAutoInstall(val : boolean) : void {
mobx.action(() => {
this.tempAutoInstall.set(val);
})();
}
@boundMethod
canResetPw() : boolean {
let {remoteEdit} = this.props;
@@ -407,23 +488,39 @@ class EditRemoteSettings extends React.Component<{model : RemotesModalModel, rem
@boundMethod
submitRemote() : void {
let {remote} = this.props;
let {remote, remoteEdit} = this.props;
let authMode = this.tempAuthMode.get();
let kwargs : Record<string, string> = {};
if (authMode == "key" || authMode == "key+password") {
kwargs["key"] = this.tempKeyFile.get();
}
else {
kwargs["key"] = "";
if (!isStrEq(this.tempKeyFile.get(), remoteEdit.keystr)) {
if (authMode == "key" || authMode == "key+password") {
kwargs["key"] = this.tempKeyFile.get();
}
else {
kwargs["key"] = "";
}
}
if (authMode == "password" || authMode == "key+password") {
kwargs["password"] = this.tempPassword.get();
if (this.tempPassword.get() != PasswordUnchangedSentinel) {
kwargs["password"] = this.tempPassword.get();
}
}
else {
kwargs["password"] = ""
if (remoteEdit.haspassword) {
kwargs["password"] = ""
}
}
if (!isStrEq(this.tempAlias.get(), remote.remotealias)) {
kwargs["alias"] = this.tempAlias.get();
}
if (!isStrEq(this.tempConnectMode.get(), remote.connectmode)) {
kwargs["connectmode"] = this.tempConnectMode.get();
}
if (!isBoolEq(this.tempAutoInstall.get(), remote.autoinstall)) {
kwargs["autoinstall"] = (this.tempAutoInstall.get() ? "1" : "0");
}
if (Object.keys(kwargs).length == 0) {
return;
}
kwargs["alias"] = this.tempAlias.get();
kwargs["connectmode"] = this.tempConnectMode.get();
kwargs["visual"] = "1";
kwargs["submit"] = "1";
GlobalCommandRunner.editRemote(remote.remoteid, kwargs);
@@ -453,7 +550,7 @@ class EditRemoteSettings extends React.Component<{model : RemotesModalModel, rem
<div className="remote-detail auth-editing">
<div className="title is-5">{getRemoteTitle(remote)}</div>
<div className="detail-subtitle">
Editing Remote Settings
Editing Connection Settings
</div>
<div className="settings-field">
<div className="settings-label">
@@ -523,6 +620,29 @@ class EditRemoteSettings extends React.Component<{model : RemotesModalModel, rem
<div className="raw-input"><div className="raw-input"><ConnectModeDropdown tempVal={this.tempConnectMode}/></div></div>
</div>
</div>
<div className="settings-field" style={{marginTop: 10}}>
<div className="settings-label">
<div>Auto Install</div>
<div className="flex-spacer"/>
<InfoMessage width={350}>
If selected, will try to auto-install the mshell client if it is not installed or out of date.
</InfoMessage>
</div>
<div className="settings-input">
<Toggle checked={this.tempAutoInstall.get()} onChange={this.handleChangeAutoInstall}/>
</div>
</div>
<div className="settings-field mt-3">
<div className="settings-label">Actions</div>
<div className="settings-input">
<div onClick={this.clickArchive} className="button is-prompt-danger is-outlined is-small is-inline-height">
Archive Connection
</div>
<div onClick={this.clickForceInstall} className="button is-prompt-danger is-outlined is-small is-inline-height ml-3">
Force Install
</div>
</div>
</div>
<If condition={!util.isBlank(remoteEdit.errorstr)}>
<div className="remoteedit-error">
Error: {remoteEdit.errorstr ?? "An error occured"}
@@ -604,38 +724,17 @@ class RemoteDetailView extends React.Component<{model : RemotesModalModel, remot
this.props.model.startEditAuth();
}
@boundMethod
clickArchive(remoteId : string) : void {
let {remote} = this.props;
if (remote.status == "connected") {
GlobalModel.showAlert({message: "Cannot archived a connected remote. Disconnect and try again."});
return;
}
let prtn = GlobalModel.showAlert({message: "Are you sure you want to archive this connection?", confirm: true});
prtn.then((confirm) => {
if (!confirm) {
return;
}
GlobalCommandRunner.archiveRemote(remoteId);
});
}
@boundMethod
editAlias(remoteId : string, alias : string) : void {
this.props.model.startEditAuth();
}
renderInstallStatus(remote : RemoteType) : any {
let statusStr : string = null;
if (remote.installstatus == "disconnected") {
if (remote.needsmshellupgrade) {
statusStr = "mshell " + remote.mshellversion + " (needs upgrade)";
statusStr = "mshell " + remote.mshellversion + " - needs upgrade";
}
else if (util.isBlank(remote.mshellversion)) {
statusStr = "mshell unknown";
}
else {
statusStr = "mshell " + remote.mshellversion + " (current)";
statusStr = "mshell " + remote.mshellversion + " - current";
}
}
else {
@@ -644,6 +743,9 @@ class RemoteDetailView extends React.Component<{model : RemotesModalModel, remot
if (statusStr == null) {
return null;
}
if (remote.autoinstall) {
statusStr = statusStr + " (autoinstall)";
}
return (
<div key="install-status" className="settings-field">
<div className="settings-label"> Install Status</div>
@@ -760,22 +862,14 @@ class RemoteDetailView extends React.Component<{model : RemotesModalModel, remot
<div className="settings-field" style={{minHeight: 24}}>
<div className="settings-label">Alias</div>
<div className="settings-input">
{remoteAliasText} <i style={{marginLeft: 12}} className="fa-sharp fa-solid fa-pen hide-hover"/>
<div onClick={() => this.editAlias()} className="button is-plain is-outlined is-small is-inline-height ml-2 update-auth-button">
<span className="icon is-small"><i className="fa-sharp fa-solid fa-pen"/></span>
<span>Update Alias</span>
</div>
{remoteAliasText}
</div>
</div>
<div className="settings-field">
<div className="settings-label">Auth Type</div>
<div className="settings-input">
<If condition={!remote.local}>
{remote.authtype} <i style={{marginLeft: 12}} className="fa-sharp fa-solid fa-pen hide-hover"/>
<div onClick={() => this.editAuthSettings()} className="button is-plain is-outlined is-small is-inline-height ml-2 update-auth-button">
<span className="icon is-small"><i className="fa-sharp fa-solid fa-pen"/></span>
<span>Update Auth Settings</span>
</div>
{remote.authtype}
</If>
<If condition={remote.local}>
local
@@ -789,16 +883,14 @@ class RemoteDetailView extends React.Component<{model : RemotesModalModel, remot
</div>
</div>
{this.renderInstallStatus(remote)}
<If condition={!remote.local}>
<div className="settings-field">
<div className="settings-label">Archive</div>
<div className="settings-input">
<div onClick={() => this.clickArchive(remote.remoteid)} className="button is-prompt-danger is-outlined is-small is-inline-height">
Archive This Connection
</div>
<div className="settings-field">
<div className="settings-label">Actions</div>
<div className="settings-input">
<div onClick={() => this.editAuthSettings()} className="button is-prompt-green is-outlined is-small is-inline-height">
Edit Connection Settings
</div>
</div>
</If>
</div>
<div className="flex-spacer" style={{minHeight: 20}}/>
<div style={{width: termWidth}}>
{remoteMessage}