mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-25 22:12:12 +01:00
198 lines
6.7 KiB
TypeScript
198 lines
6.7 KiB
TypeScript
import * as React from "react";
|
|
import * as mobxReact from "mobx-react";
|
|
import * as mobx from "mobx";
|
|
import {sprintf} from "sprintf-js";
|
|
import {boundMethod} from "autobind-decorator";
|
|
import cn from "classnames";
|
|
import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components";
|
|
import type {RemoteType} from "./types";
|
|
|
|
type OV<V> = mobx.IObservableValue<V>;
|
|
|
|
function renderCmdText(text : string) : any {
|
|
return <span>⌘{text}</span>;
|
|
}
|
|
|
|
class CmdStrCode extends React.Component<{cmdstr : string, onUse : () => void, onCopy : () => void, isCopied : boolean, fontSize : "normal" | "large", limitHeight : boolean}, {}> {
|
|
@boundMethod
|
|
handleUse(e : any) {
|
|
e.stopPropagation();
|
|
if (this.props.onUse != null) {
|
|
this.props.onUse()
|
|
}
|
|
}
|
|
|
|
@boundMethod
|
|
handleCopy(e : any) {
|
|
e.stopPropagation();
|
|
if (this.props.onCopy != null) {
|
|
this.props.onCopy();
|
|
}
|
|
}
|
|
|
|
render() {
|
|
let {isCopied, cmdstr, fontSize, limitHeight} = this.props;
|
|
return (
|
|
<div className={cn("cmdstr-code", {"is-large": (fontSize == "large")}, {"limit-height": limitHeight})}>
|
|
<If condition={isCopied}>
|
|
<div key="copied" className="copied-indicator">
|
|
<div>copied</div>
|
|
</div>
|
|
</If>
|
|
<div key="use" className="use-button" title="Use Command" onClick={this.handleUse}><i className="fa-sharp fa-solid fa-check"/></div>
|
|
<div key="code" className="code-div">
|
|
<code>{cmdstr}</code>
|
|
</div>
|
|
<div key="copy" className="copy-control">
|
|
<div className="inner-copy" onClick={this.handleCopy}>
|
|
<i title="copy" className="fa-sharp fa-regular fa-copy"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
class Toggle extends React.Component<{checked : boolean, onChange : (value : boolean) => void}, {}> {
|
|
@boundMethod
|
|
handleChange(e : any) : void {
|
|
let {onChange} = this.props;
|
|
if (onChange != null) {
|
|
onChange(e.target.checked);
|
|
}
|
|
}
|
|
|
|
render() {
|
|
return (
|
|
<label className="checkbox-toggle">
|
|
<input type="checkbox" checked={this.props.checked} onChange={this.handleChange}/>
|
|
<span className="slider"/>
|
|
</label>
|
|
);
|
|
}
|
|
}
|
|
|
|
@mobxReact.observer
|
|
class RemoteStatusLight extends React.Component<{remote : RemoteType}, {}> {
|
|
render() {
|
|
let remote = this.props.remote;
|
|
let status = "error";
|
|
let wfp = false;
|
|
if (remote != null) {
|
|
status = remote.status;
|
|
wfp = remote.waitingforpassword;
|
|
}
|
|
let icon = "fa-sharp fa-solid fa-circle"
|
|
if (status == "connecting") {
|
|
icon = (wfp ? "fa-sharp fa-solid fa-key" : "fa-sharp fa-solid fa-rotate");
|
|
}
|
|
return (
|
|
<i className={cn("remote-status", icon, "status-" + status)}/>
|
|
);
|
|
}
|
|
}
|
|
|
|
@mobxReact.observer
|
|
class InlineSettingsTextEdit extends React.Component<{text : string, value : string, onChange : (val : string) => void, maxLength : number, placeholder : string}, {}> {
|
|
isEditing : OV<boolean> = mobx.observable.box(false, {name: "inlineedit-isEditing"});
|
|
tempText : OV<string>;
|
|
|
|
@boundMethod
|
|
handleChangeText(e : any) : void {
|
|
mobx.action(() => {
|
|
this.tempText.set(e.target.value);
|
|
})();
|
|
}
|
|
|
|
@boundMethod
|
|
confirmChange() : void {
|
|
mobx.action(() => {
|
|
let newText = this.tempText.get();
|
|
this.isEditing.set(false);
|
|
this.tempText = null;
|
|
this.props.onChange(newText);
|
|
})();
|
|
}
|
|
|
|
@boundMethod
|
|
cancelChange() : void {
|
|
mobx.action(() => {
|
|
this.isEditing.set(false);
|
|
this.tempText = null;
|
|
})();
|
|
}
|
|
|
|
@boundMethod
|
|
handleKeyDown(e : any) : void {
|
|
if (e.code == "Enter") {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
this.confirmChange();
|
|
return;
|
|
}
|
|
if (e.code == "Escape") {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
this.cancelChange();
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
@boundMethod
|
|
clickEdit() : void {
|
|
mobx.action(() => {
|
|
this.isEditing.set(true);
|
|
this.tempText = mobx.observable.box(this.props.value, {name: "inlineedit-tempText"});
|
|
})();
|
|
}
|
|
|
|
render() {
|
|
if (this.isEditing.get()) {
|
|
return (
|
|
<div className={cn("settings-input inline-edit", "edit-active")}>
|
|
<div className="field has-addons">
|
|
<div className="control">
|
|
<input className="input" type="text" onKeyDown={this.handleKeyDown} placeholder={this.props.placeholder} onChange={this.handleChangeText} value={this.tempText.get()} maxLength={this.props.maxLength}/>
|
|
</div>
|
|
<div className="control">
|
|
<div onClick={this.cancelChange} title="Cancel (Esc)" className="button is-prompt-danger is-outlined is-small"><span className="icon is-small"><i className="fa-sharp fa-solid fa-xmark"/></span></div>
|
|
</div>
|
|
<div className="control">
|
|
<div onClick={this.confirmChange} title="Confirm (Enter)" className="button is-prompt-green is-outlined is-small"><span className="icon is-small"><i className="fa-sharp fa-solid fa-check"/></span></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
else {
|
|
return (
|
|
<div onClick={this.clickEdit} className={cn("settings-input inline-edit", "edit-not-active")}>
|
|
{this.props.text}
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
@mobxReact.observer
|
|
class InfoMessage extends React.Component<{width : number, children : React.ReactNode}> {
|
|
render() {
|
|
return (
|
|
<div className="info-message">
|
|
<div className="message-icon">
|
|
<i className="fa-sharp fa-solid fa-circle-info"/>
|
|
</div>
|
|
<div className="message-content" style={{width: this.props.width}}>
|
|
<div className="info-icon">
|
|
<i className="fa-sharp fa-solid fa-circle-info"/>
|
|
</div>
|
|
<div className="info-children">{this.props.children}</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
export {CmdStrCode, Toggle, renderCmdText, RemoteStatusLight, InlineSettingsTextEdit, InfoMessage};
|