mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-21 16:38:23 +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 { 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>
|
||||
);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 };
|
||||
|
@ -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 { 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]`
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user