mirror of
https://github.com/wavetermdev/backup.git
synced 2026-04-22 15:26:58 -07:00
Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 80e1e3ce55 | |||
| 85886afeb4 | |||
| 567e5b662c | |||
| 6b5d2833eb | |||
| b10910d229 | |||
| a7e6224862 | |||
| 5476b45f22 | |||
| efcd8ad03a | |||
| 03acda07b5 | |||
| 32342629c8 | |||
| d2ddf7bc58 | |||
| 01fb217785 | |||
| e5d3db7631 | |||
| c24e99e9ff | |||
| 65cab8a59a | |||
| c737c9df57 | |||
| 17cc4769af | |||
| b4d04c3a57 | |||
| 73e5515e17 | |||
| 6919dbfb5f | |||
| 1f5309e097 | |||
| af7cc866d3 | |||
| 37e56acf63 | |||
| 70088afdb5 | |||
| 455790416d | |||
| eed234a131 | |||
| 5a6575a393 | |||
| 84cea373a8 | |||
| 181e14f55c | |||
| 5e4eb738b3 | |||
| 936e9fa7b4 | |||
| af6486e8bb | |||
| 1038a08789 | |||
| 7a377c4a2a | |||
| 8afa62fff2 | |||
| 97595a7718 | |||
| e4d353b5c1 | |||
| 2462c64793 | |||
| b451ee1ef9 | |||
| 2c64668382 | |||
| de21303fb1 | |||
| f6cdd53fd4 | |||
| 840b69d100 | |||
| 683c66f386 |
@@ -13,6 +13,7 @@
|
||||
<link rel="stylesheet" href="dist-dev/waveterm.css" />
|
||||
|
||||
<link rel="stylesheet" id="theme-stylesheet" href="public/themes/themequery.css" />
|
||||
<link rel="stylesheet" href="public/themes/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="measure"></div>
|
||||
|
||||
+28
-2
@@ -20,8 +20,9 @@ import { MainSideBar } from "./sidebar/main";
|
||||
import { RightSideBar } from "./sidebar/right";
|
||||
import { DisconnectedModal, ClientStopModal } from "@/modals";
|
||||
import { ModalsProvider } from "@/modals/provider";
|
||||
import { Button } from "@/elements";
|
||||
import { Button, TermStyleBlock } from "@/elements";
|
||||
import { ErrorBoundary } from "@/common/error/errorboundary";
|
||||
import { For } from "tsx-control-statements/components";
|
||||
import cn from "classnames";
|
||||
import "./app.less";
|
||||
|
||||
@@ -80,6 +81,21 @@ class App extends React.Component<{}, {}> {
|
||||
rightSidebarModel.saveState(width, false);
|
||||
}
|
||||
|
||||
getSelector(themeKey: string) {
|
||||
const sessions = GlobalModel.getSessionNames();
|
||||
const screens = GlobalModel.getScreenNames();
|
||||
|
||||
if (themeKey === "main") {
|
||||
return ":root";
|
||||
} else if (themeKey in screens) {
|
||||
return `.main-content [data-screenid="${themeKey}"]`;
|
||||
} else if (themeKey in sessions) {
|
||||
return `.main-content [data-sessionid="${themeKey}"]`;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
const remotesModel = GlobalModel.remotesModel;
|
||||
const disconnected = !GlobalModel.ws.open.get() || !GlobalModel.waveSrvRunning.get();
|
||||
@@ -124,9 +140,12 @@ class App extends React.Component<{}, {}> {
|
||||
const rightSidebarCollapsed = GlobalModel.rightSidebarModel.getCollapsed();
|
||||
const activeMainView = GlobalModel.activeMainView.get();
|
||||
const lightDarkClass = GlobalModel.isDarkTheme.get() ? "is-dark" : "is-light";
|
||||
const termTheme = GlobalModel.getTermTheme();
|
||||
const themeKey = null;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={"version-" + renderVersion}
|
||||
key={`version- + ${renderVersion}`}
|
||||
id="main"
|
||||
className={cn(
|
||||
"platform-" + platform,
|
||||
@@ -151,6 +170,13 @@ class App extends React.Component<{}, {}> {
|
||||
</div>
|
||||
</If>
|
||||
<div ref={this.mainContentRef} className="main-content">
|
||||
<For index="idx" each="themeKey" of={Object.keys(termTheme)}>
|
||||
<TermStyleBlock
|
||||
key={themeKey}
|
||||
themeName={termTheme[themeKey]}
|
||||
selector={this.getSelector(themeKey)}
|
||||
/>
|
||||
</For>
|
||||
<MainSideBar parentRef={this.mainContentRef} />
|
||||
<ErrorBoundary>
|
||||
<PluginsView />
|
||||
|
||||
@@ -64,3 +64,7 @@ export enum StatusIndicatorLevel {
|
||||
|
||||
// matches packet.go
|
||||
export const ErrorCode_InvalidCwd = "ERRCWD";
|
||||
|
||||
export const InputAuxView_History = "history";
|
||||
export const InputAuxView_Info = "info";
|
||||
export const InputAuxView_AIChat = "aichat";
|
||||
|
||||
@@ -76,14 +76,13 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
||||
|
||||
@boundMethod
|
||||
handleChangeTermTheme(theme: string): void {
|
||||
// For global terminal theme, the key is global, otherwise it's either
|
||||
// For main terminal theme, the key is main, otherwise it's either
|
||||
// sessionId or screenId.
|
||||
const currTheme = GlobalModel.getTermTheme()["global"];
|
||||
const currTheme = GlobalModel.getTermTheme()["main"];
|
||||
if (currTheme == theme) {
|
||||
return;
|
||||
}
|
||||
|
||||
const prtn = GlobalCommandRunner.setGlobalTermTheme(theme, false);
|
||||
const prtn = GlobalCommandRunner.setMainTermTheme(theme, false);
|
||||
commandRtnHandler(prtn, this.errorMessage);
|
||||
}
|
||||
|
||||
@@ -207,8 +206,8 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
||||
const curFontSize = GlobalModel.getTermFontSize();
|
||||
const curFontFamily = GlobalModel.getTermFontFamily();
|
||||
const curTheme = GlobalModel.getThemeSource();
|
||||
const termThemes = getTermThemes(GlobalModel.termThemes, "Wave Default");
|
||||
const currTermTheme = GlobalModel.getTermTheme()["global"] ?? termThemes[0].label;
|
||||
const termThemes = getTermThemes(GlobalModel.termThemeOptions.get(), "Wave Default");
|
||||
const currTermTheme = GlobalModel.getTermTheme()["main"] ?? termThemes[0].label;
|
||||
|
||||
return (
|
||||
<MainView className="clientsettings-view" title="Client Settings" onClose={this.handleClose}>
|
||||
|
||||
@@ -6,7 +6,7 @@ import "./button.less";
|
||||
|
||||
interface ButtonProps {
|
||||
children: React.ReactNode;
|
||||
onClick?: () => void;
|
||||
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
||||
disabled?: boolean;
|
||||
leftIcon?: React.ReactNode;
|
||||
rightIcon?: React.ReactNode;
|
||||
@@ -14,6 +14,7 @@ interface ButtonProps {
|
||||
autoFocus?: boolean;
|
||||
className?: string;
|
||||
termInline?: boolean;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
class Button extends React.Component<ButtonProps> {
|
||||
@@ -23,14 +24,14 @@ class Button extends React.Component<ButtonProps> {
|
||||
};
|
||||
|
||||
@boundMethod
|
||||
handleClick() {
|
||||
handleClick(e) {
|
||||
if (this.props.onClick && !this.props.disabled) {
|
||||
this.props.onClick();
|
||||
this.props.onClick(e);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { leftIcon, rightIcon, children, disabled, style, autoFocus, termInline, className } = this.props;
|
||||
const { leftIcon, rightIcon, children, disabled, style, autoFocus, termInline, className, title } = this.props;
|
||||
|
||||
return (
|
||||
<button
|
||||
@@ -39,6 +40,7 @@ class Button extends React.Component<ButtonProps> {
|
||||
disabled={disabled}
|
||||
style={style}
|
||||
autoFocus={autoFocus}
|
||||
title={title}
|
||||
>
|
||||
{leftIcon && <span className="icon-left">{leftIcon}</span>}
|
||||
{children}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
.copy-button {
|
||||
padding: 5px 5px;
|
||||
|
||||
.fa-check {
|
||||
color: var(--app-success-color);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import * as React from "react";
|
||||
import { Button } from "./button";
|
||||
import { boundMethod } from "autobind-decorator";
|
||||
import * as mobxReact from "mobx-react";
|
||||
import * as mobx from "mobx";
|
||||
|
||||
import "./copybutton.less";
|
||||
|
||||
type CopyButtonProps = {
|
||||
title: string;
|
||||
onClick: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
||||
};
|
||||
|
||||
@mobxReact.observer
|
||||
class CopyButton extends React.Component<CopyButtonProps, {}> {
|
||||
isCopied: OV<boolean> = mobx.observable.box(false, { name: "isCopied" });
|
||||
|
||||
@boundMethod
|
||||
handleOnClick(e: React.MouseEvent<HTMLButtonElement>) {
|
||||
if (this.isCopied.get()) {
|
||||
return;
|
||||
}
|
||||
mobx.action(() => {
|
||||
this.isCopied.set(true);
|
||||
})();
|
||||
setTimeout(() => {
|
||||
mobx.action(() => {
|
||||
this.isCopied.set(false);
|
||||
})();
|
||||
}, 2000);
|
||||
if (this.props.onClick) {
|
||||
this.props.onClick(e);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { title, onClick } = this.props;
|
||||
const isCopied = this.isCopied.get();
|
||||
return (
|
||||
<Button onClick={this.handleOnClick} className="copy-button secondary ghost" title={title}>
|
||||
{isCopied ? (
|
||||
<i className="fa-sharp fa-solid fa-check"></i>
|
||||
) : (
|
||||
<i className="fa-sharp fa-solid fa-copy"></i>
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export { CopyButton };
|
||||
@@ -5,7 +5,7 @@
|
||||
width: 100%;
|
||||
border: 2px solid var(--form-element-border-color);
|
||||
border-radius: 6px;
|
||||
line-height: 22px;
|
||||
line-height: 20px;
|
||||
background: var(--form-element-bg-color);
|
||||
|
||||
&.no-label {
|
||||
|
||||
@@ -18,3 +18,5 @@ export { Toggle } from "./toggle";
|
||||
export { Tooltip } from "./tooltip";
|
||||
export { TabIcon } from "./tabicon";
|
||||
export { DatePicker } from "./datepicker";
|
||||
export { TermStyleBlock } from "./termstyleblock";
|
||||
export { CopyButton } from "./copybutton";
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
// Copyright 2023, Command Line Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import * as React from "react";
|
||||
import * as mobxReact from "mobx-react";
|
||||
import { GlobalModel } from "@/models";
|
||||
|
||||
const VALID_CSS_VARIABLES = [
|
||||
"--term-black",
|
||||
"--term-red",
|
||||
"--term-green",
|
||||
"--term-yellow",
|
||||
"--term-blue",
|
||||
"--term-magenta",
|
||||
"--term-cyan",
|
||||
"--term-white",
|
||||
"--term-bright-black",
|
||||
"--term-bright-red",
|
||||
"--term-bright-green",
|
||||
"--term-bright-yellow",
|
||||
"--term-bright-blue",
|
||||
"--term-bright-magenta",
|
||||
"--term-bright-cyan",
|
||||
"--term-bright-white",
|
||||
"--term-gray",
|
||||
"--term-cmdtext",
|
||||
"--term-foreground",
|
||||
"--term-background",
|
||||
"--term-selection-background",
|
||||
"--term-cursor-accent",
|
||||
];
|
||||
|
||||
@mobxReact.observer
|
||||
class TermStyleBlock extends React.Component<{
|
||||
themeName: string;
|
||||
selector: string;
|
||||
}> {
|
||||
componentDidMount() {
|
||||
GlobalModel.bumpTermRenderVersion();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
GlobalModel.bumpTermRenderVersion();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.themeName !== this.props.themeName || prevProps.selector !== this.props.selector) {
|
||||
GlobalModel.bumpTermRenderVersion();
|
||||
}
|
||||
}
|
||||
|
||||
isValidCSSColor(color) {
|
||||
const element = document.createElement("div");
|
||||
element.style.color = color;
|
||||
return element.style.color !== "";
|
||||
}
|
||||
|
||||
camelCaseToKebabCase(str) {
|
||||
return str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
||||
}
|
||||
|
||||
getStyleRules() {
|
||||
const { selector, themeName } = this.props;
|
||||
const termThemeOptions = GlobalModel.getTermThemeOptions();
|
||||
if (!termThemeOptions) {
|
||||
return null;
|
||||
}
|
||||
const theme = termThemeOptions[themeName];
|
||||
if (!theme) {
|
||||
return null;
|
||||
}
|
||||
const styleProperties = Object.entries(theme)
|
||||
.filter(([key, value]) => {
|
||||
const cssVarName = `--term-${this.camelCaseToKebabCase(key)}`;
|
||||
return VALID_CSS_VARIABLES.includes(cssVarName) && this.isValidCSSColor(value);
|
||||
})
|
||||
.map(([key, value]) => `--term-${key}: ${value};`)
|
||||
.join(" ");
|
||||
|
||||
if (!styleProperties) {
|
||||
return null;
|
||||
}
|
||||
return `${selector} { ${styleProperties} }`;
|
||||
}
|
||||
|
||||
render() {
|
||||
const styleRules = this.getStyleRules();
|
||||
if (!styleRules) {
|
||||
return null;
|
||||
}
|
||||
return <style>{styleRules}</style>;
|
||||
}
|
||||
}
|
||||
|
||||
export { TermStyleBlock };
|
||||
@@ -312,7 +312,7 @@ class CreateRemoteConnModal extends React.Component<{}, {}> {
|
||||
endDecoration: (
|
||||
<InputDecoration>
|
||||
<Tooltip
|
||||
message={`(Required) The path to your ssh key file.`}
|
||||
message={`(Required) The path to your ssh private key file.`}
|
||||
icon={<i className="fa-sharp fa-regular fa-circle-question" />}
|
||||
>
|
||||
<i className="fa-sharp fa-regular fa-circle-question" />
|
||||
|
||||
@@ -338,7 +338,7 @@ class EditRemoteConnModal extends React.Component<{}, {}> {
|
||||
endDecoration: (
|
||||
<InputDecoration>
|
||||
<Tooltip
|
||||
message={`(Required) The path to your ssh key file.`}
|
||||
message={`(Required) The path to your ssh private key file.`}
|
||||
icon={<i className="fa-sharp fa-regular fa-circle-question" />}
|
||||
>
|
||||
<i className="fa-sharp fa-regular fa-circle-question" />
|
||||
|
||||
@@ -160,6 +160,7 @@ class ScreenSettingsModal extends React.Component<{}, {}> {
|
||||
if (currTheme == theme) {
|
||||
return;
|
||||
}
|
||||
GlobalModel.setTermThemeScope(this.screenId, `.main-content [data-screenid="${this.screenId}"]`);
|
||||
const prtn = GlobalCommandRunner.setScreenTermTheme(this.screenId, theme, false);
|
||||
commandRtnHandler(prtn, this.errorMessage);
|
||||
}
|
||||
@@ -175,13 +176,8 @@ class ScreenSettingsModal extends React.Component<{}, {}> {
|
||||
if (screen == null) {
|
||||
return null;
|
||||
}
|
||||
let color: string = null;
|
||||
let icon: string = null;
|
||||
let index: number = 0;
|
||||
const curRemote = GlobalModel.getRemote(GlobalModel.getActiveScreen().getCurRemoteInstance().remoteid);
|
||||
const termThemes = getTermThemes(GlobalModel.termThemes);
|
||||
const currTermTheme = GlobalModel.getTermTheme()[this.screenId] ?? termThemes[0].label;
|
||||
|
||||
return (
|
||||
<Modal className="screen-settings-modal">
|
||||
<Modal.Header onClose={this.closeModal} title={`Tab Settings (${screen.name.get()})`} />
|
||||
|
||||
@@ -99,7 +99,7 @@ class SessionSettingsModal extends React.Component<{}, {}> {
|
||||
if (this.session == null) {
|
||||
return null;
|
||||
}
|
||||
const termThemes = getTermThemes(GlobalModel.termThemes);
|
||||
const termThemes = getTermThemes(GlobalModel.termThemeOptions.get());
|
||||
const currTermTheme = GlobalModel.getTermTheme()[this.sessionId] ?? termThemes[0].label;
|
||||
|
||||
return (
|
||||
|
||||
@@ -357,6 +357,10 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.wave-button {
|
||||
padding: 5px 5px;
|
||||
}
|
||||
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import localizedFormat from "dayjs/plugin/localizedFormat";
|
||||
import customParseFormat from "dayjs/plugin/customParseFormat";
|
||||
import { Line } from "@/app/line/linecomps";
|
||||
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "@/util/keyutil";
|
||||
import { TextField, Dropdown, Button, DatePicker } from "@/elements";
|
||||
import { TextField, Dropdown, Button, CopyButton } from "@/elements";
|
||||
|
||||
import { ReactComponent as ChevronLeftIcon } from "@/assets/icons/history/chevron-left.svg";
|
||||
import { ReactComponent as ChevronRightIcon } from "@/assets/icons/history/chevron-right.svg";
|
||||
@@ -22,8 +22,6 @@ import { ReactComponent as RightIcon } from "@/assets/icons/history/right.svg";
|
||||
import { ReactComponent as SearchIcon } from "@/assets/icons/history/search.svg";
|
||||
import { ReactComponent as TrashIcon } from "@/assets/icons/trash.svg";
|
||||
import { ReactComponent as CheckedCheckbox } from "@/assets/icons/checked-checkbox.svg";
|
||||
import { ReactComponent as CheckIcon } from "@/assets/icons/line/check.svg";
|
||||
import { ReactComponent as CopyIcon } from "@/assets/icons/history/copy.svg";
|
||||
|
||||
import "./history.less";
|
||||
import { MainView } from "../common/elements/mainview";
|
||||
@@ -115,7 +113,6 @@ class HistoryCmdStr extends React.Component<
|
||||
cmdstr: string;
|
||||
onUse: () => void;
|
||||
onCopy: () => void;
|
||||
isCopied: boolean;
|
||||
fontSize: "normal" | "large";
|
||||
limitHeight: boolean;
|
||||
},
|
||||
@@ -138,24 +135,17 @@ class HistoryCmdStr extends React.Component<
|
||||
}
|
||||
|
||||
render() {
|
||||
const { isCopied, cmdstr, fontSize, limitHeight } = this.props;
|
||||
const { cmdstr, fontSize, limitHeight } = this.props;
|
||||
return (
|
||||
<div className={cn("cmdstr-code", { "is-large": fontSize == "large" }, { "limit-height": limitHeight })}>
|
||||
<If condition={isCopied}>
|
||||
<div key="copied" className="copied-indicator">
|
||||
<div>copied</div>
|
||||
</div>
|
||||
</If>
|
||||
<div key="code" className="code-div">
|
||||
<code>{cmdstr}</code>
|
||||
</div>
|
||||
<div key="copy" className="actions-block">
|
||||
<div className="action-item" onClick={this.handleCopy} title="copy">
|
||||
<CopyIcon className="icon" />
|
||||
</div>
|
||||
<div key="use" className="action-item" title="Use Command" onClick={this.handleUse}>
|
||||
<CheckIcon className="icon" />
|
||||
</div>
|
||||
<CopyButton onClick={this.handleCopy} title="Copy" />
|
||||
<Button className="secondary ghost" title="Use Command" onClick={this.handleUse}>
|
||||
<i className="fa-sharp fa-solid fa-play"></i>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -190,7 +180,6 @@ class HistoryView extends React.Component<{}, {}> {
|
||||
tableRszObs: ResizeObserver;
|
||||
sessionDropdownActive: OV<boolean> = mobx.observable.box(false, { name: "sessionDropdownActive" });
|
||||
remoteDropdownActive: OV<boolean> = mobx.observable.box(false, { name: "remoteDropdownActive" });
|
||||
copiedItemId: OV<string> = mobx.observable.box(null, { name: "copiedItemId" });
|
||||
|
||||
@boundMethod
|
||||
handleNext() {
|
||||
@@ -377,14 +366,6 @@ class HistoryView extends React.Component<{}, {}> {
|
||||
return;
|
||||
}
|
||||
navigator.clipboard.writeText(item.cmdstr);
|
||||
mobx.action(() => {
|
||||
this.copiedItemId.set(item.historyid);
|
||||
})();
|
||||
setTimeout(() => {
|
||||
mobx.action(() => {
|
||||
this.copiedItemId.set(null);
|
||||
})();
|
||||
}, 600);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
@@ -394,7 +375,7 @@ class HistoryView extends React.Component<{}, {}> {
|
||||
}
|
||||
mobx.action(() => {
|
||||
GlobalModel.showSessionView();
|
||||
GlobalModel.inputModel.setCurLine(item.cmdstr);
|
||||
GlobalModel.inputModel.updateCmdLine({ str: item.cmdstr, pos: item.cmdstr.length });
|
||||
setTimeout(() => GlobalModel.inputModel.giveFocus(), 50);
|
||||
})();
|
||||
}
|
||||
@@ -569,7 +550,6 @@ class HistoryView extends React.Component<{}, {}> {
|
||||
cmdstr={item.cmdstr}
|
||||
onUse={() => this.handleUse(item)}
|
||||
onCopy={() => this.handleCopy(item)}
|
||||
isCopied={this.copiedItemId.get() == item.historyid}
|
||||
fontSize="normal"
|
||||
limitHeight={true}
|
||||
/>
|
||||
@@ -669,11 +649,6 @@ class LineContainer extends React.Component<{ historyId: string; width: number }
|
||||
this.line = hvm.getLineById(this.historyItem.lineid);
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
GlobalModel.bumpTermRenderVersion();
|
||||
GlobalModel.termThemeSrcEl.set(null);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleHeightChange(lineNum: number, newHeight: number, oldHeight: number): void {
|
||||
return;
|
||||
|
||||
@@ -27,7 +27,7 @@ class AIChatKeybindings extends React.Component<{ AIChatObject: AIChat }, {}> {
|
||||
return true;
|
||||
});
|
||||
keybindManager.registerKeybinding("pane", "aichat", "generic:cancel", (waveEvent) => {
|
||||
inputModel.closeAIAssistantChat(true);
|
||||
inputModel.closeAuxView();
|
||||
return true;
|
||||
});
|
||||
keybindManager.registerKeybinding("pane", "aichat", "aichat:clearHistory", (waveEvent) => {
|
||||
@@ -70,7 +70,7 @@ class AIChat extends React.Component<{}, {}> {
|
||||
|
||||
componentDidMount() {
|
||||
const inputModel = GlobalModel.inputModel;
|
||||
if (this.chatWindowScrollRef != null && this.chatWindowScrollRef.current != null) {
|
||||
if (this.chatWindowScrollRef?.current != null) {
|
||||
this.chatWindowScrollRef.current.scrollTop = this.chatWindowScrollRef.current.scrollHeight;
|
||||
}
|
||||
if (this.textAreaRef.current != null) {
|
||||
@@ -82,7 +82,7 @@ class AIChat extends React.Component<{}, {}> {
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.chatWindowScrollRef != null && this.chatWindowScrollRef.current != null) {
|
||||
if (this.chatWindowScrollRef?.current != null) {
|
||||
this.chatWindowScrollRef.current.scrollTop = this.chatWindowScrollRef.current.scrollHeight;
|
||||
}
|
||||
}
|
||||
@@ -252,7 +252,7 @@ class AIChat extends React.Component<{}, {}> {
|
||||
<AuxiliaryCmdView
|
||||
title="Wave AI"
|
||||
className="cmd-aichat"
|
||||
onClose={() => GlobalModel.inputModel.closeAIAssistantChat(true)}
|
||||
onClose={() => GlobalModel.inputModel.closeAuxView()}
|
||||
iconClass="fa-sharp fa-solid fa-sparkles"
|
||||
>
|
||||
<If condition={renderKeybindings}>
|
||||
|
||||
@@ -4,12 +4,11 @@
|
||||
max-height: max(300px, 40%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
z-index: 100;
|
||||
border-top: 2px solid var(--app-border-color);
|
||||
background-color: var(--app-bg-color);
|
||||
position: relative;
|
||||
|
||||
// Apply a border between the base cmdinput and any views shown above it
|
||||
// TODO: use a generic selector for this
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as React from "react";
|
||||
import * as mobxReact from "mobx-react";
|
||||
import * as mobx from "mobx";
|
||||
import { boundMethod } from "autobind-decorator";
|
||||
import { If } from "tsx-control-statements/components";
|
||||
import { Choose, If, When } from "tsx-control-statements/components";
|
||||
import cn from "classnames";
|
||||
import dayjs from "dayjs";
|
||||
import localizedFormat from "dayjs/plugin/localizedFormat";
|
||||
@@ -18,6 +18,7 @@ import { Prompt } from "@/common/prompt/prompt";
|
||||
import { CenteredIcon, RotateIcon } from "@/common/icons/icons";
|
||||
import { AIChat } from "./aichat";
|
||||
import * as util from "@/util/util";
|
||||
import * as appconst from "@/app/appconst";
|
||||
|
||||
import "./cmdinput.less";
|
||||
|
||||
@@ -61,7 +62,7 @@ class CmdInput extends React.Component<{}, {}> {
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
baseCmdInputClick(e: React.MouseEvent): void {
|
||||
baseCmdInputClick(e: React.SyntheticEvent): void {
|
||||
if (this.promptRef.current != null) {
|
||||
if (this.promptRef.current.contains(e.target)) {
|
||||
return;
|
||||
@@ -71,7 +72,7 @@ class CmdInput extends React.Component<{}, {}> {
|
||||
e.stopPropagation();
|
||||
return;
|
||||
}
|
||||
GlobalModel.inputModel.setHistoryFocus(false);
|
||||
GlobalModel.inputModel.setAuxViewFocus(false);
|
||||
GlobalModel.inputModel.giveFocus();
|
||||
}
|
||||
|
||||
@@ -80,8 +81,8 @@ class CmdInput extends React.Component<{}, {}> {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const inputModel = GlobalModel.inputModel;
|
||||
if (inputModel.aIChatShow.get()) {
|
||||
inputModel.closeAIAssistantChat(true);
|
||||
if (inputModel.getActiveAuxView() === appconst.InputAuxView_AIChat) {
|
||||
inputModel.closeAuxView();
|
||||
} else {
|
||||
inputModel.openAIAssistantChat();
|
||||
}
|
||||
@@ -93,7 +94,7 @@ class CmdInput extends React.Component<{}, {}> {
|
||||
e.stopPropagation();
|
||||
|
||||
const inputModel = GlobalModel.inputModel;
|
||||
if (inputModel.historyShow.get()) {
|
||||
if (inputModel.getActiveAuxView() === appconst.InputAuxView_History) {
|
||||
inputModel.resetHistory();
|
||||
} else {
|
||||
inputModel.openHistory();
|
||||
@@ -155,9 +156,6 @@ class CmdInput extends React.Component<{}, {}> {
|
||||
remote = GlobalModel.getRemote(rptr.remoteid);
|
||||
}
|
||||
feState = feState || {};
|
||||
const infoShow = inputModel.infoShow.get();
|
||||
const historyShow = !infoShow && inputModel.historyShow.get();
|
||||
const aiChatShow = inputModel.aIChatShow.get();
|
||||
const focusVal = inputModel.physicalInputFocused.get();
|
||||
const inputMode: string = inputModel.inputMode.get();
|
||||
const textAreaInputKey = screen == null ? "null" : screen.screenId;
|
||||
@@ -170,7 +168,7 @@ class CmdInput extends React.Component<{}, {}> {
|
||||
let shellInitMsg: string = null;
|
||||
let hidePrompt = false;
|
||||
|
||||
const openView = inputModel.getOpenView();
|
||||
const openView = inputModel.getActiveAuxView();
|
||||
const hasOpenView = openView ? `has-${openView}` : null;
|
||||
if (ri == null) {
|
||||
let shellStr = "shell";
|
||||
@@ -185,15 +183,19 @@ class CmdInput extends React.Component<{}, {}> {
|
||||
}
|
||||
return (
|
||||
<div ref={this.cmdInputRef} className={cn("cmd-input", hasOpenView, { active: focusVal })}>
|
||||
<If condition={historyShow}>
|
||||
<div className="cmd-input-grow-spacer"></div>
|
||||
<HistoryInfo />
|
||||
</If>
|
||||
<If condition={aiChatShow}>
|
||||
<div className="cmd-input-grow-spacer"></div>
|
||||
<AIChat />
|
||||
</If>
|
||||
<InfoMsg key="infomsg" />
|
||||
<Choose>
|
||||
<When condition={openView === appconst.InputAuxView_History}>
|
||||
<div className="cmd-input-grow-spacer"></div>
|
||||
<HistoryInfo />
|
||||
</When>
|
||||
<When condition={openView === appconst.InputAuxView_AIChat}>
|
||||
<div className="cmd-input-grow-spacer"></div>
|
||||
<AIChat />
|
||||
</When>
|
||||
<When condition={openView === appconst.InputAuxView_Info}>
|
||||
<InfoMsg key="infomsg" />
|
||||
</When>
|
||||
</Choose>
|
||||
<If condition={remote && remote.status != "connected"}>
|
||||
<div className="remote-status-warning">
|
||||
WARNING:
|
||||
@@ -229,7 +231,12 @@ class CmdInput extends React.Component<{}, {}> {
|
||||
</Button>
|
||||
</div>
|
||||
</If>
|
||||
<div key="base-cmdinput" className="base-cmdinput" onClick={this.baseCmdInputClick}>
|
||||
<div
|
||||
key="base-cmdinput"
|
||||
className="base-cmdinput"
|
||||
onClick={this.baseCmdInputClick}
|
||||
onSelect={this.baseCmdInputClick}
|
||||
>
|
||||
<div className="cmdinput-actions">
|
||||
<If condition={numRunningLines > 0}>
|
||||
<div
|
||||
|
||||
@@ -167,14 +167,14 @@ class HistoryInfo extends React.Component<{}, {}> {
|
||||
|
||||
@boundMethod
|
||||
handleClose() {
|
||||
GlobalModel.inputModel.toggleInfoMsg();
|
||||
GlobalModel.inputModel.closeAuxView();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleItemClick(hitem: HistoryItem) {
|
||||
const inputModel = GlobalModel.inputModel;
|
||||
const selItem = inputModel.getHistorySelectedItem();
|
||||
inputModel.setHistoryFocus(true);
|
||||
inputModel.setAuxViewFocus(false);
|
||||
if (this.lastClickHNum == hitem.historynum && selItem != null && selItem.historynum == hitem.historynum) {
|
||||
inputModel.grabSelectedHistoryItem();
|
||||
return;
|
||||
@@ -194,14 +194,14 @@ class HistoryInfo extends React.Component<{}, {}> {
|
||||
@boundMethod
|
||||
handleClickType() {
|
||||
const inputModel = GlobalModel.inputModel;
|
||||
inputModel.setHistoryFocus(true);
|
||||
inputModel.setAuxViewFocus(true);
|
||||
inputModel.toggleHistoryType();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleClickRemote() {
|
||||
const inputModel = GlobalModel.inputModel;
|
||||
inputModel.setHistoryFocus(true);
|
||||
inputModel.setAuxViewFocus(true);
|
||||
inputModel.toggleRemoteType();
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user