abstract connection selector dropdown properly. use in settings. remove old selector.

This commit is contained in:
sawka 2023-11-02 00:08:04 -07:00
parent f2baa59af6
commit d528f3db27
6 changed files with 298 additions and 415 deletions

View File

@ -10,7 +10,7 @@ import cn from "classnames";
import { GlobalModel, GlobalCommandRunner, TabColors } from "../../../model/model";
import { Toggle, InlineSettingsTextEdit, SettingsError, InfoMessage } from "../common";
import { LineType, RendererPluginType, ClientDataType, CommandRtnType } from "../../../types/types";
import { RemotesSelector } from "../../connections/connections";
import { ConnectionDropdown } from "../../connections/connections";
import { PluginModel } from "../../../plugins/plugins";
import * as util from "../../../util/util";
import { commandRtnHandler } from "../../../util/util";
@ -50,7 +50,7 @@ Are you sure you want to stop web-sharing this screen?
`.trim();
@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" });
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() {
let { sessionId, screenId, inline } = this.props;
let { sessionId, screenId } = this.props;
let inline = false;
let screen = GlobalModel.getScreenById(sessionId, screenId);
if (screen == null) {
return null;
}
let color: string = null;
let curRemote = GlobalModel.getRemote(GlobalModel.getActiveScreen().getCurRemoteInstance().remoteid);
return (
<div
className={
inline
? "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"}>
<div className={cn("modal screen-settings-modal settings-modal prompt-modal is-active")}>
<div className="modal-background"/>
<div className="modal-content">
{this.shareCopied.get() && <div className="copied-indicator" />}
{!inline && (
<header>
<div className="modal-title">screen settings ({screen.name.get()})</div>
<div className="close-icon hoverEffect" title="Close (Escape)" onClick={this.closeModal}>
<XmarkIcon />
</div>
</header>
)}
<header>
<div className="modal-title">screen settings ({screen.name.get()})</div>
<div className="close-icon hoverEffect" title="Close (Escape)" onClick={this.closeModal}>
<XmarkIcon />
</div>
</header>
<div className="inner-content">
{!inline && (
<div className="settings-field">
<div className="settings-label">Screen Id</div>
<div className="settings-input">{screen.screenId}</div>
</div>
)}
<div className="settings-field">
<div className="settings-label">Screen Id</div>
<div className="settings-input">{screen.screenId}</div>
</div>
<div className="settings-field">
<div className="settings-label">Name</div>
<div className="settings-input">
@ -240,6 +238,12 @@ class ScreenSettingsModal extends React.Component<{ sessionId: string; screenId:
/>
</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-label">Tab Color</div>
<div className="settings-input">
@ -261,47 +265,41 @@ class ScreenSettingsModal extends React.Component<{ sessionId: string; screenId:
</div>
</div>
</div>
{!inline && (
<div className="settings-field">
<div className="settings-label">
<div>Archived</div>
<InfoMessage width={400}>
Archive will hide the screen tab. Commands and output will be retained in
history.
</InfoMessage>
</div>
<div className="settings-input">
<Toggle checked={screen.archived.get()} onChange={this.handleChangeArchived} />
<div className="settings-field">
<div className="settings-label">
<div>Archived</div>
<InfoMessage width={400}>
Archive will hide the screen tab. Commands and output will be retained in
history.
</InfoMessage>
</div>
<div className="settings-input">
<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>
)}
{!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>
)}
</div>
<SettingsError errorMessage={this.errorMessage} />
</div>
{!inline && (
<footer>
<div onClick={this.closeModal} className="button is-prompt-green is-outlined is-small">
Close
</div>
</footer>
)}
<footer>
<div onClick={this.closeModal} className="button is-prompt-green is-outlined is-small">
Close
</div>
</footer>
</div>
</div>
);

View File

@ -270,65 +270,139 @@
}
}
.remotes-inline {
.icon {
width: 1em;
height: 1em;
fill: @base-color;
margin: 0 0 0 1em !important;
vertical-align: middle;
}
.dropdown {
margin-top: 1em;
.button {
color: @base-color;
border: none !important;
padding: 0 1em 0 0.2em;
&:hover,
&:focus {
border: none !important;
box-shadow: none;
.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;
}
.remote-name {
vertical-align: bottom;
.remote-status {
top: -2px;
left: 4px;
vertical-align: middle;
font-size: 0.85em;
}
.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;
}
}
}
.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 {
color: @base-color;
max-width: inherit;
margin-right: 1em;
display: inline;
}
.add-div {
display: flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
svg.add-icon {
width: 16px;
height: 16px;
.remote-name-secondary {
color: @disabled-color;
max-width: inherit;
display: inline;
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);
}
}
}
}

View File

@ -9,7 +9,7 @@ import { If, For } from "tsx-control-statements/components";
import cn from "classnames";
import { GlobalModel, GlobalCommandRunner, RemotesModalModel } from "../../model/model";
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 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 RotateLeftIcon } from "../assets/icons/rotate_left.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";
@ -28,14 +32,14 @@ const RemotePtyRows = 8;
const RemotePtyCols = 80;
const PasswordUnchangedSentinel = "--unchanged--";
function getRemoteCNWithPort(remote: RemoteType) {
function getRemoteCNWithPort(remote: T.RemoteType) {
if (util.isBlank(remote.remotevars.port) || remote.remotevars.port == "22") {
return remote.remotecanonicalname;
}
return remote.remotecanonicalname + ":" + remote.remotevars.port;
}
function getRemoteTitle(remote: RemoteType) {
function getRemoteTitle(remote: T.RemoteType) {
if (!util.isBlank(remote.remotealias)) {
return remote.remotealias + " (" + remote.remotecanonicalname + ")";
}
@ -144,7 +148,7 @@ class ConnectModeDropdown extends React.Component<{ tempVal: OV<string> }, {}> {
}
@mobxReact.observer
class CreateRemote extends React.Component<{ model: RemotesModalModel; remoteEdit: RemoteEditType }, {}> {
class CreateRemote extends React.Component<{ model: RemotesModalModel; remoteEdit: T.RemoteEditType }, {}> {
tempAlias: OV<string>;
tempHostName: OV<string>;
tempPort: OV<string>;
@ -452,7 +456,7 @@ class CreateRemote extends React.Component<{ model: RemotesModalModel; remoteEdi
@mobxReact.observer
class EditRemoteSettings extends React.Component<
{ model: RemotesModalModel; remote: RemoteType; remoteEdit: RemoteEditType },
{ model: RemotesModalModel; remote: T.RemoteType; remoteEdit: T.RemoteEditType },
{}
> {
tempAlias: OV<string>;
@ -763,7 +767,7 @@ class EditRemoteSettings extends React.Component<
}
@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();
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)) {
let unameStr = remote.uname;
unameStr = unameStr.replace("|", ", ");
@ -827,7 +831,7 @@ class RemoteDetailView extends React.Component<{ model: RemotesModalModel; remot
this.props.model.startEditAuth();
}
renderInstallStatus(remote: RemoteType): any {
renderInstallStatus(remote: T.RemoteType): any {
let statusStr: string = null;
if (remote.installstatus == "disconnected") {
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 buttons: any[] = [];
// connect, disconnect, editauth, tryreconnect, install
@ -1073,7 +1077,7 @@ class RemotesModal extends React.Component<{ model: RemotesModalModel }, {}> {
GlobalCommandRunner.openCreateRemote();
}
renderRemoteMenuItem(remote: RemoteType, selectedId: string): any {
renderRemoteMenuItem(remote: T.RemoteType, selectedId: string): any {
return (
<div
key={remote.remotecanonicalname}
@ -1120,7 +1124,7 @@ class RemotesModal extends React.Component<{ model: RemotesModalModel }, {}> {
let model = this.props.model;
let selectedRemoteId = model.selectedRemoteId.get();
let allRemotes = util.sortAndFilterRemotes(GlobalModel.remotes.slice());
let remote: RemoteType = null;
let remote: T.RemoteType = null;
let isAuthEditMode = model.isAuthEditMode();
let selectedRemote = GlobalModel.getRemote(selectedRemoteId);
let remoteEdit = model.remoteEdit.get();
@ -1175,89 +1179,107 @@ class RemotesModal extends React.Component<{ model: RemotesModalModel }, {}> {
}
@mobxReact.observer
class RemotesSelector extends React.Component<{ model: RemotesModalModel; isChangeRemoteOnSelect?: boolean }, { isOpen: boolean }> {
constructor(props: any) {
super(props);
this.state = {
isOpen: false,
};
class ConnectionDropdown extends React.Component<{ curRemote: T.RemoteType, onSelectRemote?: (cname: string) => void, allowNewConn: boolean, onNewConn?: () => void }, {}> {
connDropdownActive: OV<boolean> = mobx.observable.box(false, { name: "connDropdownActive" });
@boundMethod
toggleConnDropdown(): void {
mobx.action(() => {
this.connDropdownActive.set(!this.connDropdownActive.get());
})();
}
@boundMethod
selectRemote(remoteid: string, remotecanonicalname: string): void {
this.props.model.selectRemote(remoteid);
if (this.props.isChangeRemoteOnSelect) {
let prtn = GlobalCommandRunner.screenSetRemote(remotecanonicalname, true, false);
// TODO: see settings.tsx. use prtn to set error message
selectRemote(cname: string): void {
mobx.action(() => {
this.connDropdownActive.set(false);
})();
if (this.props.onSelectRemote) {
this.props.onSelectRemote(cname);
}
this.setState({ isOpen: false });
}
@boundMethod
clickAddRemote(): void {
GlobalModel.remotesModalModel.openModalForEdit({remoteedit: true}, true);
this.setState({ isOpen: false });
clickNewConnection(): void {
mobx.action(() => {
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() {
const allRemotes = util.sortAndFilterRemotes(GlobalModel.remotes.slice());
const remote = GlobalModel.getRemote(GlobalModel.getActiveScreen().getCurRemoteInstance().remoteid);
const selectedRemoteDiv = (
<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>
);
let { curRemote } = this.props;
let remote: T.RemoteType = null;
let allRemotes = util.sortAndFilterRemotes(GlobalModel.remotes.slice());
return (
<div className={"remotes-inline"}>
<div className="remotes-menu">
<div className={`dropdown ${this.state.isOpen ? "is-active" : ""}`}>
<div className="dropdown-trigger">
<button className="button" onClick={() => this.setState({ isOpen: !this.state.isOpen })}>
{selectedRemoteDiv}
<AngleDownIcon className="icon" />
</button>
</div>
<div className="dropdown-menu" id="dropdown-menu3" role="menu">
<div className="dropdown-content">
{allRemotes
.filter(({ remoteid }) => remoteid !== remote.remoteid)
.map((remote) => this.renderRemoteMenuItem(remote, remote.remoteid))}
<div onClick={this.clickAddRemote} className=".dropdown-item hoverEffect">
<AddIcon className="icon" /> Add SSH Connection
<div className={cn("dropdown", "conn-dropdown", { "is-active": this.connDropdownActive.get() })}>
<div className="dropdown-trigger" onClick={this.toggleConnDropdown}>
<div className="conn-dd-trigger">
<If condition={curRemote != null}>
<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>
</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 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>
@ -1265,4 +1287,4 @@ class RemotesSelector extends React.Component<{ model: RemotesModalModel; isChan
}
}
export { RemotesModal, RemotesSelector };
export { RemotesModal, ConnectionDropdown };

View File

@ -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);
}
}
}
}
}

View File

@ -19,6 +19,7 @@ import { getRemoteStr } from "../../common/prompt/prompt";
import { GlobalModel, ScreenLines, Screen, Session } from "../../../model/model";
import { Line } from "../../line/linecomps";
import { LinesView } from "../../line/linesview";
import { ConnectionDropdown } from "../../connections/connections";
import * as util from "../../../util/util";
import { ReactComponent as EllipseIcon } from "../../assets/icons/ellipse.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
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" });
@boundMethod
@ -76,92 +76,17 @@ class NewTabSettings extends React.Component<{ screen: Screen }, {}> {
util.commandRtnHandler(prtn, this.errorMessage);
}
@boundMethod
toggleConnDropdown(): void {
mobx.action(() => {
this.connDropdownActive.set(!this.connDropdownActive.get());
})();
}
@boundMethod
selectRemote(cname: string): void {
mobx.action(() => {
this.connDropdownActive.set(false);
})();
let prtn = GlobalCommandRunner.screenSetRemote(cname, true, false);
util.commandRtnHandler(prtn, this.errorMessage);
}
@boundMethod
clickNewConnection(): void {
mobx.action(() => {
this.connDropdownActive.set(false);
})();
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() {
let { screen } = this.props;
let rptr = screen.curRemote.get();
@ -170,6 +95,7 @@ class NewTabSettings extends React.Component<{ screen: Screen }, {}> {
curColor = "green";
}
let color: string = null;
let curRemote = GlobalModel.getRemote(GlobalModel.getActiveScreen().getCurRemoteInstance().remoteid);
return (
<div className="newtab-container">
<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?
</div>
<div>
{this.renderConnDropdown()}
<ConnectionDropdown curRemote={curRemote} allowNewConn={true} onSelectRemote={this.selectRemote} onNewConn={this.clickNewConnection}/>
</div>
<div className="text-caption cr-help-text">
To change connection from the command line use `cr [alias|user@host]`

View File

@ -332,7 +332,7 @@ class Screen {
name: OV<string>;
archived: OV<boolean>;
curRemote: OV<RemotePtrType>;
nextLineNum: OV<int>;
nextLineNum: OV<number>;
lastScreenSize: WindowSize;
lastCols: number;
lastRows: number;