Merge pull request #119 from wavetermdev/dev-0.5.1

pull dev-0.5.1 branch to main
This commit is contained in:
Mike Sawka
2023-12-04 09:55:11 -08:00
committed by GitHub
36 changed files with 4212 additions and 2349 deletions
+1 -1
View File
@@ -33,7 +33,7 @@ WAVETERM_DEV=1 PCLOUD_ENDPOINT="https://ot2e112zx5.execute-api.us-west-2.amazona
```bash
# @scripthaus command typecheck
# @scripthaus cd :playbook
node_modules/.bin/tsc --jsx preserve --noEmit --esModuleInterop --target ES5 --experimentalDecorators --downlevelIteration src/index.ts src/types/custom.d.ts
node_modules/.bin/tsc --noEmit
```
```bash
+49 -23
View File
@@ -49,6 +49,14 @@ textarea {
}
}
.text-primary {
font-size: 15px;
font-weight: 500;
line-height: 20px;
font-family: @text-s1-font;
color: @text-primary;
}
.text-standard {
font-size: 12.5px;
font-weight: 300;
@@ -80,6 +88,15 @@ textarea {
height: 16px;
}
body a {
color: @wave-green;
cursor: pointer;
text-decoration: none;
&:hover {
color: @wave-green;
}
}
body code {
font-family: @terminal-font;
}
@@ -148,10 +165,10 @@ svg.icon {
border-radius: 5px;
cursor: pointer;
background-color: @button-background !important;
color: @prompt-green;
color: @wave-green;
.hoverEffect;
&:hover {
color: @prompt-green;
color: @wave-green;
}
&.disabled {
color: fade(@disabled-color, 60%);
@@ -176,12 +193,6 @@ svg.icon {
left: 0;
}
.content {
a:hover {
color: #485fc7;
}
}
input[type="checkbox"] {
cursor: pointer;
}
@@ -219,7 +230,8 @@ a.a-block {
.history-view,
.bookmarks-view,
.plugins-view {
.plugins-view,
.connections-view {
flex-grow: 1;
display: flex;
flex-direction: column;
@@ -465,85 +477,99 @@ a.a-block {
}
.icon.color-red {
path, circle {
path,
circle {
fill: @tab-red;
}
}
.icon.color-green {
path, circle {
path,
circle {
fill: @tab-green;
}
}
.icon.color-orange {
path, circle {
path,
circle {
fill: @tab-orange;
}
}
.icon.color-blue {
path, circle {
path,
circle {
fill: @tab-blue;
}
}
.icon.color-yellow {
path, circle {
path,
circle {
fill: @tab-yellow;
}
}
.icon.color-pink {
path, circle {
path,
circle {
fill: @tab-pink;
}
}
.icon.color-mint {
path, circle {
path,
circle {
fill: @tab-mint;
}
}
.icon.color-cyan {
path, circle {
path,
circle {
fill: @tab-cyan;
}
}
.icon.color-violet {
path, circle {
path,
circle {
fill: @tab-violet;
}
}
.icon.color-white {
path, circle {
path,
circle {
fill: @tab-white;
}
}
.status-icon.status-connected {
path, circle {
path,
circle {
fill: @status-connected;
}
}
.status-icon.status-connecting {
path, circle {
path,
circle {
fill: @status-connecting;
}
}
.status-icon.status-disconnected {
path, circle {
path,
circle {
fill: @status-disconnected;
}
}
.status-icon.status-error {
path, circle {
path,
circle {
fill: @status-error;
}
}
+7 -24
View File
@@ -15,22 +15,16 @@ import { WorkspaceView } from "./workspace/workspaceview";
import { PluginsView } from "./pluginsview/pluginsview";
import { BookmarksView } from "./bookmarks/bookmarks";
import { HistoryView } from "./history/history";
import { ConnectionsView } from "./connections/connections";
import {
ScreenSettingsModal,
SessionSettingsModal,
LineSettingsModal,
ClientSettingsModal,
} from "./common/modals/settings";
import { RemotesModal } from "./connections/connections";
import { TosModal } from "./common/modals/modals";
import { MainSideBar } from "./sidebar/sidebar";
import {
DisconnectedModal,
ClientStopModal,
AlertModal,
AboutModal,
CreateRemoteConnModal,
} from "./common/modals/modals";
import { DisconnectedModal, ClientStopModal, ModalsProvider } from "./common/modals/modals";
import { ErrorBoundary } from "./common/error/errorboundary";
import "./app.less";
@@ -64,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) {
@@ -85,14 +79,12 @@ class App extends React.Component<{}, {}> {
let sessionSettingsModal = GlobalModel.sessionSettingsModal.get();
let lineSettingsModal = GlobalModel.lineSettingsModal.get();
let clientSettingsModal = GlobalModel.clientSettingsModal.get();
let remotesModel = GlobalModel.remotesModalModel;
let remotesModal = remotesModel.isOpen();
let selectedRemoteId = remotesModel.selectedRemoteId.get();
let remoteEdit = remotesModel.remoteEdit.get();
let remotesModel = GlobalModel.remotesModel;
let disconnected = !GlobalModel.ws.open.get() || !GlobalModel.waveSrvRunning.get();
let hasClientStop = GlobalModel.getHasClientStop();
let dcWait = this.dcWait.get();
let platform = GlobalModel.getPlatform();
if (disconnected || hasClientStop) {
if (!dcWait) {
setTimeout(() => this.updateDcWait(true), 1500);
@@ -117,7 +109,6 @@ class App extends React.Component<{}, {}> {
if (dcWait) {
setTimeout(() => this.updateDcWait(false), 0);
}
//console.log(`GlobalModel.activeMainView.get() = ${GlobalModel.activeMainView.get()}`); // @mike - if I remove this, I cant see plugins
return (
<div id="main" className={"platform-" + platform} onContextMenu={this.handleContextMenu}>
<div className="main-content">
@@ -127,18 +118,13 @@ class App extends React.Component<{}, {}> {
<WorkspaceView />
<HistoryView />
<BookmarksView />
<ConnectionsView model={remotesModel} />
</ErrorBoundary>
</div>
<AlertModal />
<If condition={GlobalModel.needsTos()}>
<TosModal />
</If>
<If condition={GlobalModel.aboutModalOpen.get()}>
<AboutModal />
</If>
<If condition={remoteEdit !== null && !remoteEdit.old}>
<CreateRemoteConnModal model={remotesModel} remoteEdit={remoteEdit} />
</If>
<ModalsProvider />
<If condition={screenSettingsModal != null}>
<ScreenSettingsModal
key={screenSettingsModal.sessionId + ":" + screenSettingsModal.screenId}
@@ -155,9 +141,6 @@ class App extends React.Component<{}, {}> {
<If condition={clientSettingsModal}>
<ClientSettingsModal />
</If>
<If condition={remotesModal}>
<RemotesModal model={GlobalModel.remotesModalModel} />
</If>
</div>
);
}
+5
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";
+236 -29
View File
@@ -247,7 +247,7 @@
}
}
.button.is-prompt-green {
.button.is-wave-green {
background-color: #222;
color: @term-white;
@@ -257,33 +257,6 @@
}
}
.wave-button {
display: flex;
padding: 6px 16px !important;
color: @term-white !important;
align-items: center;
gap: 4px;
border-radius: 6px !important;
height: auto !important;
&:hover {
color: @term-white !important;
}
}
.wave-button.is-wave-green {
color: @term-bright-white !important;
background: @term-green !important;
&:hover {
background-color: @term-green;
box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.4), 0px 0px 0.5px 0px rgba(0, 0, 0, 0.5),
0px 0px 0.5px 0px rgba(255, 255, 255, 0.8) inset, 0px 0.5px 0px 0px rgba(255, 255, 255, 0.6) inset;
color: @term-bright-white !important;
box-shadow: none;
}
}
.button.is-plain,
.button.is-prompt-cancel {
background-color: #222;
@@ -637,7 +610,8 @@
position: relative;
background-color: transparent;
height: 44px;
width: 412px;
min-width: 412px;
width: 100%;
border: 1px solid var(--element-separator, rgba(241, 246, 243, 0.15));
border-radius: 6px;
background: var(--element-hover-2, rgba(255, 255, 255, 0.06));
@@ -801,10 +775,18 @@
box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.4), 0px 0px 0.5px 0px rgba(0, 0, 0, 0.5),
0px 0px 0.5px 0px rgba(255, 255, 255, 0.5) inset, 0px 0.5px 0px 0px rgba(255, 255, 255, 0.2) inset;
&:hover {
cursor: text;
}
&.focused {
border-color: @term-green;
}
&.disabled {
opacity: 0.75;
}
&.error {
border-color: @term-red;
}
@@ -931,3 +913,228 @@
}
}
}
.wave-button {
background: none;
color: inherit;
border: none;
padding: 0;
font: inherit;
cursor: pointer;
outline: inherit;
display: flex;
padding: 6px 16px;
align-items: center;
gap: 4px;
border-radius: 6px;
height: auto;
&:hover {
color: @term-white;
}
i {
fill: rgba(255, 255, 255, 0.12);
}
&.primary {
color: @term-green;
background: none;
i {
fill: @term-green;
}
&.solid {
color: @term-bright-white;
background: @term-green;
box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.4), 0px 0px 0.5px 0px rgba(0, 0, 0, 0.5),
0px 0px 0.5px 0px rgba(255, 255, 255, 0.8) inset, 0px 0.5px 0px 0px rgba(255, 255, 255, 0.6) inset;
i {
fill: @term-white;
}
}
&.outlined {
border: 1px solid @term-green;
}
&.ghost {
// Styles for .ghost are already defined above
}
&:hover {
color: @term-bright-white;
}
}
&.secondary {
color: @term-white;
background: none;
&.solid {
background: rgba(255, 255, 255, 0.09);
box-shadow: none;
}
&.outlined {
border: 1px solid rgba(255, 255, 255, 0.09);
}
&.ghost {
padding: 6px 10px;
i {
fill: @term-green;
}
}
}
&.color-yellow {
&.solid {
border-color: @warning-yellow;
background-color: mix(@warning-yellow, @term-white, 50%);
box-shadow: none;
}
&.outlined {
color: @warning-yellow;
border-color: @warning-yellow;
&:hover {
color: @term-white;
border-color: @term-white;
}
}
&.ghost {
}
}
&.color-red {
&.solid {
border-color: @term-red;
background-color: mix(@term-red, @term-white, 50%);
box-shadow: none;
}
&.outlined {
color: @term-red;
border-color: @term-red;
}
&.ghost {
}
}
&.disabled {
opacity: 0.5;
}
&.link-button {
cursor: pointer;
}
}
.wave-status-container {
display: flex;
align-items: center;
.dot {
height: 6px;
width: 6px;
border-radius: 50%;
display: inline-block;
margin-right: 8px;
}
.dot.green {
background-color: @status-connected;
}
.dot.red {
background-color: @status-error;
}
.dot.gray {
background-color: @status-disconnected;
}
.dot.yellow {
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;
}
}
}
}
+209 -5
View File
@@ -99,7 +99,7 @@ class Toggle extends React.Component<{ checked: boolean; onChange: (value: boole
}
class Checkbox extends React.Component<
{ checked: boolean; onChange: (value: boolean) => void; label: string; id: string },
{ checked: boolean; onChange: (value: boolean) => void; label: React.ReactNode; id: string },
{}
> {
render() {
@@ -217,6 +217,115 @@ class Tooltip extends React.Component<TooltipProps, TooltipState> {
}
}
type ButtonVariantType = "outlined" | "solid" | "ghost";
type ButtonThemeType = "primary" | "secondary";
interface ButtonProps {
theme?: ButtonThemeType;
children: React.ReactNode;
onClick?: () => void;
disabled?: boolean;
variant?: ButtonVariantType;
leftIcon?: React.ReactNode;
rightIcon?: React.ReactNode;
color?: string;
style?: React.CSSProperties;
}
class Button extends React.Component<ButtonProps> {
static defaultProps = {
theme: "primary",
variant: "solid",
color: "",
style: {},
};
@boundMethod
handleClick() {
if (this.props.onClick && !this.props.disabled) {
this.props.onClick();
}
}
render() {
const { leftIcon, rightIcon, theme, children, disabled, variant, color, style } = this.props;
return (
<button
className={cn("wave-button", theme, variant, color, { disabled: disabled })}
onClick={this.handleClick}
disabled={disabled}
style={style}
>
{leftIcon && <span className="icon-left">{leftIcon}</span>}
{children}
{rightIcon && <span className="icon-right">{rightIcon}</span>}
</button>
);
}
}
class IconButton extends Button {
render() {
const { children, theme, variant = "solid", ...rest } = this.props;
const className = `wave-button icon-button ${theme} ${variant}`;
return (
<button {...rest} className={className}>
{children}
</button>
);
}
}
export default IconButton;
interface LinkButtonProps extends ButtonProps {
href: string;
target?: string;
}
class LinkButton extends IconButton {
render() {
// @ts-ignore
const { href, target, leftIcon, rightIcon, children, theme, variant }: LinkButtonProps = this.props;
return (
<a href={href} target={target} className={`wave-button link-button`}>
<button {...this.props} className={`icon-button ${theme} ${variant}`}>
{leftIcon && <span className="icon-left">{leftIcon}</span>}
{children}
{rightIcon && <span className="icon-right">{rightIcon}</span>}
</button>
</a>
);
}
}
interface StatusProps {
status: "green" | "red" | "gray" | "yellow";
text: string;
}
class Status extends React.Component<StatusProps> {
@boundMethod
renderDot() {
const { status } = this.props;
return <div className={`dot ${status}`} />;
}
render() {
const { text } = this.props;
return (
<div className="wave-status-container">
{this.renderDot()}
<span>{text}</span>
</div>
);
}
}
interface TextFieldDecorationProps {
startDecoration?: React.ReactNode;
endDecoration?: React.ReactNode;
@@ -232,6 +341,7 @@ interface TextFieldProps {
required?: boolean;
maxLength?: number;
autoFocus?: boolean;
disabled?: boolean;
}
interface TextFieldState {
@@ -242,7 +352,6 @@ interface TextFieldState {
hasContent: boolean;
}
@mobxReact.observer
class TextField extends React.Component<TextFieldProps, TextFieldState> {
inputRef: React.RefObject<HTMLInputElement>;
state: TextFieldState;
@@ -267,6 +376,22 @@ class TextField extends React.Component<TextFieldProps, TextFieldState> {
}
}
// Method to handle focus at the component level
@boundMethod
handleComponentFocus() {
if (this.inputRef.current && !this.inputRef.current.contains(document.activeElement)) {
this.inputRef.current.focus();
}
}
// Method to handle blur at the component level
@boundMethod
handleComponentBlur() {
if (this.inputRef.current && this.inputRef.current.contains(document.activeElement)) {
this.inputRef.current.blur();
}
}
@boundMethod
handleFocus() {
this.setState({ focused: true });
@@ -311,14 +436,23 @@ class TextField extends React.Component<TextFieldProps, TextFieldState> {
}
render() {
const { label, value, placeholder, decoration, className, maxLength, autoFocus } = this.props;
const { label, value, placeholder, decoration, className, maxLength, autoFocus, disabled } = this.props;
const { focused, internalValue, error } = this.state;
// Decide if the input should behave as controlled or uncontrolled
const inputValue = value !== undefined ? value : internalValue;
return (
<div className={cn(`wave-textfield ${className || ""}`, { focused: focused, error: error })}>
<div
className={cn(`wave-textfield ${className || ""}`, {
focused: focused,
error: error,
disabled: disabled,
})}
onFocus={this.handleComponentFocus}
onBlur={this.handleComponentBlur}
tabIndex={-1}
>
{decoration?.startDecoration && <>{decoration.startDecoration}</>}
<div className="wave-textfield-inner">
<label
@@ -341,6 +475,7 @@ class TextField extends React.Component<TextFieldProps, TextFieldState> {
placeholder={placeholder}
maxLength={maxLength}
autoFocus={autoFocus}
disabled={disabled}
/>
</div>
{decoration?.endDecoration && <>{decoration.endDecoration}</>}
@@ -617,7 +752,7 @@ class InlineSettingsTextEdit extends React.Component<
<div
onClick={this.confirmChange}
title="Confirm (Enter)"
className="button is-prompt-green is-outlined is-small"
className="button is-wave-green is-outlined is-small"
>
<span className="icon is-small">
<i className="fa-sharp fa-solid fa-check" />
@@ -964,6 +1099,70 @@ 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">
{onCancel && (
<Button theme="secondary" onClick={onCancel}>
{cancelLabel}
</Button>
)}
{onOk && <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,
@@ -980,4 +1179,9 @@ export {
NumberField,
PasswordField,
Tooltip,
Button,
IconButton,
LinkButton,
Status,
Modal,
};
+218 -125
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,71 +369,220 @@
}
}
.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 {
.screen-settings-modal {
width: 640px;
min-height: 329px;
.wave-modal-content {
gap: 24px;
.wave-modal-body {
display: flex;
padding: 0px 20px;
flex-direction: column;
align-items: flex-start;
gap: 4px;
align-self: stretch;
width: 100%;
}
}
}
.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;
div.button {
margin-right: 8px;
.wave-button {
padding: 4px 15px;
font-size: 11px;
margin-right: 8px;
}
}
}
}
}
}
.wave-button {
display: flex;
padding: 6px 16px;
align-items: center;
gap: var(--sizing-2-xs, 4px);
border-radius: 6px;
height: auto;
.alert-modal {
.wave-modal-content {
.wave-modal-body {
padding: 40px 20px;
}
}
}
.wave-button.color-green {
color: @term-bright-white;
background: @term-green !important; // !important is needed to override the default button color
box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.4), 0px 0px 0.5px 0px rgba(0, 0, 0, 0.5),
0px 0px 0.5px 0px rgba(255, 255, 255, 0.8) inset, 0px 0.5px 0px 0px rgba(255, 255, 255, 0.6) inset;
.rconndetail-modal {
width: 631px;
min-height: 565px;
&:hover {
color: @term-bright-white;
.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;
flex-direction: column;
gap: 16px;
align-self: stretch;
.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;
}
}
}
.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-input {
display: flex;
flex-direction: row;
align-items: center;
color: @term-white;
}
}
.settings-field:not(:first-child) {
margin-top: 4px;
}
.status {
display: flex;
height: 30px;
padding: 3px 8px;
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
}
}
}
}
}
}
}
.wave-button.color-standard {
color: @term-white;
background: var(--overlays-white-6, rgba(255, 255, 255, 0.12));
background: rgba(255, 255, 255, 0.12);
&:hover {
color: @term-white;
@@ -659,31 +751,32 @@
fill: @tab-pink;
}
.tab-colors {
.tab-colors,
.tab-icons {
display: flex;
flex-direction: row;
align-items: center;
.tab-color-sep {
.tab-color-sep,
.tab-icon-sep {
padding-left: 10px;
padding-right: 10px;
font-weight: bold;
}
.tab-color-cur {
width: 100px;
}
.tab-color-icon {
.tab-color-icon,
.tab-icon-icon {
width: 1.1em;
vertical-align: middle;
}
.tab-color-name {
.tab-color-name,
.tab-icon-name {
margin-left: 1em;
}
.tab-color-select {
.tab-color-select,
.tab-icon-select {
cursor: pointer;
margin: 5px;
&:hover {
File diff suppressed because it is too large Load Diff
+22
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 };
+139 -100
View File
@@ -7,10 +7,18 @@ import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { If, For } from "tsx-control-statements/components";
import cn from "classnames";
import { GlobalModel, GlobalCommandRunner, TabColors } from "../../../model/model";
import { Toggle, InlineSettingsTextEdit, SettingsError, InfoMessage } from "../common";
import {
GlobalModel,
GlobalCommandRunner,
TabColors,
MinFontSize,
MaxFontSize,
TabIcons,
Screen,
} from "../../../model/model";
import { Toggle, InlineSettingsTextEdit, SettingsError, InfoMessage, Modal } from "../common";
import { LineType, RendererPluginType, ClientDataType, CommandRtnType } from "../../../types/types";
import { ConnectionDropdown } from "../../connections/connections";
import { ConnectionDropdown } from "../../connections_deprecated/connections";
import { PluginModel } from "../../../plugins/plugins";
import * as util from "../../../util/util";
import { commandRtnHandler } from "../../../util/util";
@@ -50,15 +58,16 @@ Are you sure you want to stop web-sharing this tab?
`.trim();
@mobxReact.observer
class ScreenSettingsModal extends React.Component<{ sessionId: string; screenId: string; }, {}> {
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" });
screen: Screen;
constructor(props: any) {
super(props);
let { sessionId, screenId } = props;
let screen = GlobalModel.getScreenById(sessionId, screenId);
if (screen == null) {
this.screen = GlobalModel.getScreenById(sessionId, screenId);
if (this.screen == null) {
return;
}
}
@@ -84,6 +93,15 @@ class ScreenSettingsModal extends React.Component<{ sessionId: string; screenId:
commandRtnHandler(prtn, this.errorMessage);
}
@boundMethod
selectTabIcon(icon: string): void {
if (this.screen.getTabIcon() == icon) {
return;
}
let prtn = GlobalCommandRunner.screenSetSettings(this.screen.screenId, { tabicon: icon }, false);
util.commandRtnHandler(prtn, this.errorMessage);
}
@boundMethod
handleChangeArchived(val: boolean): void {
let { sessionId, screenId } = this.props;
@@ -203,105 +221,123 @@ class ScreenSettingsModal extends React.Component<{ sessionId: string; screenId:
render() {
let { sessionId, screenId } = this.props;
let inline = false;
let screen = GlobalModel.getScreenById(sessionId, screenId);
let screen = this.screen;
if (screen == null) {
return null;
}
console.log("screen.getTabIcon()", screen.getTabIcon());
let color: string = null;
let icon: string = null;
let curRemote = GlobalModel.getRemote(GlobalModel.getActiveScreen().getCurRemoteInstance().remoteid);
return (
<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" />}
<header>
<div className="modal-title">tab settings ({screen.name.get()})</div>
<div className="close-icon hoverEffect" title="Close (Escape)" onClick={this.closeModal}>
<XmarkIcon />
</div>
</header>
<div className="inner-content">
<div className="settings-field">
<div className="settings-label">Tab Id</div>
<div className="settings-input">{screen.screenId}</div>
</div>
<div className="settings-field">
<div className="settings-label">Name</div>
<div className="settings-input">
<InlineSettingsTextEdit
placeholder="name"
text={screen.name.get() ?? "(none)"}
value={screen.name.get() ?? ""}
onChange={this.inlineUpdateName}
maxLength={50}
showIcon={true}
/>
</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">
<div className="tab-colors">
<div className="tab-color-cur">
<SquareIcon className={cn("tab-color-icon", "color-" + screen.getTabColor())} />
<span className="tab-color-name">{screen.getTabColor()}</span>
</div>
<div className="tab-color-sep">|</div>
<For each="color" of={TabColors}>
<div
key={color}
className="tab-color-select"
onClick={() => this.selectTabColor(color)}
>
<SquareIcon className={cn("tab-color-icon", "color-" + color)} />
</div>
</For>
</div>
</div>
</div>
<div className="settings-field">
<div className="settings-label">
<div>Archived</div>
<InfoMessage width={400}>
Archive will hide the 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 tab, 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 Tab
</div>
</div>
</div>
<SettingsError errorMessage={this.errorMessage} />
<Modal className="screen-settings-modal">
<Modal.Header onClose={this.closeModal} title={`tab settings (${screen.name.get()})`} />
<div className="wave-modal-body">
<div className="settings-field">
<div className="settings-label">Tab Id</div>
<div className="settings-input">{screen.screenId}</div>
</div>
<footer>
<div onClick={this.closeModal} className="button is-prompt-green is-outlined is-small">
Close
<div className="settings-field">
<div className="settings-label">Name</div>
<div className="settings-input">
<InlineSettingsTextEdit
placeholder="name"
text={screen.name.get() ?? "(none)"}
value={screen.name.get() ?? ""}
onChange={this.inlineUpdateName}
maxLength={50}
showIcon={true}
/>
</div>
</footer>
</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">
<div className="tab-colors">
<div className="tab-color-cur">
<SquareIcon className={cn("tab-color-icon", "color-" + screen.getTabColor())} />
<span className="tab-color-name">{screen.getTabColor()}</span>
</div>
<div className="tab-color-sep">|</div>
<For each="color" of={TabColors}>
<div
key={color}
className="tab-color-select"
onClick={() => this.selectTabColor(color)}
>
<SquareIcon className={cn("tab-color-icon", "color-" + color)} />
</div>
</For>
</div>
</div>
</div>
<div className="settings-field">
<div className="settings-label">Tab Icon</div>
<div className="settings-input">
<div className="tab-icons">
<div className="tab-icon-cur">
<If condition={screen.getTabIcon() == "default"}>
<SquareIcon className={cn("tab-color-icon", "color-white")} />
</If>
<If condition={screen.getTabIcon() != "default"}>
<i className={`fa-sharp fa-solid fa-${screen.getTabIcon()}`}></i>
</If>
<span className="tab-icon-name">{screen.getTabIcon()}</span>
</div>
<div className="tab-icon-sep">|</div>
<For each="icon" of={TabIcons}>
<div
key={color}
className="tab-icon-select"
onClick={() => this.selectTabIcon(icon)}
>
<i className={`fa-sharp fa-solid fa-${icon}`}></i>
</div>
</For>
</div>
</div>
</div>
<div className="settings-field">
<div className="settings-label">
<div>Archived</div>
<InfoMessage width={400}>
Archive will hide the 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 tab, 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 Tab
</div>
</div>
</div>
<SettingsError errorMessage={this.errorMessage} />
</div>
</div>
<Modal.Footer cancelLabel="Close" onCancel={this.closeModal} />
</Modal>
);
}
}
@@ -436,7 +472,7 @@ class SessionSettingsModal extends React.Component<{ sessionId: string }, {}> {
<SettingsError errorMessage={this.errorMessage} />
</div>
<footer>
<div onClick={this.closeModal} className="button is-prompt-green is-outlined is-small">
<div onClick={this.closeModal} className="button is-wave-green is-outlined is-small">
Close
</div>
</footer>
@@ -572,7 +608,7 @@ class LineSettingsModal extends React.Component<{ linenum: number }, {}> {
<div style={{ height: 50 }} />
</div>
<footer>
<div onClick={this.closeModal} className="button is-prompt-green is-outlined is-small">
<div onClick={this.closeModal} className="button is-wave-green is-outlined is-small">
Close
</div>
</footer>
@@ -630,7 +666,10 @@ class ClientSettingsModal extends React.Component<{}, {}> {
}
renderFontSizeDropdown(): any {
let availableFontSizes = [8, 9, 10, 11, 12, 13, 14, 15];
let availableFontSizes = [];
for (let s = MinFontSize; s <= MaxFontSize; s++) {
availableFontSizes.push(s);
}
let fsize: number = 0;
let curSize = GlobalModel.termFontSize.get();
return (
@@ -767,7 +806,7 @@ class ClientSettingsModal extends React.Component<{}, {}> {
<SettingsError errorMessage={this.errorMessage} />
</div>
<footer>
<div onClick={this.closeModal} className="button is-prompt-green is-outlined is-small">
<div onClick={this.closeModal} className="button is-wave-green is-outlined is-small">
Close
</div>
</footer>
+1 -1
View File
@@ -7,7 +7,7 @@
vertical-align: middle;
width: 1.2em;
height: 1.2em;
fill: @prompt-green;
fill: @wave-green;
}
.term-prompt-branch {
+1 -1
View File
@@ -6,7 +6,7 @@
@background-session: rgba(13, 13, 13, 0.85);
@background-session-components: rgba(48, 49, 48, 0.6);
@background-session-components-solid: rgb(33, 34, 33);
@prompt-green: rgb(88, 193, 66);
@wave-green: rgb(88, 193, 66);
@disabled-background: rgba(76, 81, 75, 1);
@disabled-color: #adadad;
@scrollbar-background: rgba(21, 23, 21, 1);
+82 -383
View File
@@ -1,408 +1,107 @@
@import "../../app/common/themes/themes.less";
.modal.prompt-modal.remotes-modal {
.modal-content {
min-width: 850px;
}
.icon {
width: 1em;
height: 1em;
fill: @base-color;
margin: 0;
}
.button {
svg {
float: right;
margin-top: 0.3em;
margin-right: 0;
}
}
.dropdown,
.button {
display: inline-flex;
}
.dropdown .button {
border: none !important;
}
.inner-content {
display: flex;
flex-direction: row;
align-items: stretch;
padding: 0;
min-height: 45em;
max-height: 45em;
.remotes-menu {
flex: 0 0 200px;
border-right: 1px solid @disabled-color;
overflow-y: auto;
.remote-menu-item {
border-top: 1px solid @disabled-color;
padding: 0.5em;
display: flex;
flex-direction: row;
cursor: pointer;
&.add-remote {
padding: 10px 5px 10px 5px;
}
&:hover {
background-color: #333;
}
&.is-selected {
background-color: @active-menu-color;
.remote-name .remote-name-secondary {
color: @term-white;
}
}
&:first-child {
border-top: 0;
}
.remote-status-light {
width: 2em;
margin-top: 0.7em;
margin-right: 0.7em;
font-size: 0.8em;
}
.remote-name {
flex-grow: 1;
.remote-name-primary {
font-weight: bold;
max-width: 10em;
margin-right: 1em;
}
.remote-name-secondary {
color: @disabled-color;
max-width: 14em;
}
}
}
}
.remote-detail {
padding: 10px;
flex-grow: 1;
display: flex;
flex-direction: column;
.settings-field {
margin-top: 0.75em;
}
* {
flex-shrink: 0;
}
.detail-subtitle {
margin-bottom: 10px;
margin-top: 10px;
}
.title {
color: @term-white;
padding: 0.75em 0;
margin-bottom: 0;
border-bottom: 1px solid #777;
}
.terminal-wrapper {
margin-left: 0;
margin-bottom: 0;
&.has-message {
margin-top: 0;
}
box-shadow: none;
border: 1px solid #777;
border-radius: 0 0 5px 5px;
.xterm-rows {
padding-top: 0.5em;
}
}
.action-buttons {
display: flex;
flex-direction: row;
gap: 10px;
margin-top: 2px;
}
.remote-message {
margin-top: 5px;
padding: 8px;
border-radius: 5px 5px 0 0;
background-color: #333;
border: 1px solid #777;
border-bottom: none;
.message-row {
display: flex;
flex-direction: row;
align-items: center;
svg {
vertical-align: text-bottom;
}
}
.remote-status {
position: relative;
top: -1px;
}
.button {
height: 22px;
}
}
.settings-field {
.update-auth-button {
visibility: hidden;
}
&:hover {
.update-auth-button {
visibility: visible;
}
.hide-hover {
display: none;
}
}
}
&.auth-editing,
&.create-remote {
.settings-field.align-top {
align-items: flex-start;
.settings-label {
margin-top: 8px;
}
.settings-input {
align-items: flex-start;
}
}
.settings-label {
display: flex;
flex-direction: row;
align-items: center;
width: 12em !important;
}
.settings-field .settings-input .undo-icon {
cursor: pointer;
margin-left: 5px;
}
.editremote-dropdown .dropdown-trigger button {
width: 120px;
justify-content: flex-start;
color: @base-color;
border: none;
&:hover {
box-shadow: none;
}
}
.settings-field .raw-input {
width: 120px;
}
.settings-input input {
background: rgba(255, 255, 255, 0.8);
width: 250px;
outline: none;
}
.dropdown .dropdown-item {
padding: 5px 5px 5px 12px;
}
.dropdown .dropdown-content {
max-width: 10.6em;
}
.settings-input {
.info-message {
margin-left: 22px;
}
}
.settings-label {
.info-message {
margin-right: 15px;
}
}
}
}
}
.terminal-wrapper {
position: relative;
padding: 2px 10px 5px 4px;
margin: 5px 5px 10px 5px;
box-shadow: 0 0 1px 1px rgba(255, 255, 255, 0.3);
&.focus {
box-shadow: 0 0 3px 3px rgba(255, 255, 255, 0.3);
}
.term-tag {
position: absolute;
top: 0;
right: 0;
background-color: @term-red;
color: @term-white;
z-index: 110;
padding: 4px;
}
}
}
.dropdown.conn-dropdown {
padding-left: 0;
.connections-view {
background-color: @background-session;
flex-grow: 1;
display: flex;
flex-direction: column;
position: relative;
overflow: auto;
margin-bottom: 10px;
margin-right: 10px;
border-radius: 8px;
background-color: rgba(241, 246, 243, 0.08);
border: 1px solid rgba(241, 246, 243, 0.08);
background: var(--element-window, rgba(13, 13, 13, 0.85));
.conn-dd-trigger {
.header {
margin: 24px 18px;
display: flex;
flex-direction: row;
width: 413px;
padding: 6px 8px 6px 12px;
justify-content: space-between;
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;
}
.connections-title {
}
}
.conn-dd-menu {
.no-items {
display: flex;
width: 413px;
padding: 6px;
flex-direction: column;
align-items: flex-start;
border-radius: 8px;
background-color: @dropdown-menu;
flex-direction: row;
justify-content: center;
padding: 30px 0 30px 0;
border: 1px solid white;
border-radius: 3px;
margin: 20px 50px 20px 20px;
}
.dropdown-item {
display: flex;
padding: 5px 12px 5px 8px;
align-items: center;
gap: 8px;
align-self: stretch;
border-radius: 6px;
.connections-table {
margin: 0px 10px 10px 10px;
table-layout: fixed;
max-width: 970px;
.status-div {
display: flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
padding: 3px;
svg.status-icon {
width: 10px;
height: 10px;
}
colgroup {
.first-col {
max-width: 650px;
}
.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;
}
}
.second-col {
max-width: 150px;
}
.third-col {
max-width: 200px;
}
}
.text-standard {
thead {
border-radius: var(--sizing-2-xs, 4px);
border-top: 1px solid rgba(250, 250, 250, 0.1);
border-bottom: 1px solid rgba(241, 246, 243, 0.15);
background: var(--opacity-zinc-502, rgba(250, 250, 250, 0.02));
box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.4), 0px 0px 0.5px 0px rgba(0, 0, 0, 0.5),
0px 0px 0.5px 0px rgba(255, 255, 255, 0.5) inset, 0px 0.5px 0px 0px rgba(255, 255, 255, 0.2) inset;
th {
height: 32px;
padding: 5px 15px 5px 10px;
color: @text-secondary;
}
}
.text-caption {
color: @text-caption;
}
.ellipsis {
text-overflow: ellipsis;
}
tr.connections-item {
border-bottom: 1px solid rgba(241, 246, 243, 0.15);
color: @text-secondary;
cursor: pointer;
&:hover {
background-color: rgba(241, 246, 243, 0.08);
background: rgba(255, 255, 255, 0.06);
td.bookmark i {
display: block;
}
}
td {
height: 40px;
padding: 5px 15px 5px 10px;
vertical-align: middle;
.action-buttons {
display: flex;
visibility: hidden;
}
}
&.hovered {
.action-buttons {
visibility: visible;
}
}
}
}
footer {
margin-left: 10px;
}
.help-entry {
margin: 1em 2em;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,408 @@
@import "../../app/common/themes/themes.less";
.modal.prompt-modal.remotes-modal {
.modal-content {
min-width: 850px;
}
.icon {
width: 1em;
height: 1em;
fill: @base-color;
margin: 0;
}
.button {
svg {
float: right;
margin-top: 0.3em;
margin-right: 0;
}
}
.dropdown,
.button {
display: inline-flex;
}
.dropdown .button {
border: none !important;
}
.inner-content {
display: flex;
flex-direction: row;
align-items: stretch;
padding: 0;
min-height: 45em;
max-height: 45em;
.remotes-menu {
flex: 0 0 200px;
border-right: 1px solid @disabled-color;
overflow-y: auto;
.remote-menu-item {
border-top: 1px solid @disabled-color;
padding: 0.5em;
display: flex;
flex-direction: row;
cursor: pointer;
&.add-remote {
padding: 10px 5px 10px 5px;
}
&:hover {
background-color: #333;
}
&.is-selected {
background-color: @active-menu-color;
.remote-name .remote-name-secondary {
color: @term-white;
}
}
&:first-child {
border-top: 0;
}
.remote-status-light {
width: 2em;
margin-top: 0.7em;
margin-right: 0.7em;
font-size: 0.8em;
}
.remote-name {
flex-grow: 1;
.remote-name-primary {
font-weight: bold;
max-width: 10em;
margin-right: 1em;
}
.remote-name-secondary {
color: @disabled-color;
max-width: 14em;
}
}
}
}
.remote-detail {
padding: 10px;
flex-grow: 1;
display: flex;
flex-direction: column;
.settings-field {
margin-top: 0.75em;
}
* {
flex-shrink: 0;
}
.detail-subtitle {
margin-bottom: 10px;
margin-top: 10px;
}
.title {
color: @term-white;
padding: 0.75em 0;
margin-bottom: 0;
border-bottom: 1px solid #777;
}
.terminal-wrapper {
margin-left: 0;
margin-bottom: 0;
&.has-message {
margin-top: 0;
}
box-shadow: none;
border: 1px solid #777;
border-radius: 0 0 5px 5px;
.xterm-rows {
padding-top: 0.5em;
}
}
.action-buttons {
display: flex;
flex-direction: row;
gap: 10px;
margin-top: 2px;
}
.remote-message {
margin-top: 5px;
padding: 8px;
border-radius: 5px 5px 0 0;
background-color: #333;
border: 1px solid #777;
border-bottom: none;
.message-row {
display: flex;
flex-direction: row;
align-items: center;
svg {
vertical-align: text-bottom;
}
}
.remote-status {
position: relative;
top: -1px;
}
.button {
height: 22px;
}
}
.settings-field {
.update-auth-button {
visibility: hidden;
}
&:hover {
.update-auth-button {
visibility: visible;
}
.hide-hover {
display: none;
}
}
}
&.auth-editing,
&.create-remote {
.settings-field.align-top {
align-items: flex-start;
.settings-label {
margin-top: 8px;
}
.settings-input {
align-items: flex-start;
}
}
.settings-label {
display: flex;
flex-direction: row;
align-items: center;
width: 12em !important;
}
.settings-field .settings-input .undo-icon {
cursor: pointer;
margin-left: 5px;
}
.editremote-dropdown .dropdown-trigger button {
width: 120px;
justify-content: flex-start;
color: @base-color;
border: none;
&:hover {
box-shadow: none;
}
}
.settings-field .raw-input {
width: 120px;
}
.settings-input input {
background: rgba(255, 255, 255, 0.8);
width: 250px;
outline: none;
}
.dropdown .dropdown-item {
padding: 5px 5px 5px 12px;
}
.dropdown .dropdown-content {
max-width: 10.6em;
}
.settings-input {
.info-message {
margin-left: 22px;
}
}
.settings-label {
.info-message {
margin-right: 15px;
}
}
}
}
}
.terminal-wrapper {
position: relative;
padding: 2px 10px 5px 4px;
margin: 5px 5px 10px 5px;
box-shadow: 0 0 1px 1px rgba(255, 255, 255, 0.3);
&.focus {
box-shadow: 0 0 3px 3px rgba(255, 255, 255, 0.3);
}
.term-tag {
position: absolute;
top: 0;
right: 0;
background-color: @term-red;
color: @term-white;
z-index: 110;
padding: 4px;
}
}
}
.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);
}
}
}
}
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -188,7 +188,7 @@
}
&.active {
border: 1px solid rgba(@prompt-green, 0.8) !important;
border: 1px solid rgba(@wave-green, 0.8) !important;
box-shadow: 0px 0px 0.5px 0px rgba(255, 255, 255, 0.5) inset, 0px 0.5px 0px 0px rgba(255, 255, 255, 0.2) inset;
}
@@ -234,7 +234,7 @@
}
.success {
fill: @prompt-green;
fill: @wave-green;
}
.fail {
+1 -1
View File
@@ -68,7 +68,7 @@ class LinesView extends React.Component<
});
this.visibleMap = new Map();
this.collapsedMap = new Map();
this.computeVisibleMap_debounced = debounce(1000, this.computeVisibleMap.bind(this));
this.computeVisibleMap_debounced = debounce(100, this.computeVisibleMap.bind(this));
}
@boundMethod
+1 -1
View File
@@ -45,7 +45,7 @@
margin-bottom: 1em;
border: 1px solid transparent;
&.selected {
border-color: @prompt-green;
border-color: @wave-green;
}
.plugin-summary-header {
display: flex;
+12 -8
View File
@@ -110,6 +110,15 @@ class MainSideBar extends React.Component<{}, {}> {
GlobalCommandRunner.bookmarksView();
}
@boundMethod
handleConnectionsClick(): void {
if (GlobalModel.activeMainView.get() == "connections") {
GlobalModel.showSessionView();
return;
}
GlobalCommandRunner.connectionsView();
}
@boundMethod
handleWebSharingClick(): void {
if (GlobalModel.activeMainView.get() == "webshare") {
@@ -126,11 +135,6 @@ class MainSideBar extends React.Component<{}, {}> {
})();
}
@boundMethod
handleConnectionsClick(): void {
GlobalModel.remotesModalModel.openModal();
}
@boundMethod
openSessionSettings(e: any, session: Session): void {
e.preventDefault();
@@ -199,14 +203,14 @@ class MainSideBar extends React.Component<{}, {}> {
<div className="logo">
<If condition={isCollapsed}>
<div className="logo-container" onClick={this.toggleCollapsed}>
<img src="public/logos/wave-logo.png"/>
<img src="public/logos/wave-logo.png" />
</div>
</If>
<If condition={!isCollapsed}>
<div className="logo-container">
<img src="public/logos/wave-dark.png"/>
<img src="public/logos/wave-dark.png" />
</div>
<div className="spacer"/>
<div className="spacer" />
<div className="collapse-button" onClick={this.toggleCollapsed}>
<LeftChevronIcon className="icon" />
</div>

Some files were not shown because too many files have changed in this diff Show More