mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-03-11 13:23:06 +01:00
abstract connection selector dropdown properly. use in settings. remove old selector.
This commit is contained in:
parent
f2baa59af6
commit
d528f3db27
@ -10,7 +10,7 @@ import cn from "classnames";
|
|||||||
import { GlobalModel, GlobalCommandRunner, TabColors } from "../../../model/model";
|
import { GlobalModel, GlobalCommandRunner, TabColors } from "../../../model/model";
|
||||||
import { Toggle, InlineSettingsTextEdit, SettingsError, InfoMessage } from "../common";
|
import { Toggle, InlineSettingsTextEdit, SettingsError, InfoMessage } from "../common";
|
||||||
import { LineType, RendererPluginType, ClientDataType, CommandRtnType } from "../../../types/types";
|
import { LineType, RendererPluginType, ClientDataType, CommandRtnType } from "../../../types/types";
|
||||||
import { RemotesSelector } from "../../connections/connections";
|
import { ConnectionDropdown } from "../../connections/connections";
|
||||||
import { PluginModel } from "../../../plugins/plugins";
|
import { PluginModel } from "../../../plugins/plugins";
|
||||||
import * as util from "../../../util/util";
|
import * as util from "../../../util/util";
|
||||||
import { commandRtnHandler } from "../../../util/util";
|
import { commandRtnHandler } from "../../../util/util";
|
||||||
@ -50,7 +50,7 @@ Are you sure you want to stop web-sharing this screen?
|
|||||||
`.trim();
|
`.trim();
|
||||||
|
|
||||||
@mobxReact.observer
|
@mobxReact.observer
|
||||||
class ScreenSettingsModal extends React.Component<{ sessionId: string; screenId: string; inline?: boolean }, {}> {
|
class ScreenSettingsModal extends React.Component<{ sessionId: string; screenId: string; }, {}> {
|
||||||
shareCopied: OV<boolean> = mobx.observable.box(false, { name: "ScreenSettings-shareCopied" });
|
shareCopied: OV<boolean> = mobx.observable.box(false, { name: "ScreenSettings-shareCopied" });
|
||||||
errorMessage: OV<string> = mobx.observable.box(null, { name: "ScreenSettings-errorMessage" });
|
errorMessage: OV<string> = mobx.observable.box(null, { name: "ScreenSettings-errorMessage" });
|
||||||
|
|
||||||
@ -194,39 +194,37 @@ class ScreenSettingsModal extends React.Component<{ sessionId: string; screenId:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@boundMethod
|
||||||
|
selectRemote(cname: string): void {
|
||||||
|
let prtn = GlobalCommandRunner.screenSetRemote(cname, true, false);
|
||||||
|
util.commandRtnHandler(prtn, this.errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { sessionId, screenId, inline } = this.props;
|
let { sessionId, screenId } = this.props;
|
||||||
|
let inline = false;
|
||||||
let screen = GlobalModel.getScreenById(sessionId, screenId);
|
let screen = GlobalModel.getScreenById(sessionId, screenId);
|
||||||
if (screen == null) {
|
if (screen == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let color: string = null;
|
let color: string = null;
|
||||||
|
let curRemote = GlobalModel.getRemote(GlobalModel.getActiveScreen().getCurRemoteInstance().remoteid);
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={cn("modal screen-settings-modal settings-modal prompt-modal is-active")}>
|
||||||
className={
|
<div className="modal-background"/>
|
||||||
inline
|
<div className="modal-content">
|
||||||
? "screen-settings-inline"
|
|
||||||
: cn("modal screen-settings-modal settings-modal prompt-modal is-active")
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{!inline && <div className="modal-background" />}
|
|
||||||
<div className={inline ? "inline-content" : "modal-content"}>
|
|
||||||
{this.shareCopied.get() && <div className="copied-indicator" />}
|
{this.shareCopied.get() && <div className="copied-indicator" />}
|
||||||
{!inline && (
|
<header>
|
||||||
<header>
|
<div className="modal-title">screen settings ({screen.name.get()})</div>
|
||||||
<div className="modal-title">screen settings ({screen.name.get()})</div>
|
<div className="close-icon hoverEffect" title="Close (Escape)" onClick={this.closeModal}>
|
||||||
<div className="close-icon hoverEffect" title="Close (Escape)" onClick={this.closeModal}>
|
<XmarkIcon />
|
||||||
<XmarkIcon />
|
</div>
|
||||||
</div>
|
</header>
|
||||||
</header>
|
|
||||||
)}
|
|
||||||
<div className="inner-content">
|
<div className="inner-content">
|
||||||
{!inline && (
|
<div className="settings-field">
|
||||||
<div className="settings-field">
|
<div className="settings-label">Screen Id</div>
|
||||||
<div className="settings-label">Screen Id</div>
|
<div className="settings-input">{screen.screenId}</div>
|
||||||
<div className="settings-input">{screen.screenId}</div>
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="settings-field">
|
<div className="settings-field">
|
||||||
<div className="settings-label">Name</div>
|
<div className="settings-label">Name</div>
|
||||||
<div className="settings-input">
|
<div className="settings-input">
|
||||||
@ -240,6 +238,12 @@ class ScreenSettingsModal extends React.Component<{ sessionId: string; screenId:
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="settings-field">
|
||||||
|
<div className="settings-label">Connection</div>
|
||||||
|
<div className="settings-input">
|
||||||
|
<ConnectionDropdown curRemote={curRemote} onSelectRemote={this.selectRemote} allowNewConn={false}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="settings-field">
|
<div className="settings-field">
|
||||||
<div className="settings-label">Tab Color</div>
|
<div className="settings-label">Tab Color</div>
|
||||||
<div className="settings-input">
|
<div className="settings-input">
|
||||||
@ -261,47 +265,41 @@ class ScreenSettingsModal extends React.Component<{ sessionId: string; screenId:
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{!inline && (
|
<div className="settings-field">
|
||||||
<div className="settings-field">
|
<div className="settings-label">
|
||||||
<div className="settings-label">
|
<div>Archived</div>
|
||||||
<div>Archived</div>
|
<InfoMessage width={400}>
|
||||||
<InfoMessage width={400}>
|
Archive will hide the screen tab. Commands and output will be retained in
|
||||||
Archive will hide the screen tab. Commands and output will be retained in
|
history.
|
||||||
history.
|
</InfoMessage>
|
||||||
</InfoMessage>
|
</div>
|
||||||
</div>
|
<div className="settings-input">
|
||||||
<div className="settings-input">
|
<Toggle checked={screen.archived.get()} onChange={this.handleChangeArchived} />
|
||||||
<Toggle checked={screen.archived.get()} onChange={this.handleChangeArchived} />
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="settings-field">
|
||||||
|
<div className="settings-label">
|
||||||
|
<div>Actions</div>
|
||||||
|
<InfoMessage width={400}>
|
||||||
|
Delete will remove the screen, removing all commands and output from history.
|
||||||
|
</InfoMessage>
|
||||||
|
</div>
|
||||||
|
<div className="settings-input">
|
||||||
|
<div
|
||||||
|
onClick={this.handleDeleteScreen}
|
||||||
|
className="button is-prompt-danger is-outlined is-small"
|
||||||
|
>
|
||||||
|
Delete Screen
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
{!inline && (
|
|
||||||
<div className="settings-field">
|
|
||||||
<div className="settings-label">
|
|
||||||
<div>Actions</div>
|
|
||||||
<InfoMessage width={400}>
|
|
||||||
Delete will remove the screen, removing all commands and output from history.
|
|
||||||
</InfoMessage>
|
|
||||||
</div>
|
|
||||||
<div className="settings-input">
|
|
||||||
<div
|
|
||||||
onClick={this.handleDeleteScreen}
|
|
||||||
className="button is-prompt-danger is-outlined is-small"
|
|
||||||
>
|
|
||||||
Delete Screen
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<SettingsError errorMessage={this.errorMessage} />
|
<SettingsError errorMessage={this.errorMessage} />
|
||||||
</div>
|
</div>
|
||||||
{!inline && (
|
<footer>
|
||||||
<footer>
|
<div onClick={this.closeModal} className="button is-prompt-green is-outlined is-small">
|
||||||
<div onClick={this.closeModal} className="button is-prompt-green is-outlined is-small">
|
Close
|
||||||
Close
|
</div>
|
||||||
</div>
|
</footer>
|
||||||
</footer>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -270,65 +270,139 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.remotes-inline {
|
.dropdown.conn-dropdown {
|
||||||
.icon {
|
padding-left: 0;
|
||||||
width: 1em;
|
border-radius: 8px;
|
||||||
height: 1em;
|
background-color: rgba(241, 246, 243, 0.08);
|
||||||
fill: @base-color;
|
|
||||||
margin: 0 0 0 1em !important;
|
.conn-dd-trigger {
|
||||||
vertical-align: middle;
|
display: flex;
|
||||||
}
|
flex-direction: row;
|
||||||
.dropdown {
|
width: 413px;
|
||||||
margin-top: 1em;
|
padding: 6px 8px 6px 12px;
|
||||||
.button {
|
align-items: center;
|
||||||
color: @base-color;
|
height: 42px;
|
||||||
border: none !important;
|
|
||||||
padding: 0 1em 0 0.2em;
|
.lefticon {
|
||||||
&:hover,
|
margin-right: 8px;
|
||||||
&:focus {
|
margin-top: 4px;
|
||||||
border: none !important;
|
position: relative;
|
||||||
box-shadow: none;
|
|
||||||
|
.status-icon {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
stroke-width: 2px;
|
||||||
|
stroke: @status-outline;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 3px;
|
||||||
|
right: -2px;
|
||||||
}
|
}
|
||||||
.remote-name {
|
}
|
||||||
vertical-align: bottom;
|
|
||||||
.remote-status {
|
.dd-control {
|
||||||
top: -2px;
|
display: flex;
|
||||||
left: 4px;
|
padding: 4px;
|
||||||
vertical-align: middle;
|
align-items: center;
|
||||||
font-size: 0.85em;
|
|
||||||
|
.icon {
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.globe-icon {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.conntext {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: flex-start;
|
||||||
|
flex: 1 0 0;
|
||||||
|
|
||||||
|
.conntext-solo {
|
||||||
|
color: @text-primary;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.conntext-1 {
|
||||||
|
color: @text-primary;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.conntext-2 {
|
||||||
|
color: @text-secondary;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.conn-dd-menu {
|
||||||
|
display: flex;
|
||||||
|
width: 413px;
|
||||||
|
padding: 6px;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: @dropdown-menu;
|
||||||
|
|
||||||
|
.dropdown-item {
|
||||||
|
display: flex;
|
||||||
|
padding: 5px 12px 5px 8px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
align-self: stretch;
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
.status-div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
padding: 3px;
|
||||||
|
|
||||||
|
svg.status-icon {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
.dropdown-content {
|
|
||||||
background: @background-session-components-solid;
|
|
||||||
}
|
|
||||||
.dropdown-item {
|
|
||||||
min-width: max-content;
|
|
||||||
}
|
|
||||||
&.is-active:hover {
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.remote-status-light {
|
|
||||||
display: inline;
|
|
||||||
margin-right: 0.5em;
|
|
||||||
}
|
|
||||||
.remote-name {
|
|
||||||
display: inline;
|
|
||||||
flex-grow: 1;
|
|
||||||
vertical-align: super;
|
|
||||||
|
|
||||||
.remote-name-primary {
|
.add-div {
|
||||||
color: @base-color;
|
display: flex;
|
||||||
max-width: inherit;
|
align-items: center;
|
||||||
margin-right: 1em;
|
justify-content: center;
|
||||||
display: inline;
|
width: 16px;
|
||||||
}
|
height: 16px;
|
||||||
|
|
||||||
|
svg.add-icon {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
|
||||||
.remote-name-secondary {
|
path {
|
||||||
color: @disabled-color;
|
fill: @text-primary;
|
||||||
max-width: inherit;
|
}
|
||||||
display: inline;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-standard {
|
||||||
|
color: @text-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-caption {
|
||||||
|
color: @text-caption;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ellipsis {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(241, 246, 243, 0.08);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import { If, For } from "tsx-control-statements/components";
|
|||||||
import cn from "classnames";
|
import cn from "classnames";
|
||||||
import { GlobalModel, GlobalCommandRunner, RemotesModalModel } from "../../model/model";
|
import { GlobalModel, GlobalCommandRunner, RemotesModalModel } from "../../model/model";
|
||||||
import { Toggle, RemoteStatusLight, InfoMessage } from "../common/common";
|
import { Toggle, RemoteStatusLight, InfoMessage } from "../common/common";
|
||||||
import { RemoteType, RemoteEditType } from "../../types/types";
|
import * as T from "../../types/types";
|
||||||
import * as util from "../../util/util";
|
import * as util from "../../util/util";
|
||||||
import * as textmeasure from "../../util/textmeasure";
|
import * as textmeasure from "../../util/textmeasure";
|
||||||
|
|
||||||
@ -17,6 +17,10 @@ import { ReactComponent as XmarkIcon } from "../assets/icons/line/xmark.svg";
|
|||||||
import { ReactComponent as AngleDownIcon } from "../assets/icons/history/angle-down.svg";
|
import { ReactComponent as AngleDownIcon } from "../assets/icons/history/angle-down.svg";
|
||||||
import { ReactComponent as RotateLeftIcon } from "../assets/icons/rotate_left.svg";
|
import { ReactComponent as RotateLeftIcon } from "../assets/icons/rotate_left.svg";
|
||||||
import { ReactComponent as AddIcon } from "../assets/icons/add.svg";
|
import { ReactComponent as AddIcon } from "../assets/icons/add.svg";
|
||||||
|
import { ReactComponent as GlobeIcon } from "../assets/icons/globe.svg";
|
||||||
|
import { ReactComponent as StatusCircleIcon } from "../assets/icons/statuscircle.svg";
|
||||||
|
import { ReactComponent as ArrowsUpDownIcon } from "../assets/icons/arrowsupdown.svg";
|
||||||
|
import { ReactComponent as CircleIcon } from "../assets/icons/circle.svg";
|
||||||
|
|
||||||
import "./connections.less";
|
import "./connections.less";
|
||||||
|
|
||||||
@ -28,14 +32,14 @@ const RemotePtyRows = 8;
|
|||||||
const RemotePtyCols = 80;
|
const RemotePtyCols = 80;
|
||||||
const PasswordUnchangedSentinel = "--unchanged--";
|
const PasswordUnchangedSentinel = "--unchanged--";
|
||||||
|
|
||||||
function getRemoteCNWithPort(remote: RemoteType) {
|
function getRemoteCNWithPort(remote: T.RemoteType) {
|
||||||
if (util.isBlank(remote.remotevars.port) || remote.remotevars.port == "22") {
|
if (util.isBlank(remote.remotevars.port) || remote.remotevars.port == "22") {
|
||||||
return remote.remotecanonicalname;
|
return remote.remotecanonicalname;
|
||||||
}
|
}
|
||||||
return remote.remotecanonicalname + ":" + remote.remotevars.port;
|
return remote.remotecanonicalname + ":" + remote.remotevars.port;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRemoteTitle(remote: RemoteType) {
|
function getRemoteTitle(remote: T.RemoteType) {
|
||||||
if (!util.isBlank(remote.remotealias)) {
|
if (!util.isBlank(remote.remotealias)) {
|
||||||
return remote.remotealias + " (" + remote.remotecanonicalname + ")";
|
return remote.remotealias + " (" + remote.remotecanonicalname + ")";
|
||||||
}
|
}
|
||||||
@ -144,7 +148,7 @@ class ConnectModeDropdown extends React.Component<{ tempVal: OV<string> }, {}> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@mobxReact.observer
|
@mobxReact.observer
|
||||||
class CreateRemote extends React.Component<{ model: RemotesModalModel; remoteEdit: RemoteEditType }, {}> {
|
class CreateRemote extends React.Component<{ model: RemotesModalModel; remoteEdit: T.RemoteEditType }, {}> {
|
||||||
tempAlias: OV<string>;
|
tempAlias: OV<string>;
|
||||||
tempHostName: OV<string>;
|
tempHostName: OV<string>;
|
||||||
tempPort: OV<string>;
|
tempPort: OV<string>;
|
||||||
@ -452,7 +456,7 @@ class CreateRemote extends React.Component<{ model: RemotesModalModel; remoteEdi
|
|||||||
|
|
||||||
@mobxReact.observer
|
@mobxReact.observer
|
||||||
class EditRemoteSettings extends React.Component<
|
class EditRemoteSettings extends React.Component<
|
||||||
{ model: RemotesModalModel; remote: RemoteType; remoteEdit: RemoteEditType },
|
{ model: RemotesModalModel; remote: T.RemoteType; remoteEdit: T.RemoteEditType },
|
||||||
{}
|
{}
|
||||||
> {
|
> {
|
||||||
tempAlias: OV<string>;
|
tempAlias: OV<string>;
|
||||||
@ -763,7 +767,7 @@ class EditRemoteSettings extends React.Component<
|
|||||||
}
|
}
|
||||||
|
|
||||||
@mobxReact.observer
|
@mobxReact.observer
|
||||||
class RemoteDetailView extends React.Component<{ model: RemotesModalModel; remote: RemoteType }, {}> {
|
class RemoteDetailView extends React.Component<{ model: RemotesModalModel; remote: T.RemoteType }, {}> {
|
||||||
termRef: React.RefObject<any> = React.createRef();
|
termRef: React.RefObject<any> = React.createRef();
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -793,7 +797,7 @@ class RemoteDetailView extends React.Component<{ model: RemotesModalModel; remot
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getRemoteTypeStr(remote: RemoteType): string {
|
getRemoteTypeStr(remote: T.RemoteType): string {
|
||||||
if (!util.isBlank(remote.uname)) {
|
if (!util.isBlank(remote.uname)) {
|
||||||
let unameStr = remote.uname;
|
let unameStr = remote.uname;
|
||||||
unameStr = unameStr.replace("|", ", ");
|
unameStr = unameStr.replace("|", ", ");
|
||||||
@ -827,7 +831,7 @@ class RemoteDetailView extends React.Component<{ model: RemotesModalModel; remot
|
|||||||
this.props.model.startEditAuth();
|
this.props.model.startEditAuth();
|
||||||
}
|
}
|
||||||
|
|
||||||
renderInstallStatus(remote: RemoteType): any {
|
renderInstallStatus(remote: T.RemoteType): any {
|
||||||
let statusStr: string = null;
|
let statusStr: string = null;
|
||||||
if (remote.installstatus == "disconnected") {
|
if (remote.installstatus == "disconnected") {
|
||||||
if (remote.needsmshellupgrade) {
|
if (remote.needsmshellupgrade) {
|
||||||
@ -851,7 +855,7 @@ class RemoteDetailView extends React.Component<{ model: RemotesModalModel; remot
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderRemoteMessage(remote: RemoteType): any {
|
renderRemoteMessage(remote: T.RemoteType): any {
|
||||||
let message: string = "";
|
let message: string = "";
|
||||||
let buttons: any[] = [];
|
let buttons: any[] = [];
|
||||||
// connect, disconnect, editauth, tryreconnect, install
|
// connect, disconnect, editauth, tryreconnect, install
|
||||||
@ -1073,7 +1077,7 @@ class RemotesModal extends React.Component<{ model: RemotesModalModel }, {}> {
|
|||||||
GlobalCommandRunner.openCreateRemote();
|
GlobalCommandRunner.openCreateRemote();
|
||||||
}
|
}
|
||||||
|
|
||||||
renderRemoteMenuItem(remote: RemoteType, selectedId: string): any {
|
renderRemoteMenuItem(remote: T.RemoteType, selectedId: string): any {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={remote.remotecanonicalname}
|
key={remote.remotecanonicalname}
|
||||||
@ -1120,7 +1124,7 @@ class RemotesModal extends React.Component<{ model: RemotesModalModel }, {}> {
|
|||||||
let model = this.props.model;
|
let model = this.props.model;
|
||||||
let selectedRemoteId = model.selectedRemoteId.get();
|
let selectedRemoteId = model.selectedRemoteId.get();
|
||||||
let allRemotes = util.sortAndFilterRemotes(GlobalModel.remotes.slice());
|
let allRemotes = util.sortAndFilterRemotes(GlobalModel.remotes.slice());
|
||||||
let remote: RemoteType = null;
|
let remote: T.RemoteType = null;
|
||||||
let isAuthEditMode = model.isAuthEditMode();
|
let isAuthEditMode = model.isAuthEditMode();
|
||||||
let selectedRemote = GlobalModel.getRemote(selectedRemoteId);
|
let selectedRemote = GlobalModel.getRemote(selectedRemoteId);
|
||||||
let remoteEdit = model.remoteEdit.get();
|
let remoteEdit = model.remoteEdit.get();
|
||||||
@ -1175,89 +1179,107 @@ class RemotesModal extends React.Component<{ model: RemotesModalModel }, {}> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@mobxReact.observer
|
@mobxReact.observer
|
||||||
class RemotesSelector extends React.Component<{ model: RemotesModalModel; isChangeRemoteOnSelect?: boolean }, { isOpen: boolean }> {
|
class ConnectionDropdown extends React.Component<{ curRemote: T.RemoteType, onSelectRemote?: (cname: string) => void, allowNewConn: boolean, onNewConn?: () => void }, {}> {
|
||||||
constructor(props: any) {
|
connDropdownActive: OV<boolean> = mobx.observable.box(false, { name: "connDropdownActive" });
|
||||||
super(props);
|
|
||||||
this.state = {
|
@boundMethod
|
||||||
isOpen: false,
|
toggleConnDropdown(): void {
|
||||||
};
|
mobx.action(() => {
|
||||||
|
this.connDropdownActive.set(!this.connDropdownActive.get());
|
||||||
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
@boundMethod
|
@boundMethod
|
||||||
selectRemote(remoteid: string, remotecanonicalname: string): void {
|
selectRemote(cname: string): void {
|
||||||
this.props.model.selectRemote(remoteid);
|
mobx.action(() => {
|
||||||
if (this.props.isChangeRemoteOnSelect) {
|
this.connDropdownActive.set(false);
|
||||||
let prtn = GlobalCommandRunner.screenSetRemote(remotecanonicalname, true, false);
|
})();
|
||||||
// TODO: see settings.tsx. use prtn to set error message
|
if (this.props.onSelectRemote) {
|
||||||
|
this.props.onSelectRemote(cname);
|
||||||
}
|
}
|
||||||
this.setState({ isOpen: false });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@boundMethod
|
@boundMethod
|
||||||
clickAddRemote(): void {
|
clickNewConnection(): void {
|
||||||
GlobalModel.remotesModalModel.openModalForEdit({remoteedit: true}, true);
|
mobx.action(() => {
|
||||||
this.setState({ isOpen: false });
|
this.connDropdownActive.set(false);
|
||||||
|
})();
|
||||||
|
if (this.props.onNewConn) {
|
||||||
|
this.props.onNewConn();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderRemoteMenuItem(remote: RemoteType, selectedId: string): any {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={remote.remoteid}
|
|
||||||
onClick={() => this.selectRemote(remote.remoteid, remote.remotecanonicalname)}
|
|
||||||
className={cn("dropdown-item remote-menu-item hoverEffect", {
|
|
||||||
"is-selected": remote.remoteid == selectedId,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<div className="remote-status-light">
|
|
||||||
<RemoteStatusLight remote={remote} />
|
|
||||||
</div>
|
|
||||||
<If condition={util.isBlank(remote.remotealias)}>
|
|
||||||
<div className="remote-name">
|
|
||||||
<div className="remote-name-primary">{remote.remotecanonicalname}</div>
|
|
||||||
</div>
|
|
||||||
</If>
|
|
||||||
<If condition={!util.isBlank(remote.remotealias)}>
|
|
||||||
<div className="remote-name">
|
|
||||||
<div className="remote-name-primary">{remote.remotealias}</div>
|
|
||||||
<div className="remote-name-secondary">{remote.remotecanonicalname}</div>
|
|
||||||
</div>
|
|
||||||
</If>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const allRemotes = util.sortAndFilterRemotes(GlobalModel.remotes.slice());
|
let { curRemote } = this.props;
|
||||||
const remote = GlobalModel.getRemote(GlobalModel.getActiveScreen().getCurRemoteInstance().remoteid);
|
let remote: T.RemoteType = null;
|
||||||
const selectedRemoteDiv = (
|
let allRemotes = util.sortAndFilterRemotes(GlobalModel.remotes.slice());
|
||||||
<div className="remote-name">
|
|
||||||
<div className="remote-status-light">
|
|
||||||
<RemoteStatusLight remote={remote} />
|
|
||||||
</div>
|
|
||||||
<div className="remote-name-primary">{remote.remotealias}</div>
|
|
||||||
<div className="remote-name-secondary">{remote.remotecanonicalname}</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<div className={"remotes-inline"}>
|
<div className={cn("dropdown", "conn-dropdown", { "is-active": this.connDropdownActive.get() })}>
|
||||||
<div className="remotes-menu">
|
<div className="dropdown-trigger" onClick={this.toggleConnDropdown}>
|
||||||
<div className={`dropdown ${this.state.isOpen ? "is-active" : ""}`}>
|
<div className="conn-dd-trigger">
|
||||||
<div className="dropdown-trigger">
|
<If condition={curRemote != null}>
|
||||||
<button className="button" onClick={() => this.setState({ isOpen: !this.state.isOpen })}>
|
<div className="lefticon">
|
||||||
{selectedRemoteDiv}
|
<GlobeIcon className="globe-icon"/>
|
||||||
<AngleDownIcon className="icon" />
|
<StatusCircleIcon className={cn("status-icon", "status-" + curRemote.status)}/>
|
||||||
</button>
|
</div>
|
||||||
</div>
|
<div className="conntext">
|
||||||
<div className="dropdown-menu" id="dropdown-menu3" role="menu">
|
<If condition={util.isBlank(curRemote.remotealias)}>
|
||||||
<div className="dropdown-content">
|
<div className="text-standard conntext-solo">
|
||||||
{allRemotes
|
{curRemote.remotecanonicalname}
|
||||||
.filter(({ remoteid }) => remoteid !== remote.remoteid)
|
</div>
|
||||||
.map((remote) => this.renderRemoteMenuItem(remote, remote.remoteid))}
|
</If>
|
||||||
<div onClick={this.clickAddRemote} className=".dropdown-item hoverEffect">
|
<If condition={!util.isBlank(curRemote.remotealias)}>
|
||||||
<AddIcon className="icon" /> Add SSH Connection
|
<div className="text-secondary conntext-1">
|
||||||
|
{curRemote.remotealias}
|
||||||
|
</div>
|
||||||
|
<div className="text-caption conntext-2">
|
||||||
|
{curRemote.remotecanonicalname}
|
||||||
|
</div>
|
||||||
|
</If>
|
||||||
|
</div>
|
||||||
|
<div className="dd-control">
|
||||||
|
<ArrowsUpDownIcon className="icon"/>
|
||||||
|
</div>
|
||||||
|
</If>
|
||||||
|
<If condition={curRemote == null}>
|
||||||
|
<div className="lefticon">
|
||||||
|
<GlobeIcon className="globe-icon"/>
|
||||||
|
</div>
|
||||||
|
<div className="conntext">
|
||||||
|
<div className="text-standard conntext-solo">
|
||||||
|
(no connection)
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="dd-control">
|
||||||
|
<ArrowsUpDownIcon className="icon"/>
|
||||||
|
</div>
|
||||||
|
</If>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="dropdown-menu" role="menu">
|
||||||
|
<div className="dropdown-content conn-dd-menu">
|
||||||
|
<For each="remote" of={allRemotes}>
|
||||||
|
<div className="dropdown-item" key={remote.remoteid} onClick={() => this.selectRemote(remote.remotecanonicalname)}>
|
||||||
|
<div className="status-div">
|
||||||
|
<CircleIcon className={cn("status-icon", "status-" + remote.status)}/>
|
||||||
|
</div>
|
||||||
|
<If condition={util.isBlank(remote.remotealias)}>
|
||||||
|
<div className="text-standard">{remote.remotecanonicalname}</div>
|
||||||
|
</If>
|
||||||
|
<If condition={!util.isBlank(remote.remotealias)}>
|
||||||
|
<div className="text-standard">{remote.remotealias}</div>
|
||||||
|
<div className="text-caption">{remote.remotecanonicalname}</div>
|
||||||
|
</If>
|
||||||
|
</div>
|
||||||
|
</For>
|
||||||
|
<If condition={this.props.allowNewConn}>
|
||||||
|
<div className="dropdown-item" onClick={this.clickNewConnection}>
|
||||||
|
<div className="add-div">
|
||||||
|
<AddIcon className="add-icon"/>
|
||||||
|
</div>
|
||||||
|
<div className="text-standard">New Connection</div>
|
||||||
|
</div>
|
||||||
|
</If>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -1265,4 +1287,4 @@ class RemotesSelector extends React.Component<{ model: RemotesModalModel; isChan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { RemotesModal, RemotesSelector };
|
export { RemotesModal, ConnectionDropdown };
|
||||||
|
@ -176,141 +176,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown.conn-dropdown {
|
|
||||||
padding-left: 0;
|
|
||||||
border-radius: 8px;
|
|
||||||
background-color: rgba(241, 246, 243, 0.08);
|
|
||||||
|
|
||||||
.conn-dd-trigger {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
width: 413px;
|
|
||||||
padding: 6px 8px 6px 12px;
|
|
||||||
align-items: center;
|
|
||||||
height: 42px;
|
|
||||||
|
|
||||||
.lefticon {
|
|
||||||
margin-right: 8px;
|
|
||||||
margin-top: 4px;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.status-icon {
|
|
||||||
width: 10px;
|
|
||||||
height: 10px;
|
|
||||||
stroke-width: 2px;
|
|
||||||
stroke: @status-outline;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 3px;
|
|
||||||
right: -2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dd-control {
|
|
||||||
display: flex;
|
|
||||||
padding: 4px;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.globe-icon {
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conntext {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: flex-start;
|
|
||||||
flex: 1 0 0;
|
|
||||||
|
|
||||||
.conntext-solo {
|
|
||||||
color: @text-primary;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conntext-1 {
|
|
||||||
color: @text-primary;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conntext-2 {
|
|
||||||
color: @text-secondary;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.conn-dd-menu {
|
|
||||||
display: flex;
|
|
||||||
width: 413px;
|
|
||||||
padding: 6px;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
border-radius: 8px;
|
|
||||||
background-color: @dropdown-menu;
|
|
||||||
|
|
||||||
.dropdown-item {
|
|
||||||
display: flex;
|
|
||||||
padding: 5px 12px 5px 8px;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
align-self: stretch;
|
|
||||||
border-radius: 6px;
|
|
||||||
|
|
||||||
.status-div {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
padding: 3px;
|
|
||||||
|
|
||||||
svg.status-icon {
|
|
||||||
width: 10px;
|
|
||||||
height: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-div {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
|
|
||||||
svg.add-icon {
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
|
|
||||||
path {
|
|
||||||
fill: @text-primary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-standard {
|
|
||||||
color: @text-secondary;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-caption {
|
|
||||||
color: @text-caption;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ellipsis {
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: rgba(241, 246, 243, 0.08);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import { getRemoteStr } from "../../common/prompt/prompt";
|
|||||||
import { GlobalModel, ScreenLines, Screen, Session } from "../../../model/model";
|
import { GlobalModel, ScreenLines, Screen, Session } from "../../../model/model";
|
||||||
import { Line } from "../../line/linecomps";
|
import { Line } from "../../line/linecomps";
|
||||||
import { LinesView } from "../../line/linesview";
|
import { LinesView } from "../../line/linesview";
|
||||||
|
import { ConnectionDropdown } from "../../connections/connections";
|
||||||
import * as util from "../../../util/util";
|
import * as util from "../../../util/util";
|
||||||
import { ReactComponent as EllipseIcon } from "../../assets/icons/ellipse.svg";
|
import { ReactComponent as EllipseIcon } from "../../assets/icons/ellipse.svg";
|
||||||
import { ReactComponent as Check12Icon } from "../../assets/icons/check12.svg";
|
import { ReactComponent as Check12Icon } from "../../assets/icons/check12.svg";
|
||||||
@ -53,7 +54,6 @@ class ScreenView extends React.Component<{ session: Session, screen: Screen }, {
|
|||||||
|
|
||||||
@mobxReact.observer
|
@mobxReact.observer
|
||||||
class NewTabSettings extends React.Component<{ screen: Screen }, {}> {
|
class NewTabSettings extends React.Component<{ screen: Screen }, {}> {
|
||||||
connDropdownActive: OV<boolean> = mobx.observable.box(false, { name: "NewTabSettings-connDropdownActive" });
|
|
||||||
errorMessage: OV<string> = mobx.observable.box(null, { name: "NewTabSettings-errorMessage" });
|
errorMessage: OV<string> = mobx.observable.box(null, { name: "NewTabSettings-errorMessage" });
|
||||||
|
|
||||||
@boundMethod
|
@boundMethod
|
||||||
@ -76,92 +76,17 @@ class NewTabSettings extends React.Component<{ screen: Screen }, {}> {
|
|||||||
util.commandRtnHandler(prtn, this.errorMessage);
|
util.commandRtnHandler(prtn, this.errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@boundMethod
|
|
||||||
toggleConnDropdown(): void {
|
|
||||||
mobx.action(() => {
|
|
||||||
this.connDropdownActive.set(!this.connDropdownActive.get());
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
|
|
||||||
@boundMethod
|
@boundMethod
|
||||||
selectRemote(cname: string): void {
|
selectRemote(cname: string): void {
|
||||||
mobx.action(() => {
|
|
||||||
this.connDropdownActive.set(false);
|
|
||||||
})();
|
|
||||||
let prtn = GlobalCommandRunner.screenSetRemote(cname, true, false);
|
let prtn = GlobalCommandRunner.screenSetRemote(cname, true, false);
|
||||||
util.commandRtnHandler(prtn, this.errorMessage);
|
util.commandRtnHandler(prtn, this.errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@boundMethod
|
@boundMethod
|
||||||
clickNewConnection(): void {
|
clickNewConnection(): void {
|
||||||
mobx.action(() => {
|
|
||||||
this.connDropdownActive.set(false);
|
|
||||||
})();
|
|
||||||
GlobalModel.remotesModalModel.openModalForEdit({remoteedit: true}, true);
|
GlobalModel.remotesModalModel.openModalForEdit({remoteedit: true}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderConnDropdown(): any {
|
|
||||||
let { screen } = this.props;
|
|
||||||
let allRemotes = util.sortAndFilterRemotes(GlobalModel.remotes.slice());
|
|
||||||
let remote: T.RemoteType = null;
|
|
||||||
let curRemote = GlobalModel.getRemote(GlobalModel.getActiveScreen().getCurRemoteInstance().remoteid);
|
|
||||||
// TODO no remote?
|
|
||||||
return (
|
|
||||||
<div className={cn("dropdown", "conn-dropdown", { "is-active": this.connDropdownActive.get() })}>
|
|
||||||
<div className="dropdown-trigger" onClick={this.toggleConnDropdown}>
|
|
||||||
<div className="conn-dd-trigger">
|
|
||||||
<div className="lefticon">
|
|
||||||
<GlobeIcon className="globe-icon"/>
|
|
||||||
<StatusCircleIcon className={cn("status-icon", "status-" + curRemote.status)}/>
|
|
||||||
</div>
|
|
||||||
<div className="conntext">
|
|
||||||
<If condition={util.isBlank(curRemote.remotealias)}>
|
|
||||||
<div className="text-standard conntext-solo">
|
|
||||||
{curRemote.remotecanonicalname}
|
|
||||||
</div>
|
|
||||||
</If>
|
|
||||||
<If condition={!util.isBlank(curRemote.remotealias)}>
|
|
||||||
<div className="text-secondary conntext-1">
|
|
||||||
{curRemote.remotealias}
|
|
||||||
</div>
|
|
||||||
<div className="text-caption conntext-2">
|
|
||||||
{curRemote.remotecanonicalname}
|
|
||||||
</div>
|
|
||||||
</If>
|
|
||||||
</div>
|
|
||||||
<div className="dd-control">
|
|
||||||
<ArrowsUpDownIcon className="icon"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="dropdown-menu" role="menu">
|
|
||||||
<div className="dropdown-content conn-dd-menu">
|
|
||||||
<For each="remote" of={allRemotes}>
|
|
||||||
<div className="dropdown-item" key={remote.remoteid} onClick={() => this.selectRemote(remote.remotecanonicalname)}>
|
|
||||||
<div className="status-div">
|
|
||||||
<CircleIcon className={cn("status-icon", "status-" + remote.status)}/>
|
|
||||||
</div>
|
|
||||||
<If condition={util.isBlank(remote.remotealias)}>
|
|
||||||
<div className="text-standard">{remote.remotecanonicalname}</div>
|
|
||||||
</If>
|
|
||||||
<If condition={!util.isBlank(remote.remotealias)}>
|
|
||||||
<div className="text-standard">{remote.remotealias}</div>
|
|
||||||
<div className="text-caption">{remote.remotecanonicalname}</div>
|
|
||||||
</If>
|
|
||||||
</div>
|
|
||||||
</For>
|
|
||||||
<div className="dropdown-item" onClick={this.clickNewConnection}>
|
|
||||||
<div className="add-div">
|
|
||||||
<AddIcon className="add-icon"/>
|
|
||||||
</div>
|
|
||||||
<div className="text-standard">New Connection</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { screen } = this.props;
|
let { screen } = this.props;
|
||||||
let rptr = screen.curRemote.get();
|
let rptr = screen.curRemote.get();
|
||||||
@ -170,6 +95,7 @@ class NewTabSettings extends React.Component<{ screen: Screen }, {}> {
|
|||||||
curColor = "green";
|
curColor = "green";
|
||||||
}
|
}
|
||||||
let color: string = null;
|
let color: string = null;
|
||||||
|
let curRemote = GlobalModel.getRemote(GlobalModel.getActiveScreen().getCurRemoteInstance().remoteid);
|
||||||
return (
|
return (
|
||||||
<div className="newtab-container">
|
<div className="newtab-container">
|
||||||
<div className="newtab-section conn-section">
|
<div className="newtab-section conn-section">
|
||||||
@ -177,7 +103,7 @@ class NewTabSettings extends React.Component<{ screen: Screen }, {}> {
|
|||||||
You're connected to [{getRemoteStr(rptr)}]. Do you want to change it?
|
You're connected to [{getRemoteStr(rptr)}]. Do you want to change it?
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{this.renderConnDropdown()}
|
<ConnectionDropdown curRemote={curRemote} allowNewConn={true} onSelectRemote={this.selectRemote} onNewConn={this.clickNewConnection}/>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-caption cr-help-text">
|
<div className="text-caption cr-help-text">
|
||||||
To change connection from the command line use `cr [alias|user@host]`
|
To change connection from the command line use `cr [alias|user@host]`
|
||||||
|
@ -332,7 +332,7 @@ class Screen {
|
|||||||
name: OV<string>;
|
name: OV<string>;
|
||||||
archived: OV<boolean>;
|
archived: OV<boolean>;
|
||||||
curRemote: OV<RemotePtrType>;
|
curRemote: OV<RemotePtrType>;
|
||||||
nextLineNum: OV<int>;
|
nextLineNum: OV<number>;
|
||||||
lastScreenSize: WindowSize;
|
lastScreenSize: WindowSize;
|
||||||
lastCols: number;
|
lastCols: number;
|
||||||
lastRows: number;
|
lastRows: number;
|
||||||
|
Loading…
Reference in New Issue
Block a user