mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-22 16:48:23 +01:00
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 commit962da77918
, reversing changes made to34cbe34ba5
. * 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:
parent
fc79da776c
commit
23b6bb29e7
@ -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
5
src/app/appconst.ts
Normal 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";
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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
22
src/app/common/modals/modalsRegistry.tsx
Normal file
22
src/app/common/modals/modalsRegistry.tsx
Normal 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 };
|
@ -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 (
|
||||
|
@ -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> {
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user