merge branch 'main' into 'ssh--auth-control'

This was mostly straightforward, but it appears that a previous commit
to main broke the user input modals by deleting a function. This adds
that back in addition to the merge.
This commit is contained in:
Sylvia Crowe 2024-02-13 16:30:07 -08:00
parent 6bd60e8330
commit 5abff8075b
142 changed files with 2437 additions and 2502 deletions

View File

@ -7,10 +7,9 @@ import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { If } from "tsx-control-statements/components";
import dayjs from "dayjs";
import type { ContextMenuOpts } from "../types/types";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { GlobalModel } from "../models";
import { isBlank } from "../util/util";
import { GlobalModel } from "@/models";
import { isBlank } from "@/util/util";
import { WorkspaceView } from "./workspace/workspaceview";
import { PluginsView } from "./pluginsview/pluginsview";
import { BookmarksView } from "./bookmarks/bookmarks";
@ -25,8 +24,6 @@ import "./app.less";
dayjs.extend(localizedFormat);
type OV<V> = mobx.IObservableValue<V>;
@mobxReact.observer
class App extends React.Component<{}, {}> {
dcWait: OV<boolean> = mobx.observable.box(false, { name: "dcWait" });

View File

@ -47,3 +47,13 @@ export const TabIcons = [
export const VERSION = __WAVETERM_VERSION__;
// @ts-ignore
export const BUILD = __WAVETERM_BUILD__;
/**
* Levels for the screen status indicator
*/
export enum StatusIndicatorLevel {
None = 0,
Output = 1,
Success = 2,
Error = 3,
}

View File

@ -1,4 +1,4 @@
@import "../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.bookmarks-view {
background-color: @background-session;

View File

@ -7,15 +7,14 @@ import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { If, For } from "tsx-control-statements/components";
import cn from "classnames";
import type { BookmarkType } from "../../types/types";
import { GlobalModel } from "../../models";
import { CmdStrCode, Markdown } from "../common/elements";
import { GlobalModel } from "@/models";
import { CmdStrCode, Markdown } from "@/common/elements";
import { ReactComponent as XmarkIcon } from "../assets/icons/line/xmark.svg";
import { ReactComponent as CopyIcon } from "../assets/icons/favourites/copy.svg";
import { ReactComponent as PenIcon } from "../assets/icons/favourites/pen.svg";
import { ReactComponent as TrashIcon } from "../assets/icons/favourites/trash.svg";
import { ReactComponent as FavoritesIcon } from "../assets/icons/favourites.svg";
import { ReactComponent as XmarkIcon } from "@/assets/icons/line/xmark.svg";
import { ReactComponent as CopyIcon } from "@/assets/icons/favourites/copy.svg";
import { ReactComponent as PenIcon } from "@/assets/icons/favourites/pen.svg";
import { ReactComponent as TrashIcon } from "@/assets/icons/favourites/trash.svg";
import { ReactComponent as FavoritesIcon } from "@/assets/icons/favourites.svg";
import "./bookmarks.less";

View File

@ -1,4 +1,4 @@
@import "../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.clientsettings-view {
background-color: @background-session;

View File

@ -6,20 +6,19 @@ import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import cn from "classnames";
import { GlobalModel, GlobalCommandRunner, RemotesModel } from "../../models";
import { Toggle, InlineSettingsTextEdit, SettingsError, Dropdown } from "../common/elements";
import * as types from "../../types/types";
import { commandRtnHandler, isBlank } from "../../util/util";
import * as appconst from "../appconst";
import { GlobalModel, GlobalCommandRunner, RemotesModel } from "@/models";
import { Toggle, InlineSettingsTextEdit, SettingsError, Dropdown } from "@/common/elements";
import { commandRtnHandler, isBlank } from "@/util/util";
import * as appconst from "@/app/appconst";
import "./clientsettings.less";
@mobxReact.observer
class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hoveredItemId: string }> {
fontSizeDropdownActive: types.OV<boolean> = mobx.observable.box(false, {
fontSizeDropdownActive: OV<boolean> = mobx.observable.box(false, {
name: "clientSettings-fontSizeDropdownActive",
});
errorMessage: types.OV<string> = mobx.observable.box(null, { name: "ClientSettings-errorMessage" });
errorMessage: OV<string> = mobx.observable.box(null, { name: "ClientSettings-errorMessage" });
@boundMethod
dismissError(): void {
@ -48,7 +47,7 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
@boundMethod
handleChangeTelemetry(val: boolean): void {
let prtn: Promise<types.CommandRtnType> = null;
let prtn: Promise<CommandRtnType> = null;
if (val) {
prtn = GlobalCommandRunner.telemetryOn(false);
} else {
@ -59,7 +58,7 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
@boundMethod
handleChangeReleaseCheck(val: boolean): void {
let prtn: Promise<types.CommandRtnType> = null;
let prtn: Promise<CommandRtnType> = null;
if (val) {
prtn = GlobalCommandRunner.releaseCheckAutoOn(false);
} else {
@ -112,7 +111,7 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
return null;
}
let cdata: types.ClientDataType = GlobalModel.clientData.get();
let cdata: ClientDataType = GlobalModel.clientData.get();
let openAIOpts = cdata.openaiopts ?? {};
let apiTokenStr = isBlank(openAIOpts.apitoken) ? "(not set)" : "********";
let maxTokensStr = String(

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.wave-button {
background: none;

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.checkbox {
display: flex;

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.cmdstr-code {
position: relative;

View File

@ -6,8 +6,8 @@ import { boundMethod } from "autobind-decorator";
import cn from "classnames";
import { If } from "tsx-control-statements/components";
import { ReactComponent as CheckIcon } from "../../assets/icons/line/check.svg";
import { ReactComponent as CopyIcon } from "../../assets/icons/history/copy.svg";
import { ReactComponent as CheckIcon } from "@/assets/icons/line/check.svg";
import { ReactComponent as CopyIcon } from "@/assets/icons/history/copy.svg";
import "./cmdstrcode.less";

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.wave-dropdown {
position: relative;

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.inline-edit {
.icon {

View File

@ -7,12 +7,10 @@ import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import cn from "classnames";
import { If } from "tsx-control-statements/components";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "../../../util/keyutil";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "@/util/keyutil";
import "./inlinesettingstextedit.less";
type OV<V> = mobx.IObservableValue<V>;
@mobxReact.observer
class InlineSettingsTextEdit extends React.Component<
{

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.wave-input-decoration {
display: flex;

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.markdown {
color: @term-white;

View File

@ -6,7 +6,7 @@ import * as mobxReact from "mobx-react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import cn from "classnames";
import { GlobalModel } from "../../../models";
import { GlobalModel } from "@/models";
import "./markdown.less";

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.wave-modal-container {
position: fixed;

View File

@ -10,8 +10,6 @@ import { IconButton } from "./iconbutton";
import "./modal.less";
type OV<V> = mobx.IObservableValue<V>;
interface ModalHeaderProps {
onClose?: () => void;
title: string;

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.wave-password {
.wave-textfield-inner-eye {

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.sidebar-handle {
position: absolute;

View File

@ -6,13 +6,11 @@ import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import cn from "classnames";
import { GlobalModel, GlobalCommandRunner } from "../../../models";
import { MagicLayout } from "../../magiclayout";
import { GlobalModel, GlobalCommandRunner } from "@/models";
import { MagicLayout } from "@/app/magiclayout";
import "./resizablesidebar.less";
type OV<V> = mobx.IObservableValue<V>;
interface ResizableSidebarProps {
parentRef: React.RefObject<HTMLElement>;
position: "left" | "right";

View File

@ -6,8 +6,6 @@ import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
type OV<V> = mobx.IObservableValue<V>;
@mobxReact.observer
class SettingsError extends React.Component<{ errorMessage: OV<string> }, {}> {
@boundMethod

View File

@ -1,8 +1,8 @@
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import { GlobalModel } from "../../../models";
import * as appconst from "../../appconst";
import { GlobalModel } from "@/models";
import * as appconst from "@/app/appconst";
function ShowWaveShellInstallPrompt(callbackFn: () => void) {
let message: string = `

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.wave-status-container {
display: flex;

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.wave-textfield {
display: flex;

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.checkbox-toggle {
position: relative;

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.wave-tooltip {
display: flex;

View File

@ -1,5 +1,4 @@
import React, { Component, ReactNode } from "react";
import { RendererContext } from "../../../types/types";
import cn from "classnames";
interface ErrorBoundaryState {

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.front-icon {
margin-right: 5px;

View File

@ -1,12 +1,12 @@
import React from "react";
import { StatusIndicatorLevel } from "../../../types/types";
import cn from "classnames";
import { ReactComponent as SpinnerIndicator } from "../../assets/icons/spinner-indicator.svg";
import { ReactComponent as SpinnerIndicator } from "@/assets/icons/spinner-indicator.svg";
import { boundMethod } from "autobind-decorator";
import * as mobx from "mobx";
import * as mobxReact from "mobx-react";
import * as appconst from "@/app/appconst";
import { ReactComponent as RotateIconSvg } from "../../assets/icons/line/rotate.svg";
import { ReactComponent as RotateIconSvg } from "@/assets/icons/line/rotate.svg";
interface PositionalIconProps {
children?: React.ReactNode;
@ -131,7 +131,7 @@ interface StatusIndicatorProps {
/**
* The level of the status indicator. This will determine the color of the status indicator.
*/
level: StatusIndicatorLevel;
level: appconst.StatusIndicatorLevel;
className?: string;
/**
* If true, a spinner will be shown around the status indicator.
@ -191,16 +191,16 @@ export class StatusIndicator extends React.Component<StatusIndicatorProps> {
const { level, className, runningCommands } = this.props;
const spinnerVisible = this.spinnerVisible.get();
let statusIndicator = null;
if (level != StatusIndicatorLevel.None || spinnerVisible) {
if (level != appconst.StatusIndicatorLevel.None || spinnerVisible) {
let indicatorLevelClass = null;
switch (level) {
case StatusIndicatorLevel.Output:
case appconst.StatusIndicatorLevel.Output:
indicatorLevelClass = "output";
break;
case StatusIndicatorLevel.Success:
case appconst.StatusIndicatorLevel.Success:
indicatorLevelClass = "success";
break;
case StatusIndicatorLevel.Error:
case appconst.StatusIndicatorLevel.Error:
indicatorLevelClass = "error";
break;
}

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.about-modal {
.wave-modal-content {

View File

@ -5,12 +5,12 @@ import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { GlobalModel } from "../../../models";
import { Modal, LinkButton } from "../elements";
import * as util from "../../../util/util";
import * as appconst from "../../appconst";
import { GlobalModel } from "@/models";
import { Modal, LinkButton } from "@/elements";
import * as util from "@/util/util";
import * as appconst from "@/app/appconst";
import logo from "../../assets/waveterm-logo-with-bg.svg";
import logo from "@/assets/waveterm-logo-with-bg.svg";
import "./about.less";
@mobxReact.observer

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.alert-modal {
width: 500px;

View File

@ -5,8 +5,8 @@ import * as React from "react";
import * as mobxReact from "mobx-react";
import { boundMethod } from "autobind-decorator";
import { If } from "tsx-control-statements/components";
import { Markdown, Modal, Button, Checkbox } from "../elements";
import { GlobalModel, GlobalCommandRunner } from "../../../models";
import { Markdown, Modal, Button, Checkbox } from "@/elements";
import { GlobalModel, GlobalCommandRunner } from "@/models";
import "./alert.less";

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.clientstop-modal {
.inner-content {

View File

@ -5,8 +5,8 @@ import * as React from "react";
import * as mobxReact from "mobx-react";
import { boundMethod } from "autobind-decorator";
import { If } from "tsx-control-statements/components";
import { GlobalModel } from "../../../models";
import { Modal, Button } from "../elements";
import { GlobalModel } from "@/models";
import { Modal, Button } from "@/elements";
import "./clientstop.less";

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.crconn-modal {
width: 452px;

View File

@ -6,8 +6,7 @@ import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { If } from "tsx-control-statements/components";
import { GlobalModel, GlobalCommandRunner, RemotesModel } from "../../../models";
import * as T from "../../../types/types";
import { GlobalModel, GlobalCommandRunner, RemotesModel } from "@/models";
import {
Modal,
TextField,
@ -17,13 +16,11 @@ import {
PasswordField,
Tooltip,
ShowWaveShellInstallPrompt,
} from "../elements";
import * as util from "../../../util/util";
} from "@/elements";
import * as util from "@/util/util";
import "./createremoteconn.less";
type OV<V> = mobx.IObservableValue<V>;
@mobxReact.observer
class CreateRemoteConnModal extends React.Component<{}, {}> {
tempAlias: OV<string>;
@ -35,7 +32,7 @@ class CreateRemoteConnModal extends React.Component<{}, {}> {
tempKeyFile: OV<string>;
tempShellPref: OV<string>;
errorStr: OV<string>;
remoteEdit: T.RemoteEditType;
remoteEdit: RemoteEditType;
model: RemotesModel;
constructor(props: { remotesModel?: RemotesModel }) {

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.disconnected-modal {
.wave-modal-content {

View File

@ -5,8 +5,8 @@ import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { GlobalModel } from "../../../models";
import { Modal, Button } from "../elements";
import { GlobalModel } from "@/models";
import { Modal, Button } from "@/elements";
import "./disconnected.less";

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.erconn-modal {
width: 502px;

View File

@ -6,15 +6,12 @@ import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { If } from "tsx-control-statements/components";
import { boundMethod } from "autobind-decorator";
import { GlobalModel, GlobalCommandRunner, RemotesModel } from "../../../models";
import * as T from "../../../types/types";
import { Modal, TextField, InputDecoration, Dropdown, PasswordField, Tooltip } from "../elements";
import * as util from "../../../util/util";
import { GlobalModel, GlobalCommandRunner, RemotesModel } from "@/models";
import { Modal, TextField, InputDecoration, Dropdown, PasswordField, Tooltip } from "@/elements";
import * as util from "@/util/util";
import "./editremoteconn.less";
type OV<V> = mobx.IObservableValue<V>;
const PasswordUnchangedSentinel = "--unchanged--";
@mobxReact.observer
@ -42,11 +39,11 @@ class EditRemoteConnModal extends React.Component<{}, {}> {
return this.model.selectedRemoteId.get();
}
get selectedRemote(): T.RemoteType {
get selectedRemote(): RemoteType {
return GlobalModel.getRemote(this.selectedRemoteId);
}
get remoteEdit(): T.RemoteEditType {
get remoteEdit(): RemoteEditType {
return this.model.remoteEdit.get();
}

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.line-settings-modal {
width: 640px;

View File

@ -5,16 +5,13 @@ import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { GlobalModel, GlobalCommandRunner } from "../../../models";
import { SettingsError, Modal, Dropdown } from "../elements";
import { LineType, RendererPluginType } from "../../../types/types";
import { PluginModel } from "../../../plugins/plugins";
import { commandRtnHandler } from "../../../util/util";
import { GlobalModel, GlobalCommandRunner } from "@/models";
import { SettingsError, Modal, Dropdown } from "@/elements";
import { PluginModel } from "@/plugins/plugins";
import { commandRtnHandler } from "@/util/util";
import "./linesettings.less";
type OV<V> = mobx.IObservableValue<V>;
@mobxReact.observer
class LineSettingsModal extends React.Component<{}, {}> {
rendererDropdownActive: OV<boolean> = mobx.observable.box(false, { name: "lineSettings-rendererDropdownActive" });

View File

@ -3,7 +3,7 @@
import * as React from "react";
import * as mobxReact from "mobx-react";
import { GlobalModel } from "../../../models";
import { GlobalModel } from "@/models";
import { TosModal } from "./tos";
@mobxReact.observer

View File

@ -13,8 +13,8 @@ import {
ScreenSettingsModal,
LineSettingsModal,
UserInputModal,
} from "../modals";
import * as constants from "../../appconst";
} from "@/modals";
import * as constants from "@/app/appconst";
const modalsRegistry: { [key: string]: React.ComponentType } = {
[constants.ABOUT]: AboutModal,

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.screen-settings-modal {
width: 640px;

View File

@ -7,20 +7,16 @@ 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, Screen } from "../../../models";
import { Toggle, InlineSettingsTextEdit, SettingsError, Modal, Dropdown, Tooltip } from "../elements";
import { RemoteType } from "../../../types/types";
import * as util from "../../../util/util";
import { commandRtnHandler } from "../../../util/util";
import { ReactComponent as SquareIcon } from "../../assets/icons/tab/square.svg";
import { ReactComponent as GlobeIcon } from "../../assets/icons/globe.svg";
import { ReactComponent as StatusCircleIcon } from "../../assets/icons/statuscircle.svg";
import * as appconst from "../../appconst";
import { GlobalModel, GlobalCommandRunner, Screen } from "@/models";
import { Toggle, InlineSettingsTextEdit, SettingsError, Modal, Dropdown, Tooltip } from "@/elements";
import * as util from "@/util/util";
import { ReactComponent as SquareIcon } from "@/assets/icons/tab/square.svg";
import { ReactComponent as GlobeIcon } from "@/assets/icons/globe.svg";
import { ReactComponent as StatusCircleIcon } from "@/assets/icons/statuscircle.svg";
import * as appconst from "@/app/appconst";
import "./screensettings.less";
type OV<V> = mobx.IObservableValue<V>;
const ScreenDeleteMessage = `
Are you sure you want to delete this tab?
@ -98,7 +94,7 @@ class ScreenSettingsModal extends React.Component<{}, {}> {
return;
}
let prtn = GlobalCommandRunner.screenSetSettings(this.screenId, { tabcolor: color }, false);
commandRtnHandler(prtn, this.errorMessage);
util.commandRtnHandler(prtn, this.errorMessage);
}
@boundMethod
@ -119,7 +115,7 @@ class ScreenSettingsModal extends React.Component<{}, {}> {
return;
}
let prtn = GlobalCommandRunner.screenArchive(this.screenId, val);
commandRtnHandler(prtn, this.errorMessage);
util.commandRtnHandler(prtn, this.errorMessage);
}
@boundMethod
@ -137,7 +133,7 @@ class ScreenSettingsModal extends React.Component<{}, {}> {
return;
}
let prtn = GlobalCommandRunner.screenWebShare(this.screen.screenId, val);
commandRtnHandler(prtn, this.errorMessage);
util.commandRtnHandler(prtn, this.errorMessage);
});
}
@ -170,7 +166,7 @@ class ScreenSettingsModal extends React.Component<{}, {}> {
return;
}
let prtn = GlobalCommandRunner.screenSetSettings(this.screenId, { name: val }, false);
commandRtnHandler(prtn, this.errorMessage);
util.commandRtnHandler(prtn, this.errorMessage);
}
@boundMethod
@ -182,7 +178,7 @@ class ScreenSettingsModal extends React.Component<{}, {}> {
return;
}
let prtn = GlobalCommandRunner.screenSetSettings(this.screenId, { sharename: val }, false);
commandRtnHandler(prtn, this.errorMessage);
util.commandRtnHandler(prtn, this.errorMessage);
}
@boundMethod
@ -209,7 +205,7 @@ class ScreenSettingsModal extends React.Component<{}, {}> {
return;
}
let prtn = GlobalCommandRunner.screenDelete(this.screenId, false);
commandRtnHandler(prtn, this.errorMessage);
util.commandRtnHandler(prtn, this.errorMessage);
GlobalModel.modalsModel.popModal();
});
}

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.session-settings-modal {
width: 640px;

View File

@ -5,15 +5,12 @@ import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { GlobalModel, GlobalCommandRunner, Session } from "../../../models";
import { Toggle, InlineSettingsTextEdit, SettingsError, Modal, Tooltip } from "../elements";
import * as util from "../../../util/util";
import { commandRtnHandler } from "../../../util/util";
import { GlobalModel, GlobalCommandRunner, Session } from "@/models";
import { Toggle, InlineSettingsTextEdit, SettingsError, Modal, Tooltip } from "@/elements";
import * as util from "@/util/util";
import "./sessionsettings.less";
type OV<V> = mobx.IObservableValue<V>;
const SessionDeleteMessage = `
Are you sure you want to delete this workspace?
@ -52,7 +49,7 @@ class SessionSettingsModal extends React.Component<{}, {}> {
return;
}
let prtn = GlobalCommandRunner.sessionSetSettings(this.sessionId, { name: newVal }, false);
commandRtnHandler(prtn, this.errorMessage);
util.commandRtnHandler(prtn, this.errorMessage);
}
@boundMethod
@ -64,7 +61,7 @@ class SessionSettingsModal extends React.Component<{}, {}> {
return;
}
let prtn = GlobalCommandRunner.sessionArchive(this.sessionId, val);
commandRtnHandler(prtn, this.errorMessage);
util.commandRtnHandler(prtn, this.errorMessage);
}
@boundMethod
@ -76,7 +73,7 @@ class SessionSettingsModal extends React.Component<{}, {}> {
return;
}
let prtn = GlobalCommandRunner.sessionDelete(this.sessionId);
commandRtnHandler(prtn, this.errorMessage, () => GlobalModel.modalsModel.popModal());
util.commandRtnHandler(prtn, this.errorMessage, () => GlobalModel.modalsModel.popModal());
});
}

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.tabswitcher-modal {
width: 452px;

View File

@ -5,18 +5,20 @@ import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { For } from "tsx-control-statements/components";
import { If, For } from "tsx-control-statements/components";
import cn from "classnames";
import { GlobalModel, GlobalCommandRunner } from "../../../models";
import { Modal, TextField, InputDecoration, Tooltip } from "../elements";
import * as util from "../../../util/util";
import { Screen } from "../../../models";
import { ReactComponent as SquareIcon } from "../../assets/icons/tab/square.svg";
import { GlobalModel, GlobalCommandRunner } from "@/models";
import { Modal, TextField, InputDecoration, Tooltip } from "@/elements";
import * as util from "@/util/util";
import { Screen } from "@/models";
import { ReactComponent as SquareIcon } from "@/assets/icons/tab/square.svg";
import "./tabswitcher.less";
type OV<V> = mobx.IObservableValue<V>;
type OArr<V> = mobx.IObservableArray<V>;
type ViewDataType = {
label: string;
value: string;
};
type SwitcherDataType = {
sessionId: string;
@ -27,9 +29,25 @@ type SwitcherDataType = {
screenName: string;
icon: string;
color: string;
viewData?: ViewDataType;
};
const MaxOptionsToDisplay = 100;
const additionalOptions = [
{ label: "Connections", value: "connections" },
{ label: "History", value: "history" },
{ label: "Settings", value: "clientsettings" },
].map((item, index) => ({
sessionId: `additional-${index}`,
sessionName: "",
sessionIdx: -1,
screenId: `additional-${index}`,
screenIdx: -1,
screenName: "",
icon: "",
color: "",
viewData: item,
}));
@mobxReact.observer
class TabSwitcherModal extends React.Component<{}, {}> {
@ -47,8 +65,8 @@ class TabSwitcherModal extends React.Component<{}, {}> {
componentDidMount() {
this.activeSessionIdx = GlobalModel.getActiveSession().sessionIdx.get();
let oSessions = GlobalModel.sessionList;
let oScreens = GlobalModel.screenMap;
const oSessions = GlobalModel.sessionList;
const oScreens = GlobalModel.screenMap;
oScreens.forEach((oScreen) => {
if (oScreen == null) {
return;
@ -57,13 +75,13 @@ class TabSwitcherModal extends React.Component<{}, {}> {
return;
}
// Find the matching session in the observable array
let foundSession = oSessions.find((s) => {
const foundSession = oSessions.find((s) => {
return s.sessionId == oScreen.sessionId && !s.archived.get();
});
if (!foundSession) {
return;
}
let data: SwitcherDataType = {
const data: SwitcherDataType = {
sessionName: foundSession.name.get(),
sessionId: foundSession.sessionId,
sessionIdx: foundSession.sessionIdx.get(),
@ -88,11 +106,11 @@ class TabSwitcherModal extends React.Component<{}, {}> {
}
componentDidUpdate() {
let currFocusedIdx = this.focusedIdx.get();
const currFocusedIdx = this.focusedIdx.get();
// Check if selectedIdx has changed
if (currFocusedIdx !== this.prevFocusedIdx) {
let optionElement = this.optionRefs[currFocusedIdx]?.current;
const optionElement = this.optionRefs[currFocusedIdx]?.current;
if (optionElement) {
optionElement.scrollIntoView({ block: "nearest" });
@ -109,7 +127,7 @@ class TabSwitcherModal extends React.Component<{}, {}> {
@boundMethod
getTabIcon(screen: Screen): string {
let tabIcon = "default";
let screenOpts = screen.opts.get();
const screenOpts = screen.opts.get();
if (screenOpts != null && !util.isBlank(screenOpts.tabicon)) {
tabIcon = screenOpts.tabicon;
}
@ -119,7 +137,7 @@ class TabSwitcherModal extends React.Component<{}, {}> {
@boundMethod
getTabColor(screen: Screen): string {
let tabColor = "default";
let screenOpts = screen.opts.get();
const screenOpts = screen.opts.get();
if (screenOpts != null && !util.isBlank(screenOpts.tabcolor)) {
tabColor = screenOpts.tabcolor;
}
@ -132,7 +150,7 @@ class TabSwitcherModal extends React.Component<{}, {}> {
this.closeModal();
} else if (e.key === "ArrowUp" || e.key === "ArrowDown") {
e.preventDefault();
let newIndex = this.calculateNewIndex(e.key === "ArrowUp");
const newIndex = this.calculateNewIndex(e.key === "ArrowUp");
this.setFocusedIndex(newIndex);
} else if (e.key === "Enter") {
e.preventDefault();
@ -142,7 +160,7 @@ class TabSwitcherModal extends React.Component<{}, {}> {
@boundMethod
calculateNewIndex(isUpKey) {
let currentIndex = this.focusedIdx.get();
const currentIndex = this.focusedIdx.get();
if (isUpKey) {
return Math.max(currentIndex - 1, 0);
} else {
@ -165,6 +183,11 @@ class TabSwitcherModal extends React.Component<{}, {}> {
@boundMethod
handleSelect(index: number): void {
const selectedOption = this.sOptions[index];
if (selectedOption.sessionIdx === -1) {
GlobalCommandRunner.switchView(selectedOption.viewData.value);
this.closeModal();
return;
}
if (selectedOption) {
GlobalCommandRunner.switchScreen(selectedOption.screenId, selectedOption.sessionId);
this.closeModal();
@ -192,27 +215,28 @@ class TabSwitcherModal extends React.Component<{}, {}> {
@mobx.computed
@boundMethod
filterOptions(searchInput: string): SwitcherDataType[] {
let filteredScreens = [];
for (let i = 0; i < this.options.length; i++) {
let tab = this.options[i];
let match = false;
const searchLower = searchInput.toLowerCase();
let filteredScreens = this.options.filter((tab) => {
if (searchInput.includes("/")) {
let [sessionFilter, screenFilter] = searchInput.split("/").map((s) => s.trim().toLowerCase());
match =
const [sessionFilter, screenFilter] = searchInput.split("/").map((s) => s.trim().toLowerCase());
return (
tab.sessionName.toLowerCase().includes(sessionFilter) &&
tab.screenName.toLowerCase().includes(screenFilter);
tab.screenName.toLowerCase().includes(screenFilter)
);
} else {
match =
tab.sessionName.toLowerCase().includes(searchInput) ||
tab.screenName.toLowerCase().includes(searchInput);
return (
tab.sessionName.toLowerCase().includes(searchLower) ||
tab.screenName.toLowerCase().includes(searchLower)
);
}
});
// Add tab to filtered list if it matches the criteria
if (match) {
filteredScreens.push(tab);
}
if (searchLower.length > 0) {
const additionalFiltered = additionalOptions.filter((item) =>
item.viewData?.label.toLowerCase().includes(searchLower)
);
filteredScreens = filteredScreens.concat(additionalFiltered);
}
return filteredScreens;
@ -221,9 +245,10 @@ class TabSwitcherModal extends React.Component<{}, {}> {
@mobx.computed
@boundMethod
sortOptions(options: SwitcherDataType[]): SwitcherDataType[] {
return options.sort((a, b) => {
let aInCurrentSession = a.sessionIdx === this.activeSessionIdx;
let bInCurrentSession = b.sessionIdx === this.activeSessionIdx;
const mainOptions = options.filter((o) => o.sessionIdx !== -1);
mainOptions.sort((a, b) => {
const aInCurrentSession = a.sessionIdx === this.activeSessionIdx;
const bInCurrentSession = b.sessionIdx === this.activeSessionIdx;
// Tabs in the current session are sorted by screenIdx
if (aInCurrentSession && bInCurrentSession) {
@ -246,11 +271,16 @@ class TabSwitcherModal extends React.Component<{}, {}> {
}
}
});
const additionalOptions = options.filter((o) => o.sessionIdx === -1);
additionalOptions.sort((a, b) => a.viewData?.label.localeCompare(b.viewData?.label));
return mainOptions.concat(additionalOptions);
}
@boundMethod
renderIcon(option: SwitcherDataType): React.ReactNode {
let tabIcon = option.icon;
const tabIcon = option.icon;
if (tabIcon === "default" || tabIcon === "square") {
return <SquareIcon className="left-icon" />;
}
@ -271,10 +301,15 @@ class TabSwitcherModal extends React.Component<{}, {}> {
})}
onClick={() => this.handleSelect(index)}
>
<div className={cn("icon", "color-" + option.color)}>{this.renderIcon(option)}</div>
<div className="tabname">
#{option.sessionName} / {option.screenName}
</div>
<If condition={option.sessionIdx != -1}>
<div className={cn("icon", "color-" + option.color)}>{this.renderIcon(option)}</div>
<div className="tabname">
#{option.sessionName} / {option.screenName}
</div>
</If>
<If condition={option.sessionIdx == -1}>
<div className="tabname">{option.viewData?.label}</div>
</If>
</div>
);
}
@ -293,13 +328,13 @@ class TabSwitcherModal extends React.Component<{}, {}> {
decoration={{
startDecoration: (
<InputDecoration position="start">
<div className="tabswitcher-search-prefix">Switch to Tab:</div>
<div className="tabswitcher-search-prefix">Go to:</div>
</InputDecoration>
),
endDecoration: (
<InputDecoration>
<Tooltip
message={`Type to filter workspaces and tabs.`}
message={`Type to filter workspaces, tabs and views.`}
icon={<i className="fa-sharp fa-regular fa-circle-question" />}
>
<i className="fa-sharp fa-regular fa-circle-question" />

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.tos-modal {
width: 640px;

View File

@ -4,14 +4,13 @@
import * as React from "react";
import * as mobxReact from "mobx-react";
import { boundMethod } from "autobind-decorator";
import { GlobalModel, GlobalCommandRunner } from "../../../models";
import { Toggle, Modal, Button } from "../elements";
import * as util from "../../../util/util";
import { ClientDataType } from "../../../types/types";
import { GlobalModel, GlobalCommandRunner } from "@/models";
import { Toggle, Modal, Button } from "@/elements";
import * as util from "@/util/util";
import shield from "../../assets/icons/shield_check.svg";
import help from "../../assets/icons/help_filled.svg";
import github from "../../assets/icons/github.svg";
import shield from "@/assets/icons/shield_check.svg";
import help from "@/assets/icons/help_filled.svg";
import github from "@/assets/icons/github.svg";
import "./tos.less";

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.userinput-modal {
width: 500px;

View File

@ -1,8 +1,7 @@
import * as React from "react";
import { GlobalModel } from "../../../models";
import { GlobalModel } from "@/models";
import { Choose, When, If } from "tsx-control-statements/components";
import { Modal, PasswordField, Markdown } from "../elements";
import { UserInputRequest } from "../../../types/types";
import { Modal, PasswordField, Markdown } from "@/elements";
import "./userinput.less";

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.rconndetail-modal {
width: 631px;
@ -54,6 +54,8 @@
}
.remote-detail {
width: 100%;
.settings-field {
display: flex;
flex-direction: row;
@ -91,8 +93,9 @@
}
.terminal-wrapper {
width: 100%;
margin-top: 5px;
overflow-x: auto;
overflow-y: hidden;
.terminal-connectelem {
height: 163px !important; // Needed to override plugin height
@ -111,7 +114,6 @@
.xterm-screen {
padding: 10px;
width: 541px !important; // Needed to override plugin width
}
}
}

View File

@ -7,17 +7,14 @@ 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, RemotesModel } from "../../../models";
import * as T from "../../../types/types";
import { Modal, Tooltip, Button, Status } from "../elements";
import * as util from "../../../util/util";
import * as textmeasure from "../../../util/textmeasure";
import { GlobalModel, GlobalCommandRunner, RemotesModel } from "@/models";
import { Modal, Tooltip, Button, Status } from "@/elements";
import * as util from "@/util/util";
import * as textmeasure from "@/util/textmeasure";
import * as appconst from "@/app/appconst";
import "./viewremoteconndetail.less";
const RemotePtyRows = 9;
const RemotePtyCols = 80;
@mobxReact.observer
class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
termRef: React.RefObject<any> = React.createRef();
@ -29,7 +26,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
}
@mobx.computed
getSelectedRemote(): T.RemoteType {
getSelectedRemote(): RemoteType {
const selectedRemoteId = this.model.selectedRemoteId.get();
return GlobalModel.getRemote(selectedRemoteId);
}
@ -60,7 +57,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
}
}
getRemoteTypeStr(remote: T.RemoteType): string {
getRemoteTypeStr(remote: RemoteType): string {
if (!util.isBlank(remote.uname)) {
let unameStr = remote.uname;
unameStr = unameStr.replace("|", ", ");
@ -138,7 +135,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
this.model.setRecentConnAdded(false);
}
renderInstallStatus(remote: T.RemoteType): any {
renderInstallStatus(remote: RemoteType): any {
let statusStr: string = null;
if (remote.installstatus == "disconnected") {
if (remote.needsmshellupgrade) {
@ -162,7 +159,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
);
}
renderHeaderBtns(remote: T.RemoteType): React.ReactNode {
renderHeaderBtns(remote: RemoteType): React.ReactNode {
let buttons: React.ReactNode[] = [];
const disconnectButton = (
<Button theme="secondary" onClick={() => this.disconnectRemote(remote.remoteid)}>
@ -256,7 +253,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
);
}
getMessage(remote: T.RemoteType): string {
getMessage(remote: RemoteType): string {
let message = "";
if (remote.status == "connected") {
message = "Connected and ready to run commands.";
@ -295,7 +292,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
let model = this.model;
let isTermFocused = this.model.remoteTermWrapFocus.get();
let termFontSize = GlobalModel.termFontSize.get();
let termWidth = textmeasure.termWidthFromCols(RemotePtyCols, termFontSize);
let termWidth = textmeasure.termWidthFromCols(appconst.RemotePtyCols, termFontSize);
let remoteAliasText = util.isBlank(remote.remotealias) ? "(none)" : remote.remotealias;
let selectedRemoteStatus = this.getSelectedRemote().status;
@ -373,7 +370,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
ref={this.termRef}
data-remoteid={remote.remoteid}
style={{
height: textmeasure.termHeightFromRows(RemotePtyRows, termFontSize),
height: textmeasure.termHeightFromRows(appconst.RemotePtyRows, termFontSize),
width: termWidth,
}}
></div>
@ -397,7 +394,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
}
}
function getImportTooltip(remote: T.RemoteType): React.ReactElement<any, any> {
function getImportTooltip(remote: RemoteType): React.ReactElement<any, any> {
if (remote.sshconfigsrc == "sshconfig-import") {
return (
<Tooltip

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.term-prompt {
font-weight: 300;

View File

@ -3,42 +3,17 @@
import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { GlobalModel } from "../../../models";
import type {
LineType,
RemoteType,
RemotePtrType,
LineHeightChangeCallbackType,
LineContainerType,
} from "../../../types/types";
import { GlobalModel } from "@/models";
import cn from "classnames";
import { isBlank } from "../../../util/util";
import { ReactComponent as FolderIcon } from "../../assets/icons/folder.svg";
import { isBlank } from "@/util/util";
import { ReactComponent as FolderIcon } from "@/assets/icons/folder.svg";
import "./prompt.less";
dayjs.extend(localizedFormat);
type OV<V> = mobx.IObservableValue<V>;
type OArr<V> = mobx.IObservableArray<V>;
type OMap<K, V> = mobx.ObservableMap<K, V>;
type RendererComponentProps = {
screen: LineContainerType;
line: LineType;
width: number;
staticRender: boolean;
visible: OV<boolean>;
onHeightChange: LineHeightChangeCallbackType;
collapsed: boolean;
};
type RendererComponentType = {
new (props: RendererComponentProps): React.Component<RendererComponentProps, {}>;
};
function makeFullRemoteRef(ownerName: string, remoteRef: string, name: string): string {
if (isBlank(ownerName) && isBlank(name)) {
return remoteRef;

View File

@ -1,4 +1,4 @@
@import "../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.connections-view {
.no-items {

View File

@ -7,16 +7,12 @@ import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { If, For } from "tsx-control-statements/components";
import cn from "classnames";
import { GlobalModel, RemotesModel, GlobalCommandRunner } from "../../models";
import { Button, Status, ShowWaveShellInstallPrompt } from "../common/elements";
import * as T from "../../types/types";
import * as util from "../../util/util";
import * as appconst from "../appconst";
import { GlobalModel, RemotesModel, GlobalCommandRunner } from "@/models";
import { Button, Status, ShowWaveShellInstallPrompt } from "@/common/elements";
import * as util from "@/util/util";
import "./connections.less";
type OV<V> = mobx.IObservableValue<V>;
@mobxReact.observer
class ConnectionsView extends React.Component<{ model: RemotesModel }, { hoveredItemId: string }> {
tableRef: React.RefObject<any> = React.createRef();
@ -54,13 +50,13 @@ class ConnectionsView extends React.Component<{ model: RemotesModel }, { hovered
}
@boundMethod
getName(item: T.RemoteType) {
getName(item: RemoteType) {
const { remotealias, remotecanonicalname } = item;
return remotealias ? `${remotealias} [${remotecanonicalname}]` : remotecanonicalname;
}
@boundMethod
getImportSymbol(item: T.RemoteType): React.ReactElement<any, any> {
getImportSymbol(item: RemoteType): React.ReactElement<any, any> {
const { sshconfigsrc } = item;
if (sshconfigsrc == "sshconfig-import") {
return <i title="Connection Imported from SSH Config" className="fa-sharp fa-solid fa-file-import" />;
@ -131,7 +127,7 @@ class ConnectionsView extends React.Component<{ model: RemotesModel }, { hovered
}
let items = util.sortAndFilterRemotes(GlobalModel.remotes.slice());
let item: T.RemoteType = null;
let item: RemoteType = null;
return (
<div className={cn("view connections-view")}>

View File

@ -1,4 +1,4 @@
@import "../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.history-view {
background-color: @background-session;
@ -14,7 +14,7 @@
width: 16px;
height: 16px;
border-radius: 4px;
border: 1px solid #3B3F3A;
border: 1px solid #3b3f3a;
background: rgba(213, 254, 175, 0.03);
}
@ -30,7 +30,7 @@
height: 16px;
fill: rgba(213, 254, 175, 0.03);
stroke-width: 1px;
stroke: #3B3F3A;
stroke: #3b3f3a;
}
}
@ -264,6 +264,7 @@
margin: 0px 10px 10px 10px;
table-layout: fixed;
border-top: 2px solid #ccc;
width: calc(100% - 20px);
tr.active-history-item {
td {
@ -309,9 +310,8 @@
tr.history-item {
padding: 0 10px 0 10px;
display: flex;
border-bottom: 1px solid rgba(250, 250, 250, 0.10);
border-bottom: 1px solid rgba(250, 250, 250, 0.1);
align-items: center;
height: 40px;
color: @text-secondary;
&.is-selected {

View File

@ -8,40 +8,30 @@ import { If, For } from "tsx-control-statements/components";
import { sprintf } from "sprintf-js";
import { boundMethod } from "autobind-decorator";
import cn from "classnames";
import { GlobalModel, GlobalCommandRunner, Cmd } from "../../models";
import { HistoryItem, RemotePtrType, LineType, CmdDataType } from "../../types/types";
import { GlobalModel, GlobalCommandRunner, Cmd } from "@/models";
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import customParseFormat from "dayjs/plugin/customParseFormat";
import { Line } from "../line/linecomps";
import { CmdStrCode } from "../common/elements";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "../../util/keyutil";
import { Line } from "@/app/line/linecomps";
import { CmdStrCode } from "@/common/elements";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "@/util/keyutil";
import { ReactComponent as FavoritesIcon } from "../assets/icons/favourites.svg";
import { ReactComponent as XmarkIcon } from "../assets/icons/line/xmark.svg";
import { ReactComponent as AngleDownIcon } from "../assets/icons/history/angle-down.svg";
import { ReactComponent as ChevronLeftIcon } from "../assets/icons/history/chevron-left.svg";
import { ReactComponent as ChevronRightIcon } from "../assets/icons/history/chevron-right.svg";
import { ReactComponent as RightIcon } from "../assets/icons/history/right.svg";
import { ReactComponent as SearchIcon } from "../assets/icons/history/search.svg";
import { ReactComponent as SquareCheckIcon } from "../assets/icons/history/square-check.svg";
import { ReactComponent as SquareMinusIcon } from "../assets/icons/history/square-minus.svg";
import { ReactComponent as SquareIcon } from "../assets/icons/history/square.svg";
import { ReactComponent as TrashIcon } from "../assets/icons/trash.svg";
import { ReactComponent as CheckedCheckbox } from "../assets/icons/checked-checkbox.svg";
import { ReactComponent as CheckIcon } from "../assets/icons/line/check.svg";
import { ReactComponent as CopyIcon } from "../assets/icons/history/copy.svg";
import { ReactComponent as XmarkIcon } from "@/assets/icons/line/xmark.svg";
import { ReactComponent as AngleDownIcon } from "@/assets/icons/history/angle-down.svg";
import { ReactComponent as ChevronLeftIcon } from "@/assets/icons/history/chevron-left.svg";
import { ReactComponent as ChevronRightIcon } from "@/assets/icons/history/chevron-right.svg";
import { ReactComponent as RightIcon } from "@/assets/icons/history/right.svg";
import { ReactComponent as SearchIcon } from "@/assets/icons/history/search.svg";
import { ReactComponent as TrashIcon } from "@/assets/icons/trash.svg";
import { ReactComponent as CheckedCheckbox } from "@/assets/icons/checked-checkbox.svg";
import { ReactComponent as CheckIcon } from "@/assets/icons/line/check.svg";
import { ReactComponent as CopyIcon } from "@/assets/icons/history/copy.svg";
import "./history.less";
dayjs.extend(customParseFormat);
dayjs.extend(localizedFormat);
type OV<V> = mobx.IObservableValue<V>;
type OArr<V> = mobx.IObservableArray<V>;
type OMap<K, V> = mobx.ObservableMap<K, V>;
type CV<V> = mobx.IComputedValue<V>;
function isBlank(s: string) {
return s == null || s == "";
}
@ -429,8 +419,16 @@ class HistoryView extends React.Component<{}, {}> {
let sessionId: string = null;
let remoteIds = Object.keys(rnames);
let remoteId: string = null;
// TODO: something is weird with how we calculate width for views. Before, history view was not honoring tab width. This fix is copied from workspaceview.tsx, which had a similar issue.
const width = window.innerWidth - 6 - GlobalModel.mainSidebarModel.getWidth();
return (
<div className={cn("history-view", { "is-hidden": isHidden })}>
<div
className={cn("history-view", "view", { "is-hidden": isHidden })}
style={{
width: `${width}px`,
}}
>
<div className="header">
<div className="history-title">History</div>
<div className="history-search">

View File

@ -9,48 +9,36 @@ import { boundMethod } from "autobind-decorator";
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { If } from "tsx-control-statements/components";
import { GlobalModel, GlobalCommandRunner, Cmd } from "../../models";
import { termHeightFromRows } from "../../util/textmeasure";
import type {
LineType,
RenderModeType,
RendererOpts,
RendererPluginType,
LineHeightChangeCallbackType,
RendererModelInitializeParams,
RendererModel,
LineContainerType,
} from "../../types/types";
import { GlobalModel, GlobalCommandRunner, Cmd } from "@/models";
import { termHeightFromRows } from "@/util/textmeasure";
import cn from "classnames";
import { getTermPtyData } from "../../util/modelutil";
import { getTermPtyData } from "@/util/modelutil";
import { renderCmdText } from "../common/elements";
import { SimpleBlobRenderer } from "../../plugins/core/basicrenderer";
import { IncrementalRenderer } from "../../plugins/core/incrementalrenderer";
import { TerminalRenderer } from "../../plugins/terminal/terminal";
import { isBlank } from "../../util/util";
import { PluginModel } from "../../plugins/plugins";
import { Prompt } from "../common/prompt/prompt";
import { renderCmdText } from "@/common/elements";
import { SimpleBlobRenderer } from "@/plugins/core/basicrenderer";
import { IncrementalRenderer } from "@/plugins/core/incrementalrenderer";
import { TerminalRenderer } from "@/plugins/terminal/terminal";
import { isBlank } from "@/util/util";
import { PluginModel } from "@/plugins/plugins";
import { Prompt } from "@/common/prompt/prompt";
import * as lineutil from "./lineutil";
import { ErrorBoundary } from "../../app/common/error/errorboundary";
import * as appconst from "../appconst";
import { ErrorBoundary } from "@/common/error/errorboundary";
import * as appconst from "@/app/appconst";
import { ReactComponent as CheckIcon } from "../assets/icons/line/check.svg";
import { ReactComponent as CommentIcon } from "../assets/icons/line/comment.svg";
import { ReactComponent as QuestionIcon } from "../assets/icons/line/question.svg";
import { ReactComponent as WarningIcon } from "../assets/icons/line/triangle-exclamation.svg";
import { ReactComponent as XmarkIcon } from "../assets/icons/line/xmark.svg";
import { ReactComponent as FillIcon } from "../assets/icons/line/fill.svg";
import { ReactComponent as GearIcon } from "../assets/icons/line/gear.svg";
import { ReactComponent as CheckIcon } from "@/assets/icons/line/check.svg";
import { ReactComponent as CommentIcon } from "@/assets/icons/line/comment.svg";
import { ReactComponent as QuestionIcon } from "@/assets/icons/line/question.svg";
import { ReactComponent as WarningIcon } from "@/assets/icons/line/triangle-exclamation.svg";
import { ReactComponent as XmarkIcon } from "@/assets/icons/line/xmark.svg";
import { ReactComponent as FillIcon } from "@/assets/icons/line/fill.svg";
import { ReactComponent as GearIcon } from "@/assets/icons/line/gear.svg";
import { RotateIcon } from "../common/icons/icons";
import { RotateIcon } from "@/common/icons/icons";
import "./lines.less";
dayjs.extend(localizedFormat);
type OV<V> = mobx.IObservableValue<V>;
@mobxReact.observer
class SmallLineAvatar extends React.Component<{ line: LineType; cmd: Cmd; onRightClick?: (e: any) => void }, {}> {
render() {

View File

@ -1,4 +1,4 @@
@import "../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.line.line-text {
flex-direction: row;

View File

@ -11,16 +11,12 @@ import cn from "classnames";
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { debounce, throttle } from "throttle-debounce";
import * as T from "../../types/types";
import * as util from "../../util/util";
import * as util from "@/util/util";
import * as lineutil from "./lineutil";
import "./lines.less";
dayjs.extend(localizedFormat);
type OV<V> = mobx.IObservableValue<V>;
type OArr<V> = mobx.IObservableArray<V>;
type OMap<K, V> = mobx.ObservableMap<K, V>;
const LinesVisiblePadding = 500;
@ -29,20 +25,20 @@ type ScreenInterface = {
getSelectedLine(): number;
getAnchor(): { anchorLine: number; anchorOffset: number };
isLineIdInSidebar(lineId: string): boolean;
getLineByNum(lineNum: number): T.LineType;
getLineByNum(lineNum: number): LineType;
};
// <Line key={line.lineid} line={line} screen={screen} width={width} visible={this.visibleMap.get(lineNumStr)} staticRender={this.staticRender.get()} onHeightChange={this.onHeightChange} overrideCollapsed={this.collapsedMap.get(lineNumStr)} topBorder={topBorder} renderMode={renderMode}/>;
type LineCompFactory = (props: T.LineFactoryProps) => JSX.Element;
type LineCompFactory = (props: LineFactoryProps) => JSX.Element;
@mobxReact.observer
class LinesView extends React.Component<
{
screen: ScreenInterface;
width: number;
lines: T.LineInterface[];
renderMode: T.RenderModeType;
lines: LineInterface[];
renderMode: RenderModeType;
lineFactory: LineCompFactory;
},
{}
@ -384,7 +380,7 @@ class LinesView extends React.Component<
this.computeVisibleMap_debounced();
}
hasTopBorder(lines: T.LineInterface[], idx: number): boolean {
hasTopBorder(lines: LineInterface[], idx: number): boolean {
if (idx == 0) {
return false;
}
@ -394,7 +390,7 @@ class LinesView extends React.Component<
}
getDateSepStr(
lines: T.LineInterface[],
lines: LineInterface[],
idx: number,
prevStr: string,
todayStr: string,
@ -410,7 +406,7 @@ class LinesView extends React.Component<
return null;
}
findClosestLineIndex(lineNum: number): { line: T.LineInterface; index: number } {
findClosestLineIndex(lineNum: number): { line: LineInterface; index: number } {
let { lines } = this.props;
if (lines.length == 0) {
throw new Error("invalid lines, cannot have 0 length in LinesView");
@ -444,7 +440,7 @@ class LinesView extends React.Component<
render() {
let { screen, width, lines, renderMode } = this.props;
let selectedLine = screen.getSelectedLine(); // for re-rendering
let line: T.LineInterface = null;
let line: LineInterface = null;
for (let i = 0; i < lines.length; i++) {
let key = String(lines[i].linenum);
let visObs = this.visibleMap.get(key);

View File

@ -3,8 +3,7 @@
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { isBlank, getDateStr } from "../../util/util";
import { LineType, WebLine, RendererContext } from "../../types/types";
import { isBlank, getDateStr } from "@/util/util";
dayjs.extend(localizedFormat);

View File

@ -4,32 +4,10 @@
import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { sprintf } from "sprintf-js";
import { boundMethod } from "autobind-decorator";
import { If, For, When, Otherwise, Choose } from "tsx-control-statements/components";
import type {
RendererModelInitializeParams,
TermOptsType,
RendererContext,
RendererOpts,
SimpleBlobRendererComponent,
RendererModelContainerApi,
RendererPluginType,
PtyDataType,
RendererModel,
RendererOptsUpdate,
LineStateType,
LineType,
TermContextUnion,
RendererContainerType,
ExtBlob,
} from "../../../types/types";
import { debounce } from "throttle-debounce";
import * as util from "../../../util/util";
import { GlobalModel } from "../../../models";
type OV<V> = mobx.IObservableValue<V>;
type CV<V> = mobx.IComputedValue<V>;
import { debounce } from "throttle-debounce";
import * as util from "@/util";
import { GlobalModel } from "@/models";
class SimpleBlobRendererModel {
context: RendererContext;

View File

@ -1,4 +1,4 @@
@import "../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.plugins-view {
background-color: @background-session;

View File

@ -5,11 +5,11 @@ import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { GlobalModel } from "../../models";
import { PluginModel } from "../../plugins/plugins";
import { Markdown } from "../common/elements";
import { GlobalModel } from "@/models";
import { PluginModel } from "@/plugins/plugins";
import { Markdown } from "@/common/elements";
import { ReactComponent as XmarkIcon } from "../assets/icons/line/xmark.svg";
import { ReactComponent as XmarkIcon } from "@/assets/icons/line/xmark.svg";
import "./pluginsview.less";

View File

@ -1,5 +1,5 @@
@import "../../app/common/themes/themes.less";
@import "../../app/common/icons/icons.less";
@import "@/common/themes/themes.less";
@import "@/common/icons/icons.less";
.main-sidebar {
padding: 0;

View File

@ -7,23 +7,22 @@ import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import cn from "classnames";
import dayjs from "dayjs";
import type { ClientDataType, RemoteType } from "../../types/types";
import { If } from "tsx-control-statements/components";
import { compareLoose } from "semver";
import { ReactComponent as LeftChevronIcon } from "../assets/icons/chevron_left.svg";
import { ReactComponent as AppsIcon } from "../assets/icons/apps.svg";
import { ReactComponent as WorkspacesIcon } from "../assets/icons/workspaces.svg";
import { ReactComponent as SettingsIcon } from "../assets/icons/settings.svg";
import { ReactComponent as LeftChevronIcon } from "@/assets/icons/chevron_left.svg";
import { ReactComponent as AppsIcon } from "@/assets/icons/apps.svg";
import { ReactComponent as WorkspacesIcon } from "@/assets/icons/workspaces.svg";
import { ReactComponent as SettingsIcon } from "@/assets/icons/settings.svg";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { GlobalModel, GlobalCommandRunner, Session } from "../../models";
import { isBlank, openLink } from "../../util/util";
import { ResizableSidebar } from "../common/elements";
import * as appconst from "../appconst";
import { GlobalModel, GlobalCommandRunner, Session } from "@/models";
import { isBlank, openLink } from "@/util/util";
import { ResizableSidebar } from "@/common/elements";
import * as appconst from "@/app/appconst";
import "./sidebar.less";
import { ActionsIcon, CenteredIcon, FrontIcon, StatusIndicator } from "../common/icons/icons";
import { ActionsIcon, CenteredIcon, FrontIcon, StatusIndicator } from "@/common/icons/icons";
dayjs.extend(localizedFormat);

View File

@ -4,16 +4,13 @@
import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { GlobalModel } from "../../../models";
import { isBlank } from "../../../util/util";
import { GlobalModel } from "@/models";
import { isBlank } from "@/util";
import { boundMethod } from "autobind-decorator";
import cn from "classnames";
import { Prompt } from "../../common/prompt/prompt";
import { TextAreaInput } from "./textareainput";
import { If, For } from "tsx-control-statements/components";
import type { OpenAICmdInfoChatMessageType } from "../../../types/types";
import { Markdown } from "../../common/elements";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "../../../util/keyutil";
import { For } from "tsx-control-statements/components";
import { Markdown } from "@/elements";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "@/util/keyutil";
@mobxReact.observer
class AIChat extends React.Component<{}, {}> {

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.cmd-input {
border-radius: 6px;

View File

@ -8,16 +8,15 @@ import { boundMethod } from "autobind-decorator";
import { If } from "tsx-control-statements/components";
import cn from "classnames";
import dayjs from "dayjs";
import type { RemoteType, RemoteInstanceType, RemotePtrType } from "../../../types/types";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { GlobalModel, GlobalCommandRunner, Screen } from "../../../models";
import { renderCmdText } from "../../common/elements";
import { GlobalModel, GlobalCommandRunner, Screen } from "@/models";
import { renderCmdText } from "@/elements";
import { TextAreaInput } from "./textareainput";
import { InfoMsg } from "./infomsg";
import { HistoryInfo } from "./historyinfo";
import { Prompt } from "../../common/prompt/prompt";
import { ReactComponent as ExecIcon } from "../../assets/icons/exec.svg";
import { RotateIcon } from "../../common/icons/icons";
import { Prompt } from "@/common/prompt/prompt";
import { ReactComponent as ExecIcon } from "@/assets/icons/exec.svg";
import { RotateIcon } from "@/common/icons/icons";
import { AIChat } from "./aichat";
import "./cmdinput.less";

View File

@ -9,10 +9,9 @@ import { boundMethod } from "autobind-decorator";
import { If, For } from "tsx-control-statements/components";
import cn from "classnames";
import dayjs from "dayjs";
import type { HistoryItem, HistoryQueryOpts } from "../../../types/types";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { GlobalModel } from "../../../models";
import { isBlank } from "../../../util/util";
import { GlobalModel } from "@/models";
import { isBlank } from "@/util/util";
dayjs.extend(localizedFormat);

View File

@ -7,8 +7,8 @@ import { If, For } from "tsx-control-statements/components";
import cn from "classnames";
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { GlobalModel } from "../../../models";
import { makeExternLink } from "../../../util/util";
import { GlobalModel } from "@/models";
import { makeExternLink } from "@/util/util";
dayjs.extend(localizedFormat);

View File

@ -4,16 +4,14 @@
import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import type * as T from "../../../types/types";
import * as util from "../../../util/util";
import * as util from "@/util/util";
import { If } from "tsx-control-statements/components";
import { boundMethod } from "autobind-decorator";
import cn from "classnames";
import { GlobalModel, GlobalCommandRunner, Screen } from "../../../models";
import { getMonoFontSize } from "../../../util/textmeasure";
import { isModKeyPress, hasNoModifiers } from "../../../util/util";
import * as appconst from "../../appconst";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "../../../util/keyutil";
import { GlobalModel, GlobalCommandRunner, Screen } from "@/models";
import { getMonoFontSize } from "@/util/textmeasure";
import * as appconst from "@/app/appconst";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "@/util/keyutil";
type OV<T> = mobx.IObservableValue<T>;
@ -51,7 +49,7 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: ()
historyInputRef: React.RefObject<HTMLInputElement> = React.createRef();
controlRef: React.RefObject<HTMLDivElement> = React.createRef();
lastHeight: number = 0;
lastSP: T.StrWithPos = { str: "", pos: appconst.NoStrPos };
lastSP: StrWithPos = { str: "", pos: appconst.NoStrPos };
version: OV<number> = mobx.observable.box(0); // forces render updates
incVersion(): void {
@ -59,7 +57,7 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: ()
mobx.action(() => this.version.set(v + 1))();
}
getCurSP(): T.StrWithPos {
getCurSP(): StrWithPos {
let textarea = this.mainInputRef.current;
if (textarea == null) {
return this.lastSP;
@ -169,7 +167,7 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: ()
@boundMethod
onKeyDown(e: any) {
mobx.action(() => {
if (isModKeyPress(e)) {
if (util.isModKeyPress(e)) {
return;
}
let model = GlobalModel;

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.main-content {
.screen-view {
@ -6,7 +6,8 @@
position: relative;
}
.screen-sidebar, .window-view {
.screen-sidebar,
.window-view {
transition: width 0.5s ease-in-out;
}

View File

@ -10,21 +10,19 @@ import { If, For } from "tsx-control-statements/components";
import cn from "classnames";
import { debounce } from "throttle-debounce";
import dayjs from "dayjs";
import { GlobalCommandRunner, ForwardLineContainer, GlobalModel, ScreenLines, Screen, Session } from "../../../models";
import type { LineType, RenderModeType, LineFactoryProps } from "../../../types/types";
import * as T from "../../../types/types";
import { GlobalCommandRunner, ForwardLineContainer, GlobalModel, ScreenLines, Screen, Session } from "@/models";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { Button, TextField, Dropdown } from "../../common/elements";
import { getRemoteStr } from "../../common/prompt/prompt";
import { Line } from "../../line/linecomps";
import { LinesView } from "../../line/linesview";
import * as util from "../../../util/util";
import { ReactComponent as EllipseIcon } from "../../assets/icons/ellipse.svg";
import { ReactComponent as Check12Icon } from "../../assets/icons/check12.svg";
import { ReactComponent as SquareIcon } from "../../assets/icons/tab/square.svg";
import { ReactComponent as GlobeIcon } from "../../assets/icons/globe.svg";
import { ReactComponent as StatusCircleIcon } from "../../assets/icons/statuscircle.svg";
import * as appconst from "../../appconst";
import { Button, TextField, Dropdown } from "@/elements";
import { getRemoteStr } from "@/common/prompt/prompt";
import { Line } from "@/app/line/linecomps";
import { LinesView } from "@/app/line/linesview";
import * as util from "@/util/util";
import { ReactComponent as EllipseIcon } from "@/assets/icons/ellipse.svg";
import { ReactComponent as Check12Icon } from "@/assets/icons/check12.svg";
import { ReactComponent as SquareIcon } from "@/assets/icons/tab/square.svg";
import { ReactComponent as GlobeIcon } from "@/assets/icons/globe.svg";
import { ReactComponent as StatusCircleIcon } from "@/assets/icons/statuscircle.svg";
import * as appconst from "@/app/appconst";
import "./screenview.less";
import "./tabs.less";
@ -32,8 +30,6 @@ import { MagicLayout } from "../../magiclayout";
dayjs.extend(localizedFormat);
type OV<V> = mobx.IObservableValue<V>;
@mobxReact.observer
class ScreenView extends React.Component<{ session: Session; screen: Screen }, {}> {
rszObs: ResizeObserver;
@ -164,7 +160,7 @@ class ScreenView extends React.Component<{ session: Session; screen: Screen }, {
type SidebarLineContainerPropsType = {
screen: Screen;
winSize: T.WindowSize;
winSize: WindowSize;
lineId: string;
};
@ -230,7 +226,7 @@ class SidebarLineContainer extends React.Component<SidebarLineContainerPropsType
@mobxReact.observer
class ScreenSidebar extends React.Component<{ screen: Screen; width: string }, {}> {
rszObs: ResizeObserver;
sidebarSize: OV<T.WindowSize> = mobx.observable.box({ height: 0, width: 0 }, { name: "sidebarSize" });
sidebarSize: OV<WindowSize> = mobx.observable.box({ height: 0, width: 0 }, { name: "sidebarSize" });
sidebarRef: React.RefObject<any> = React.createRef();
handleResize_debounced: (entries: ResizeObserverEntry[]) => void;
@ -288,7 +284,7 @@ class ScreenSidebar extends React.Component<{ screen: Screen; width: string }, {
GlobalCommandRunner.screenSidebarOpen("500px");
}
getSidebarConfig(): T.ScreenSidebarOptsType {
getSidebarConfig(): ScreenSidebarOptsType {
let { screen } = this.props;
let viewOpts = screen.viewOpts.get();
return viewOpts?.sidebar;
@ -344,7 +340,7 @@ class ScreenSidebar extends React.Component<{ screen: Screen; width: string }, {
class NewTabSettings extends React.Component<{ screen: Screen }, {}> {
connDropdownActive: OV<boolean> = mobx.observable.box(false, { name: "NewTabSettings-connDropdownActive" });
errorMessage: OV<string | null> = mobx.observable.box(null, { name: "NewTabSettings-errorMessage" });
remotes: T.RemoteType[];
remotes: RemoteType[];
constructor(props) {
super(props);

View File

@ -6,13 +6,13 @@ import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import cn from "classnames";
import { GlobalModel, GlobalCommandRunner, Screen } from "../../../models";
import { ActionsIcon, StatusIndicator, CenteredIcon } from "../../common/icons/icons";
import { renderCmdText } from "../../common/elements";
import { ReactComponent as SquareIcon } from "../../assets/icons/tab/square.svg";
import * as constants from "../../appconst";
import { GlobalModel, GlobalCommandRunner, Screen } from "@/models";
import { ActionsIcon, StatusIndicator, CenteredIcon } from "@/common/icons/icons";
import { renderCmdText } from "@/elements";
import { ReactComponent as SquareIcon } from "@/assets/icons/tab/square.svg";
import * as constants from "@/app/appconst";
import { Reorder } from "framer-motion";
import { MagicLayout } from "../../magiclayout";
import { MagicLayout } from "@/app/magiclayout";
@mobxReact.observer
class ScreenTab extends React.Component<

View File

@ -1,5 +1,5 @@
@import "../../../app/common/themes/themes.less";
@import "../../../app/common/icons/icons.less";
@import "@/common/themes/themes.less";
@import "@/common/icons/icons.less";
#main .screen-tabs .screen-tab {
border-top: 1px solid transparent;

View File

@ -7,8 +7,8 @@ import * as mobx from "mobx";
import { sprintf } from "sprintf-js";
import { boundMethod } from "autobind-decorator";
import { For } from "tsx-control-statements/components";
import { GlobalModel, GlobalCommandRunner, Session, Screen } from "../../../models";
import { ReactComponent as AddIcon } from "../../assets/icons/add.svg";
import { GlobalModel, GlobalCommandRunner, Session, Screen } from "@/models";
import { ReactComponent as AddIcon } from "@/assets/icons/add.svg";
import { Reorder } from "framer-motion";
import { ScreenTab } from "./tab";

View File

@ -1,4 +1,4 @@
@import "../../app/common/themes/themes.less";
@import "@/common/themes/themes.less";
.session-view {
flex-grow: 1;

View File

@ -7,18 +7,16 @@ import * as mobx from "mobx";
import cn from "classnames";
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { GlobalModel } from "../../models";
import { GlobalModel } from "@/models";
import { CmdInput } from "./cmdinput/cmdinput";
import { ScreenView } from "./screen/screenview";
import { ScreenTabs } from "./screen/tabs";
import { ErrorBoundary } from "../../app/common/error/errorboundary";
import { ErrorBoundary } from "@/common/error/errorboundary";
import { MagicLayout } from "../magiclayout";
import "./workspace.less";
dayjs.extend(localizedFormat);
type OV<V> = mobx.IObservableValue<V>;
@mobxReact.observer
class WorkspaceView extends React.Component<{}, {}> {
render() {

View File

@ -7,12 +7,12 @@ import * as fs from "fs";
import fetch from "node-fetch";
import * as child_process from "node:child_process";
import { debounce } from "throttle-debounce";
import { handleJsonFetchResponse } from "../util/util";
import * as winston from "winston";
import * as util from "util";
import { sprintf } from "sprintf-js";
import * as util from "util";
import { handleJsonFetchResponse } from "@/util/util";
import { v4 as uuidv4 } from "uuid";
import { checkKeyPressed, adaptFromElectronKeyEvent, setKeyUtilPlatform } from "../util/keyutil";
import { checkKeyPressed, adaptFromElectronKeyEvent, setKeyUtilPlatform } from "@/util/keyutil";
import { platform } from "os";
const WaveAppPathVarName = "WAVETERM_APP_PATH";
@ -40,19 +40,21 @@ let unameArch: string = process.arch;
if (unameArch == "x64") {
unameArch = "amd64";
}
let logger;
let loggerTransports: winston.transport[] = [
new winston.transports.File({ filename: path.join(waveHome, "waveterm-app.log"), level: "info" }),
];
if (isDev) {
loggerTransports.push(new winston.transports.Console());
}
let loggerConfig = {
level: "info",
format: winston.format.combine(
winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
winston.format.printf((info) => `${info.timestamp} ${info.message}`)
),
transports: [new winston.transports.File({ filename: path.join(waveHome, "waveterm-app.log"), level: "info" })],
transports: loggerTransports,
};
if (isDev) {
loggerConfig.transports.push(new winston.transports.Console());
}
logger = winston.createLogger(loggerConfig);
let logger = winston.createLogger(loggerConfig);
function log(...msg) {
try {
logger.info(util.format(...msg));
@ -75,7 +77,7 @@ if (isDev) {
}
let app = electron.app;
app.setName(isDev ? "Wave (Dev)" : "Wave");
let waveSrvProc = null;
let waveSrvProc: child_process.ChildProcessWithoutNullStreams | null = null;
let waveSrvShouldRestart = false;
electron.dialog.showErrorBox = (title, content) => {
@ -101,8 +103,11 @@ function checkPromptMigrate() {
// don't migrate if we're running dev version or if wave home directory already exists
return;
}
let homeDir = process.env.HOME;
let promptHome = path.join(homeDir, "prompt");
if (process.env.HOME == null) {
return;
}
let homeDir: string = process.env.HOME;
let promptHome: string = path.join(homeDir, "prompt");
if (!fs.existsSync(promptHome) || !fs.existsSync(path.join(promptHome, "prompt.db"))) {
// make sure we have a valid prompt home directory (prompt.db must exist inside)
return;
@ -170,7 +175,7 @@ function readAuthKey() {
return authKeyStr.trim();
}
let menuTemplate = [
let menuTemplate: Electron.MenuItemConstructorOptions[] = [
{
role: "appMenu",
submenu: [
@ -222,7 +227,7 @@ function getMods(input: any) {
return { meta: input.meta, shift: input.shift, ctrl: input.control, alt: input.alt };
}
function shNavHandler(event: any, url: any) {
function shNavHandler(event: Electron.Event<Electron.WebContentsWillNavigateEventParams>, url: string) {
event.preventDefault();
if (url.startsWith("https://") || url.startsWith("http://") || url.startsWith("file://")) {
console.log("open external, shNav", url);
@ -232,12 +237,13 @@ function shNavHandler(event: any, url: any) {
}
}
function shFrameNavHandler(event: any, url: any) {
function shFrameNavHandler(event: Electron.Event<Electron.WebContentsWillFrameNavigateEventParams>) {
if (!event.frame || event.frame.parent == null) {
// only use this handler to process iframe events (non-iframe events go to shNavHandler)
return;
}
event.preventDefault();
let url = event.url;
console.log(`frame-navigation url=${url} frame=${event.frame.name}`);
if (event.frame.name == "webview") {
// "webview" links always open in new window
@ -250,7 +256,7 @@ function shFrameNavHandler(event: any, url: any) {
return;
}
function createMainWindow(clientData) {
function createMainWindow(clientData: ClientDataType | null) {
let bounds = calcBounds(clientData);
setKeyUtilPlatform(platform());
let win = new electron.BrowserWindow({
@ -644,12 +650,11 @@ electron.ipcMain.on("context-editmenu", (event, { x, y }, opts) => {
}
console.log("context-editmenu");
let menu = new electron.Menu();
let menuItem = null;
if (opts.showCut) {
menuItem = new electron.MenuItem({ label: "Cut", role: "cut" });
let menuItem = new electron.MenuItem({ label: "Cut", role: "cut" });
menu.append(menuItem);
}
menuItem = new electron.MenuItem({ label: "Copy", role: "copy" });
let menuItem = new electron.MenuItem({ label: "Copy", role: "copy" });
menu.append(menuItem);
menuItem = new electron.MenuItem({ label: "Paste", role: "paste" });
menu.append(menuItem);
@ -657,7 +662,7 @@ electron.ipcMain.on("context-editmenu", (event, { x, y }, opts) => {
});
async function createMainWindowWrap() {
let clientData = null;
let clientData: ClientDataType | null = null;
try {
clientData = await getClientDataPoll(1);
} catch (e) {

View File

@ -5,7 +5,7 @@ import * as mobx from "mobx";
import * as React from "react";
import { createRoot } from "react-dom/client";
import { sprintf } from "sprintf-js";
import { App } from "./app/app";
import { App } from "@/app/app";
import * as DOMPurify from "dompurify";
import { loadFonts } from "./util/util";

View File

@ -4,10 +4,8 @@
import * as mobx from "mobx";
import { sprintf } from "sprintf-js";
import { boundMethod } from "autobind-decorator";
import { genMergeSimpleData } from "../util/util";
import { BookmarkType } from "../types/types";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "../util/keyutil";
import { OV, OArr } from "../types/types";
import { genMergeSimpleData } from "@/util/util";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "@/util/keyutil";
import { GlobalCommandRunner } from "./global";
import { Model } from "./model";

View File

@ -2,20 +2,10 @@
// SPDX-License-Identifier: Apache-2.0
import * as mobx from "mobx";
import { stringToBase64 } from "../util/util";
import { TermWrap } from "../plugins/terminal/term";
import {
RemotePtrType,
CmdDataType,
TermOptsType,
FeInputPacketType,
RendererModel,
WebCmd,
WebRemote,
} from "../types/types";
import { cmdStatusIsRunning } from "../app/line/lineutil";
import { stringToBase64 } from "@/util/util";
import { TermWrap } from "@/plugins/terminal/term";
import { cmdStatusIsRunning } from "@/app/line/lineutil";
import { Model } from "./model";
import { OV } from "../types/types";
const InputChunkSize = 500;
class Cmd {

View File

@ -2,13 +2,12 @@
// SPDX-License-Identifier: Apache-2.0
import * as mobx from "mobx";
import { RendererContext, CommandRtnType, HistorySearchParams, LineStateType } from "../types/types";
import { GlobalModel } from "./global";
class CommandRunner {
private constructor() {}
static getInstance() {
static getInstance(): CommandRunner {
if (!(window as any).GlobalCommandRunner) {
(window as any).GlobalCommandRunner = new CommandRunner();
}
@ -35,6 +34,12 @@ class CommandRunner {
return prtn;
}
switchView(view: string) {
mobx.action(() => {
GlobalModel.activeMainView.set(view);
})();
}
switchSession(session: string) {
mobx.action(() => {
GlobalModel.activeMainView.set("session");

View File

@ -1,10 +1,9 @@
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import { TermWrap } from "../plugins/terminal/term";
import * as types from "../types/types";
import { windowWidthToCols, windowHeightToRows } from "../util/textmeasure";
import { MagicLayout } from "../app/magiclayout";
import { TermWrap } from "@/plugins/terminal/term";
import { windowWidthToCols, windowHeightToRows } from "@/util/textmeasure";
import { MagicLayout } from "@/app/magiclayout";
import { Model } from "./model";
import { GlobalCommandRunner } from "./global";
import { Cmd } from "./cmd";
@ -12,12 +11,12 @@ import { Screen } from "./screen";
class ForwardLineContainer {
globalModel: Model;
winSize: types.WindowSize;
winSize: WindowSize;
screen: Screen;
containerType: types.LineContainerStrs;
containerType: LineContainerStrs;
lineId: string;
constructor(screen: Screen, winSize: types.WindowSize, containerType: types.LineContainerStrs, lineId: string) {
constructor(screen: Screen, winSize: WindowSize, containerType: LineContainerStrs, lineId: string) {
this.globalModel = Model.getInstance();
this.screen = screen;
this.winSize = winSize;
@ -25,7 +24,7 @@ class ForwardLineContainer {
this.lineId = lineId;
}
screenSizeCallback(winSize: types.WindowSize): void {
screenSizeCallback(winSize: WindowSize): void {
this.winSize = winSize;
let termWrap = this.getTermWrap(this.lineId);
if (termWrap != null) {
@ -37,11 +36,11 @@ class ForwardLineContainer {
}
}
getContainerType(): types.LineContainerStrs {
getContainerType(): LineContainerStrs {
return this.containerType;
}
getCmd(line: types.LineType): Cmd {
getCmd(line: LineType): Cmd {
return this.screen.getCmd(line);
}
@ -57,25 +56,25 @@ class ForwardLineContainer {
this.screen.setLineFocus(lineNum, focus);
}
setContentHeight(context: types.RendererContext, height: number): void {
setContentHeight(context: RendererContext, height: number): void {
return;
}
getMaxContentSize(): types.WindowSize {
getMaxContentSize(): WindowSize {
let rtn = { width: this.winSize.width, height: this.winSize.height };
rtn.width = rtn.width - MagicLayout.ScreenMaxContentWidthBuffer;
return rtn;
}
getIdealContentSize(): types.WindowSize {
getIdealContentSize(): WindowSize {
return this.winSize;
}
loadTerminalRenderer(elem: Element, line: types.LineType, cmd: Cmd, width: number): void {
loadTerminalRenderer(elem: Element, line: LineType, cmd: Cmd, width: number): void {
this.screen.loadTerminalRenderer(elem, line, cmd, width);
}
registerRenderer(lineId: string, renderer: types.RendererModel): void {
registerRenderer(lineId: string, renderer: RendererModel): void {
this.screen.registerRenderer(lineId, renderer);
}
@ -83,11 +82,11 @@ class ForwardLineContainer {
this.screen.unloadRenderer(lineId);
}
getContentHeight(context: types.RendererContext): number {
getContentHeight(context: RendererContext): number {
return this.screen.getContentHeight(context);
}
getUsedRows(context: types.RendererContext, line: types.LineType, cmd: Cmd, width: number): number {
getUsedRows(context: RendererContext, line: LineType, cmd: Cmd, width: number): number {
return this.screen.getUsedRows(context, line, cmd, width);
}
@ -95,7 +94,7 @@ class ForwardLineContainer {
return this.screen.getIsFocused(lineNum);
}
getRenderer(lineId: string): types.RendererModel {
getRenderer(lineId: string): RendererModel {
return this.screen.getRenderer(lineId);
}
@ -103,7 +102,7 @@ class ForwardLineContainer {
return this.screen.getTermWrap(lineId);
}
getFocusType(): types.FocusTypeStrs {
getFocusType(): FocusTypeStrs {
return this.screen.getFocusType();
}

View File

@ -1,6 +1,6 @@
import { Model } from "./model";
import { CommandRunner } from "./commandrunner";
const GlobalModel = Model.getInstance();
const GlobalCommandRunner = CommandRunner.getInstance();
const GlobalModel: Model = Model.getInstance();
const GlobalCommandRunner: CommandRunner = CommandRunner.getInstance();
export { GlobalModel, GlobalCommandRunner };

View File

@ -3,20 +3,11 @@
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { isBlank } from "../util/util";
import {
LineType,
HistoryItem,
CmdDataType,
HistoryViewDataType,
HistorySearchParams,
CommandRtnType,
} from "../types/types";
import { termWidthFromCols, termHeightFromRows } from "../util/textmeasure";
import { isBlank } from "@/util/util";
import { termWidthFromCols, termHeightFromRows } from "@/util/textmeasure";
import dayjs from "dayjs";
import * as appconst from "../app/appconst";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "../util/keyutil";
import { OV, OArr, OMap } from "../types/types";
import * as appconst from "@/app/appconst";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "@/util/keyutil";
import { GlobalCommandRunner } from "./global";
import { Model } from "./model";
import { Cmd } from "./cmd";

View File

@ -4,19 +4,8 @@
import type React from "react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { isBlank } from "../util/util";
import {
HistoryItem,
RemotePtrType,
InfoType,
HistoryInfoType,
HistoryQueryOpts,
HistoryTypeStrs,
OpenAICmdInfoChatMessageType,
} from "../types/types";
import { StrWithPos } from "../types/types";
import * as appconst from "../app/appconst";
import { OV } from "../types/types";
import { isBlank } from "@/util/util";
import * as appconst from "@/app/appconst";
import { Model } from "./model";
import { GlobalCommandRunner } from "./global";
@ -207,7 +196,6 @@ class InputModel {
this.historyQueryOpts.set(opts);
let bestIndex = this.findBestNewIndex(oldItem);
setTimeout(() => this.setHistoryIndex(bestIndex, true), 10);
return;
})();
}
@ -624,13 +612,17 @@ class InputModel {
}
openAIAssistantChat(): void {
this.aIChatShow.set(true);
this.setAIChatFocus();
mobx.action(() => {
this.aIChatShow.set(true);
this.setAIChatFocus();
})();
}
closeAIAssistantChat(): void {
this.aIChatShow.set(false);
this.giveFocus();
mobx.action(() => {
this.aIChatShow.set(false);
this.giveFocus();
})();
}
clearAIAssistantChat(): void {
@ -721,14 +713,6 @@ class InputModel {
setCurLine(val: string): void {
let hidx = this.historyIndex.get();
mobx.action(() => {
// if (val == "\" ") {
// this.setInputMode("comment");
// val = "";
// }
// if (val == "//") {
// this.setInputMode("global");
// val = "";
// }
if (this.modHistory.length <= hidx) {
this.modHistory.length = hidx + 1;
}

View File

@ -2,9 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
import * as mobx from "mobx";
import { MagicLayout } from "../app/magiclayout";
import { OV } from "../types/types";
import { MagicLayout } from "@/app/magiclayout";
import { Model } from "./model";
class MainSidebarModel {
globalModel: Model = null;
tempWidth: OV<number> = mobx.observable.box(null, {

View File

@ -3,9 +3,7 @@
import * as mobx from "mobx";
import { v4 as uuidv4 } from "uuid";
import { ModalStoreEntry } from "../types/types";
import { modalsRegistry } from "../app/common/modals/registry";
import { OArr } from "../types/types";
import { modalsRegistry } from "@/modals/registry";
class ModalsModel {
store: OArr<ModalStoreEntry> = mobx.observable.array([], { name: "ModalsModel-store", deep: false });

File diff suppressed because it is too large Load Diff

View File

@ -18,9 +18,9 @@ import {
genMergeSimpleData,
boundInt,
isModKeyPress,
} from "../util/util";
import { TermWrap } from "../plugins/terminal/term";
import { PluginModel } from "../plugins/plugins";
} from "@/util/util";
import { TermWrap } from "@/plugins/terminal/term";
import { PluginModel } from "@/plugins/plugins";
import {
SessionDataType,
LineType,
@ -76,15 +76,15 @@ import {
windowHeightToRows,
termWidthFromCols,
termHeightFromRows,
} from "../util/textmeasure";
} from "@/util/textmeasure";
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import customParseFormat from "dayjs/plugin/customParseFormat";
import { getRendererContext, cmdStatusIsRunning } from "../app/line/lineutil";
import { MagicLayout } from "../app/magiclayout";
import { modalsRegistry } from "../app/common/modals/registry";
import * as appconst from "../app/appconst";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent, setKeyUtilPlatform } from "../util/keyutil";
import { getRendererContext, cmdStatusIsRunning } from "@/app/line/lineutil";
import { MagicLayout } from "@/app/magiclayout";
import { modalsRegistry } from "@/modals/registry";
import * as appconst from "@/app/appconst";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent, setKeyUtilPlatform } from "@/util/keyutil";
dayjs.extend(customParseFormat);
dayjs.extend(localizedFormat);

View File

@ -2,10 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
import * as mobx from "mobx";
import { PluginModel } from "../plugins/plugins";
import { RendererPluginType } from "../types/types";
import { OV } from "../types/types";
import { GlobalCommandRunner } from "./global";
import { PluginModel } from "@/plugins/plugins";
import { Model } from "./model";
class PluginsModel {

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