mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-09 19:48:45 +01:00
disconnected modal
This commit is contained in:
parent
bba43c8540
commit
9027edc0e1
146
src/main.tsx
146
src/main.tsx
@ -2488,113 +2488,82 @@ function sortAndFilterRemotes(origRemotes : RemoteType[]) : RemoteType[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@mobxReact.observer
|
@mobxReact.observer
|
||||||
class AddRemoteModal extends React.Component<{}, {}> {
|
class DisconnectedModal extends React.Component<{}, {}> {
|
||||||
@boundMethod
|
logRef : any = React.createRef();
|
||||||
handleModalClose() : void {
|
showLog : mobx.IObservableValue<boolean> = mobx.observable.box(false)
|
||||||
mobx.action(() => {
|
|
||||||
GlobalModel.addRemoteModalOpen.set(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
|
@boundMethod
|
||||||
handleModalClose() : void {
|
restartServer() {
|
||||||
mobx.action(() => {
|
|
||||||
GlobalModel.remotesModalOpen.set(false);
|
|
||||||
})();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@boundMethod
|
@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(() => {
|
mobx.action(() => {
|
||||||
GlobalModel.addRemoteModalOpen.set(true);
|
this.showLog.set(!this.showLog.get());
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let model = GlobalModel;
|
let model = GlobalModel;
|
||||||
let remotes = sortAndFilterRemotes(model.remotes);
|
let logLine : string = null;
|
||||||
let remote : RemoteType = null;
|
let idx : number = 0;
|
||||||
return (
|
return (
|
||||||
<div className="sc-modal remote-modal modal is-active">
|
<div className="sc-modal disconnected-modal modal is-active">
|
||||||
<div onClick={this.handleModalClose} className="modal-background"></div>
|
<div className="modal-background"></div>
|
||||||
<div className="modal-content message">
|
<div className="modal-content message">
|
||||||
<div className="message-header">
|
<div className="message-header">
|
||||||
<p>Remotes</p>
|
<p>ScriptHaus Client Disconnected</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="message-content">
|
<If condition={this.showLog.get()}>
|
||||||
<table className="table">
|
<div className="message-content">
|
||||||
<thead>
|
<div className="ws-log" ref={this.logRef}>
|
||||||
<tr>
|
<For each="logLine" index="idx" of={GlobalModel.ws.wsLog}>
|
||||||
<th className="status-header">Status</th>
|
<div key={idx} className="ws-logline">{logLine}</div>
|
||||||
<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>
|
|
||||||
</For>
|
</For>
|
||||||
</tbody>
|
</div>
|
||||||
</table>
|
</div>
|
||||||
</div>
|
</If>
|
||||||
<div className="message-footer">
|
<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">
|
<span className="icon">
|
||||||
<i className="fa fa-plus"/>
|
<i className="fa fa-refresh"/>
|
||||||
</span>
|
</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>
|
</button>
|
||||||
<div className="spacer"></div>
|
|
||||||
<button onClick={this.handleModalClose} className="button">Close</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button onClick={this.handleModalClose} className="modal-close is-large" aria-label="close"></button>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -2617,11 +2586,8 @@ class Main extends React.Component<{}, {}> {
|
|||||||
<MainSideBar/>
|
<MainSideBar/>
|
||||||
<SessionView/>
|
<SessionView/>
|
||||||
</div>
|
</div>
|
||||||
<If condition={GlobalModel.addRemoteModalOpen.get()}>
|
<If condition={!GlobalModel.ws.open.get()}>
|
||||||
<AddRemoteModal/>
|
<DisconnectedModal/>
|
||||||
</If>
|
|
||||||
<If condition={GlobalModel.remotesModalOpen.get() && !GlobalModel.addRemoteModalOpen.get()}>
|
|
||||||
<RemoteModal/>
|
|
||||||
</If>
|
</If>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1525,8 +1525,6 @@ class Model {
|
|||||||
windows : OMap<string, Window> = mobx.observable.map({}, {name: "windows", deep: false}); // key = "sessionid/windowid"
|
windows : OMap<string, Window> = mobx.observable.map({}, {name: "windows", deep: false}); // key = "sessionid/windowid"
|
||||||
inputModel : InputModel;
|
inputModel : InputModel;
|
||||||
termUsedRowsCache : Record<string, number> = {};
|
termUsedRowsCache : Record<string, number> = {};
|
||||||
remotesModalOpen : OV<boolean> = mobx.observable.box(false);
|
|
||||||
addRemoteModalOpen : OV<boolean> = mobx.observable.box(false);
|
|
||||||
debugCmds : number = 0;
|
debugCmds : number = 0;
|
||||||
debugSW : OV<boolean> = mobx.observable.box(false);
|
debugSW : OV<boolean> = mobx.observable.box(false);
|
||||||
|
|
||||||
@ -1653,7 +1651,7 @@ class Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmdStatusUpdate(sessionId : string, cmdId : string, origStatus : string, newStatus : string) {
|
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);
|
let lines = this.getActiveLinesByCmdId(sessionId, cmdId);
|
||||||
for (let ptr of lines) {
|
for (let ptr of lines) {
|
||||||
let sw = ptr.sw;
|
let sw = ptr.sw;
|
||||||
@ -2290,7 +2288,7 @@ function cmdPacketString(pk : FeCmdPacketType) : string {
|
|||||||
|
|
||||||
let GlobalModel : Model = null;
|
let GlobalModel : Model = null;
|
||||||
let GlobalCommandRunner : CommandRunner = 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).GlobalModel = new Model();
|
||||||
(window as any).GlobalCommandRunner = new CommandRunner();
|
(window as any).GlobalCommandRunner = new CommandRunner();
|
||||||
}
|
}
|
||||||
|
45
src/sh2.less
45
src/sh2.less
@ -1330,9 +1330,11 @@ input[type=checkbox] {
|
|||||||
.sc-modal {
|
.sc-modal {
|
||||||
.modal-content {
|
.modal-content {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
background-color: #666;
|
||||||
|
|
||||||
.message-header {
|
.message-header {
|
||||||
font-size: 20px;
|
.mono-font();
|
||||||
|
font-size: 16px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1342,43 +1344,44 @@ input[type=checkbox] {
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-footer {
|
.message-footer {
|
||||||
border-top: 1px solid #666;
|
border-top: 1px solid #666;
|
||||||
padding-top: 15px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
.spacer {
|
.spacer {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.footer-text-link {
|
||||||
|
.mono-font(12px);
|
||||||
|
color: @term-white;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
.mono-font();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.remote-modal {
|
.disconnected-modal {
|
||||||
.message-content {
|
.message-content {
|
||||||
.table {
|
.ws-log {
|
||||||
th.status-header {
|
padding: 5px;
|
||||||
width: 40px;
|
background-color: black;
|
||||||
}
|
height: 250px;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
tbody td {
|
.ws-logline {
|
||||||
vertical-align: middle;
|
.mono-font(12px);
|
||||||
}
|
color: @term-white;
|
||||||
|
|
||||||
.status-cell {
|
|
||||||
.remote-status {
|
|
||||||
font-size: 16px;
|
|
||||||
top: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-text {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
72
src/ws.ts
72
src/ws.ts
@ -2,6 +2,7 @@ import * as mobx from "mobx";
|
|||||||
import {sprintf} from "sprintf-js";
|
import {sprintf} from "sprintf-js";
|
||||||
import {boundMethod} from "autobind-decorator";
|
import {boundMethod} from "autobind-decorator";
|
||||||
import {WatchScreenPacketType} from "./types";
|
import {WatchScreenPacketType} from "./types";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
class WSControl {
|
class WSControl {
|
||||||
wsConn : any;
|
wsConn : any;
|
||||||
@ -13,6 +14,7 @@ class WSControl {
|
|||||||
messageCallback : (any) => void = null;
|
messageCallback : (any) => void = null;
|
||||||
watchSessionId : string = null;
|
watchSessionId : string = null;
|
||||||
watchScreenId : string = null;
|
watchScreenId : string = null;
|
||||||
|
wsLog : mobx.IObservableArray<string> = mobx.observable.array([], {name: "wsLog"})
|
||||||
|
|
||||||
constructor(clientId : string, messageCallback : (any) => void) {
|
constructor(clientId : string, messageCallback : (any) => void) {
|
||||||
this.messageCallback = messageCallback;
|
this.messageCallback = messageCallback;
|
||||||
@ -21,19 +23,47 @@ class WSControl {
|
|||||||
setInterval(this.sendPing, 5000);
|
setInterval(this.sendPing, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@mobx.action
|
log(str : string) {
|
||||||
setOpen(val : boolean) {
|
mobx.action(() => {
|
||||||
this.open.set(val);
|
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()) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
this.reconnectTimes++;
|
this.reconnectTimes++;
|
||||||
if (this.reconnectTimes > 20) {
|
if (this.reconnectTimes > 20) {
|
||||||
console.log("websocket cannot connect, giving up");
|
this.log("cannot connect, giving up");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let timeoutArr = [0, 0, 2, 5, 10, 10, 30, 60];
|
let timeoutArr = [0, 0, 2, 5, 10, 10, 30, 60];
|
||||||
@ -42,32 +72,22 @@ class WSControl {
|
|||||||
timeout = timeoutArr[this.reconnectTimes];
|
timeout = timeoutArr[this.reconnectTimes];
|
||||||
}
|
}
|
||||||
if (timeout > 0) {
|
if (timeout > 0) {
|
||||||
console.log(sprintf("websocket reconnect(%d), sleep %ds", this.reconnectTimes, timeout));
|
this.log(sprintf("sleeping %ds", timeout));
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
console.log(sprintf("websocket reconnect(%d)", this.reconnectTimes));
|
this.connectNow(String(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;
|
|
||||||
}, timeout*1000);
|
}, 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
|
@boundMethod
|
||||||
onclose(event : any) {
|
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) {
|
if (this.open.get() || this.opening) {
|
||||||
this.setOpen(false);
|
this.setOpen(false);
|
||||||
this.opening = false;
|
this.opening = false;
|
||||||
@ -77,7 +97,7 @@ class WSControl {
|
|||||||
|
|
||||||
@boundMethod
|
@boundMethod
|
||||||
onopen() {
|
onopen() {
|
||||||
console.log("websocket open");
|
this.log("connection open");
|
||||||
this.setOpen(true);
|
this.setOpen(true);
|
||||||
this.opening = false;
|
this.opening = false;
|
||||||
this.runMsgQueue();
|
this.runMsgQueue();
|
||||||
|
Loading…
Reference in New Issue
Block a user