Clean up the input model's auxiliary view logic (#553)

* Clean up the input model's auxiliary view logic

* fix

* save work

* rename appconst

* fix keybindings

* remove debugs

* Add comments

* fix focus order

* givefocus whenever focus var is updated, don't update if nothign changes

* remove debug statements

* one more debug

* revert unnecessary newline

* remove cmdinput placeholder to allow for better window resizing
This commit is contained in:
Evan Simkowitz 2024-04-05 17:39:27 -07:00 committed by GitHub
parent eed234a131
commit 455790416d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 158 additions and 223 deletions

View File

@ -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";

View File

@ -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}>

View File

@ -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

View File

@ -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";
@ -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:&nbsp;

View File

@ -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();
}

View File

@ -45,7 +45,7 @@ class InfoMsg extends React.Component<{}, {}> {
render() {
const inputModel = GlobalModel.inputModel;
const infoMsg: InfoType = inputModel.infoMsg.get();
const infoShow: boolean = inputModel.infoShow.get();
const infoShow = inputModel.getActiveAuxView() == appconst.InputAuxView_Info;
let line: string = null;
let istr: string = null;
let idx: number = 0;

View File

@ -152,11 +152,7 @@ class CmdInputKeybindings extends React.Component<{ inputObject: TextAreaInput }
});
keybindManager.registerKeybinding("pane", "cmdinput", "generic:cancel", (waveEvent) => {
GlobalModel.closeTabSettings();
inputModel.toggleInfoMsg();
if (inputModel.inputMode.get() != null) {
inputModel.resetInputMode();
}
inputModel.closeAIAssistantChat(true);
inputModel.closeAuxView();
return true;
});
keybindManager.registerKeybinding("pane", "cmdinput", "cmdinput:expandInput", (waveEvent) => {
@ -254,8 +250,6 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: ()
lastHeight: number = 0;
lastSP: StrWithPos = { str: "", pos: appconst.NoStrPos };
version: OV<number> = mobx.observable.box(0, { name: "textAreaInput-version" }); // forces render updates
mainInputFocused: OV<boolean> = mobx.observable.box(true, { name: "textAreaInput-mainInputFocused" });
historyFocused: OV<boolean> = mobx.observable.box(false, { name: "textAreaInput-historyFocused" });
incVersion(): void {
const v = this.version.get();
@ -286,16 +280,7 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: ()
}
setFocus(): void {
const inputModel = GlobalModel.inputModel;
if (inputModel.historyFocus.get()) {
if (this.historyInputRef.current != null && document.activeElement != this.historyInputRef.current) {
this.historyInputRef.current.focus();
}
} else {
if (this.mainInputRef.current != null && document.activeElement != this.mainInputRef.current) {
this.mainInputRef.current.focus();
}
}
GlobalModel.inputModel.giveFocus();
}
getTextAreaMaxCols(): number {
@ -536,7 +521,7 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: ()
if (selStart > value.length || selEnd > value.length) {
return;
}
const newValue = value.substr(0, selStart) + clipText + value.substr(selEnd);
const newValue = value.substring(0, selStart) + clipText + value.substring(selEnd);
const cmdLineUpdate = { str: newValue, pos: selStart + clipText.length };
GlobalModel.inputModel.updateCmdLine(cmdLineUpdate);
});
@ -553,19 +538,9 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: ()
}
@boundMethod
handleMainFocus(e: any) {
const inputModel = GlobalModel.inputModel;
if (inputModel.historyFocus.get()) {
e.preventDefault();
if (this.historyInputRef.current != null) {
this.historyInputRef.current.focus();
}
return;
}
inputModel.setPhysicalInputFocused(true);
mobx.action(() => {
this.mainInputFocused.set(true);
})();
handleFocus(e: any) {
e.preventDefault();
GlobalModel.inputModel.giveFocus();
}
@boundMethod
@ -574,25 +549,6 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: ()
return;
}
GlobalModel.inputModel.setPhysicalInputFocused(false);
mobx.action(() => {
this.mainInputFocused.set(false);
})();
}
@boundMethod
handleHistoryFocus(e: any) {
const inputModel = GlobalModel.inputModel;
if (!inputModel.historyFocus.get()) {
e.preventDefault();
if (this.mainInputRef.current != null) {
this.mainInputRef.current.focus();
}
return;
}
inputModel.setPhysicalInputFocused(true);
mobx.action(() => {
this.historyFocused.set(true);
})();
}
@boundMethod
@ -601,9 +557,6 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: ()
return;
}
GlobalModel.inputModel.setPhysicalInputFocused(false);
mobx.action(() => {
this.historyFocused.set(false);
})();
}
render() {
@ -621,9 +574,8 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: ()
displayLines = 5;
}
// TODO: invert logic here. We should track focus on the main textarea and assume aux view is focused if not.
const disabled = inputModel.historyFocus.get();
if (disabled) {
const auxViewFocused = inputModel.getAuxViewFocus();
if (auxViewFocused) {
displayLines = 1;
}
const activeScreen = GlobalModel.getActiveScreen();
@ -639,7 +591,7 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: ()
const screen = GlobalModel.getActiveScreen();
if (screen != null) {
const ri = screen.getCurRemoteInstance();
if (ri != null && ri.shelltype != null) {
if (ri?.shelltype != null) {
shellType = ri.shelltype;
}
if (shellType == "") {
@ -652,15 +604,14 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: ()
}
}
}
const isMainInputFocused = inputModel.hasFocus() && this.mainInputFocused.get();
const isHistoryFocused = this.historyFocused.get();
const isHistoryFocused = auxViewFocused && inputModel.getActiveAuxView() == appconst.InputAuxView_History;
return (
<div
className="textareainput-div control is-expanded"
ref={this.controlRef}
style={{ height: computedOuterHeight }}
>
<If condition={isMainInputFocused}>
<If condition={!auxViewFocused}>
<CmdInputKeybindings inputObject={this}></CmdInputKeybindings>
</If>
<If condition={isHistoryFocused}>
@ -677,7 +628,7 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: ()
autoComplete="off"
autoCorrect="off"
id="main-cmd-input"
onFocus={this.handleMainFocus}
onFocus={this.handleFocus}
onBlur={this.handleMainBlur}
style={{ height: computedInnerHeight, minHeight: computedInnerHeight, fontSize: termFontSize }}
value={curLine}
@ -685,7 +636,7 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: ()
onChange={this.onChange}
onSelect={this.onSelect}
placeholder="Type here..."
className={cn("textarea", { "display-disabled": disabled })}
className={cn("textarea", { "display-disabled": auxViewFocused })}
></textarea>
<input
key="history"
@ -695,7 +646,7 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: ()
autoCorrect="off"
className="history-input"
type="text"
onFocus={this.handleHistoryFocus}
onFocus={this.handleFocus}
onBlur={this.handleHistoryBlur}
onKeyDown={this.onHistoryKeyDown}
onChange={this.handleHistoryInput}

View File

@ -318,7 +318,6 @@ class WorkspaceView extends React.Component<{}, {}> {
session={session}
screen={activeScreen}
/>
<div className="cmdinput-height-placeholder" style={{ height: cmdInputHeight }}></div>
<If condition={activeScreen != null}>
<CmdInput key={"cmdinput-" + sessionId} />
</If>

View File

@ -8,6 +8,7 @@ import { isBlank } from "@/util/util";
import * as appconst from "@/app/appconst";
import { Model } from "./model";
import { GlobalCommandRunner } from "./global";
import { app } from "electron";
function getDefaultHistoryQueryOpts(): HistoryQueryOpts {
return {
@ -24,10 +25,8 @@ function getDefaultHistoryQueryOpts(): HistoryQueryOpts {
class InputModel {
globalModel: Model;
historyShow: OV<boolean> = mobx.observable.box(false);
historyFocus: OV<boolean> = mobx.observable.box(false);
infoShow: OV<boolean> = mobx.observable.box(false);
aIChatShow: OV<boolean> = mobx.observable.box(false);
activeAuxView: OV<InputAuxViewType> = mobx.observable.box(null);
auxViewFocus: OV<boolean> = mobx.observable.box(false);
cmdInputHeight: OV<number> = mobx.observable.box(0);
aiChatTextAreaRef: React.RefObject<HTMLTextAreaElement>;
aiChatWindowRef: React.RefObject<HTMLDivElement>;
@ -139,26 +138,39 @@ class InputModel {
})();
}
_focusCmdInput(): void {
const elem = document.getElementById("main-cmd-input");
if (elem != null) {
elem.focus();
}
}
_focusHistoryInput(): void {
const elem: HTMLElement = document.querySelector(".cmd-input input.history-input");
if (elem != null) {
elem.focus();
}
}
// Focuses the main input or the auxiliary view, depending on the active auxiliary view
giveFocus(): void {
if (this.historyFocus.get()) {
this._focusHistoryInput();
} else {
this._focusCmdInput();
}
// Override active view to the main input if aux view does not have focus
const activeAuxView = this.getAuxViewFocus() ? this.getActiveAuxView() : null;
mobx.action(() => {
switch (activeAuxView) {
case appconst.InputAuxView_History: {
const elem: HTMLElement = document.querySelector(".cmd-input input.history-input");
if (elem != null) {
elem.focus();
}
break;
}
case "aichat":
this.setAIChatFocus();
break;
case null: {
const elem = document.getElementById("main-cmd-input");
if (elem != null) {
elem.focus();
}
this.setPhysicalInputFocused(true);
break;
}
default: {
const elem: HTMLElement = document.querySelector(".cmd-input .auxview");
if (elem != null) {
elem.focus();
}
break;
}
}
})();
}
setPhysicalInputFocused(isFocused: boolean): void {
@ -191,19 +203,6 @@ class InputModel {
return false;
}
getOpenView(): string {
if (this.historyShow.get()) {
return "history";
}
if (this.aIChatShow.get()) {
return "aichat";
}
if (this.infoShow.get()) {
return "info";
}
return null;
}
setHistoryType(htype: HistoryTypeStrs): void {
if (this.historyQueryOpts.get().queryType == htype) {
return;
@ -244,45 +243,11 @@ class InputModel {
})();
}
setInputPopUpType(type: string) {
this.inputPopUpType = type;
this.aIChatShow.set(type == "aichat");
this.historyShow.set(type == "history");
}
setOpenAICmdInfoChat(chat: OpenAICmdInfoChatMessageType[]): void {
this.AICmdInfoChatItems.replace(chat);
this.codeSelectBlockRefArray = [];
}
setHistoryShow(show: boolean): void {
if (this.historyShow.get() == show) {
return;
}
mobx.action(() => {
if (show) {
this.setInputPopUpType("history");
} else {
this.setInputPopUpType("none");
}
this.historyShow.set(show);
this.historyFocus.set(show);
if (this.hasFocus()) {
this.giveFocus();
}
})();
}
setHistoryFocus(focus: boolean): void {
if (this.historyFocus.get() == focus) {
return;
}
mobx.action(() => {
this.historyFocus.set(focus);
this.giveFocus();
})();
}
isHistoryLoaded(): boolean {
if (this.historyLoading.get()) {
return false;
@ -315,14 +280,9 @@ class InputModel {
this.loadHistory(true, 0, "screen");
return;
}
if (!this.historyShow.get()) {
mobx.action(() => {
this.setHistoryShow(true);
this.aIChatShow.set(false);
this.infoShow.set(false);
this.dropModHistory(true);
this.giveFocus();
})();
if (this.getActiveAuxView() != appconst.InputAuxView_History) {
this.dropModHistory(true);
this.setActiveAuxView(appconst.InputAuxView_History);
}
}
@ -495,6 +455,51 @@ class InputModel {
})();
}
// Closes the auxiliary view if it is open, focuses the main input
closeAuxView(): void {
if (this.activeAuxView.get() == null) {
return;
}
this.setActiveAuxView(null);
}
// Gets the active auxiliary view, or null if none
getActiveAuxView(): InputAuxViewType {
return this.activeAuxView.get();
}
// Sets the active auxiliary view
setActiveAuxView(view: InputAuxViewType): void {
if (view == this.activeAuxView.get()) {
return;
}
mobx.action(() => {
this.auxViewFocus.set(view != null);
this.activeAuxView.set(view);
})();
this.giveFocus();
}
// Gets the focus state of the auxiliary view. If true, the view will get focus. Otherwise, the main input will get focus.
// If the auxiliary view is not open, this will return false.
getAuxViewFocus(): boolean {
if (this.getActiveAuxView() == null) {
return false;
}
return this.auxViewFocus.get();
}
// Sets the focus state of the auxiliary view. If true, the view will get focus. Otherwise, the main input will get focus.
setAuxViewFocus(focus: boolean): void {
if (this.getAuxViewFocus() == focus) {
return;
}
mobx.action(() => {
this.auxViewFocus.set(focus);
})();
this.giveFocus();
}
setHistoryIndex(hidx: number, force?: boolean): void {
if (hidx < 0) {
return;
@ -504,7 +509,7 @@ class InputModel {
}
mobx.action(() => {
this.historyIndex.set(hidx);
if (this.historyShow.get()) {
if (this.getActiveAuxView() == appconst.InputAuxView_History) {
let hitem = this.getHistorySelectedItem();
if (hitem == null) {
hitem = this.getFirstHistoryItem();
@ -538,16 +543,18 @@ class InputModel {
this._clearInfoTimeout();
mobx.action(() => {
this.infoMsg.set(info);
if (info == null) {
this.infoShow.set(false);
} else {
this.infoShow.set(true);
this.setHistoryShow(false);
}
})();
if (info == null && this.getActiveAuxView() == appconst.InputAuxView_Info) {
this.setActiveAuxView(null);
} else {
this.setActiveAuxView(appconst.InputAuxView_Info);
}
if (info != null && timeoutMs) {
this.infoTimeoutId = setTimeout(() => {
if (this.historyShow.get()) {
console.log("clearing info msg");
if (this.activeAuxView.get() != appconst.InputAuxView_Info) {
return;
}
this.clearInfoMsg(false);
@ -683,28 +690,7 @@ class InputModel {
}
openAIAssistantChat(): void {
mobx.action(() => {
this.setInputPopUpType("aichat");
this.aIChatShow.set(true);
this.historyShow.set(false);
this.infoShow.set(false);
this.setAIChatFocus();
})();
}
// pass true to give focus to the input (e.g. if this is an 'active' close of the chat)
// when resetting the input (when switching screens, don't give focus)
closeAIAssistantChat(giveFocus: boolean): void {
if (!this.aIChatShow.get()) {
return;
}
mobx.action(() => {
this.setInputPopUpType("none");
this.aIChatShow.set(false);
if (giveFocus) {
this.giveFocus();
}
})();
this.setActiveAuxView(appconst.InputAuxView_AIChat);
}
clearAIAssistantChat(): void {
@ -719,7 +705,7 @@ class InputModel {
}
hasScrollingInfoMsg(): boolean {
if (!this.infoShow.get()) {
if (this.activeAuxView.get() !== appconst.InputAuxView_Info) {
return false;
}
const info = this.infoMsg.get();
@ -742,9 +728,11 @@ class InputModel {
clearInfoMsg(setNull: boolean): void {
this._clearInfoTimeout();
if (this.getActiveAuxView() == appconst.InputAuxView_Info) {
this.setActiveAuxView(null);
}
mobx.action(() => {
this.setHistoryShow(false);
this.infoShow.set(false);
if (setNull) {
this.infoMsg.set(null);
}
@ -753,20 +741,11 @@ class InputModel {
toggleInfoMsg(): void {
this._clearInfoTimeout();
mobx.action(() => {
if (this.historyShow.get()) {
this.setHistoryShow(false);
return;
}
const isShowing = this.infoShow.get();
if (isShowing) {
this.infoShow.set(false);
} else {
if (this.infoMsg.get() != null) {
this.infoShow.set(true);
}
}
})();
if (this.activeAuxView.get() == appconst.InputAuxView_Info) {
this.setActiveAuxView(null);
} else if (this.infoMsg.get() != null) {
this.setActiveAuxView(appconst.InputAuxView_Info);
}
}
@boundMethod
@ -804,9 +783,7 @@ class InputModel {
resetInput(): void {
mobx.action(() => {
this.setHistoryShow(false);
this.closeAIAssistantChat(false);
this.infoShow.set(false);
this.setActiveAuxView(null);
this.inputMode.set(null);
this.resetHistory();
this.dropModHistory(false);
@ -854,7 +831,9 @@ class InputModel {
resetHistory(): void {
mobx.action(() => {
this.setHistoryShow(false);
if (this.getActiveAuxView() == appconst.InputAuxView_History) {
this.setActiveAuxView(null);
}
this.historyLoading.set(false);
this.historyType.set("screen");
this.historyItems.set(null);

View File

@ -1082,7 +1082,7 @@ class Model {
this.ws.watchScreen(newActiveSessionId, newActiveScreenId);
this.closeTabSettings();
const activeScreen = this.getActiveScreen();
if (activeScreen != null && activeScreen.getCurRemoteInstance() != null) {
if (activeScreen?.getCurRemoteInstance() != null) {
setTimeout(() => {
GlobalCommandRunner.syncShellState();
}, 100);

View File

@ -15,6 +15,7 @@ declare global {
type LineContainerStrs = "main" | "sidebar" | "history";
type AppUpdateStatusType = "unavailable" | "ready";
type NativeThemeSource = "system" | "light" | "dark";
type InputAuxViewType = null | "history" | "info" | "aichat";
type OV<V> = mobx.IObservableValue<V>;
type OArr<V> = mobx.IObservableArray<V>;