Compare commits

..

6 Commits

Author SHA1 Message Date
Sylvia Crowe 00c2ab9fc4 merge branch 'main' into ssh-extra-fixes 2024-03-14 16:20:55 -07:00
Sylvia Crowe 81294820c8 feat: add connection segfault protection
A user recently reported a crash on a failed connection. This handles
these errors more gracefully than the previous system and prints the
errors to the connection prompt.
2024-03-14 16:19:32 -07:00
Sylvia Crowe bb8f5dc660 chore: remove legacy remote launcher
The Legacy Launch function was kept as a way to maintain the old ssh
system while adding the new one. Now that the new system has been
released with minimal issues, it is safe to fully remove the legacy
launcher.
2024-03-14 01:07:54 -07:00
Sylvia Crowe c3917444a2 merge branch 'main' into ssh-extra-fixes 2024-03-13 18:08:29 -07:00
Sylvia Crowe 2cc86f39d6 feat: relax user requirement for canonical name
Previously, the canonical name required a user as a part of it. This
change makes it possible to omit the username if desired. In this case,
the connection will default to your current user.
2024-03-08 00:32:46 -08:00
Sylvia Crowe af22fd38af feat: don't hide nonsecret kbd-interactive answers
Some Kbd-Interactive challenges are marked with echo true. For these, it
makes sense to use a TextField in place of a PasswordField. This change
differentiates between the two options.
2024-03-07 23:32:15 -08:00
42 changed files with 261 additions and 573 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
},
"productName": "Wave",
"description": "An Open-Source, AI-Native, Terminal Built for Seamless Workflows",
"version": "0.7.1",
"version": "0.7.0",
"main": "dist/emain.js",
"license": "Apache-2.0",
"repository": {
+1 -4
View File
@@ -44,10 +44,6 @@
--floating-logo-width: 40px;
--floating-logo-height: var(--screentabs-height);
/* right sidebar triggers */
--floating-right-sidebar-triggers-width-darwin: 50px;
--floating-right-sidebar-triggers-width: 40px;
/* global colors */
--app-bg-color: black;
--app-accent-color: rgb(88, 193, 66);
@@ -156,6 +152,7 @@
--line-text-color: rgb(211, 215, 207);
--line-svg-fill-color: rgb(150, 152, 150);
--line-svg-hover-fill-color: #eceeec;
--line-selected-border-color: rgb(193, 195, 193);
--line-separator-color: rgb(126, 126, 126);
--line-error-color: var(--app-error-color);
--line-warning-color: var(--app-warning-color);
-19
View File
@@ -302,25 +302,6 @@ a.a-block {
}
}
.right-sidebar-triggers {
position: absolute;
z-index: 25;
right: 0px;
display: flex;
flex-direction: row;
align-items: center;
pointer-events: none;
height: 38px;
padding: 0 5px;
.right-sidebar-trigger {
cursor: pointer;
user-select: none;
-webkit-app-region: no-drag;
pointer-events: all;
}
}
.copied-indicator {
position: absolute;
top: 0;
+11 -35
View File
@@ -16,12 +16,10 @@ import { BookmarksView } from "./bookmarks/bookmarks";
import { HistoryView } from "./history/history";
import { ConnectionsView } from "./connections/connections";
import { ClientSettingsView } from "./clientsettings/clientsettings";
import { MainSideBar } from "./sidebar/main";
import { RightSideBar } from "./sidebar/right";
import { DisconnectedModal, ClientStopModal } from "@/modals";
import { ModalsProvider } from "@/modals/provider";
import { Button } from "@/elements";
import { ErrorBoundary } from "@/common/error/errorboundary";
import { MainSideBar } from "./sidebar/sidebar";
import { DisconnectedModal, ClientStopModal } from "./common/modals";
import { ModalsProvider } from "./common/modals/provider";
import { ErrorBoundary } from "./common/error/errorboundary";
import cn from "classnames";
import "./app.less";
@@ -67,17 +65,9 @@ class App extends React.Component<{}, {}> {
}
@boundMethod
openMainSidebar() {
const mainSidebarModel = GlobalModel.mainSidebarModel;
const width = mainSidebarModel.getWidth(true);
mainSidebarModel.saveState(width, false);
}
@boundMethod
openRightSidebar() {
const rightSidebarModel = GlobalModel.rightSidebarModel;
const width = rightSidebarModel.getWidth(true);
rightSidebarModel.saveState(width, false);
openSidebar() {
const width = GlobalModel.mainSidebarModel.getWidth(true);
GlobalCommandRunner.clientSetSidebar(width, false);
}
render() {
@@ -120,36 +110,23 @@ class App extends React.Component<{}, {}> {
}
// used to force a full reload of the application
const renderVersion = GlobalModel.renderVersion.get();
const mainSidebarCollapsed = GlobalModel.mainSidebarModel.getCollapsed();
const rightSidebarCollapsed = GlobalModel.rightSidebarModel.getCollapsed();
const activeMainView = GlobalModel.activeMainView.get();
const sidebarCollapsed = GlobalModel.mainSidebarModel.getCollapsed();
const lightDarkClass = GlobalModel.isThemeDark() ? "is-dark" : "is-light";
return (
<div
key={"version-" + renderVersion}
id="main"
className={cn(
"platform-" + platform,
{ "mainsidebar-collapsed": mainSidebarCollapsed, "rightsidebar-collapsed": rightSidebarCollapsed },
lightDarkClass
)}
className={cn("platform-" + platform, { "sidebar-collapsed": sidebarCollapsed }, lightDarkClass)}
onContextMenu={this.handleContextMenu}
>
<If condition={mainSidebarCollapsed}>
<If condition={sidebarCollapsed}>
<div key="logo-button" className="logo-button-container">
<div className="logo-button-spacer" />
<div className="logo-button" onClick={this.openMainSidebar}>
<div className="logo-button" onClick={this.openSidebar}>
<img src="public/logos/wave-logo.png" alt="logo" />
</div>
</div>
</If>
<If condition={GlobalModel.isDev && rightSidebarCollapsed && activeMainView == "session"}>
<div className="right-sidebar-triggers">
<Button className="secondary ghost right-sidebar-trigger" onClick={this.openRightSidebar}>
<i className="fa-sharp fa-regular fa-lightbulb"></i>
</Button>
</div>
</If>
<div ref={this.mainContentRef} className="main-content">
<MainSideBar parentRef={this.mainContentRef} clientData={clientData} />
<ErrorBoundary>
@@ -160,7 +137,6 @@ class App extends React.Component<{}, {}> {
<ConnectionsView model={remotesModel} />
<ClientSettingsView model={remotesModel} />
</ErrorBoundary>
<RightSideBar parentRef={this.mainContentRef} clientData={clientData} />
</div>
<ModalsProvider />
</div>
-56
View File
@@ -22,59 +22,6 @@ type BookmarkProps = {
bookmark: BookmarkType;
};
class BookmarkKeybindings extends React.Component<{}, {}> {
@boundMethod
componentDidMount(): void {
let keybindManager = GlobalModel.keybindManager;
let bookmarksModel = GlobalModel.bookmarksModel;
keybindManager.registerKeybinding("mainview", "bookmarks", "generic:cancel", (waveEvent) => {
bookmarksModel.handleUserClose();
return true;
});
keybindManager.registerKeybinding("mainview", "bookmarks", "generic:deleteItem", (waveEvent) => {
bookmarksModel.handleUserDelete();
return true;
});
keybindManager.registerKeybinding("mainview", "bookmarks", "generic:selectAbove", (waveEvent) => {
bookmarksModel.handleUserNavigate(-1);
return true;
});
keybindManager.registerKeybinding("mainview", "bookmarks", "generic:selectBelow", (waveEvent) => {
bookmarksModel.handleUserNavigate(1);
return true;
});
keybindManager.registerKeybinding("mainview", "bookmarks", "generic:selectPageAbove", (waveEvent) => {
bookmarksModel.handleUserNavigate(-10);
return true;
});
keybindManager.registerKeybinding("mainview", "bookmarks", "generic:selectPageBelow", (waveEvent) => {
bookmarksModel.handleUserNavigate(10);
return true;
});
keybindManager.registerKeybinding("mainview", "bookmarks", "generic:confirm", (waveEvent) => {
bookmarksModel.handleUserConfirm();
return true;
});
keybindManager.registerKeybinding("mainview", "bookmarks", "bookmarks:edit", (waveEvent) => {
bookmarksModel.handleUserEdit();
return true;
});
keybindManager.registerKeybinding("mainview", "bookmarks", "bookmarks:copy", (waveEvent) => {
bookmarksModel.handleUserCopy();
return true;
});
}
@boundMethod
componentWillUnmount() {
GlobalModel.keybindManager.unregisterDomain("bookmarks");
}
render() {
return null;
}
}
@mobxReact.observer
class Bookmark extends React.Component<BookmarkProps, {}> {
@boundMethod
@@ -247,9 +194,6 @@ class BookmarksView extends React.Component<{}, {}> {
let bookmark: BookmarkType = null;
return (
<MainView className="bookmarks-view" title="Bookmarks" onClose={this.handleClose}>
<If condition={!isHidden}>
<BookmarkKeybindings></BookmarkKeybindings>
</If>
<div className="bookmarks-list">
<For index="idx" each="bookmark" of={bookmarks}>
<Bookmark key={bookmark.bookmarkid} bookmark={bookmark} />
+3 -9
View File
@@ -5,6 +5,7 @@
font: inherit;
cursor: pointer;
outline: inherit;
display: flex;
padding: 6px 16px;
align-items: center;
@@ -14,8 +15,7 @@
line-height: 1.5;
&.primary {
color: var(--form-element-text-color);
background: var(--form-element-primary-color);
background: none;
i {
fill: var(--form-element-primary-color);
@@ -31,12 +31,11 @@
}
&.outlined {
background: none;
border: 1px solid var(--form-element-primary-color);
}
&.ghost {
background: none;
// Styles for .ghost are already defined above
}
&:hover {
@@ -47,9 +46,6 @@
&.secondary {
color: var(--form-element-text-color);
background: none;
color: var(--form-element-text-color);
background: var(--form-element-secondary-color);
box-shadow: none;
&.solid {
color: var(--form-element-text-color);
@@ -58,12 +54,10 @@
}
&.outlined {
background: none;
border: 1px solid var(--form-element-secondary-color);
}
&.ghost {
background: none;
padding: 6px 10px;
i {
+34 -3
View File
@@ -1,15 +1,24 @@
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import * as React from "react";
import { boundMethod } from "autobind-decorator";
import cn from "classnames";
import "./button.less";
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;
autoFocus?: boolean;
className?: string;
@@ -18,8 +27,10 @@ interface ButtonProps {
class Button extends React.Component<ButtonProps> {
static defaultProps = {
theme: "primary",
variant: "solid",
color: "",
style: {},
className: "primary",
};
@boundMethod
@@ -30,11 +41,31 @@ class Button extends React.Component<ButtonProps> {
}
render() {
const { leftIcon, rightIcon, children, disabled, style, autoFocus, termInline, className } = this.props;
const {
leftIcon,
rightIcon,
theme,
children,
disabled,
variant,
color,
style,
autoFocus,
termInline,
className,
} = this.props;
return (
<button
className={cn("wave-button", { disabled }, { "term-inline": termInline }, className)}
className={cn(
"wave-button",
theme,
variant,
color,
{ disabled: disabled },
{ "term-inline": termInline },
className
)}
onClick={this.handleClick}
disabled={disabled}
style={style}
+21
View File
@@ -0,0 +1,21 @@
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import * as React from "react";
import { Button } from "./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;
export { IconButton };
+1
View File
@@ -3,6 +3,7 @@ export { Checkbox } from "./checkbox";
export { CmdStrCode } from "./cmdstrcode";
export { renderCmdText } from "./cmdtext";
export { Dropdown } from "./dropdown";
export { IconButton } from "./iconbutton";
export { InlineSettingsTextEdit } from "./inlinesettingstextedit";
export { InputDecoration } from "./inputdecoration";
export { LinkButton } from "./linkbutton";
+2 -2
View File
@@ -42,10 +42,10 @@
// This ensures the tab bar does not collide with the floating logo. The floating logo sits above the sidebar when it is not collapsed, so no additional margin is needed in that case.
// More margin is given on macOS to account for the traffic light buttons
#main.platform-darwin.mainsidebar-collapsed .header {
#main.platform-darwin.sidebar-collapsed .header {
margin-left: var(--floating-logo-width-darwin);
}
#main:not(.platform-darwin).mainsidebar-collapsed .header {
#main:not(.platform-darwin).sidebar-collapsed .header {
margin-left: var(--floating-logo-width);
}
+5 -8
View File
@@ -6,6 +6,7 @@ import * as mobx from "mobx";
import { If } from "tsx-control-statements/components";
import ReactDOM from "react-dom";
import { Button } from "./button";
import { IconButton } from "./iconbutton";
import "./modal.less";
@@ -18,9 +19,9 @@ const ModalHeader: React.FC<ModalHeaderProps> = ({ onClose, title }) => (
<div className="wave-modal-header">
{<div className="wave-modal-title">{title}</div>}
<If condition={onClose}>
<Button className="secondary ghost" onClick={onClose}>
<IconButton theme="secondary" variant="ghost" onClick={onClose}>
<i className="fa-sharp fa-solid fa-xmark"></i>
</Button>
</IconButton>
</If>
</div>
);
@@ -35,15 +36,11 @@ interface ModalFooterProps {
const ModalFooter: React.FC<ModalFooterProps> = ({ onCancel, onOk, cancelLabel = "Cancel", okLabel = "Ok" }) => (
<div className="wave-modal-footer">
{onCancel && (
<Button className="secondary" onClick={onCancel}>
<Button theme="secondary" onClick={onCancel}>
{cancelLabel}
</Button>
)}
{onOk && (
<Button className="primary" onClick={onOk}>
{okLabel}
</Button>
)}
{onOk && <Button onClick={onOk}>{okLabel}</Button>}
</div>
);
+33 -24
View File
@@ -6,7 +6,7 @@ import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import cn from "classnames";
import { GlobalCommandRunner, SidebarModel } from "@/models";
import { GlobalModel, GlobalCommandRunner } from "@/models";
import { MagicLayout } from "@/app/magiclayout";
import "./resizablesidebar.less";
@@ -14,7 +14,6 @@ import "./resizablesidebar.less";
interface ResizableSidebarProps {
parentRef: React.RefObject<HTMLElement>;
position: "left" | "right";
model: SidebarModel;
enableSnap?: boolean;
className?: string;
children?: (toggleCollapsed: () => void) => React.ReactNode;
@@ -33,7 +32,7 @@ class ResizableSidebar extends React.Component<ResizableSidebarProps> {
startResizing(event: React.MouseEvent<HTMLDivElement>) {
event.preventDefault();
const { parentRef, position, model } = this.props;
const { parentRef, position } = this.props;
const parentRect = parentRef.current?.getBoundingClientRect();
if (!parentRect) return;
@@ -44,16 +43,17 @@ class ResizableSidebar extends React.Component<ResizableSidebarProps> {
this.startX = event.clientX - parentRect.left;
}
const collapsed = model.getCollapsed();
const mainSidebarModel = GlobalModel.mainSidebarModel;
const collapsed = mainSidebarModel.getCollapsed();
this.resizeStartWidth = model.getWidth();
this.resizeStartWidth = mainSidebarModel.getWidth();
document.addEventListener("mousemove", this.onMouseMove);
document.addEventListener("mouseup", this.stopResizing);
document.body.style.cursor = "col-resize";
mobx.action(() => {
model.setTempWidthAndTempCollapsed(this.resizeStartWidth, collapsed);
model.isDragging.set(true);
mainSidebarModel.setTempWidthAndTempCollapsed(this.resizeStartWidth, collapsed);
mainSidebarModel.isDragging.set(true);
})();
}
@@ -61,10 +61,11 @@ class ResizableSidebar extends React.Component<ResizableSidebarProps> {
onMouseMove(event: MouseEvent) {
event.preventDefault();
const { parentRef, enableSnap, position, model } = this.props;
const { parentRef, enableSnap, position } = this.props;
const parentRect = parentRef.current?.getBoundingClientRect();
const mainSidebarModel = GlobalModel.mainSidebarModel;
if (!model.isDragging.get() || !parentRect) return;
if (!mainSidebarModel.isDragging.get() || !parentRect) return;
let delta: number, newWidth: number;
@@ -99,27 +100,34 @@ class ResizableSidebar extends React.Component<ResizableSidebarProps> {
if (newWidth - dragResistance > minWidth && newWidth < snapPoint && dragDirection == "+") {
newWidth = snapPoint;
model.setTempWidthAndTempCollapsed(newWidth, false);
mainSidebarModel.setTempWidthAndTempCollapsed(newWidth, false);
} else if (newWidth + dragResistance < snapPoint && dragDirection == "-") {
newWidth = minWidth;
model.setTempWidthAndTempCollapsed(newWidth, true);
mainSidebarModel.setTempWidthAndTempCollapsed(newWidth, true);
} else if (newWidth > snapPoint) {
model.setTempWidthAndTempCollapsed(newWidth, false);
mainSidebarModel.setTempWidthAndTempCollapsed(newWidth, false);
}
} else {
if (newWidth <= MagicLayout.MainSidebarMinWidth) {
model.setTempWidthAndTempCollapsed(newWidth, true);
mainSidebarModel.setTempWidthAndTempCollapsed(newWidth, true);
} else {
model.setTempWidthAndTempCollapsed(newWidth, false);
mainSidebarModel.setTempWidthAndTempCollapsed(newWidth, false);
}
}
}
@boundMethod
stopResizing() {
const { model } = this.props;
let mainSidebarModel = GlobalModel.mainSidebarModel;
model.saveState(model.tempWidth.get(), model.tempCollapsed.get());
GlobalCommandRunner.clientSetSidebar(
mainSidebarModel.tempWidth.get(),
mainSidebarModel.tempCollapsed.get()
).finally(() => {
mobx.action(() => {
mainSidebarModel.isDragging.set(false);
})();
});
document.removeEventListener("mousemove", this.onMouseMove);
document.removeEventListener("mouseup", this.stopResizing);
@@ -128,18 +136,19 @@ class ResizableSidebar extends React.Component<ResizableSidebarProps> {
@boundMethod
toggleCollapsed() {
const { model } = this.props;
const mainSidebarModel = GlobalModel.mainSidebarModel;
const tempCollapsed = model.getCollapsed();
const width = model.getWidth(true);
model.setTempWidthAndTempCollapsed(width, !tempCollapsed);
model.saveState(width, !tempCollapsed);
const tempCollapsed = mainSidebarModel.getCollapsed();
const width = mainSidebarModel.getWidth(true);
mainSidebarModel.setTempWidthAndTempCollapsed(width, !tempCollapsed);
GlobalCommandRunner.clientSetSidebar(width, !tempCollapsed);
}
render() {
const { className, children, model } = this.props;
const width = model.getWidth();
const isCollapsed = model.getCollapsed();
const { className, children } = this.props;
const mainSidebarModel = GlobalModel.mainSidebarModel;
const width = mainSidebarModel.getWidth();
const isCollapsed = mainSidebarModel.getCollapsed();
return (
<div className={cn("sidebar", className, { collapsed: isCollapsed })} style={{ width, minWidth: width }}>
+1 -1
View File
@@ -54,7 +54,7 @@ class AlertModal extends React.Component<{}, {}> {
</div>
<div className="wave-modal-footer">
<If condition={isConfirm}>
<Button className="secondary" onClick={this.closeModal}>
<Button theme="secondary" onClick={this.closeModal}>
Cancel
</Button>
<Button autoFocus={true} onClick={this.handleOK}>
+1 -1
View File
@@ -31,7 +31,7 @@ class ClientStopModal extends React.Component<{}, {}> {
</If>
<div>
<Button
className="secondary"
theme="secondary"
onClick={this.refreshClient}
leftIcon={<i className="fa-sharp fa-solid fa-rotate"></i>}
>
+2 -2
View File
@@ -75,7 +75,7 @@ class DisconnectedModal extends React.Component<{}, {}> {
</div>
<div className="wave-modal-footer">
<Button
className="secondary"
theme="secondary"
onClick={this.tryReconnect}
leftIcon={
<span className="icon">
@@ -86,7 +86,7 @@ class DisconnectedModal extends React.Component<{}, {}> {
Try Reconnect
</Button>
<Button
className="secondary"
theme="secondary"
onClick={this.restartServer}
leftIcon={<i className="fa-sharp fa-solid fa-triangle-exclamation"></i>}
>
+2 -9
View File
@@ -48,15 +48,8 @@ class TosModal extends React.Component<{}, {}> {
<div className="item-inner">
<div className="item-title">Telemetry</div>
<div className="item-text">
We only collect minimal <i>anonymous</i>
<a
target="_blank"
href={util.makeExternLink("https://docs.waveterm.dev/reference/telemetry")}
rel={"noopener"}
>
&nbsp;telemetry data&nbsp;
</a>
to help us understand how many people are using Wave.
We only collect minimal <i>anonymous</i> telemetry data to help us understand
how many people are using Wave.
</div>
<div className="item-field" style={{ marginTop: 2 }}>
<Toggle
+10 -10
View File
@@ -162,42 +162,42 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
renderHeaderBtns(remote: RemoteType): React.ReactNode {
let buttons: React.ReactNode[] = [];
const disconnectButton = (
<Button className="secondary" onClick={() => this.disconnectRemote(remote.remoteid)}>
<Button theme="secondary" onClick={() => this.disconnectRemote(remote.remoteid)}>
Disconnect Now
</Button>
);
const connectButton = (
<Button className="secondary" onClick={() => this.connectRemote(remote.remoteid)}>
<Button theme="secondary" onClick={() => this.connectRemote(remote.remoteid)}>
Connect Now
</Button>
);
const tryReconnectButton = (
<Button className="secondary" onClick={() => this.connectRemote(remote.remoteid)}>
<Button theme="secondary" onClick={() => this.connectRemote(remote.remoteid)}>
Try Reconnect
</Button>
);
let updateAuthButton = (
<Button className="secondary" onClick={() => this.openEditModal()}>
<Button theme="secondary" onClick={() => this.openEditModal()}>
Edit
</Button>
);
let cancelInstallButton = (
<Button className="secondary" onClick={() => this.cancelInstall(remote.remoteid)}>
<Button theme="secondary" onClick={() => this.cancelInstall(remote.remoteid)}>
Cancel Install
</Button>
);
let installNowButton = (
<Button className="secondary" onClick={() => this.installRemote(remote.remoteid)}>
<Button theme="secondary" onClick={() => this.installRemote(remote.remoteid)}>
Install Now
</Button>
);
let archiveButton = (
<Button className="secondary" onClick={() => this.clickArchive()}>
<Button theme="secondary" onClick={() => this.clickArchive()}>
Delete
</Button>
);
const reinstallButton = (
<Button className="secondary" onClick={this.clickReinstall}>
<Button theme="secondary" onClick={this.clickReinstall}>
Reinstall
</Button>
);
@@ -207,7 +207,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
}
if (remote.sshconfigsrc == "sshconfig-import") {
archiveButton = (
<Button className="secondary" onClick={() => this.clickArchive()}>
<Button theme="secondary" onClick={() => this.clickArchive()}>
Delete
<Tooltip
message={
@@ -383,7 +383,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
</div>
<div className="wave-modal-footer">
<Button
className="secondary"
theme="secondary"
disabled={selectedRemoteStatus == "connecting"}
onClick={this.handleClose}
>
+2 -2
View File
@@ -180,14 +180,14 @@ class ConnectionsView extends React.Component<{ model: RemotesModel }, { hovered
</table>
<footer>
<Button
className="secondary"
theme="secondary"
leftIcon={<i className="fa-sharp fa-solid fa-plus"></i>}
onClick={this.handleAddConnection}
>
New Connection
</Button>
<Button
className="secondary"
theme="secondary"
leftIcon={<i className="fa-sharp fa-solid fa-fw fa-file-import"></i>}
onClick={this.handleImportSshConfig}
>
+1
View File
@@ -69,6 +69,7 @@
&.error-mask {
background-color: var(--line-error-bg-color);
border-left: 4px solid var(--line-error-border-left-color);
}
}
+3 -11
View File
@@ -53,16 +53,8 @@ let heightLog = {};
dayjs.extend(localizedFormat);
function cmdShouldMarkError(cmd: Cmd): boolean {
if (cmd.getStatus() == "error") {
return true;
}
let exitCode = cmd.getExitCode();
// 0, SIGINT, or SIGPIPE
if (exitCode == 0 || exitCode == 130 || exitCode == 141) {
return false;
}
return true;
function cmdHasError(cmd: Cmd): boolean {
return cmd.getStatus() == "error" || cmd.getExitCode() != 0;
}
function getIsHidePrompt(line: LineType): boolean {
@@ -709,7 +701,7 @@ class LineCmd extends React.Component<
)
.get();
const isRunning = cmd.isRunning();
const cmdError = cmdShouldMarkError(cmd);
const cmdError = cmdHasError(cmd);
const mainDivCn = cn(
"line",
"line-cmd",

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