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

View File

@ -47,3 +47,13 @@ export const TabIcons = [
export const VERSION = __WAVETERM_VERSION__; export const VERSION = __WAVETERM_VERSION__;
// @ts-ignore // @ts-ignore
export const BUILD = __WAVETERM_BUILD__; 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 { .bookmarks-view {
background-color: @background-session; background-color: @background-session;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,12 +5,12 @@ import * as React from "react";
import * as mobxReact from "mobx-react"; import * as mobxReact from "mobx-react";
import * as mobx from "mobx"; import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator"; import { boundMethod } from "autobind-decorator";
import { GlobalModel } from "../../../models"; import { GlobalModel } from "@/models";
import { Modal, LinkButton } from "../elements"; import { Modal, LinkButton } from "@/elements";
import * as util from "../../../util/util"; import * as util from "@/util/util";
import * as appconst from "../../appconst"; 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"; import "./about.less";
@mobxReact.observer @mobxReact.observer

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
@import "../../../app/common/themes/themes.less"; @import "@/common/themes/themes.less";
.rconndetail-modal { .rconndetail-modal {
width: 631px; width: 631px;
@ -54,6 +54,8 @@
} }
.remote-detail { .remote-detail {
width: 100%;
.settings-field { .settings-field {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -91,8 +93,9 @@
} }
.terminal-wrapper { .terminal-wrapper {
width: 100%;
margin-top: 5px; margin-top: 5px;
overflow-x: auto;
overflow-y: hidden;
.terminal-connectelem { .terminal-connectelem {
height: 163px !important; // Needed to override plugin height height: 163px !important; // Needed to override plugin height
@ -111,7 +114,6 @@
.xterm-screen { .xterm-screen {
padding: 10px; 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 { boundMethod } from "autobind-decorator";
import { If, For } from "tsx-control-statements/components"; import { If, For } from "tsx-control-statements/components";
import cn from "classnames"; import cn from "classnames";
import { GlobalModel, GlobalCommandRunner, RemotesModel } from "../../../models"; import { GlobalModel, GlobalCommandRunner, RemotesModel } from "@/models";
import * as T from "../../../types/types"; import { Modal, Tooltip, Button, Status } from "@/elements";
import { Modal, Tooltip, Button, Status } from "../elements"; import * as util from "@/util/util";
import * as util from "../../../util/util"; import * as textmeasure from "@/util/textmeasure";
import * as textmeasure from "../../../util/textmeasure"; import * as appconst from "@/app/appconst";
import "./viewremoteconndetail.less"; import "./viewremoteconndetail.less";
const RemotePtyRows = 9;
const RemotePtyCols = 80;
@mobxReact.observer @mobxReact.observer
class ViewRemoteConnDetailModal extends React.Component<{}, {}> { class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
termRef: React.RefObject<any> = React.createRef(); termRef: React.RefObject<any> = React.createRef();
@ -29,7 +26,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
} }
@mobx.computed @mobx.computed
getSelectedRemote(): T.RemoteType { getSelectedRemote(): RemoteType {
const selectedRemoteId = this.model.selectedRemoteId.get(); const selectedRemoteId = this.model.selectedRemoteId.get();
return GlobalModel.getRemote(selectedRemoteId); 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)) { if (!util.isBlank(remote.uname)) {
let unameStr = remote.uname; let unameStr = remote.uname;
unameStr = unameStr.replace("|", ", "); unameStr = unameStr.replace("|", ", ");
@ -138,7 +135,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
this.model.setRecentConnAdded(false); this.model.setRecentConnAdded(false);
} }
renderInstallStatus(remote: T.RemoteType): any { renderInstallStatus(remote: RemoteType): any {
let statusStr: string = null; let statusStr: string = null;
if (remote.installstatus == "disconnected") { if (remote.installstatus == "disconnected") {
if (remote.needsmshellupgrade) { 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[] = []; let buttons: React.ReactNode[] = [];
const disconnectButton = ( const disconnectButton = (
<Button theme="secondary" onClick={() => this.disconnectRemote(remote.remoteid)}> <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 = ""; let message = "";
if (remote.status == "connected") { if (remote.status == "connected") {
message = "Connected and ready to run commands."; message = "Connected and ready to run commands.";
@ -295,7 +292,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
let model = this.model; let model = this.model;
let isTermFocused = this.model.remoteTermWrapFocus.get(); let isTermFocused = this.model.remoteTermWrapFocus.get();
let termFontSize = GlobalModel.termFontSize.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 remoteAliasText = util.isBlank(remote.remotealias) ? "(none)" : remote.remotealias;
let selectedRemoteStatus = this.getSelectedRemote().status; let selectedRemoteStatus = this.getSelectedRemote().status;
@ -373,7 +370,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
ref={this.termRef} ref={this.termRef}
data-remoteid={remote.remoteid} data-remoteid={remote.remoteid}
style={{ style={{
height: textmeasure.termHeightFromRows(RemotePtyRows, termFontSize), height: textmeasure.termHeightFromRows(appconst.RemotePtyRows, termFontSize),
width: termWidth, width: termWidth,
}} }}
></div> ></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") { if (remote.sshconfigsrc == "sshconfig-import") {
return ( return (
<Tooltip <Tooltip

View File

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

View File

@ -3,42 +3,17 @@
import * as React from "react"; import * as React from "react";
import * as mobxReact from "mobx-react"; import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import dayjs from "dayjs"; import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat"; import localizedFormat from "dayjs/plugin/localizedFormat";
import { GlobalModel } from "../../../models"; import { GlobalModel } from "@/models";
import type {
LineType,
RemoteType,
RemotePtrType,
LineHeightChangeCallbackType,
LineContainerType,
} from "../../../types/types";
import cn from "classnames"; import cn from "classnames";
import { isBlank } from "../../../util/util"; import { isBlank } from "@/util/util";
import { ReactComponent as FolderIcon } from "../../assets/icons/folder.svg"; import { ReactComponent as FolderIcon } from "@/assets/icons/folder.svg";
import "./prompt.less"; import "./prompt.less";
dayjs.extend(localizedFormat); 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 { function makeFullRemoteRef(ownerName: string, remoteRef: string, name: string): string {
if (isBlank(ownerName) && isBlank(name)) { if (isBlank(ownerName) && isBlank(name)) {
return remoteRef; return remoteRef;

View File

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

View File

@ -7,16 +7,12 @@ import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator"; import { boundMethod } from "autobind-decorator";
import { If, For } from "tsx-control-statements/components"; import { If, For } from "tsx-control-statements/components";
import cn from "classnames"; import cn from "classnames";
import { GlobalModel, RemotesModel, GlobalCommandRunner } from "../../models"; import { GlobalModel, RemotesModel, GlobalCommandRunner } from "@/models";
import { Button, Status, ShowWaveShellInstallPrompt } from "../common/elements"; import { Button, Status, ShowWaveShellInstallPrompt } from "@/common/elements";
import * as T from "../../types/types"; import * as util from "@/util/util";
import * as util from "../../util/util";
import * as appconst from "../appconst";
import "./connections.less"; import "./connections.less";
type OV<V> = mobx.IObservableValue<V>;
@mobxReact.observer @mobxReact.observer
class ConnectionsView extends React.Component<{ model: RemotesModel }, { hoveredItemId: string }> { class ConnectionsView extends React.Component<{ model: RemotesModel }, { hoveredItemId: string }> {
tableRef: React.RefObject<any> = React.createRef(); tableRef: React.RefObject<any> = React.createRef();
@ -54,13 +50,13 @@ class ConnectionsView extends React.Component<{ model: RemotesModel }, { hovered
} }
@boundMethod @boundMethod
getName(item: T.RemoteType) { getName(item: RemoteType) {
const { remotealias, remotecanonicalname } = item; const { remotealias, remotecanonicalname } = item;
return remotealias ? `${remotealias} [${remotecanonicalname}]` : remotecanonicalname; return remotealias ? `${remotealias} [${remotecanonicalname}]` : remotecanonicalname;
} }
@boundMethod @boundMethod
getImportSymbol(item: T.RemoteType): React.ReactElement<any, any> { getImportSymbol(item: RemoteType): React.ReactElement<any, any> {
const { sshconfigsrc } = item; const { sshconfigsrc } = item;
if (sshconfigsrc == "sshconfig-import") { if (sshconfigsrc == "sshconfig-import") {
return <i title="Connection Imported from SSH Config" className="fa-sharp fa-solid fa-file-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 items = util.sortAndFilterRemotes(GlobalModel.remotes.slice());
let item: T.RemoteType = null; let item: RemoteType = null;
return ( return (
<div className={cn("view connections-view")}> <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 { .history-view {
background-color: @background-session; background-color: @background-session;
@ -14,10 +14,10 @@
width: 16px; width: 16px;
height: 16px; height: 16px;
border-radius: 4px; border-radius: 4px;
border: 1px solid #3B3F3A; border: 1px solid #3b3f3a;
background: rgba(213, 254, 175, 0.03); background: rgba(213, 254, 175, 0.03);
} }
&.checkbox-icon { &.checkbox-icon {
width: 16px; width: 16px;
height: 16px; height: 16px;
@ -30,7 +30,7 @@
height: 16px; height: 16px;
fill: rgba(213, 254, 175, 0.03); fill: rgba(213, 254, 175, 0.03);
stroke-width: 1px; stroke-width: 1px;
stroke: #3B3F3A; stroke: #3b3f3a;
} }
} }
@ -264,6 +264,7 @@
margin: 0px 10px 10px 10px; margin: 0px 10px 10px 10px;
table-layout: fixed; table-layout: fixed;
border-top: 2px solid #ccc; border-top: 2px solid #ccc;
width: calc(100% - 20px);
tr.active-history-item { tr.active-history-item {
td { td {
@ -309,9 +310,8 @@
tr.history-item { tr.history-item {
padding: 0 10px 0 10px; padding: 0 10px 0 10px;
display: flex; 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; align-items: center;
height: 40px;
color: @text-secondary; color: @text-secondary;
&.is-selected { &.is-selected {

View File

@ -8,40 +8,30 @@ import { If, For } from "tsx-control-statements/components";
import { sprintf } from "sprintf-js"; import { sprintf } from "sprintf-js";
import { boundMethod } from "autobind-decorator"; import { boundMethod } from "autobind-decorator";
import cn from "classnames"; import cn from "classnames";
import { GlobalModel, GlobalCommandRunner, Cmd } from "../../models"; import { GlobalModel, GlobalCommandRunner, Cmd } from "@/models";
import { HistoryItem, RemotePtrType, LineType, CmdDataType } from "../../types/types";
import dayjs from "dayjs"; import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat"; import localizedFormat from "dayjs/plugin/localizedFormat";
import customParseFormat from "dayjs/plugin/customParseFormat"; import customParseFormat from "dayjs/plugin/customParseFormat";
import { Line } from "../line/linecomps"; import { Line } from "@/app/line/linecomps";
import { CmdStrCode } from "../common/elements"; import { CmdStrCode } from "@/common/elements";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "../../util/keyutil"; 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 XmarkIcon } from "../assets/icons/line/xmark.svg"; import { ReactComponent as AngleDownIcon } from "@/assets/icons/history/angle-down.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 ChevronLeftIcon } from "../assets/icons/history/chevron-left.svg"; import { ReactComponent as ChevronRightIcon } from "@/assets/icons/history/chevron-right.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 RightIcon } from "../assets/icons/history/right.svg"; import { ReactComponent as SearchIcon } from "@/assets/icons/history/search.svg";
import { ReactComponent as SearchIcon } from "../assets/icons/history/search.svg"; import { ReactComponent as TrashIcon } from "@/assets/icons/trash.svg";
import { ReactComponent as SquareCheckIcon } from "../assets/icons/history/square-check.svg"; import { ReactComponent as CheckedCheckbox } from "@/assets/icons/checked-checkbox.svg";
import { ReactComponent as SquareMinusIcon } from "../assets/icons/history/square-minus.svg"; import { ReactComponent as CheckIcon } from "@/assets/icons/line/check.svg";
import { ReactComponent as SquareIcon } from "../assets/icons/history/square.svg"; import { ReactComponent as CopyIcon } from "@/assets/icons/history/copy.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"; import "./history.less";
dayjs.extend(customParseFormat); dayjs.extend(customParseFormat);
dayjs.extend(localizedFormat); 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) { function isBlank(s: string) {
return s == null || s == ""; return s == null || s == "";
} }
@ -429,8 +419,16 @@ class HistoryView extends React.Component<{}, {}> {
let sessionId: string = null; let sessionId: string = null;
let remoteIds = Object.keys(rnames); let remoteIds = Object.keys(rnames);
let remoteId: string = null; 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 ( 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="header">
<div className="history-title">History</div> <div className="history-title">History</div>
<div className="history-search"> <div className="history-search">

View File

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

View File

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

View File

@ -11,16 +11,12 @@ import cn from "classnames";
import dayjs from "dayjs"; import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat"; import localizedFormat from "dayjs/plugin/localizedFormat";
import { debounce, throttle } from "throttle-debounce"; 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 * as lineutil from "./lineutil";
import "./lines.less"; import "./lines.less";
dayjs.extend(localizedFormat); 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; const LinesVisiblePadding = 500;
@ -29,20 +25,20 @@ type ScreenInterface = {
getSelectedLine(): number; getSelectedLine(): number;
getAnchor(): { anchorLine: number; anchorOffset: number }; getAnchor(): { anchorLine: number; anchorOffset: number };
isLineIdInSidebar(lineId: string): boolean; 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}/>; // <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 @mobxReact.observer
class LinesView extends React.Component< class LinesView extends React.Component<
{ {
screen: ScreenInterface; screen: ScreenInterface;
width: number; width: number;
lines: T.LineInterface[]; lines: LineInterface[];
renderMode: T.RenderModeType; renderMode: RenderModeType;
lineFactory: LineCompFactory; lineFactory: LineCompFactory;
}, },
{} {}
@ -384,7 +380,7 @@ class LinesView extends React.Component<
this.computeVisibleMap_debounced(); this.computeVisibleMap_debounced();
} }
hasTopBorder(lines: T.LineInterface[], idx: number): boolean { hasTopBorder(lines: LineInterface[], idx: number): boolean {
if (idx == 0) { if (idx == 0) {
return false; return false;
} }
@ -394,7 +390,7 @@ class LinesView extends React.Component<
} }
getDateSepStr( getDateSepStr(
lines: T.LineInterface[], lines: LineInterface[],
idx: number, idx: number,
prevStr: string, prevStr: string,
todayStr: string, todayStr: string,
@ -410,7 +406,7 @@ class LinesView extends React.Component<
return null; return null;
} }
findClosestLineIndex(lineNum: number): { line: T.LineInterface; index: number } { findClosestLineIndex(lineNum: number): { line: LineInterface; index: number } {
let { lines } = this.props; let { lines } = this.props;
if (lines.length == 0) { if (lines.length == 0) {
throw new Error("invalid lines, cannot have 0 length in LinesView"); throw new Error("invalid lines, cannot have 0 length in LinesView");
@ -444,7 +440,7 @@ class LinesView extends React.Component<
render() { render() {
let { screen, width, lines, renderMode } = this.props; let { screen, width, lines, renderMode } = this.props;
let selectedLine = screen.getSelectedLine(); // for re-rendering let selectedLine = screen.getSelectedLine(); // for re-rendering
let line: T.LineInterface = null; let line: LineInterface = null;
for (let i = 0; i < lines.length; i++) { for (let i = 0; i < lines.length; i++) {
let key = String(lines[i].linenum); let key = String(lines[i].linenum);
let visObs = this.visibleMap.get(key); let visObs = this.visibleMap.get(key);

View File

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

View File

@ -4,32 +4,10 @@
import * as React from "react"; import * as React from "react";
import * as mobxReact from "mobx-react"; import * as mobxReact from "mobx-react";
import * as mobx from "mobx"; 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>; import { debounce } from "throttle-debounce";
type CV<V> = mobx.IComputedValue<V>; import * as util from "@/util";
import { GlobalModel } from "@/models";
class SimpleBlobRendererModel { class SimpleBlobRendererModel {
context: RendererContext; context: RendererContext;

View File

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

View File

@ -5,11 +5,11 @@ import * as React from "react";
import * as mobxReact from "mobx-react"; import * as mobxReact from "mobx-react";
import * as mobx from "mobx"; import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator"; import { boundMethod } from "autobind-decorator";
import { GlobalModel } from "../../models"; import { GlobalModel } from "@/models";
import { PluginModel } from "../../plugins/plugins"; import { PluginModel } from "@/plugins/plugins";
import { Markdown } from "../common/elements"; 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"; import "./pluginsview.less";

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,9 +3,7 @@
import * as mobx from "mobx"; import * as mobx from "mobx";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
import { ModalStoreEntry } from "../types/types"; import { modalsRegistry } from "@/modals/registry";
import { modalsRegistry } from "../app/common/modals/registry";
import { OArr } from "../types/types";
class ModalsModel { class ModalsModel {
store: OArr<ModalStoreEntry> = mobx.observable.array([], { name: "ModalsModel-store", deep: false }); 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, genMergeSimpleData,
boundInt, boundInt,
isModKeyPress, isModKeyPress,
} from "../util/util"; } from "@/util/util";
import { TermWrap } from "../plugins/terminal/term"; import { TermWrap } from "@/plugins/terminal/term";
import { PluginModel } from "../plugins/plugins"; import { PluginModel } from "@/plugins/plugins";
import { import {
SessionDataType, SessionDataType,
LineType, LineType,
@ -76,15 +76,15 @@ import {
windowHeightToRows, windowHeightToRows,
termWidthFromCols, termWidthFromCols,
termHeightFromRows, termHeightFromRows,
} from "../util/textmeasure"; } from "@/util/textmeasure";
import dayjs from "dayjs"; import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat"; import localizedFormat from "dayjs/plugin/localizedFormat";
import customParseFormat from "dayjs/plugin/customParseFormat"; import customParseFormat from "dayjs/plugin/customParseFormat";
import { getRendererContext, cmdStatusIsRunning } from "../app/line/lineutil"; import { getRendererContext, cmdStatusIsRunning } from "@/app/line/lineutil";
import { MagicLayout } from "../app/magiclayout"; import { MagicLayout } from "@/app/magiclayout";
import { modalsRegistry } from "../app/common/modals/registry"; import { modalsRegistry } from "@/modals/registry";
import * as appconst from "../app/appconst"; import * as appconst from "@/app/appconst";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent, setKeyUtilPlatform } from "../util/keyutil"; import { checkKeyPressed, adaptFromReactOrNativeKeyEvent, setKeyUtilPlatform } from "@/util/keyutil";
dayjs.extend(customParseFormat); dayjs.extend(customParseFormat);
dayjs.extend(localizedFormat); dayjs.extend(localizedFormat);

View File

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

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