disconnected modal

This commit is contained in:
sawka 2022-10-28 14:17:45 -07:00
parent bba43c8540
commit 9027edc0e1
4 changed files with 128 additions and 141 deletions

View File

@ -2488,113 +2488,82 @@ function sortAndFilterRemotes(origRemotes : RemoteType[]) : RemoteType[] {
}
@mobxReact.observer
class AddRemoteModal extends React.Component<{}, {}> {
@boundMethod
handleModalClose() : void {
mobx.action(() => {
GlobalModel.addRemoteModalOpen.set(false);
})();
}
class DisconnectedModal extends React.Component<{}, {}> {
logRef : any = React.createRef();
showLog : mobx.IObservableValue<boolean> = mobx.observable.box(false)
render() {
return (
<div className="sc-modal add-remote-modal modal is-active">
<div onClick={this.handleModalClose} className="modal-background"></div>
<div className="modal-content message">
<div className="message-header">
<p>Add Remote</p>
</div>
<div className="message-content">
hello
</div>
<div className="message-footer">
<button onClick={this.handleModalClose} className="button">Cancel</button>
<div className="spacer"></div>
<button className="button is-primary">
<span className="icon">
<i className="fa fa-plus"/>
</span>
<span>Add Remote</span>
</button>
</div>
</div>
</div>
);
}
}
@mobxReact.observer
class RemoteModal extends React.Component<{}, {}> {
@boundMethod
handleModalClose() : void {
mobx.action(() => {
GlobalModel.remotesModalOpen.set(false);
})();
restartServer() {
}
@boundMethod
handleAddRemote() : void {
tryReconnect() {
GlobalModel.ws.connectNow("manual");
}
componentDidMount() {
if (this.logRef.current != null) {
this.logRef.current.scrollTop = this.logRef.current.scrollHeight;
}
}
componentDidUpdate() {
if (this.logRef.current != null) {
this.logRef.current.scrollTop = this.logRef.current.scrollHeight;
}
}
@boundMethod
handleShowLog() : void {
mobx.action(() => {
GlobalModel.addRemoteModalOpen.set(true);
this.showLog.set(!this.showLog.get());
})();
}
render() {
let model = GlobalModel;
let remotes = sortAndFilterRemotes(model.remotes);
let remote : RemoteType = null;
let logLine : string = null;
let idx : number = 0;
return (
<div className="sc-modal remote-modal modal is-active">
<div onClick={this.handleModalClose} className="modal-background"></div>
<div className="sc-modal disconnected-modal modal is-active">
<div className="modal-background"></div>
<div className="modal-content message">
<div className="message-header">
<p>Remotes</p>
<p>ScriptHaus Client Disconnected</p>
</div>
<div className="message-content">
<table className="table">
<thead>
<tr>
<th className="status-header">Status</th>
<th>Alias</th>
<th>User@Host</th>
<th>Connect</th>
</tr>
</thead>
<tbody>
<For each="remote" of={remotes}>
<tr key={remote.remoteid}>
<td className="status-cell">
<div><RemoteStatusLight remote={remote}/></div>
</td>
<td>
{remote.remotealias}
<If condition={isBlank(remote.remotealias)}>
-
</If>
</td>
<td>
{remote.remotecanonicalname}
</td>
<td>
{remote.connectmode}
</td>
</tr>
<If condition={this.showLog.get()}>
<div className="message-content">
<div className="ws-log" ref={this.logRef}>
<For each="logLine" index="idx" of={GlobalModel.ws.wsLog}>
<div key={idx} className="ws-logline">{logLine}</div>
</For>
</tbody>
</table>
</div>
</div>
</div>
</If>
<div className="message-footer">
<button onClick={this.handleAddRemote} className="button is-primary">
<div className="footer-text-link" style={{marginLeft: 10}} onClick={this.handleShowLog}>
<If condition={!this.showLog.get()}>
<i className="fa fa-plus"/> Show Log
</If>
<If condition={this.showLog.get()}>
<i className="fa fa-minus"/> Hide Log
</If>
</div>
<div className="spacer"/>
<button onClick={this.tryReconnect} className="button">
<span className="icon">
<i className="fa fa-plus"/>
<i className="fa fa-refresh"/>
</span>
<span>Add Remote</span>
<span>Try Reconnect</span>
</button>
<button onClick={this.restartServer} className="button is-danger" style={{marginLeft: 10}}>
<span className="icon">
<i className="fa fa-exclamation-triangle"/>
</span>
<span>Restart Server</span>
</button>
<div className="spacer"></div>
<button onClick={this.handleModalClose} className="button">Close</button>
</div>
</div>
<button onClick={this.handleModalClose} className="modal-close is-large" aria-label="close"></button>
</div>
);
}
@ -2617,11 +2586,8 @@ class Main extends React.Component<{}, {}> {
<MainSideBar/>
<SessionView/>
</div>
<If condition={GlobalModel.addRemoteModalOpen.get()}>
<AddRemoteModal/>
</If>
<If condition={GlobalModel.remotesModalOpen.get() && !GlobalModel.addRemoteModalOpen.get()}>
<RemoteModal/>
<If condition={!GlobalModel.ws.open.get()}>
<DisconnectedModal/>
</If>
</div>
);

View File

@ -1525,8 +1525,6 @@ class Model {
windows : OMap<string, Window> = mobx.observable.map({}, {name: "windows", deep: false}); // key = "sessionid/windowid"
inputModel : InputModel;
termUsedRowsCache : Record<string, number> = {};
remotesModalOpen : OV<boolean> = mobx.observable.box(false);
addRemoteModalOpen : OV<boolean> = mobx.observable.box(false);
debugCmds : number = 0;
debugSW : OV<boolean> = mobx.observable.box(false);
@ -1653,7 +1651,7 @@ class Model {
}
cmdStatusUpdate(sessionId : string, cmdId : string, origStatus : string, newStatus : string) {
console.log("cmd status", sessionId, cmdId, origStatus, "=>", newStatus);
// console.log("cmd status", sessionId, cmdId, origStatus, "=>", newStatus);
let lines = this.getActiveLinesByCmdId(sessionId, cmdId);
for (let ptr of lines) {
let sw = ptr.sw;
@ -2290,7 +2288,7 @@ function cmdPacketString(pk : FeCmdPacketType) : string {
let GlobalModel : Model = null;
let GlobalCommandRunner : CommandRunner = null;
if ((window as any).GlobalModal == null) {
if ((window as any).GlobalModel == null) {
(window as any).GlobalModel = new Model();
(window as any).GlobalCommandRunner = new CommandRunner();
}

View File

@ -1330,9 +1330,11 @@ input[type=checkbox] {
.sc-modal {
.modal-content {
padding: 10px;
background-color: #666;
.message-header {
font-size: 20px;
.mono-font();
font-size: 16px;
margin-bottom: 10px;
}
@ -1342,43 +1344,44 @@ input[type=checkbox] {
overflow-y: auto;
display: flex;
flex-direction: column;
margin-bottom: 10px;
}
.message-footer {
border-top: 1px solid #666;
padding-top: 15px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
.spacer {
flex-grow: 1;
}
.footer-text-link {
.mono-font(12px);
color: @term-white;
cursor: pointer;
}
}
.button {
.mono-font();
}
}
}
.remote-modal {
.disconnected-modal {
.message-content {
.table {
th.status-header {
width: 40px;
}
.ws-log {
padding: 5px;
background-color: black;
height: 250px;
overflow: auto;
tbody td {
vertical-align: middle;
}
.status-cell {
.remote-status {
font-size: 16px;
top: 0;
margin-right: 0;
}
.status-text {
font-size: 12px;
}
.ws-logline {
.mono-font(12px);
color: @term-white;
}
}
}

View File

@ -2,6 +2,7 @@ import * as mobx from "mobx";
import {sprintf} from "sprintf-js";
import {boundMethod} from "autobind-decorator";
import {WatchScreenPacketType} from "./types";
import dayjs from "dayjs";
class WSControl {
wsConn : any;
@ -13,6 +14,7 @@ class WSControl {
messageCallback : (any) => void = null;
watchSessionId : string = null;
watchScreenId : string = null;
wsLog : mobx.IObservableArray<string> = mobx.observable.array([], {name: "wsLog"})
constructor(clientId : string, messageCallback : (any) => void) {
this.messageCallback = messageCallback;
@ -21,19 +23,47 @@ class WSControl {
setInterval(this.sendPing, 5000);
}
@mobx.action
setOpen(val : boolean) {
this.open.set(val);
log(str : string) {
mobx.action(() => {
let ts = dayjs().format("YYYY-MM-DD HH:mm:ss");
this.wsLog.push("[" + ts + "] " + str);
if (this.wsLog.length > 50) {
this.wsLog.splice(0, this.wsLog.length-50);
}
})();
}
reconnect() {
@mobx.action
setOpen(val : boolean) {
mobx.action(() => {
this.open.set(val);
})();
}
connectNow(desc : string) {
if (this.open.get()) {
this.wsConn.close(); // this will force a reconnect
return;
}
this.log(sprintf("try reconnect (%s)", desc));
this.opening = true;
this.wsConn = new WebSocket("ws://localhost:8081/ws?clientid=" + this.clientId);
this.wsConn.onopen = this.onopen;
this.wsConn.onmessage = this.onmessage;
this.wsConn.onclose = this.onclose;
// turns out onerror is not necessary (onclose always follows onerror)
// this.wsConn.onerror = this.onerror;
}
reconnect(forceClose? : boolean) {
if (this.open.get()) {
if (forceClose) {
this.wsConn.close(); // this will force a reconnect
}
return;
}
this.reconnectTimes++;
if (this.reconnectTimes > 20) {
console.log("websocket cannot connect, giving up");
this.log("cannot connect, giving up");
return;
}
let timeoutArr = [0, 0, 2, 5, 10, 10, 30, 60];
@ -42,32 +72,22 @@ class WSControl {
timeout = timeoutArr[this.reconnectTimes];
}
if (timeout > 0) {
console.log(sprintf("websocket reconnect(%d), sleep %ds", this.reconnectTimes, timeout));
this.log(sprintf("sleeping %ds", timeout));
}
setTimeout(() => {
console.log(sprintf("websocket reconnect(%d)", this.reconnectTimes));
this.opening = true;
this.wsConn = new WebSocket("ws://localhost:8081/ws?clientid=" + this.clientId);
this.wsConn.onopen = this.onopen;
this.wsConn.onmessage = this.onmessage;
this.wsConn.onerror = this.onerror;
this.wsConn.onclose = this.onclose;
this.connectNow(String(this.reconnectTimes));
}, timeout*1000);
}
@boundMethod
onerror(event : any) {
console.log("websocket error", event);
if (this.open.get() || this.opening) {
this.setOpen(false);
this.opening = false;
this.reconnect();
}
}
@boundMethod
onclose(event : any) {
console.log("websocket closed", event);
console.log("close", event);
if (event.wasClean) {
this.log("connection closed");
}
else {
this.log("connection error/disconnected");
}
if (this.open.get() || this.opening) {
this.setOpen(false);
this.opening = false;
@ -77,7 +97,7 @@ class WSControl {
@boundMethod
onopen() {
console.log("websocket open");
this.log("connection open");
this.setOpen(true);
this.opening = false;
this.runMsgQueue();