From 3a9f6dec6d7a03beba2028cd1de5194735be7558 Mon Sep 17 00:00:00 2001 From: Red J Adaya Date: Fri, 2 Feb 2024 11:02:45 +0800 Subject: [PATCH] remove modals.tsx as it's no longer used. rename modals.less to settings.less (#271) --- src/app/common/modals/modals.tsx | 1833 ----------------- .../modals/{modals.less => settings.less} | 0 src/app/common/modals/settings.tsx | 2 +- 3 files changed, 1 insertion(+), 1834 deletions(-) delete mode 100644 src/app/common/modals/modals.tsx rename src/app/common/modals/{modals.less => settings.less} (100%) diff --git a/src/app/common/modals/modals.tsx b/src/app/common/modals/modals.tsx deleted file mode 100644 index e154296b..00000000 --- a/src/app/common/modals/modals.tsx +++ /dev/null @@ -1,1833 +0,0 @@ -// Copyright 2023, Command Line Inc. -// SPDX-License-Identifier: Apache-2.0 - -import * as React from "react"; -import * as mobxReact from "mobx-react"; -import * as mobx from "mobx"; -import { boundMethod } from "autobind-decorator"; -import { If, For } from "tsx-control-statements/components"; -import cn from "classnames"; -import dayjs from "dayjs"; -import localizedFormat from "dayjs/plugin/localizedFormat"; -import { GlobalModel, GlobalCommandRunner, RemotesModel } from "../../../model/model"; -import * as T from "../../../types/types"; -import { - Markdown, - Toggle, - Modal, - TextField, - NumberField, - InputDecoration, - Dropdown, - PasswordField, - Tooltip, - Button, - Status, - Checkbox, - ShowWaveShellInstallPrompt, -} from "../common"; -import * as util from "../../../util/util"; -import * as textmeasure from "../../../util/textmeasure"; -import * as appconst from "../../appconst"; -import { ClientDataType } from "../../../types/types"; -import { Screen } from "../../../model/model"; -import { ReactComponent as SquareIcon } from "../../assets/icons/tab/square.svg"; - -import shield from "../../assets/icons/shield_check.svg"; -import help from "../../assets/icons/help_filled.svg"; -import github from "../../assets/icons/github.svg"; -import logo from "../../assets/waveterm-logo-with-bg.svg"; - -dayjs.extend(localizedFormat); - -// @ts-ignore -const VERSION = __WAVETERM_VERSION__; -// @ts-ignore -let BUILD = __WAVETERM_BUILD__; - -type OV = mobx.IObservableValue; -type OArr = mobx.IObservableArray; - -const RemotePtyRows = 9; -const RemotePtyCols = 80; -const NumOfLines = 50; -const PasswordUnchangedSentinel = "--unchanged--"; - -@mobxReact.observer -class ModalsProvider extends React.Component { - render() { - let store = GlobalModel.modalsModel.store.slice(); - if (GlobalModel.needsTos()) { - return ; - } - let rtn: JSX.Element[] = []; - for (let i = 0; i < store.length; i++) { - let entry = store[i]; - let Comp = entry.component; - rtn.push(); - } - return <>{rtn}; - } -} - -@mobxReact.observer -class DisconnectedModal extends React.Component<{}, {}> { - logRef: any = React.createRef(); - logs: mobx.IObservableValue = mobx.observable.box(""); - logInterval: NodeJS.Timeout = null; - - @boundMethod - restartServer() { - GlobalModel.restartWaveSrv(); - } - - @boundMethod - tryReconnect() { - GlobalModel.ws.connectNow("manual"); - } - - componentDidMount() { - this.fetchLogs(); - - this.logInterval = setInterval(() => { - this.fetchLogs(); - }, 5000); - } - - componentWillUnmount() { - if (this.logInterval) { - clearInterval(this.logInterval); - } - } - - componentDidUpdate() { - if (this.logRef.current != null) { - this.logRef.current.scrollTop = this.logRef.current.scrollHeight; - } - } - - fetchLogs() { - GlobalModel.getLastLogs( - NumOfLines, - mobx.action((logs) => { - this.logs.set(logs); - if (this.logRef.current != null) { - this.logRef.current.scrollTop = this.logRef.current.scrollHeight; - } - }) - ); - } - - render() { - return ( - - -
-
-
-
-
{this.logs.get()}
-
-
-
-
-
- - -
-
- ); - } -} - -@mobxReact.observer -class ClientStopModal extends React.Component<{}, {}> { - @boundMethod - refreshClient() { - GlobalModel.refreshClient(); - } - - render() { - let model = GlobalModel; - let cdata = model.clientData.get(); - let title = "Client Not Ready"; - return ( -
-
-
-
-
{title}
-
-
- -
Cannot get client data.
-
-
-
- -
-
-
- ); - } -} - -@mobxReact.observer -class LoadingSpinner extends React.Component<{}, {}> { - render() { - return ( -
-
-
-
-
-
- ); - } -} - -@mobxReact.observer -class AlertModal extends React.Component<{}, {}> { - @boundMethod - closeModal(): void { - GlobalModel.cancelAlert(); - } - - @boundMethod - handleOK(): void { - GlobalModel.confirmAlert(); - } - - @boundMethod - handleDontShowAgain(checked: boolean) { - let message = GlobalModel.alertMessage.get(); - if (message.confirmflag == null) { - return; - } - GlobalCommandRunner.clientSetConfirmFlag(message.confirmflag, checked); - } - - render() { - let message = GlobalModel.alertMessage.get(); - let title = message?.title ?? (message?.confirm ? "Confirm" : "Alert"); - let isConfirm = message?.confirm ?? false; - - return ( - - -
- - - - {message?.message} - - - -
-
- - - - - - - -
-
- ); - } -} - -@mobxReact.observer -class TosModal extends React.Component<{}, {}> { - @boundMethod - acceptTos(): void { - GlobalCommandRunner.clientAcceptTos(); - GlobalModel.modalsModel.popModal(); - } - - @boundMethod - handleChangeTelemetry(val: boolean): void { - if (val) { - GlobalCommandRunner.telemetryOn(false); - } else { - GlobalCommandRunner.telemetryOff(false); - } - } - - render() { - let cdata: ClientDataType = GlobalModel.clientData.get(); - - return ( - -
-
-
-
Welcome to Wave Terminal!
-
Lets set everything for you
-
-
-
- Privacy -
-
Telemetry
-
- We only collect minimal anonymous telemetry data to help us understand - how many people are using Wave. -
-
- -
- Telemetry {cdata.clientopts.notelemetry ? "Disabled" : "Enabled"} -
-
-
-
-
- - Help - -
-
Join our Community
-
- Get help, submit feature requests, report bugs, or just chat with fellow - terminal enthusiasts. -
- - Join the Wave Discord Channel - -
-
-
-
- - Github - -
-
Support us on GitHub
-
- We're open source and committed to providing a free terminal for - individual users. Please show your support us by giving us a star on{" "} - - Github (wavetermdev/waveterm) - -
-
-
-
- -
-
-
- ); - } -} - -@mobxReact.observer -class AboutModal extends React.Component<{}, {}> { - @boundMethod - closeModal(): void { - mobx.action(() => { - GlobalModel.modalsModel.popModal(); - })(); - } - - @boundMethod - isUpToDate(): boolean { - return true; - } - - @boundMethod - updateApp(): void { - // GlobalCommandRunner.updateApp(); - } - - @boundMethod - getStatus(isUpToDate: boolean): JSX.Element { - // TODO no up-to-date status reporting - return ( -
-
- Client Version {VERSION} ({BUILD}) -
-
- ); - - if (isUpToDate) { - return ( -
-
- - Up to Date -
-
- Client Version {VERSION} ({BUILD}) -
-
- ); - } - return ( -
-
- - Outdated Version -
-
- Client Version {VERSION} ({BUILD}) -
-
- -
-
- ); - } - - render() { - return ( - - -
-
-
- logo -
-
-
Wave Terminal
-
- Modern Terminal for -
- Seamless Workflow -
-
-
-
{this.getStatus(this.isUpToDate())}
- -
© 2023 Command Line Inc.
-
-
- ); - } -} - -@mobxReact.observer -class CreateRemoteConnModal extends React.Component<{}, {}> { - tempAlias: OV; - tempHostName: OV; - tempPort: OV; - tempAuthMode: OV; - tempConnectMode: OV; - tempPassword: OV; - tempKeyFile: OV; - errorStr: OV; - remoteEdit: T.RemoteEditType; - model: RemotesModel; - - constructor(props: { remotesModel?: RemotesModel }) { - super(props); - this.model = GlobalModel.remotesModel; - this.remoteEdit = this.model.remoteEdit.get(); - this.tempAlias = mobx.observable.box("", { name: "CreateRemote-alias" }); - this.tempHostName = mobx.observable.box("", { name: "CreateRemote-hostName" }); - this.tempPort = mobx.observable.box("", { name: "CreateRemote-port" }); - this.tempAuthMode = mobx.observable.box("none", { name: "CreateRemote-authMode" }); - this.tempConnectMode = mobx.observable.box("auto", { name: "CreateRemote-connectMode" }); - this.tempKeyFile = mobx.observable.box("", { name: "CreateRemote-keystr" }); - this.tempPassword = mobx.observable.box("", { name: "CreateRemote-password" }); - this.errorStr = mobx.observable.box(this.remoteEdit?.errorstr ?? null, { name: "CreateRemote-errorStr" }); - } - - componentDidMount(): void { - GlobalModel.getClientData(); - } - - remoteCName(): string { - let hostName = this.tempHostName.get(); - if (hostName == "") { - return "[no host]"; - } - if (hostName.indexOf("@") == -1) { - hostName = "[no user]@" + hostName; - } - return hostName; - } - - getErrorStr(): string { - if (this.errorStr.get() != null) { - return this.errorStr.get(); - } - return this.remoteEdit?.errorstr ?? null; - } - - @boundMethod - handleOk(): void { - ShowWaveShellInstallPrompt(this.submitRemote); - } - - @boundMethod - submitRemote(): void { - mobx.action(() => { - this.errorStr.set(null); - })(); - let authMode = this.tempAuthMode.get(); - let cname = this.tempHostName.get(); - if (cname == "") { - this.errorStr.set("You must specify a 'user@host' value to create a new connection"); - return; - } - let kwargs: Record = {}; - kwargs["alias"] = this.tempAlias.get(); - if (this.tempPort.get() != "" && this.tempPort.get() != "22") { - kwargs["port"] = this.tempPort.get(); - } - if (authMode == "key" || authMode == "key+password") { - if (this.tempKeyFile.get() == "") { - this.errorStr.set("When AuthMode is set to 'key', you must supply a valid key file name."); - return; - } - kwargs["key"] = this.tempKeyFile.get(); - } else { - kwargs["key"] = ""; - } - if (authMode == "password" || authMode == "key+password") { - if (this.tempPassword.get() == "") { - this.errorStr.set("When AuthMode is set to 'password', you must supply a password."); - return; - } - kwargs["password"] = this.tempPassword.get(); - } else { - kwargs["password"] = ""; - } - kwargs["connectmode"] = this.tempConnectMode.get(); - kwargs["visual"] = "1"; - kwargs["submit"] = "1"; - let prtn = GlobalCommandRunner.createRemote(cname, kwargs, false); - prtn.then((crtn) => { - if (crtn.success) { - this.model.setRecentConnAdded(true); - this.model.closeModal(); - - let crRtn = GlobalCommandRunner.screenSetRemote(cname, true, false); - crRtn.then((crcrtn) => { - if (crcrtn.success) { - return; - } - mobx.action(() => { - this.errorStr.set(crcrtn.error); - })(); - }); - return; - } - mobx.action(() => { - this.errorStr.set(crtn.error); - })(); - }); - } - - @boundMethod - handleChangeKeyFile(value: string): void { - mobx.action(() => { - this.tempKeyFile.set(value); - })(); - } - - @boundMethod - handleChangePassword(value: string): void { - mobx.action(() => { - this.tempPassword.set(value); - })(); - } - - @boundMethod - handleChangeAlias(value: string): void { - mobx.action(() => { - this.tempAlias.set(value); - })(); - } - - @boundMethod - handleChangeAuthMode(value: string): void { - mobx.action(() => { - this.tempAuthMode.set(value); - })(); - } - - @boundMethod - handleChangePort(value: string): void { - mobx.action(() => { - this.tempPort.set(value); - })(); - } - - @boundMethod - handleChangeHostName(value: string): void { - mobx.action(() => { - this.tempHostName.set(value); - })(); - } - - @boundMethod - handleChangeConnectMode(value: string): void { - mobx.action(() => { - this.tempConnectMode.set(value); - })(); - } - - render() { - let authMode = this.tempAuthMode.get(); - - if (this.remoteEdit == null) { - return null; - } - - return ( - - -
-
- - } - > - - - - ), - }} - /> -
-
- - } - > - - - - ), - }} - /> -
-
- - } - > - - - - ), - }} - /> -
-
- { - this.tempAuthMode.set(val); - }} - decoration={{ - endDecoration: ( - - -
  • - none - no authentication, or authentication is already - configured in your ssh config. -
  • -
  • - key - use a private key. -
  • -
  • - password - use a password. -
  • -
  • - key+password - use a key with a passphrase. -
  • - - } - icon={} - > - -
    -
    - ), - }} - /> -
    - - - } - > - - - - ), - }} - /> - - - - -
    - { - this.tempConnectMode.set(val); - }} - /> -
    - -
    Error: {this.getErrorStr()}
    -
    -
    - -
    - ); - } -} - -@mobxReact.observer -class ViewRemoteConnDetailModal extends React.Component<{}, {}> { - termRef: React.RefObject = React.createRef(); - model: RemotesModel; - - constructor(props: { remotesModel?: RemotesModel }) { - super(props); - this.model = GlobalModel.remotesModel; - } - - @mobx.computed - getSelectedRemote(): T.RemoteType { - const selectedRemoteId = this.model.selectedRemoteId.get(); - return GlobalModel.getRemote(selectedRemoteId); - } - - componentDidMount() { - let elem = this.termRef.current; - if (elem == null) { - console.log("ERROR null term-remote element"); - return; - } - this.model.createTermWrap(elem); - } - - componentDidUpdate() { - if (this.getSelectedRemote() == null || this.getSelectedRemote().archived) { - this.model.deSelectRemote(); - } - } - - componentWillUnmount() { - this.model.disposeTerm(); - } - - @boundMethod - clickTermBlock(): void { - if (this.model.remoteTermWrap != null) { - this.model.remoteTermWrap.giveFocus(); - } - } - - getRemoteTypeStr(remote: T.RemoteType): string { - if (!util.isBlank(remote.uname)) { - let unameStr = remote.uname; - unameStr = unameStr.replace("|", ", "); - return remote.remotetype + " (" + unameStr + ")"; - } - return remote.remotetype; - } - - @boundMethod - connectRemote(remoteId: string) { - GlobalCommandRunner.connectRemote(remoteId); - } - - @boundMethod - disconnectRemote(remoteId: string) { - GlobalCommandRunner.disconnectRemote(remoteId); - } - - @boundMethod - installRemote(remoteId: string) { - GlobalCommandRunner.installRemote(remoteId); - } - - @boundMethod - cancelInstall(remoteId: string) { - GlobalCommandRunner.installCancelRemote(remoteId); - } - - @boundMethod - openEditModal(): void { - GlobalModel.remotesModel.startEditAuth(); - } - - @boundMethod - getStatus(status: string) { - switch (status) { - case "connected": - return "green"; - case "disconnected": - return "gray"; - default: - return "red"; - } - } - - @boundMethod - clickArchive(): void { - if (this.getSelectedRemote() && this.getSelectedRemote().status == "connected") { - GlobalModel.showAlert({ message: "Cannot delete when connected. Disconnect and try again." }); - return; - } - let prtn = GlobalModel.showAlert({ - message: "Are you sure you want to delete this connection?", - confirm: true, - }); - prtn.then((confirm) => { - if (!confirm) { - return; - } - if (this.getSelectedRemote()) { - GlobalCommandRunner.archiveRemote(this.getSelectedRemote().remoteid); - } - GlobalModel.modalsModel.popModal(); - }); - } - - @boundMethod - clickReinstall(): void { - GlobalCommandRunner.installRemote(this.getSelectedRemote().remoteid); - } - - @boundMethod - handleClose(): void { - this.model.closeModal(); - this.model.setRecentConnAdded(false); - } - - renderInstallStatus(remote: T.RemoteType): any { - let statusStr: string = null; - if (remote.installstatus == "disconnected") { - if (remote.needsmshellupgrade) { - statusStr = "mshell " + remote.mshellversion + " - needs upgrade"; - } else if (util.isBlank(remote.mshellversion)) { - statusStr = "mshell unknown"; - } else { - statusStr = "mshell " + remote.mshellversion + " - current"; - } - } else { - statusStr = remote.installstatus; - } - if (statusStr == null) { - return null; - } - return ( -
    -
    Install Status
    -
    {statusStr}
    -
    - ); - } - - renderHeaderBtns(remote: T.RemoteType): React.ReactNode { - let buttons: React.ReactNode[] = []; - const disconnectButton = ( - - ); - const connectButton = ( - - ); - const tryReconnectButton = ( - - ); - let updateAuthButton = ( - - ); - let cancelInstallButton = ( - - ); - let installNowButton = ( - - ); - let archiveButton = ( - - ); - const reinstallButton = ( - - ); - if (remote.local) { - installNowButton = <>; - updateAuthButton = <>; - cancelInstallButton = <>; - } - if (remote.sshconfigsrc == "sshconfig-import") { - archiveButton = ( - - ); - } - if (remote.status == "connected" || remote.status == "connecting") { - buttons.push(disconnectButton); - } else if (remote.status == "disconnected") { - buttons.push(connectButton); - } else if (remote.status == "error") { - if (remote.needsmshellupgrade) { - if (remote.installstatus == "connecting") { - buttons.push(cancelInstallButton); - } else { - buttons.push(installNowButton); - } - } else { - buttons.push(tryReconnectButton); - } - } - buttons.push(reinstallButton); - buttons.push(updateAuthButton); - buttons.push(archiveButton); - - let i = 0; - let button: React.ReactNode = null; - - return ( - -
    {button}
    -
    - ); - } - - getMessage(remote: T.RemoteType): string { - let message = ""; - if (remote.status == "connected") { - message = "Connected and ready to run commands."; - } else if (remote.status == "connecting") { - message = remote.waitingforpassword ? "Connecting, waiting for user-input..." : "Connecting..."; - let connectTimeout = remote.connecttimeout ?? 0; - message = message + " (" + connectTimeout + "s)"; - } else if (remote.status == "disconnected") { - message = "Disconnected"; - } else if (remote.status == "error") { - if (remote.noinitpk) { - message = "Error, could not connect."; - } else if (remote.needsmshellupgrade) { - if (remote.installstatus == "connecting") { - message = "Installing..."; - } else { - message = "Error, needs install."; - } - } else { - message = "Error"; - } - } - - return message; - } - - render() { - let remote = this.getSelectedRemote(); - - if (remote == null) { - return null; - } - - let model = this.model; - let isTermFocused = this.model.remoteTermWrapFocus.get(); - let termFontSize = GlobalModel.termFontSize.get(); - let termWidth = textmeasure.termWidthFromCols(RemotePtyCols, termFontSize); - let remoteAliasText = util.isBlank(remote.remotealias) ? "(none)" : remote.remotealias; - let selectedRemoteStatus = this.getSelectedRemote().status; - - return ( - - -
    -
    -
    - {util.getRemoteName(remote)}  {getImportTooltip(remote)} -
    -
    {this.renderHeaderBtns(remote)}
    -
    -
    -
    -
    Conn Id
    -
    {remote.remoteid}
    -
    -
    -
    Type
    -
    {this.getRemoteTypeStr(remote)}
    -
    -
    -
    Canonical Name
    -
    - {remote.remotecanonicalname} - - (port {remote.remotevars.port}) - -
    -
    -
    -
    Alias
    -
    {remoteAliasText}
    -
    -
    -
    Auth Type
    -
    - {remote.authtype} - local -
    -
    -
    -
    Connect Mode
    -
    {remote.connectmode}
    -
    - {this.renderInstallStatus(remote)} -
    -
    - -
    -
    - -
    -
    - -
    - input is only allowed while status is 'connecting' -
    -
    -
    -
    -
    -
    -
    - - -
    - - ); - } -} - -@mobxReact.observer -class EditRemoteConnModal extends React.Component<{}, {}> { - tempAlias: OV; - tempKeyFile: OV; - tempPassword: OV; - tempConnectMode: OV; - tempAuthMode: OV; - model: RemotesModel; - - constructor(props: { remotesModel?: RemotesModel }) { - super(props); - this.model = GlobalModel.remotesModel; - this.tempAlias = mobx.observable.box(null, { name: "EditRemoteSettings-tempAlias" }); - this.tempAuthMode = mobx.observable.box(null, { name: "EditRemoteSettings-tempAuthMode" }); - this.tempKeyFile = mobx.observable.box(null, { name: "EditRemoteSettings-tempKeyFile" }); - this.tempPassword = mobx.observable.box(null, { name: "EditRemoteSettings-tempPassword" }); - this.tempConnectMode = mobx.observable.box(null, { name: "EditRemoteSettings-tempConnectMode" }); - } - - get selectedRemoteId() { - return this.model.selectedRemoteId.get(); - } - - get selectedRemote(): T.RemoteType { - return GlobalModel.getRemote(this.selectedRemoteId); - } - - get remoteEdit(): T.RemoteEditType { - return this.model.remoteEdit.get(); - } - - get isAuthEditMode(): boolean { - return this.model.isAuthEditMode(); - } - - componentDidMount(): void { - mobx.action(() => { - this.tempAlias.set(this.selectedRemote?.remotealias); - this.tempKeyFile.set(this.remoteEdit?.keystr); - this.tempPassword.set(this.remoteEdit?.haspassword ? PasswordUnchangedSentinel : ""); - this.tempConnectMode.set(this.selectedRemote?.connectmode); - this.tempAuthMode.set(this.selectedRemote?.authtype); - })(); - } - - componentDidUpdate() { - if (this.selectedRemote == null || this.selectedRemote.archived) { - this.model.deSelectRemote(); - } - } - - @boundMethod - handleChangeKeyFile(value: string): void { - mobx.action(() => { - this.tempKeyFile.set(value); - })(); - } - - @boundMethod - handleChangePassword(value: string): void { - mobx.action(() => { - this.tempPassword.set(value); - })(); - } - - @boundMethod - handleChangeAlias(value: string): void { - mobx.action(() => { - this.tempAlias.set(value); - })(); - } - - @boundMethod - handleChangeAuthMode(value: string): void { - mobx.action(() => { - this.tempAuthMode.set(value); - })(); - } - - @boundMethod - handleChangeConnectMode(value: string): void { - mobx.action(() => { - this.tempConnectMode.set(value); - })(); - } - - @boundMethod - canResetPw(): boolean { - if (this.remoteEdit == null) { - return false; - } - return Boolean(this.remoteEdit.haspassword) && this.tempPassword.get() != PasswordUnchangedSentinel; - } - - @boundMethod - resetPw(): void { - mobx.action(() => { - this.tempPassword.set(PasswordUnchangedSentinel); - })(); - } - - @boundMethod - onFocusPassword(e: any) { - if (this.tempPassword.get() == PasswordUnchangedSentinel) { - e.target.select(); - } - } - - @boundMethod - submitRemote(): void { - let authMode = this.tempAuthMode.get(); - let kwargs: Record = {}; - if (authMode == "key" || authMode == "key+password") { - let keyStrEq = util.isStrEq(this.tempKeyFile.get(), this.remoteEdit?.keystr); - if (!keyStrEq) { - kwargs["key"] = this.tempKeyFile.get(); - } - } else { - if (!util.isBlank(this.tempKeyFile.get())) { - kwargs["key"] = ""; - } - } - if (authMode == "password" || authMode == "key+password") { - if (this.tempPassword.get() != PasswordUnchangedSentinel) { - kwargs["password"] = this.tempPassword.get(); - } - } else { - if (this.remoteEdit?.haspassword) { - kwargs["password"] = ""; - } - } - if (!util.isStrEq(this.tempAlias.get(), this.selectedRemote?.remotealias)) { - kwargs["alias"] = this.tempAlias.get(); - } - if (!util.isStrEq(this.tempConnectMode.get(), this.selectedRemote?.connectmode)) { - kwargs["connectmode"] = this.tempConnectMode.get(); - } - kwargs["visual"] = "1"; - kwargs["submit"] = "1"; - GlobalCommandRunner.editRemote(this.selectedRemote?.remoteid, kwargs); - this.model.closeModal(); - } - - renderAuthModeMessage(): any { - let authMode = this.tempAuthMode.get(); - if (authMode == "none") { - return ( - - This connection requires no authentication. -
    - Or authentication is already configured in ssh_config. -
    - ); - } - if (authMode == "key") { - return Use a public/private keypair.; - } - if (authMode == "password") { - return Use a password.; - } - if (authMode == "key+password") { - return Use a public/private keypair with a passphrase.; - } - return null; - } - - render() { - let authMode = this.tempAuthMode.get(); - if (this.remoteEdit === null || !this.isAuthEditMode) { - return null; - } - return ( - - -
    -
    -
    {util.getRemoteName(this.selectedRemote)}
    -
    -
    - - } - > - - - - ), - }} - /> -
    -
    - - -
  • - none - no authentication, or authentication is already - configured in your ssh config. -
  • -
  • - key - use a private key. -
  • -
  • - password - use a password. -
  • -
  • - key+password - use a key with a passphrase. -
  • - - } - icon={} - > - -
    - - ), - }} - /> -
    - - - } - > - - - - ), - }} - /> - - - - -
    - -
    - -
    Error: {this.remoteEdit?.errorstr}
    -
    -
    - -
    - ); - } -} - -type SwitcherDataType = { - sessionId: string; - sessionName: string; - sessionIdx: number; - screenId: string; - screenIdx: number; - screenName: string; - icon: string; - color: string; -}; - -const MaxOptionsToDisplay = 100; - -@mobxReact.observer -class TabSwitcherModal extends React.Component<{}, {}> { - screens: Map>[]; - sessions: Map>[]; - options: SwitcherDataType[] = []; - sOptions: OArr = mobx.observable.array(null, { - name: "TabSwitcherModal-sOptions", - }); - focusedIdx: OV = mobx.observable.box(0, { name: "TabSwitcherModal-selectedIdx" }); - activeSessionIdx: number; - optionRefs = []; - listWrapperRef = React.createRef(); - prevFocusedIdx = 0; - - componentDidMount() { - this.activeSessionIdx = GlobalModel.getActiveSession().sessionIdx.get(); - let oSessions = GlobalModel.sessionList; - let oScreens = GlobalModel.screenMap; - oScreens.forEach((oScreen) => { - // Find the matching session in the observable array - let foundSession = oSessions.find((s) => { - if (s.sessionId === oScreen.sessionId && s.archived.get() == false) { - return true; - } - return false; - }); - - if (foundSession) { - let data: SwitcherDataType = { - sessionName: foundSession.name.get(), - sessionId: foundSession.sessionId, - sessionIdx: foundSession.sessionIdx.get(), - screenName: oScreen.name.get(), - screenId: oScreen.screenId, - screenIdx: oScreen.screenIdx.get(), - icon: this.getTabIcon(oScreen), - color: this.getTabColor(oScreen), - }; - this.options.push(data); - } - }); - - mobx.action(() => { - this.sOptions.replace(this.sortOptions(this.options).slice(0, MaxOptionsToDisplay)); - })(); - - document.addEventListener("keydown", this.handleKeyDown); - } - - componentWillUnmount() { - document.removeEventListener("keydown", this.handleKeyDown); - } - - componentDidUpdate() { - let currFocusedIdx = this.focusedIdx.get(); - - // Check if selectedIdx has changed - if (currFocusedIdx !== this.prevFocusedIdx) { - let optionElement = this.optionRefs[currFocusedIdx]?.current; - - if (optionElement) { - optionElement.scrollIntoView({ block: "nearest" }); - } - - // Update prevFocusedIdx for the next update cycle - this.prevFocusedIdx = currFocusedIdx; - } - if (currFocusedIdx >= this.sOptions.length && this.sOptions.length > 0) { - this.setFocusedIndex(this.sOptions.length - 1); - } - } - - @boundMethod - getTabIcon(screen: Screen): string { - let tabIcon = "default"; - let screenOpts = screen.opts.get(); - if (screenOpts != null && !util.isBlank(screenOpts.tabicon)) { - tabIcon = screenOpts.tabicon; - } - return tabIcon; - } - - @boundMethod - getTabColor(screen: Screen): string { - let tabColor = "default"; - let screenOpts = screen.opts.get(); - if (screenOpts != null && !util.isBlank(screenOpts.tabcolor)) { - tabColor = screenOpts.tabcolor; - } - return tabColor; - } - - @boundMethod - handleKeyDown(e) { - if (e.key === "Escape") { - this.closeModal(); - } else if (e.key === "ArrowUp" || e.key === "ArrowDown") { - e.preventDefault(); - let newIndex = this.calculateNewIndex(e.key === "ArrowUp"); - this.setFocusedIndex(newIndex); - } else if (e.key === "Enter") { - e.preventDefault(); - this.handleSelect(this.focusedIdx.get()); - } - } - - @boundMethod - calculateNewIndex(isUpKey) { - let currentIndex = this.focusedIdx.get(); - if (isUpKey) { - return Math.max(currentIndex - 1, 0); - } else { - return Math.min(currentIndex + 1, this.sOptions.length - 1); - } - } - - @boundMethod - setFocusedIndex(index) { - mobx.action(() => { - this.focusedIdx.set(index); - })(); - } - - @boundMethod - closeModal(): void { - GlobalModel.modalsModel.popModal(); - } - - @boundMethod - handleSelect(index: number): void { - const selectedOption = this.sOptions[index]; - if (selectedOption) { - GlobalCommandRunner.switchScreen(selectedOption.screenId, selectedOption.sessionId); - this.closeModal(); - } - } - - @boundMethod - handleSearch(val: string): void { - let sOptions: SwitcherDataType[]; - if (val == "") { - sOptions = this.sortOptions(this.options).slice(0, MaxOptionsToDisplay); - } else { - sOptions = this.filterOptions(val); - sOptions = this.sortOptions(sOptions); - if (sOptions.length > MaxOptionsToDisplay) { - sOptions = sOptions.slice(0, MaxOptionsToDisplay); - } - } - mobx.action(() => { - this.sOptions.replace(sOptions); - this.focusedIdx.set(0); - })(); - } - - @mobx.computed - @boundMethod - filterOptions(searchInput: string): SwitcherDataType[] { - let filteredScreens = []; - - for (let i = 0; i < this.options.length; i++) { - let tab = this.options[i]; - let match = false; - - if (searchInput.includes("/")) { - let [sessionFilter, screenFilter] = searchInput.split("/").map((s) => s.trim().toLowerCase()); - match = - tab.sessionName.toLowerCase().includes(sessionFilter) && - tab.screenName.toLowerCase().includes(screenFilter); - } else { - match = - tab.sessionName.toLowerCase().includes(searchInput) || - tab.screenName.toLowerCase().includes(searchInput); - } - - // Add tab to filtered list if it matches the criteria - if (match) { - filteredScreens.push(tab); - } - } - - return filteredScreens; - } - - @mobx.computed - @boundMethod - sortOptions(options: SwitcherDataType[]): SwitcherDataType[] { - return options.sort((a, b) => { - let aInCurrentSession = a.sessionIdx === this.activeSessionIdx; - let bInCurrentSession = b.sessionIdx === this.activeSessionIdx; - - // Tabs in the current session are sorted by screenIdx - if (aInCurrentSession && bInCurrentSession) { - return a.screenIdx - b.screenIdx; - } - // a is in the current session and b is not, so a comes first - else if (aInCurrentSession) { - return -1; - } - // b is in the current session and a is not, so b comes first - else if (bInCurrentSession) { - return 1; - } - // Both are in different, non-current sessions - sort by sessionIdx and then by screenIdx - else { - if (a.sessionIdx === b.sessionIdx) { - return a.screenIdx - b.screenIdx; - } else { - return a.sessionIdx - b.sessionIdx; - } - } - }); - } - - @boundMethod - renderIcon(option: SwitcherDataType): React.ReactNode { - let tabIcon = option.icon; - if (tabIcon === "default" || tabIcon === "square") { - return ; - } - return ; - } - - @boundMethod - renderOption(option: SwitcherDataType, index: number): JSX.Element { - if (!this.optionRefs[index]) { - this.optionRefs[index] = React.createRef(); - } - return ( -
    this.handleSelect(index)} - > -
    {this.renderIcon(option)}
    -
    - #{option.sessionName} / {option.screenName} -
    -
    - ); - } - - render() { - let option: SwitcherDataType; - let index: number; - return ( - -
    -
    - -
    Switch to Tab:
    - - ), - endDecoration: ( - - } - > - - - - ), - }} - /> -
    -
    -
    -
    - - {this.renderOption(option, index)} - -
    -
    -
    -
    -
    - ); - } -} - -const getImportTooltip = (remote: T.RemoteType): React.ReactElement => { - if (remote.sshconfigsrc == "sshconfig-import") { - return ( - } - > - - - ); - } else { - return <>; - } -}; - -export { - LoadingSpinner, - ClientStopModal, - AlertModal, - DisconnectedModal, - TosModal, - AboutModal, - CreateRemoteConnModal, - ViewRemoteConnDetailModal, - EditRemoteConnModal, - ModalsProvider, - TabSwitcherModal, -}; diff --git a/src/app/common/modals/modals.less b/src/app/common/modals/settings.less similarity index 100% rename from src/app/common/modals/modals.less rename to src/app/common/modals/settings.less diff --git a/src/app/common/modals/settings.tsx b/src/app/common/modals/settings.tsx index 1ba089a2..7f61e2ab 100644 --- a/src/app/common/modals/settings.tsx +++ b/src/app/common/modals/settings.tsx @@ -26,7 +26,7 @@ import { ReactComponent as SquareIcon } from "../../assets/icons/tab/square.svg" import { ReactComponent as GlobeIcon } from "../../assets/icons/globe.svg"; import { ReactComponent as StatusCircleIcon } from "../../assets/icons/statuscircle.svg"; -import "./modals.less"; +import "./settings.less"; type OV = mobx.IObservableValue;