modals system (#106)

* init

* connections table

* view styles

* new components. header and status.

* action buttons

* use Button component in other modals

* hook add connection button

* RemoteConnDetailModal component

* refactor remotes model. read connection modal.

* remote conn detail modal layout and styles

* fix xterm styles

* use correct status message in xterm

* tone down color of settings input

* clean up

* edit remote conn modal

* fix buttons gap

* change button label

* archive and force install features

* use classnames

* add some class names and also set some widths / maxwidth for the table.  too hard to read on large screens.

* small style updates

* fix some typescript errors, other small fixups

* fix type error

* move add button to the bottom of the table

* more improvements

* adjust layout, behavior, and style accrdg to mike's feedback

* set table max-width in css

* open detail modal after creation of new remote

* new modal component. migrate about modal to new modal component.

* migrate create remote conn modal to modal component

* working modals stack

* update some working (remote -> connection).  fix typescript error in connections.  remove some console.logs

* fix a couple of mobx warnings (need to wrap in action)

* register create conn modal

* follow model naming convention

* register edit remote conn modal

* reset

* reset

* reset

* reset

* use remotes model methods and wrap pushModal calls in mobx action

* only close connect modal after update for remotes returns

* register alert modal

* fix type error in app.tsx

* migrate remote detail and alert modal to base modal component

* Revert "fix conflicts"

This reverts commit 962da77918, reversing
changes made to 34cbe34ba5.

* only wrapper ModalProvider with mobx provider

* change archive label to delete

* fix error where isOpen method does not exist

* remove registry modal

* rename ModalStoreModel to ModalsModal

* fix issue where edit remote conn modal doesn't show

* simplify modal component

* grab remoteModel from within the remote modals

* fix edit modal

* minor change

* cleanup

* more cleanup

* change confirm wording to 'delete' instead of 'archive'.  remove or-equals since isBlank is designed to check for exactly that.

* undo some of the strict typescript fixes

* undo more typescript fixes

* cleanup

* fix import

* revert build.md change
This commit is contained in:
Red J Adaya 2023-12-02 12:04:59 +08:00 committed by GitHub
parent fc79da776c
commit 23b6bb29e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 954 additions and 955 deletions

View File

@ -22,18 +22,9 @@ import {
LineSettingsModal,
ClientSettingsModal,
} from "./common/modals/settings";
import { RemotesModal } from "./connections_deprecated/connections";
import { TosModal } from "./common/modals/modals";
import { MainSideBar } from "./sidebar/sidebar";
import {
DisconnectedModal,
ClientStopModal,
AlertModal,
AboutModal,
CreateRemoteConnModal,
ViewRemoteConnDetailModal,
EditRemoteConnModal,
} from "./common/modals/modals";
import { DisconnectedModal, ClientStopModal, ModalsProvider } from "./common/modals/modals";
import { ErrorBoundary } from "./common/error/errorboundary";
import "./app.less";
@ -67,7 +58,7 @@ class App extends React.Component<{}, {}> {
opts.showCut = true;
}
let sel = window.getSelection();
if (!isBlank(sel.toString())) {
if (!isBlank(sel?.toString())) {
GlobalModel.contextEditMenu(e, opts);
} else {
if (isInNonTermInput) {
@ -89,11 +80,6 @@ class App extends React.Component<{}, {}> {
let lineSettingsModal = GlobalModel.lineSettingsModal.get();
let clientSettingsModal = GlobalModel.clientSettingsModal.get();
let remotesModel = GlobalModel.remotesModel;
let remotesModalMode = remotesModel.modalMode.get();
let selectedRemoteId = remotesModel.selectedRemoteId.get();
let selectedRemote = GlobalModel.getRemote(selectedRemoteId);
let isAuthEditMode = remotesModel.isAuthEditMode();
let remoteEdit = remotesModel.remoteEdit.get();
let disconnected = !GlobalModel.ws.open.get() || !GlobalModel.waveSrvRunning.get();
let hasClientStop = GlobalModel.getHasClientStop();
let dcWait = this.dcWait.get();
@ -135,33 +121,10 @@ class App extends React.Component<{}, {}> {
<ConnectionsView model={remotesModel} />
</ErrorBoundary>
</div>
<AlertModal />
<If condition={GlobalModel.needsTos()}>
<TosModal />
</If>
<If condition={GlobalModel.aboutModalOpen.get()}>
<AboutModal />
</If>
<If condition={remoteEdit !== null && remotesModalMode === "add"}>
<CreateRemoteConnModal model={remotesModel} remoteEdit={remoteEdit} />
</If>
<If condition={selectedRemote != null}>
<If condition={!isAuthEditMode && remotesModalMode === "read"}>
<ViewRemoteConnDetailModal
key={"remotedetail-" + selectedRemoteId}
remote={selectedRemote}
model={remotesModel}
/>
</If>
<If condition={remoteEdit !== null && isAuthEditMode && remotesModalMode === "edit"}>
<EditRemoteConnModal
key={"remotedetail-" + selectedRemoteId}
remote={selectedRemote}
model={remotesModel}
remoteEdit={remoteEdit}
/>
</If>
</If>
<ModalsProvider />
<If condition={screenSettingsModal != null}>
<ScreenSettingsModal
key={screenSettingsModal.sessionId + ":" + screenSettingsModal.screenId}

5
src/app/appconst.ts Normal file
View File

@ -0,0 +1,5 @@
export const ABOUT = "about";
export const CREATE_REMOTE = "createRemote";
export const VIEW_REMOTE = "viewRemote";
export const EDIT_REMOTE = "editRemote";
export const ALERT = "alert";

View File

@ -1045,3 +1045,76 @@
background-color: @status-connecting;
}
}
.wave-modal-container {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
z-index: 500;
.wave-modal-backdrop {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(21, 23, 21, 0.7);
z-index: 1;
}
}
.wave-modal {
z-index: 2;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 16px;
border-radius: 10px;
background: #151715;
box-shadow: 0px 3px 5px 0px rgba(0, 0, 0, 0.35), 0px 10px 24px 0px rgba(0, 0, 0, 0.45),
0px 0px 0.5px 0px rgba(255, 255, 255, 0.5) inset, 0px 0.5px 0px 0px rgba(255, 255, 255, 0.2) inset;
.wave-modal-content {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
.wave-modal-header {
width: 100%;
display: flex;
align-items: center;
padding: 12px 14px 12px 20px;
justify-content: space-between;
line-height: 20px;
border-bottom: 1px solid rgba(250, 250, 250, 0.1);
button {
i {
font-size: 18px;
}
}
}
.wave-modal-body {
width: 100%;
padding: 0px 20px;
}
.wave-modal-footer {
display: flex;
justify-content: flex-end;
width: 100%;
padding: 0 20px 20px;
button:first-child {
margin-right: 8px;
}
}
}
}

View File

@ -349,7 +349,6 @@ interface TextFieldState {
hasContent: boolean;
}
@mobxReact.observer
class TextField extends React.Component<TextFieldProps, TextFieldState> {
inputRef: React.RefObject<HTMLInputElement>;
state: TextFieldState;
@ -1097,6 +1096,68 @@ class Dropdown extends React.Component<DropdownProps, DropdownState> {
}
}
interface ModalHeaderProps {
onClose: () => void;
title: string;
}
const ModalHeader: React.FC<ModalHeaderProps> = ({ onClose, title }) => (
<div className="wave-modal-header">
{<div>{title}</div>}
<IconButton theme="secondary" variant="ghost" onClick={onClose}>
<i className="fa-sharp fa-solid fa-xmark"></i>
</IconButton>
</div>
);
interface ModalFooterProps {
onCancel?: () => void;
onOk?: () => void;
cancelLabel?: string;
okLabel?: string;
}
const ModalFooter: React.FC<ModalFooterProps> = ({ onCancel, onOk, cancelLabel = "Cancel", okLabel = "Ok" }) => (
<div className="wave-modal-footer">
<Button theme="secondary" onClick={onCancel}>
{cancelLabel}
</Button>
<Button onClick={onOk}>{okLabel}</Button>
</div>
);
interface ModalProps {
className?: string;
children?: React.ReactNode;
onClickBackdrop?: () => void;
}
class Modal extends React.Component<ModalProps> {
static Header = ModalHeader;
static Footer = ModalFooter;
renderBackdrop(onClick: (() => void) | undefined) {
return <div className="wave-modal-backdrop" onClick={onClick}></div>;
}
renderModal() {
const { className, children } = this.props;
return (
<div className="wave-modal-container">
{this.renderBackdrop(this.props.onClickBackdrop)}
<div className={`wave-modal ${className}`}>
<div className="wave-modal-content">{children}</div>
</div>
</div>
);
}
render() {
return ReactDOM.createPortal(this.renderModal(), document.getElementById("app") as HTMLElement);
}
}
export {
CmdStrCode,
Toggle,
@ -1117,4 +1178,5 @@ export {
IconButton,
LinkButton,
Status,
Modal,
};

View File

@ -59,22 +59,6 @@
}
}
.modal.alert-modal {
z-index: 205;
footer {
justify-content: center;
.button {
margin-left: 20px;
}
.button:first-child {
margin-left: 0;
}
}
}
.modal.settings-modal {
footer {
justify-content: center;
@ -181,59 +165,6 @@
}
}
.modal.wave-modal {
.wave-modal-content {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 16px;
border-radius: 10px;
background: var(--olive-dark-1, #151715);
box-shadow: 0px 3px 5px 0px rgba(0, 0, 0, 0.35), 0px 10px 24px 0px rgba(0, 0, 0, 0.45),
0px 0px 0.5px 0px rgba(255, 255, 255, 0.5) inset, 0px 0.5px 0px 0px rgba(255, 255, 255, 0.2) inset;
.wave-modal-content-inner {
display: flex;
flex-direction: column;
align-items: center;
gap: 24px;
width: 100%;
.wave-modal-header {
width: 100%;
display: flex;
align-items: center;
padding: 12px 20px;
justify-content: space-between;
line-height: 20px;
border-bottom: 1px solid rgba(250, 250, 250, 0.1);
.wave-modal-title {
color: @term-bright-white;
font-style: normal;
line-height: 20px;
font-size: 13px;
}
.wave-modal-close {
display: flex;
padding: 4px;
align-items: center;
gap: 8px;
}
}
.wave-modal-body {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 24px;
width: 87%;
}
}
}
}
.modal.tos-modal {
.modal-content.wave-modal-content {
padding: 32px 48px;
@ -323,14 +254,26 @@
}
}
.modal.about-modal {
.about-wave-modal-content {
width: 401px;
.about-modal {
width: 382px;
.about-wave-modal-body {
.wave-modal-content {
gap: 24px;
.wave-modal-body {
margin-bottom: 0;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 24px;
.about-section {
display: flex;
align-items: center;
gap: 16px;
align-self: stretch;
width: 100%;
.wave-modal-section {
.logo-wrapper {
width: 72px;
height: 72px;
@ -403,7 +346,7 @@
}
}
.wave-modal-section:nth-child(3) {
.about-section:nth-child(3) {
display: flex;
align-items: flex-start;
gap: 10px;
@ -418,7 +361,7 @@
}
}
.wave-modal-section:last-child {
.about-section:last-child {
margin-bottom: 24px;
color: @term-white;
}
@ -426,251 +369,195 @@
}
}
.wave-modal.crconn-modal {
.wave-modal-content.crconn-wave-modal-content {
width: 452px;
min-height: 411px;
overflow: visible;
.crconn-modal {
width: 452px;
min-height: 411px;
.wave-modal-content-inner.crconn-wave-modal-content-inner {
.wave-modal-content {
gap: 24px;
.wave-modal-body {
display: flex;
padding-bottom: 0px;
padding: 0px 20px;
flex-direction: column;
align-items: center;
gap: 20px;
flex-shrink: 0;
align-items: flex-start;
gap: 12px;
align-self: stretch;
width: 100%;
}
}
}
.crconn-wave-modal-body {
.erconn-modal {
width: 502px;
min-height: 411px;
.wave-modal-content {
gap: 20px;
.wave-modal-body {
display: flex;
padding: 0px 20px;
flex-direction: column;
align-items: flex-start;
gap: 12px;
align-self: stretch;
width: 100%;
> div {
width: 100%;
}
.name-actions-section {
margin-bottom: 10px;
display: flex;
padding: 0px 20px;
flex-direction: column;
align-items: flex-start;
gap: 12px;
align-self: stretch;
width: 100%;
}
}
.crconn-wave-modal-footer {
display: flex;
justify-content: flex-end;
width: 100%;
padding: 0 20px 20px;
.name {
color: @term-bright-white;
font-size: 15px;
font-weight: 500;
line-height: 20px;
}
.action-buttons {
display: flex;
.header-actions {
display: flex;
justify-content: flex-end;
align-items: flex-start;
button:first-child {
margin-right: 8px;
.wave-button {
padding: 4px 15px;
font-size: 11px;
margin-right: 8px;
}
}
}
}
}
}
.wave-modal.rconndetail-modal {
.wave-modal-content.rconndetail-wave-modal-content {
width: 631px;
min-height: 565px;
overflow: visible;
.alert-modal {
.wave-modal-content {
.wave-modal-body {
padding: 40px 20px;
}
}
}
.wave-modal-content-inner.rconndetail-wave-modal-content-inner {
.rconndetail-modal {
width: 631px;
min-height: 565px;
.wave-modal-content {
display: flex;
padding-bottom: 0px;
flex-direction: column;
align-items: center;
gap: 20px;
flex-shrink: 0;
.wave-modal-body {
display: flex;
padding: 0px 20px;
align-items: flex-start;
width: 100%;
display: flex;
padding-bottom: 0px;
flex-direction: column;
align-items: center;
gap: 20px;
flex-shrink: 0;
gap: 16px;
align-self: stretch;
.rconndetail-wave-modal-body {
display: flex;
padding: 0px 20px;
align-items: flex-start;
width: 100%;
.name-header-actions-wrapper {
display: flex;
flex-direction: column;
gap: 16px;
align-self: stretch;
align-items: flex-start;
gap: 12px;
.name-header-actions-wrapper {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 12px;
.rconndetail-name {
color: @term-bright-white;
font-size: 15px;
font-weight: 500;
line-height: 20px;
}
.header-actions {
display: flex;
justify-content: flex-end;
align-items: flex-start;
.wave-button {
padding: 4px 15px;
font-size: 11px;
margin-right: 8px;
}
}
.rconndetail-name {
color: @term-bright-white;
font-size: 15px;
font-weight: 500;
line-height: 20px;
}
.remote-detail {
.settings-field {
.header-actions {
display: flex;
justify-content: flex-end;
align-items: flex-start;
.wave-button {
padding: 4px 15px;
font-size: 11px;
margin-right: 8px;
}
}
}
.remote-detail {
.settings-field {
display: flex;
flex-direction: row;
align-items: center;
.settings-label {
font-weight: bold;
width: 12em;
display: flex;
flex-direction: row;
align-items: center;
.settings-label {
font-weight: bold;
width: 12em;
display: flex;
flex-direction: row;
align-items: center;
}
.settings-input {
display: flex;
flex-direction: row;
align-items: center;
color: @term-white;
}
}
.settings-field:not(:first-child) {
margin-top: 4px;
}
.status {
.settings-input {
display: flex;
height: 30px;
padding: 3px 8px;
flex-direction: row;
align-items: center;
gap: 8px;
align-self: stretch;
border-radius: 6px;
background: rgba(241, 246, 243, 0.08);
}
.terminal-wrapper {
width: 100%;
margin-top: 5px;
.terminal-connectelem {
height: 163px !important; // Needed to override plugin height
.xterm-viewport {
display: flex;
padding: 6px 10px;
gap: 8px;
align-items: flex-start;
align-self: stretch;
border-radius: 6px;
border: 1px solid var(--element-separator, rgba(241, 246, 243, 0.15));
background: #080a08;
height: 163px !important; // Needed to override plugin height
}
.xterm-screen {
padding: 10px;
width: 541px !important; // Needed to override plugin width
}
}
color: @term-white;
}
}
}
}
.rconndetail-wave-modal-footer {
display: flex;
justify-content: flex-end;
width: 100%;
padding: 0 20px 20px;
.action-buttons {
display: flex;
button:first-child {
margin-right: 8px;
}
}
}
}
}
.wave-modal.erconn-modal {
.wave-modal-content.erconn-wave-modal-content {
width: 502px;
min-height: 411px;
overflow: visible;
.wave-modal-content-inner.erconn-wave-modal-content-inner {
display: flex;
padding-bottom: 0px;
flex-direction: column;
align-items: center;
gap: 20px;
flex-shrink: 0;
.erconn-wave-modal-body {
display: flex;
padding: 0px 20px;
flex-direction: column;
align-items: flex-start;
gap: 12px;
align-self: stretch;
width: 100%;
> div {
width: 100%;
.settings-field:not(:first-child) {
margin-top: 4px;
}
.name-actions-section {
margin-bottom: 10px;
.status {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 12px;
height: 30px;
padding: 3px 8px;
align-items: center;
gap: 8px;
align-self: stretch;
border-radius: 6px;
background: rgba(241, 246, 243, 0.08);
}
.name {
color: @term-bright-white;
font-size: 15px;
font-weight: 500;
line-height: 20px;
}
.terminal-wrapper {
width: 100%;
margin-top: 5px;
.header-actions {
display: flex;
justify-content: flex-end;
align-items: flex-start;
.terminal-connectelem {
height: 163px !important; // Needed to override plugin height
.wave-button {
padding: 4px 15px;
font-size: 11px;
margin-right: 8px;
.xterm-viewport {
display: flex;
padding: 6px 10px;
gap: 8px;
align-items: flex-start;
align-self: stretch;
border-radius: 6px;
border: 1px solid var(--element-separator, rgba(241, 246, 243, 0.15));
background: #080a08;
height: 163px !important; // Needed to override plugin height
}
.xterm-screen {
padding: 10px;
width: 541px !important; // Needed to override plugin width
}
}
}
}
}
.erconn-wave-modal-footer {
display: flex;
justify-content: flex-end;
width: 100%;
padding: 0 20px 20px;
.action-buttons {
display: flex;
button:first-child {
margin-right: 8px;
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import * as React from "react";
import {
AboutModal,
CreateRemoteConnModal,
ViewRemoteConnDetailModal,
EditRemoteConnModal,
AlertModal,
} from "./modals";
import * as constants from "../../appconst";
const modalsRegistry: { [key: string]: () => React.ReactElement } = {
[constants.ABOUT]: () => <AboutModal />,
[constants.CREATE_REMOTE]: () => <CreateRemoteConnModal />,
[constants.VIEW_REMOTE]: () => <ViewRemoteConnDetailModal />,
[constants.EDIT_REMOTE]: () => <EditRemoteConnModal />,
[constants.ALERT]: () => <AlertModal />,
};
export { modalsRegistry };

View File

@ -20,7 +20,7 @@ type OV<V> = mobx.IObservableValue<V>;
class ConnectionsView extends React.Component<{ model: RemotesModel }, { hoveredItemId: string }> {
tableRef: React.RefObject<any> = React.createRef();
tableWidth: OV<number> = mobx.observable.box(0, { name: "tableWidth" });
tableRszObs: ResizeObserver;
tableRszObs: ResizeObserver = null;
constructor(props) {
super(props);
@ -105,7 +105,6 @@ class ConnectionsView extends React.Component<{ model: RemotesModel }, { hovered
}
let items = util.sortAndFilterRemotes(GlobalModel.remotes.slice());
let remote = this.props.model.selectedRemoteId.get();
let item: T.RemoteType = null;
return (

View File

@ -1,6 +1,7 @@
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import type React from "react";
import * as mobx from "mobx";
import { sprintf } from "sprintf-js";
import { boundMethod } from "autobind-decorator";
@ -65,7 +66,6 @@ import type {
import * as T from "../types/types";
import { WSControl } from "./ws";
import {
measureText,
getMonoFontSize,
windowWidthToCols,
windowHeightToRows,
@ -76,8 +76,9 @@ import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import customParseFormat from "dayjs/plugin/customParseFormat";
import { getRendererContext, cmdStatusIsRunning } from "../app/line/lineutil";
import { sortAndFilterRemotes } from "../util/util";
import { MagicLayout } from "../app/magiclayout";
import { modalsRegistry } from "../app/common/modals/modalsRegistry";
import * as constants from "../app/appconst";
dayjs.extend(customParseFormat);
dayjs.extend(localizedFormat);
@ -2709,13 +2710,10 @@ class RemotesModalModel {
}
class RemotesModel {
modalMode: OV<null | "read" | "add" | "edit"> = mobx.observable.box(null, {
name: "RemotesModel-modalMode",
});
selectedRemoteId: OV<string> = mobx.observable.box(null, {
name: "RemotesModel-selectedRemoteId",
});
remoteTermWrap: TermWrap;
remoteTermWrap: TermWrap = null;
remoteTermWrapFocus: OV<boolean> = mobx.observable.box(false, {
name: "RemotesModel-remoteTermWrapFocus",
});
@ -2730,10 +2728,6 @@ class RemotesModel {
name: "RemotesModel-recentlyAdded",
});
isOpen(): boolean {
return this.modalMode.get() != null;
}
get recentConnAdded(): boolean {
return this.recentConnAddedState.get();
}
@ -2753,26 +2747,26 @@ class RemotesModel {
mobx.action(() => {
this.selectedRemoteId.set(remoteId);
this.remoteEdit.set(null);
this.modalMode.set("read");
GlobalModel.modalsModel.pushModal(constants.VIEW_REMOTE);
})();
}
openAddModal(redit: RemoteEditType): void {
mobx.action(() => {
this.remoteEdit.set(redit);
this.modalMode.set("add");
GlobalModel.modalsModel.pushModal(constants.CREATE_REMOTE);
})();
}
openEditModal(redit?: RemoteEditType): void {
if (redit === undefined) {
if (redit == null) {
this.startEditAuth();
}
if (redit != null) {
GlobalModel.modalsModel.pushModal(constants.EDIT_REMOTE);
} else {
mobx.action(() => {
this.selectedRemoteId.set(redit.remoteid);
this.selectedRemoteId.set(redit?.remoteid);
this.remoteEdit.set(redit);
this.modalMode.set("edit");
GlobalModel.modalsModel.pushModal(constants.EDIT_REMOTE);
})();
}
}
@ -2795,10 +2789,6 @@ class RemotesModel {
}
}
getModalMode(): string {
return this.modalMode.get();
}
isAuthEditMode(): boolean {
return this.remoteEdit.get() != null;
}
@ -2806,8 +2796,7 @@ class RemotesModel {
@boundMethod
closeModal(): void {
mobx.action(() => {
this.modalMode.set(null);
this.selectedRemoteId.set(null);
GlobalModel.modalsModel.popModal();
})();
setTimeout(() => GlobalModel.refocus(), 10);
}
@ -2904,6 +2893,32 @@ class RemotesModel {
}
}
class ModalsModel {
store: Array<{ id: string; component: React.ComponentType }> = [];
constructor() {
mobx.makeAutoObservable(this);
}
pushModal(modalId: string) {
const modalFactory = modalsRegistry[modalId];
if (modalFactory && !this.store.some((modal) => modal.id === modalId)) {
this.store.push({ id: modalId, component: modalFactory });
}
}
popModal() {
this.store.pop();
}
get activeModals() {
return this.store.slice().map((modal) => {
return modal.component;
});
}
}
class Model {
clientId: string;
activeSessionId: OV<string> = mobx.observable.box(null, {
@ -2965,6 +2980,7 @@ class Model {
bookmarksModel: BookmarksModel;
historyViewModel: HistoryViewModel;
connectionViewModel: ConnectionsViewModel;
modalsModel: ModalsModel;
clientData: OV<ClientDataType> = mobx.observable.box(null, {
name: "clientData",
});
@ -2987,6 +3003,7 @@ class Model {
this.connectionViewModel = new ConnectionsViewModel();
this.remotesModalModel = new RemotesModalModel();
this.remotesModel = new RemotesModel();
this.modalsModel = new ModalsModel();
let isWaveSrvRunning = getApi().getWaveSrvStatus();
this.waveSrvRunning = mobx.observable.box(isWaveSrvRunning, {
name: "model-wavesrv-running",
@ -3075,6 +3092,7 @@ class Model {
showAlert(alertMessage: AlertMessageType): Promise<boolean> {
mobx.action(() => {
this.alertMessage.set(alertMessage);
GlobalModel.modalsModel.pushModal(constants.ALERT);
})();
let prtn = new Promise<boolean>((resolve, reject) => {
this.alertPromiseResolver = resolve;
@ -3085,6 +3103,7 @@ class Model {
cancelAlert(): void {
mobx.action(() => {
this.alertMessage.set(null);
GlobalModel.modalsModel.popModal();
})();
if (this.alertPromiseResolver != null) {
this.alertPromiseResolver(false);
@ -3095,6 +3114,7 @@ class Model {
confirmAlert(): void {
mobx.action(() => {
this.alertMessage.set(null);
GlobalModel.modalsModel.popModal();
})();
if (this.alertPromiseResolver != null) {
this.alertPromiseResolver(true);
@ -3212,10 +3232,6 @@ class Model {
GlobalModel.screenSettingsModal.set(null);
didSomething = true;
}
if (GlobalModel.remotesModel.isOpen()) {
GlobalModel.remotesModel.closeModal();
didSomething = true;
}
if (GlobalModel.clientSettingsModal.get()) {
GlobalModel.clientSettingsModal.set(false);
didSomething = true;
@ -3355,7 +3371,7 @@ class Model {
onMenuItemAbout(): void {
mobx.action(() => {
this.aboutModalOpen.set(true);
this.modalsModel.pushModal(constants.ABOUT);
})();
}
@ -3486,8 +3502,9 @@ class Model {
this.remotes.clear();
}
this.updateRemotes(update.remotes);
if (update.remotes?.length && this.remotesModel.recentConnAddedState.get()) {
this.remotesModel.openReadModal(update.remotes[0].remoteid);
if (update.remotes && update.remotes.length && this.remotesModel.recentConnAddedState.get()) {
GlobalModel.remotesModel.closeModal();
GlobalModel.remotesModel.openReadModal(update.remotes![0].remoteid);
}
}
if ("mainview" in update) {
@ -3737,7 +3754,7 @@ class Model {
submitCommand(
metaCmd: string,
metaSubCmd: string,
args: string[] | null,
args: string[],
kwargs: Record<string, string>,
interactive: boolean
): Promise<CommandRtnType> {
@ -3816,12 +3833,10 @@ class Model {
}
getRemote(remoteId: string): RemoteType {
for (let i = 0; i < this.remotes.length; i++) {
if (this.remotes[i].remoteid == remoteId) {
return this.remotes[i];
}
if (remoteId == null) {
return null;
}
return null;
return this.remotes.find((remote) => remote.remoteid === remoteId);
}
getRemoteNames(): Record<string, string> {

View File

@ -168,7 +168,7 @@ type FeCmdPacketType = {
type: string;
metacmd: string;
metasubcmd?: string;
args: string[] | null;
args: string[];
kwargs: Record<string, string>;
rawstr?: string;
uicontext: UIContextType;