Compare commits

..

5 Commits

Author SHA1 Message Date
Evan Simkowitz 45e2db0739 Merge branch 'main' into evan/grid 2024-05-06 14:18:25 -07:00
Evan Simkowitz 1a9ba17a95 save 2024-05-06 14:17:54 -07:00
Evan Simkowitz fd2cb82065 remove more main window references 2024-05-06 12:27:50 -07:00
Evan Simkowitz 2d890e63a7 more cleanup 2024-05-06 12:24:42 -07:00
Evan Simkowitz 9b3f9cb419 Use native window ID to track main window instead of a ref 2024-05-06 12:16:14 -07:00
28 changed files with 1993 additions and 16079 deletions
-14710
View File
File diff suppressed because it is too large Load Diff
+1 -2
View File
@@ -38,7 +38,7 @@
"monaco-editor": "0.48.0",
"mustache": "^4.2.0",
"node-fetch": "^3.2.10",
"overlayscrollbars": "^2.7.3",
"overlayscrollbars": "^2.6.1",
"overlayscrollbars-react": "^0.5.5",
"papaparse": "^5.4.1",
"react": "^18.1.0",
@@ -48,7 +48,6 @@
"remark-gfm": "^4.0.0",
"sprintf-js": "^1.1.2",
"throttle-debounce": "^5.0.0",
"tinycolor2": "^1.6.0",
"tsx-control-statements": "^5.1.1",
"uuid": "^9.0.0",
"winston": "^3.8.2",
+13 -11
View File
@@ -43,17 +43,19 @@ class CodeBlockMarkdown extends React.Component<
this.blockIndex = GlobalModel.inputModel.addCodeBlockToCodeSelect(this.blockRef, this.props.uuid);
}
@boundMethod
handleClick(e: React.MouseEvent<HTMLPreElement>) {
// console.log("this.blockIndex", this.blockIndex);
GlobalModel.inputModel.setCodeSelectSelectedCodeBlock(this.blockIndex);
}
render() {
// console.log("this.blockIndex", this.blockIndex);
let clickHandler: (e: React.MouseEvent<HTMLElement>, blockIndex: number) => void;
let inputModel = GlobalModel.inputModel;
clickHandler = (e: React.MouseEvent<HTMLElement>, blockIndex: number) => {
inputModel.setCodeSelectSelectedCodeBlock(blockIndex);
};
let selected = this.blockIndex == this.props.codeSelectSelectedIndex;
return (
<pre ref={this.blockRef} className={clsx({ selected: selected })} onClick={this.handleClick}>
<pre
ref={this.blockRef}
className={clsx({ selected: selected })}
onClick={(event) => clickHandler(event, this.blockIndex)}
>
{this.props.children}
</pre>
);
@@ -73,7 +75,7 @@ class Markdown extends React.Component<
}
@boundMethod
codeBlockRenderer(props: any, codeSelect: boolean, codeSelectIndex: number, curUuid: string): any {
CodeBlockRenderer(props: any, codeSelect: boolean, codeSelectIndex: number, curUuid: string): any {
if (codeSelect) {
return (
<CodeBlockMarkdown codeSelectSelectedIndex={codeSelectIndex} uuid={curUuid}>
@@ -93,7 +95,7 @@ class Markdown extends React.Component<
}
render() {
let { text } = this.props;
let text = this.props.text;
let codeSelect = this.props.codeSelect;
let curCodeSelectIndex = GlobalModel.inputModel.getCodeSelectSelectedIndex();
let markdownComponents = {
@@ -105,7 +107,7 @@ class Markdown extends React.Component<
h5: (props) => HeaderRenderer(props, 5),
h6: (props) => HeaderRenderer(props, 6),
code: (props) => CodeRenderer(props),
pre: (props) => this.codeBlockRenderer(props, codeSelect, curCodeSelectIndex, this.curUuid),
pre: (props) => this.CodeBlockRenderer(props, codeSelect, curCodeSelectIndex, this.curUuid),
};
return (
<div className={clsx("markdown content", this.props.extraClassName)} style={this.props.style}>
+1 -1
View File
@@ -23,7 +23,7 @@ let MagicLayout = {
MainSidebarDefaultWidth: 240,
RightSidebarMinWidth: 0,
RightSidebarMaxWidth: 400,
RightSidebarMaxWidth: 300,
RightSidebarSnapThreshold: 90,
RightSidebarDragResistance: 50,
RightSidebarDefaultWidth: 240,
-97
View File
@@ -1,97 +0,0 @@
.sidebar-aichat {
display: flex;
flex-direction: column;
overflow: hidden;
height: 100%;
.titlebar {
background-color: var(--app-panel-bg-color);
color: var(--term-blue);
padding: 6px 15px;
display: flex;
flex: 0 0 auto;
flex-direction: row;
width: 100%;
border-bottom: 1px solid var(--app-border-color);
font: var(--base-font);
user-select: none;
cursor: default;
line-height: 18px;
overflow: hidden;
.title-string {
font-weight: bold;
}
}
> .content {
flex-flow: column nowrap;
flex: 1;
margin-bottom: 0;
overflow-y: auto;
.chat-window {
display: flex;
// margin-bottom: 5px;
flex-direction: column;
height: 100%;
// This is the filler that will push the chat messages to the bottom until the chat window is full
.filler {
flex: 1 1 auto;
}
}
.chat-msg {
padding: calc(var(--termpad) * 2);
display: flex;
.chat-msg-header {
display: flex;
margin-bottom: 2px;
i {
margin-right: 0.5em;
}
}
}
.chat-msg-assistant {
color: var(--app-text-color);
pre {
white-space: pre-wrap;
word-break: break-word;
max-width: 100%;
overflow-x: auto;
margin-left: 0;
}
}
.chat-msg-error {
color: var(--cmdinput-text-error);
font-family: var(--markdown-font);
font-size: 14px;
}
}
.chat-input {
padding: 16px 15px 7px;
flex: 0 0 auto;
border-top: 1px solid var(--app-border-color);
.chat-textarea {
color: var(--app-text-primary-color);
background-color: var(--cmdinput-textarea-bg);
resize: none;
width: 100%;
border: transparent;
outline: none;
overflow: auto;
overflow-wrap: anywhere;
font-family: var(--termfontfamily);
font-weight: normal;
line-height: var(--termlineheight);
}
}
}
-355
View File
@@ -1,355 +0,0 @@
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { GlobalModel } from "@/models";
import { boundMethod } from "autobind-decorator";
import { If, For } from "tsx-control-statements/components";
import { Markdown } from "@/elements";
import type { OverlayScrollbars } from "overlayscrollbars";
import { OverlayScrollbarsComponent, OverlayScrollbarsComponentRef } from "overlayscrollbars-react";
import tinycolor from "tinycolor2";
import * as appconst from "@/app/appconst";
import "./aichat.less";
class AIChatKeybindings extends React.Component<{ AIChatObject: AIChat }, {}> {
componentDidMount(): void {
const AIChatObject = this.props.AIChatObject;
const keybindManager = GlobalModel.keybindManager;
const inputModel = GlobalModel.inputModel;
keybindManager.registerKeybinding("pane", "aichat", "generic:confirm", (waveEvent) => {
AIChatObject.onEnterKeyPressed();
return true;
});
keybindManager.registerKeybinding("pane", "aichat", "generic:expandTextInput", (waveEvent) => {
AIChatObject.onExpandInputPressed();
return true;
});
keybindManager.registerKeybinding("pane", "aichat", "generic:cancel", (waveEvent) => {
inputModel.closeAuxView();
return true;
});
keybindManager.registerKeybinding("pane", "aichat", "aichat:clearHistory", (waveEvent) => {
inputModel.clearAIAssistantChat();
return true;
});
keybindManager.registerKeybinding("pane", "aichat", "generic:selectAbove", (waveEvent) => {
return AIChatObject.onArrowUpPressed();
});
keybindManager.registerKeybinding("pane", "aichat", "generic:selectBelow", (waveEvent) => {
return AIChatObject.onArrowDownPressed();
});
}
componentWillUnmount(): void {
GlobalModel.keybindManager.unregisterDomain("aichat");
}
render() {
return null;
}
}
@mobxReact.observer
class ChatContent extends React.Component<{ chatWindowRef }, {}> {
chatListKeyCount: number = 0;
containerRef: React.RefObject<OverlayScrollbarsComponentRef> = React.createRef();
osInstance: OverlayScrollbars = null;
componentDidUpdate() {
this.chatListKeyCount = 0;
if (this.containerRef?.current && this.osInstance) {
const { viewport } = this.osInstance.elements();
// viewport.scrollTo({
// behavior: "auto",
// top: this.props.chatWindowRef.current.scrollHeight,
// });
}
}
componentWillUnmount() {
if (this.osInstance) {
this.osInstance.destroy();
this.osInstance = null;
}
}
@boundMethod
onScrollbarInitialized(instance) {
console.log("got here");
GlobalModel.inputModel.setChatOsInstance(instance);
this.osInstance = instance;
const { viewport } = instance.elements();
viewport.scrollTo({
behavior: "auto",
top: this.props.chatWindowRef.current.scrollHeight,
});
}
renderError(err: string): any {
return <div className="chat-msg-error">{err}</div>;
}
renderChatMessage(chatItem: OpenAICmdInfoChatMessageType): any {
const curKey = "chatmsg-" + this.chatListKeyCount;
this.chatListKeyCount++;
const senderClassName = chatItem.isassistantresponse ? "chat-msg-assistant" : "chat-msg-user";
const msgClassName = `chat-msg ${senderClassName}`;
let innerHTML: React.JSX.Element = (
<>
<div className="chat-msg-header">
<i className="fa-sharp fa-solid fa-user"></i>
</div>
<div className="msg-text">{chatItem.userquery}</div>
</>
);
if (chatItem.isassistantresponse) {
if (chatItem.assistantresponse.error != null && chatItem.assistantresponse.error !== "") {
innerHTML = this.renderError(chatItem.assistantresponse.error);
} else {
innerHTML = (
<>
<div className="chat-msg-header">
<i className="fa-sharp fa-solid fa-sparkles"></i>
</div>
<Markdown text={chatItem.assistantresponse.message} codeSelect />
</>
);
}
}
const cssVar = GlobalModel.isDev ? "--app-panel-bg-color-dev" : "--app-panel-bg-color";
const panelBgColor = getComputedStyle(document.documentElement).getPropertyValue(cssVar).trim();
const color = tinycolor(panelBgColor);
const newColor = color.isValid() ? tinycolor(panelBgColor).darken(6).toString() : "none";
const backgroundColor = this.chatListKeyCount % 2 === 0 ? "none" : newColor;
return (
<div className={msgClassName} key={curKey} style={{ backgroundColor }}>
{innerHTML}
</div>
);
}
render() {
const chatMessageItems = GlobalModel.inputModel.AICmdInfoChatItems.slice();
const chitem: OpenAICmdInfoChatMessageType = null;
return (
<OverlayScrollbarsComponent
ref={this.containerRef}
className="content"
options={{ scrollbars: { autoHide: "leave" } }}
events={{ initialized: this.onScrollbarInitialized }}
>
<div ref={this.props.chatWindowRef} className="chat-window">
<div className="filler"></div>
<For each="chitem" index="idx" of={chatMessageItems}>
{this.renderChatMessage(chitem)}
</For>
</div>
</OverlayScrollbarsComponent>
);
}
}
@mobxReact.observer
class AIChat extends React.Component<{}, {}> {
textAreaRef: React.RefObject<HTMLTextAreaElement> = React.createRef();
chatWindowRef: React.RefObject<HTMLDivElement> = React.createRef();
termFontSize: number = 14;
constructor(props) {
super(props);
mobx.makeObservable(this);
}
componentDidMount() {
const inputModel = GlobalModel.inputModel;
inputModel.openAIAssistantChat();
if (this.textAreaRef.current != null) {
this.textAreaRef.current.focus();
inputModel.setCmdInfoChatRefs(this.textAreaRef, this.chatWindowRef);
}
this.requestChatUpdate();
this.onTextAreaChange(null);
}
requestChatUpdate() {
const chatMessageItems = GlobalModel.inputModel.AICmdInfoChatItems.slice();
if (chatMessageItems == null || chatMessageItems.length == 0) {
this.submitChatMessage("");
}
}
// Adjust the height of the textarea to fit the text
@boundMethod
onTextAreaChange(e: any) {
if (this.textAreaRef.current == null) {
return;
}
// Calculate the bounding height of the text area
const textAreaMaxLines = 4;
const textAreaLineHeight = this.termFontSize * 1.5;
const textAreaMinHeight = textAreaLineHeight;
const textAreaMaxHeight = textAreaLineHeight * textAreaMaxLines;
// Get the height of the wrapped text area content. Courtesy of https://stackoverflow.com/questions/995168/textarea-to-resize-based-on-content-length
this.textAreaRef.current.style.height = "1px";
const scrollHeight: number = this.textAreaRef.current.scrollHeight;
// Set the new height of the text area, bounded by the min and max height.
const newHeight = Math.min(Math.max(scrollHeight, textAreaMinHeight), textAreaMaxHeight);
this.textAreaRef.current.style.height = newHeight + "px";
GlobalModel.inputModel.codeSelectDeselectAll();
}
submitChatMessage(messageStr: string) {
const curLine = GlobalModel.inputModel.curLine;
const prtn = GlobalModel.submitChatInfoCommand(messageStr, curLine, false);
prtn.then((rtn) => {
if (!rtn.success) {
console.log("submit chat command error: " + rtn.error);
}
}).catch((_) => {});
}
getLinePos(elem: any): { numLines: number; linePos: number } {
const numLines = elem.value.split("\n").length;
const linePos = elem.value.substr(0, elem.selectionStart).split("\n").length;
return { numLines, linePos };
}
@mobx.action.bound
onTextAreaFocused(e: any) {
GlobalModel.inputModel.setAuxViewFocus(true);
GlobalModel.inputModel.setActiveAuxView(appconst.InputAuxView_AIChat);
this.onTextAreaChange(e);
}
@mobx.action.bound
onTextAreaBlur(e: any) {
mobx.action(() => {
GlobalModel.inputModel.setAuxViewFocus(false);
})();
}
@boundMethod
onTextAreaInput(e: any) {
GlobalModel.inputModel.codeSelectDeselectAll();
}
onEnterKeyPressed() {
const inputModel = GlobalModel.inputModel;
const currentRef = this.textAreaRef.current;
if (currentRef == null) {
return;
}
if (inputModel.getCodeSelectSelectedIndex() == -1) {
const messageStr = currentRef.value;
this.submitChatMessage(messageStr);
currentRef.value = "";
} else {
mobx.action(() => {
inputModel.grabCodeSelectSelection();
inputModel.setAuxViewFocus(false);
})();
}
}
onExpandInputPressed() {
const currentRef = this.textAreaRef.current;
if (currentRef == null) {
return;
}
currentRef.setRangeText("\n", currentRef.selectionStart, currentRef.selectionEnd, "end");
GlobalModel.inputModel.codeSelectDeselectAll();
}
onArrowUpPressed(): boolean {
console.log("arrow up pressed==================");
const currentRef = this.textAreaRef.current;
console.log("inputModel.getCodeSelectSelectedIndex()", GlobalModel.inputModel.getCodeSelectSelectedIndex());
if (currentRef == null) {
return false;
}
// if (this.getLinePos(currentRef).linePos > 1) {
// // normal up arrow
// // GlobalModel.inputModel.codeSelectDeselectAll();
// // return false;
// }
GlobalModel.inputModel.codeSelectSelectNextOldestCodeBlock();
return true;
}
onArrowDownPressed(): boolean {
const currentRef = this.textAreaRef.current;
const inputModel = GlobalModel.inputModel;
if (currentRef == null) {
return false;
}
if (inputModel.getCodeSelectSelectedIndex() == inputModel.codeSelectBottom) {
GlobalModel.inputModel.codeSelectDeselectAll();
return false;
}
inputModel.codeSelectSelectNextNewestCodeBlock();
return true;
}
@mobx.action.bound
onKeyDown(e: any) {}
renderError(err: string): any {
return <div className="chat-msg-error">{err}</div>;
}
render() {
const chatMessageItems = GlobalModel.inputModel.AICmdInfoChatItems.slice();
const renderAIChatKeybindings = GlobalModel.inputModel.shouldRenderAuxViewKeybindings(
appconst.InputAuxView_AIChat
);
console.log("renderAIChatKeybindings=====", renderAIChatKeybindings);
console.log("codeSelectBlockRefArray", GlobalModel.inputModel.codeSelectBlockRefArray);
return (
<div className="sidebar-aichat">
<If condition={renderAIChatKeybindings}>
<AIChatKeybindings AIChatObject={this}></AIChatKeybindings>
</If>
<div className="titlebar">
<div className="title-string">Wave AI</div>
</div>
<If condition={chatMessageItems.length > 0}>
<ChatContent chatWindowRef={this.chatWindowRef} />
</If>
<div className="chat-input">
<textarea
key="main"
ref={this.textAreaRef}
autoComplete="off"
autoCorrect="off"
autoFocus={true}
className="chat-cmd-input chat-textarea"
onFocus={this.onTextAreaFocused}
onBlur={this.onTextAreaBlur}
onChange={this.onTextAreaChange}
onInput={this.onTextAreaInput}
onKeyDown={this.onKeyDown}
style={{ fontSize: this.termFontSize }}
placeholder="Send a Message..."
></textarea>
</div>
</div>
);
}
}
export { AIChat };
+44 -50
View File
@@ -13,64 +13,58 @@
font-weight: var(--sidebar-font-weight);
border-left: 1px solid var(--app-border-color);
.sidebar-content {
.header {
height: 39px;
display: flex;
flex-direction: column;
height: 100%;
align-items: center;
justify-content: flex-end;
padding: 0 5px;
border-bottom: 1px solid var(--app-border-color);
}
.rsb-modes {
display: flex;
flex-direction: row;
padding: 5px 10px;
gap: 5px;
border-bottom: 1px solid var(--app-border-color);
.icon-container {
padding: 2px;
cursor: pointer;
}
.icon-container:hover {
background-color: var(--app-selected-mask-color);
}
}
&.collapsed {
display: none;
}
.keybind-debug-pane {
padding: 10px;
overflow: hidden;
width: 100%;
.header {
height: 39px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 5px;
border-bottom: 1px solid var(--app-border-color);
.keybind-pane-title {
font-size: 18px;
font-weight: bold;
padding-bottom: 5px;
}
.rsb-modes {
display: flex;
flex-direction: row;
padding: 5px 10px;
gap: 5px;
.icon-container {
padding: 2px;
cursor: pointer;
}
.icon-container:hover {
background-color: var(--app-selected-mask-color);
}
.keybind-level {
margin-top: 10px;
font-weight: bold;
font-size: 16px;
}
&.collapsed {
display: none;
}
.keybind-debug-pane {
padding: 10px;
.keybind-domain {
font-size: 14px;
margin-left: 20px;
white-space: nowrap;
overflow: hidden;
width: 100%;
.keybind-pane-title {
font-size: 18px;
font-weight: bold;
padding-bottom: 5px;
}
.keybind-level {
margin-top: 10px;
font-weight: bold;
font-size: 16px;
}
.keybind-domain {
font-size: 14px;
margin-left: 20px;
white-space: nowrap;
overflow: hidden;
}
}
}
}
+21 -32
View File
@@ -11,7 +11,6 @@ import localizedFormat from "dayjs/plugin/localizedFormat";
import { GlobalModel } from "@/models";
import { ResizableSidebar, Button } from "@/elements";
import { WaveBookDisplay } from "./wavebook";
import { AIChat } from "./aichat";
import "./right.less";
@@ -78,45 +77,35 @@ class RightSideBar extends React.Component<RightSideBarProps, {}> {
{(toggleCollapse) => (
<React.Fragment>
<div className="header">
<div className="rsb-modes">
<div
className="icon-container"
title="Show Keybinding Debugger"
onClick={() => this.setMode("ai")}
>
<i className="fa-sharp fa-regular fa-sparkles fa-fw" />
</div>
<div className="flex-spacer" />
<If condition={GlobalModel.isDev}>
<div
className="icon-container"
title="Show Keybinding Debugger"
onClick={() => this.setMode("keybind")}
>
<i className="fa-fw fa-sharp fa-keyboard fa-solid" />
</div>
</If>
<div
className="icon-container"
title="Show Keybinding Debugger"
onClick={() => this.setMode("wavebook")}
>
<i className="fa-sharp fa-solid fa-book-sparkles"></i>
</div>
</div>
<Button className="secondary ghost" onClick={toggleCollapse}>
<i className="fa-sharp fa-regular fa-xmark"></i>
</Button>
</div>
{/* <If condition={this.mode.get() == "keybind"}>
<div className="rsb-modes">
<div className="flex-spacer" />
<If condition={GlobalModel.isDev}>
<div
className="icon-container"
title="Show Keybinding Debugger"
onClick={() => this.setMode("keybind")}
>
<i className="fa-fw fa-sharp fa-keyboard fa-solid" />
</div>
</If>
<div
className="icon-container"
title="Show Keybinding Debugger"
onClick={() => this.setMode("wavebook")}
>
<i className="fa-sharp fa-solid fa-book-sparkles"></i>
</div>
</div>
<If condition={this.mode.get() == "keybind"}>
<KeybindDevPane></KeybindDevPane>
</If> */}
</If>
<If condition={this.mode.get() == "wavebook"}>
<WaveBookDisplay></WaveBookDisplay>
</If>
<If condition={this.mode.get() == "ai"}>
<AIChat />
</If>
</React.Fragment>
)}
</ResizableSidebar>
+2 -2
View File
@@ -241,7 +241,6 @@ class AIChat extends React.Component<{}, {}> {
const chatMessageItems = GlobalModel.inputModel.AICmdInfoChatItems.slice();
const chitem: OpenAICmdInfoChatMessageType = null;
const renderKeybindings = GlobalModel.inputModel.shouldRenderAuxViewKeybindings(appconst.InputAuxView_AIChat);
console.log("renderKeybindings", renderKeybindings);
return (
<AuxiliaryCmdView
title="Wave AI"
@@ -264,13 +263,14 @@ class AIChat extends React.Component<{}, {}> {
ref={this.textAreaRef}
autoComplete="off"
autoCorrect="off"
className="chat-cmd-input chat-textarea"
id="chat-cmd-input"
onFocus={this.onTextAreaFocused}
onBlur={this.onTextAreaBlur}
onChange={this.onTextAreaChange}
onInput={this.onTextAreaInput}
onKeyDown={this.onKeyDown}
style={{ fontSize: this.termFontSize }}
className="chat-textarea"
placeholder="Send a Message..."
></textarea>
</div>
+1 -1
View File
@@ -10,7 +10,7 @@ import "./auxview.less";
import { OverlayScrollbarsComponent } from "overlayscrollbars-react";
interface AuxiliaryCmdViewProps {
title?: string;
title: string;
className?: string;
iconClass?: string;
titleBarContents?: React.ReactElement[];
+3 -3
View File
@@ -12,7 +12,7 @@
// Apply a border between the base cmdinput and any views shown above it
// TODO: use a generic selector for this
// &.has-aichat,
&.has-aichat,
&.has-history,
&.has-info,
&.has-suggestions {
@@ -21,8 +21,8 @@
}
}
// &.has-aichat,
&.has-history {
&.has-history,
&.has-aichat {
height: max(300px, 70%);
}
+4 -4
View File
@@ -86,9 +86,9 @@ class CmdInput extends React.Component<{}, {}> {
e.stopPropagation();
const inputModel = GlobalModel.inputModel;
if (inputModel.getActiveAuxView() === appconst.InputAuxView_AIChat) {
// inputModel.closeAuxView();
inputModel.closeAuxView();
} else {
// inputModel.openAIAssistantChat();
inputModel.openAIAssistantChat();
}
}
@@ -191,10 +191,10 @@ class CmdInput extends React.Component<{}, {}> {
<div className="cmd-input-grow-spacer"></div>
<HistoryInfo />
</When>
{/* <When condition={openView === appconst.InputAuxView_AIChat}>
<When condition={openView === appconst.InputAuxView_AIChat}>
<div className="cmd-input-grow-spacer"></div>
<AIChat />
</When> */}
</When>
<When condition={openView === appconst.InputAuxView_Info}>
<InfoMsg key="infomsg" />
</When>
@@ -621,8 +621,6 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: ()
inputModel.shouldRenderAuxViewKeybindings(null) ||
inputModel.shouldRenderAuxViewKeybindings(appconst.InputAuxView_Info);
const renderHistoryKeybindings = inputModel.shouldRenderAuxViewKeybindings(appconst.InputAuxView_History);
console.log("renderCmdInputKeybindings", renderCmdInputKeybindings);
console.log("renderHistoryKeybindings", renderHistoryKeybindings);
return (
<div
className="textareainput-div control is-expanded"
+160
View File
@@ -0,0 +1,160 @@
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { clsx } from "clsx";
import { If } from "tsx-control-statements/components";
import { GlobalModel } from "@/models";
import { isBlank } from "@/util/util";
import { WorkspaceView } from "@/app/workspace/workspaceview";
import { PluginsView } from "@/app/pluginsview/pluginsview";
import { BookmarksView } from "@/app/bookmarks/bookmarks";
import { HistoryView } from "@/app/history/history";
import { ConnectionsView } from "@/app/connections/connections";
import { ClientSettingsView } from "@/app/clientsettings/clientsettings";
import { MainSideBar } from "@/app/sidebar/main";
import { RightSideBar } from "@/app/sidebar/right";
import { DisconnectedModal, ClientStopModal } from "@/modals";
import { ModalsProvider } from "@/modals/provider";
import { Button, TermStyleList } from "@/elements";
import { ErrorBoundary } from "@/common/error/errorboundary";
import "@/app/app.less";
export const App2: React.FC = mobxReact.observer(() => {
const [dcWait, setDcWait] = React.useState(false);
const mainContentRef = React.useRef<HTMLDivElement>(null);
const [termThemesLoaded, setTermThemesLoaded] = React.useState(false);
const handleContextMenu = (e: React.MouseEvent<HTMLElement>) => {
let isInNonTermInput = false;
const activeElem = document.activeElement;
if (activeElem != null && activeElem.nodeName == "TEXTAREA") {
if (!activeElem.classList.contains("xterm-helper-textarea")) {
isInNonTermInput = true;
}
}
if (activeElem != null && activeElem.nodeName == "INPUT" && activeElem.getAttribute("type") == "text") {
isInNonTermInput = true;
}
const opts: ContextMenuOpts = {};
if (isInNonTermInput) {
opts.showCut = true;
}
const sel = window.getSelection();
if (!isBlank(sel?.toString()) || isInNonTermInput) {
GlobalModel.contextEditMenu(e, opts);
}
};
const openMainSidebar = mobx.action(() => {
const mainSidebarModel = GlobalModel.mainSidebarModel;
const width = mainSidebarModel.getWidth(true);
mainSidebarModel.saveState(width, false);
});
const openRightSidebar = mobx.action(() => {
const rightSidebarModel = GlobalModel.rightSidebarModel;
const width = rightSidebarModel.getWidth(true);
rightSidebarModel.saveState(width, false);
});
const remotesModel = GlobalModel.remotesModel;
const disconnected = !GlobalModel.ws.open.get() || !GlobalModel.waveSrvRunning.get();
const hasClientStop = GlobalModel.getHasClientStop();
const platform = GlobalModel.getPlatform();
const clientData = GlobalModel.clientData.get();
// Previously, this is done in sidebar.tsx but it causes flicker when clientData is null cos screen-view shifts around.
// Doing it here fixes the flicker cos app is not rendered until clientData is populated.
// wait for termThemes as well (this actually means that the "connect" packet has been received)
if (clientData == null || GlobalModel.termThemes.get() == null) {
return null;
}
if (disconnected || hasClientStop) {
if (!dcWait) {
setTimeout(() => setDcWait(true), 1500);
}
return (
<div id="main" className={"platform-" + platform} onContextMenu={handleContextMenu}>
<div ref={mainContentRef} className="main-content">
<MainSideBar parentRef={mainContentRef} />
<div className="session-view" />
</div>
<If condition={dcWait}>
<If condition={disconnected}>
<DisconnectedModal />
</If>
<If condition={!disconnected && hasClientStop}>
<ClientStopModal />
</If>
</If>
</div>
);
}
if (dcWait) {
setTimeout(() => setDcWait(false), 0);
}
// used to force a full reload of the application
const renderVersion = GlobalModel.renderVersion.get();
const mainSidebarCollapsed = GlobalModel.mainSidebarModel.getCollapsed();
const rightSidebarCollapsed = GlobalModel.rightSidebarModel.getCollapsed();
const activeMainView = GlobalModel.activeMainView.get();
const lightDarkClass = GlobalModel.isDarkTheme.get() ? "is-dark" : "is-light";
const mainClassName = clsx(
"platform-" + platform,
{
"mainsidebar-collapsed": mainSidebarCollapsed,
"rightsidebar-collapsed": rightSidebarCollapsed,
},
lightDarkClass
);
return (
<>
<TermStyleList onRendered={() => setTermThemesLoaded(true)} />
<div
key={`version- + ${renderVersion}`}
id="main"
className={mainClassName}
onContextMenu={handleContextMenu}
>
<If condition={termThemesLoaded}>
<If condition={mainSidebarCollapsed}>
<div key="logo-button" className="logo-button-container">
<div className="logo-button-spacer" />
<div className="logo-button" onClick={openMainSidebar}>
<img src="public/logos/wave-logo.png" alt="logo" />
</div>
</div>
</If>
<If condition={GlobalModel.isDev && rightSidebarCollapsed && activeMainView == "session"}>
<div className="right-sidebar-triggers">
<Button className="secondary ghost right-sidebar-trigger" onClick={openRightSidebar}>
<i className="fa-sharp fa-solid fa-sidebar-flip"></i>
</Button>
</div>
</If>
<div ref={mainContentRef} className="main-content">
<MainSideBar parentRef={mainContentRef} />
<ErrorBoundary>
<PluginsView />
<WorkspaceView />
<HistoryView />
<BookmarksView />
<ConnectionsView model={remotesModel} />
<ClientSettingsView model={remotesModel} />
</ErrorBoundary>
<RightSideBar parentRef={mainContentRef} />
</div>
<ModalsProvider />
</If>
</div>
</>
);
});
+5
View File
@@ -520,6 +520,10 @@ electron.ipcMain.on("get-id", (event) => {
event.returnValue = instanceId + ":" + event.processId;
});
electron.ipcMain.on("get-window-id", (event) => {
event.returnValue = event.sender.id;
});
electron.ipcMain.on("get-platform", (event) => {
event.returnValue = unamePlatform;
});
@@ -985,6 +989,7 @@ function configureAutoUpdater(enabled: boolean) {
setTimeout(runActiveTimer, 5000); // start active timer, wait 5s just to be safe
await app.whenReady();
await createWindowWrap();
await createWindowWrap();
app.on("activate", () => {
if (electron.BrowserWindow.getAllWindows().length === 0) {
+1
View File
@@ -4,6 +4,7 @@ contextBridge.exposeInMainWorld("api", {
hideWindow: () => ipc.Renderer.send("hide-window"),
toggleDeveloperTools: () => ipcRenderer.send("toggle-developer-tools"),
getId: () => ipcRenderer.sendSync("get-id"),
getWindowId: () => ipcRenderer.sendSync("get-window-id"),
getPlatform: () => ipcRenderer.sendSync("get-platform"),
getIsDev: () => ipcRenderer.sendSync("get-isdev"),
getAuthKey: () => ipcRenderer.sendSync("get-authkey"),
+8 -1
View File
@@ -6,9 +6,11 @@ import * as React from "react";
import { createRoot } from "react-dom/client";
import { sprintf } from "sprintf-js";
import { App } from "@/app/app";
import { App2 } from "@/app2/app";
import * as DOMPurify from "dompurify";
import { loadFonts } from "@/util/fontutil";
import * as textmeasure from "@/util/textmeasure";
import { getApi } from "./models";
// @ts-ignore
let VERSION = __WAVETERM_VERSION__;
@@ -18,7 +20,12 @@ let BUILD = __WAVETERM_BUILD__;
loadFonts();
document.addEventListener("DOMContentLoaded", () => {
let reactElem = React.createElement(App, null, null);
let reactElem;
if (getApi().getWindowId() === 1) {
reactElem = React.createElement(App, null, null);
} else {
reactElem = React.createElement(App2, null, null);
}
let elem = document.getElementById("app");
let root = createRoot(elem);
document.fonts.ready.then(() => {
-188
View File
@@ -1,188 +0,0 @@
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import type React from "react";
import * as mobx from "mobx";
import { Model } from "./model";
class AIChatModel {
globalModel: Model;
chatTextAreaRef: React.RefObject<HTMLTextAreaElement>;
chatWindowRef: React.RefObject<HTMLDivElement>;
codeSelectBlockRefArray: Array<React.RefObject<HTMLElement>>;
codeSelectSelectedIndex: OV<number> = mobx.observable.box(-1);
codeSelectUuid: string;
aiCmdInfoChatItems: mobx.IObservableArray<OpenAICmdInfoChatMessageType> = mobx.observable.array([], {
name: "aicmdinfo-chat",
});
isFocused: OV<boolean> = mobx.observable.box(false, {
name: "isFocused",
});
readonly codeSelectTop: number = -2;
readonly codeSelectBottom: number = -1;
constructor(globalModel: Model) {
this.globalModel = globalModel;
mobx.makeObservable(this);
mobx.action(() => {
this.codeSelectSelectedIndex.set(-1);
this.codeSelectBlockRefArray = [];
})();
this.codeSelectUuid = "";
}
@mobx.action
focus(): void {
if (this.chatTextAreaRef?.current != null) {
this.chatTextAreaRef.current.focus();
}
this.isFocused.set(true);
}
@mobx.action
unFocus() {
if (this.chatTextAreaRef?.current != null) {
this.chatTextAreaRef.current.blur();
}
this.isFocused.set(false);
}
@mobx.action
setOpenAICmdInfoChat(chat: OpenAICmdInfoChatMessageType[]): void {
this.aiCmdInfoChatItems.replace(chat);
this.codeSelectBlockRefArray = [];
}
close(): void {
// close and give focus back to main input
}
shouldRenderKeybindings(view: InputAuxViewType): boolean {
// when aichat sidebar is mounted, it will render the keybindings
return true;
}
setRefs(textAreaRef: React.RefObject<HTMLTextAreaElement>, chatWindowRef: React.RefObject<HTMLDivElement>) {
this.chatTextAreaRef = textAreaRef;
this.chatWindowRef = chatWindowRef;
}
unsetRefs() {
this.chatTextAreaRef = null;
this.chatWindowRef = null;
}
addCodeBlockToCodeSelect(blockRef: React.RefObject<HTMLElement>, uuid: string): number {
let rtn = -1;
if (uuid != this.codeSelectUuid) {
this.codeSelectUuid = uuid;
this.codeSelectBlockRefArray = [];
}
rtn = this.codeSelectBlockRefArray.length;
this.codeSelectBlockRefArray.push(blockRef);
return rtn;
}
@mobx.action
setCodeSelectSelectedCodeBlock(blockIndex: number) {
if (blockIndex >= 0 && blockIndex < this.codeSelectBlockRefArray.length) {
this.codeSelectSelectedIndex.set(blockIndex);
const currentRef = this.codeSelectBlockRefArray[blockIndex].current;
if (currentRef != null && this.chatWindowRef?.current != null) {
const chatWindowTop = this.chatWindowRef.current.scrollTop;
const chatWindowBottom = chatWindowTop + this.chatWindowRef.current.clientHeight - 100;
const elemTop = currentRef.offsetTop;
let elemBottom = elemTop - currentRef.offsetHeight;
const elementIsInView = elemBottom < chatWindowBottom && elemTop > chatWindowTop;
if (!elementIsInView) {
this.chatWindowRef.current.scrollTop = elemBottom - this.chatWindowRef.current.clientHeight / 3;
}
}
}
this.codeSelectBlockRefArray = [];
}
@mobx.action
codeSelectSelectNextNewestCodeBlock() {
// oldest code block = index 0 in array
// this decrements codeSelectSelected index
if (this.codeSelectSelectedIndex.get() == this.codeSelectTop) {
this.codeSelectSelectedIndex.set(this.codeSelectBottom);
} else if (this.codeSelectSelectedIndex.get() == this.codeSelectBottom) {
return;
}
const incBlockIndex = this.codeSelectSelectedIndex.get() + 1;
if (this.codeSelectSelectedIndex.get() == this.codeSelectBlockRefArray.length - 1) {
this.codeSelectDeselectAll();
if (this.chatWindowRef?.current != null) {
this.chatWindowRef.current.scrollTop = this.chatWindowRef.current.scrollHeight;
}
}
if (incBlockIndex >= 0 && incBlockIndex < this.codeSelectBlockRefArray.length) {
this.setCodeSelectSelectedCodeBlock(incBlockIndex);
}
}
@mobx.action
codeSelectSelectNextOldestCodeBlock() {
if (this.codeSelectSelectedIndex.get() == this.codeSelectBottom) {
if (this.codeSelectBlockRefArray.length > 0) {
this.codeSelectSelectedIndex.set(this.codeSelectBlockRefArray.length);
} else {
return;
}
} else if (this.codeSelectSelectedIndex.get() == this.codeSelectTop) {
return;
}
const decBlockIndex = this.codeSelectSelectedIndex.get() - 1;
if (decBlockIndex < 0) {
this.codeSelectDeselectAll(this.codeSelectTop);
if (this.chatWindowRef?.current != null) {
this.chatWindowRef.current.scrollTop = 0;
}
}
if (decBlockIndex >= 0 && decBlockIndex < this.codeSelectBlockRefArray.length) {
this.setCodeSelectSelectedCodeBlock(decBlockIndex);
}
}
getCodeSelectSelectedIndex() {
return this.codeSelectSelectedIndex.get();
}
getCodeSelectRefArrayLength() {
return this.codeSelectBlockRefArray.length;
}
codeBlockIsSelected(blockIndex: number): boolean {
return blockIndex == this.codeSelectSelectedIndex.get();
}
codeSelectDeselectAll(direction: number = this.codeSelectBottom) {
if (this.codeSelectSelectedIndex.get() == direction) {
return;
}
mobx.action(() => {
this.codeSelectSelectedIndex.set(direction);
this.codeSelectBlockRefArray = [];
})();
}
@mobx.action
openAIAssistantChat(): void {
// open aichat sidebar
}
clearAIAssistantChat(): void {
const prtn = this.globalModel.submitChatInfoCommand("", "", true);
prtn.then((rtn) => {
if (!rtn.success) {
console.log("submit chat command error: " + rtn.error);
}
}).catch((error) => {
console.log("submit chat command error: ", error);
});
}
}
export { AIChatModel };
-1
View File
@@ -6,7 +6,6 @@ export { ClientSettingsViewModel } from "./clientsettingsview";
export { Cmd } from "./cmd";
export { ConnectionsViewModel } from "./connectionsview";
export { InputModel } from "./input";
export { AIChatModel } from "./aichat";
export { MainSidebarModel } from "./mainsidebar";
export { RightSidebarModel } from "./rightsidebar";
export { ModalsModel } from "./modals";
+36 -116
View File
@@ -7,8 +7,6 @@ import { isBlank } from "@/util/util";
import * as appconst from "@/app/appconst";
import type { Model } from "./model";
import { GlobalCommandRunner, GlobalModel } from "./global";
import type { OverlayScrollbars } from "overlayscrollbars";
import { boundMethod } from "autobind-decorator";
function getDefaultHistoryQueryOpts(): HistoryQueryOpts {
return {
@@ -30,17 +28,17 @@ class InputModel {
cmdInputHeight: OV<number> = mobx.observable.box(0);
aiChatTextAreaRef: React.RefObject<HTMLTextAreaElement>;
aiChatWindowRef: React.RefObject<HTMLDivElement>;
chatOsInstance: OverlayScrollbars;
codeSelectBlockRefArray: Array<React.RefObject<HTMLElement>>;
codeSelectSelectedIndex: OV<number> = mobx.observable.box(null, {
name: "codeSelectSelectedIndex",
});
codeSelectSelectedIndex: OV<number> = mobx.observable.box(-1);
codeSelectUuid: string;
inputPopUpType: OV<string> = mobx.observable.box("none");
AICmdInfoChatItems: mobx.IObservableArray<OpenAICmdInfoChatMessageType> = mobx.observable.array([], {
name: "aicmdinfo-chat",
});
readonly codeSelectTop: number = -2;
readonly codeSelectBottom: number = -1;
historyType: mobx.IObservableValue<HistoryTypeStrs> = mobx.observable.box("screen");
historyLoading: mobx.IObservableValue<boolean> = mobx.observable.box(false);
historyAfterLoadIndex: number = 0;
@@ -141,7 +139,6 @@ class InputModel {
giveFocus(): void {
// Override active view to the main input if aux view does not have focus
const activeAuxView = this.getAuxViewFocus() ? this.getActiveAuxView() : null;
console.log("activeAuxView", activeAuxView);
switch (activeAuxView) {
case appconst.InputAuxView_History: {
const elem: HTMLElement = document.querySelector(".cmd-input input.history-input");
@@ -193,7 +190,7 @@ class InputModel {
if (document.activeElement == historyInputElem) {
return true;
}
let aiChatInputElem = document.querySelector(".cmd-input .chat-cmd-input");
let aiChatInputElem = document.querySelector(".cmd-input chat-cmd-input");
if (document.activeElement == aiChatInputElem) {
return true;
}
@@ -463,21 +460,16 @@ class InputModel {
}
shouldRenderAuxViewKeybindings(view: InputAuxViewType): boolean {
console.log("view", view, this.getAuxViewFocus(), this.getActiveAuxView());
if (GlobalModel.activeMainView.get() != "session") {
console.log("1");
return false;
}
if (GlobalModel.getActiveScreen()?.getFocusType() != "input") {
console.log("2");
return false;
}
// (view == null) means standard cmdinput keybindings
if (view == null) {
console.log("3");
return !this.getAuxViewFocus();
} else {
console.log("4");
return this.getAuxViewFocus() && view == this.getActiveAuxView();
}
}
@@ -549,11 +541,6 @@ class InputModel {
this.aiChatWindowRef = chatWindowRef;
}
setChatOsInstance(osInstance: OverlayScrollbars) {
console.log("triggered***********");
this.chatOsInstance = osInstance;
}
setAIChatFocus() {
if (this.aiChatTextAreaRef?.current != null) {
this.aiChatTextAreaRef.current.focus();
@@ -572,15 +559,12 @@ class InputModel {
}
}
@mobx.action
addCodeBlockToCodeSelect(blockRef: React.RefObject<HTMLElement>, uuid: string): number {
let rtn = -1;
// Why is codeSelectBlockRefArray being reset here? This causes a bug where multiple code blocks are highlighted
// because multiple code blocks have the same index.
// if (uuid != this.codeSelectUuid) {
// this.codeSelectUuid = uuid;
// this.codeSelectBlockRefArray = [];
// }
if (uuid != this.codeSelectUuid) {
this.codeSelectUuid = uuid;
this.codeSelectBlockRefArray = [];
}
rtn = this.codeSelectBlockRefArray.length;
this.codeSelectBlockRefArray.push(blockRef);
return rtn;
@@ -588,37 +572,17 @@ class InputModel {
@mobx.action
setCodeSelectSelectedCodeBlock(blockIndex: number) {
// const { viewport, scrollOffsetElement } = this.chatOsInstance.elements();
// const { scrollTop } = scrollOffsetElement;
// console.log("setCodeSelectSelectedCodeBlock", scrollTop);
// console.log("clientHeight", this.aiChatWindowRef.current.clientHeight);
if (blockIndex >= 0 && blockIndex < this.codeSelectBlockRefArray.length) {
this.codeSelectSelectedIndex.set(blockIndex);
const currentRef = this.codeSelectBlockRefArray[blockIndex].current;
if (currentRef != null && this.aiChatWindowRef?.current != null) {
// const chatWindowTop = this.aiChatWindowRef.current.scrollTop;
const { viewport, scrollOffsetElement } = this.chatOsInstance.elements();
const chatWindowTop = scrollOffsetElement.scrollTop;
console.log("chatWindowTop", chatWindowTop);
const chatWindowTop = this.aiChatWindowRef.current.scrollTop;
const chatWindowBottom = chatWindowTop + this.aiChatWindowRef.current.clientHeight - 100;
console.log("chatWindowTop", chatWindowTop);
console.log("this.aiChatWindowRef.current.clientHeight", this.aiChatWindowRef.current.clientHeight);
const elemTop = currentRef.offsetTop;
let elemBottom = elemTop - currentRef.offsetHeight;
const elementIsInView = elemBottom < chatWindowBottom && elemTop > chatWindowTop;
if (!elementIsInView) {
console.log("elemBottom", elemBottom);
console.log(
"this.aiChatWindowRef.current.clientHeight",
this.aiChatWindowRef.current.clientHeight,
this.aiChatWindowRef.current.clientHeight / 2
);
// this.aiChatWindowRef.current.scrollTop = elemBottom - this.aiChatWindowRef.current.clientHeight / 3;
viewport.scrollTo({
behavior: "auto",
top: elemTop - 20,
});
this.aiChatWindowRef.current.scrollTop = elemBottom - this.aiChatWindowRef.current.clientHeight / 3;
}
}
}
@@ -627,58 +591,22 @@ class InputModel {
this.setAuxViewFocus(true);
}
// @mobx.action
// setCodeSelectSelectedCodeBlock(blockIndex: number) {
// const { viewport, scrollOffsetElement } = this.chatOsInstance.elements();
// const { scrollTop } = scrollOffsetElement;
// console.log("setCodeSelectSelectedCodeBlock", scrollTop);
// console.log("clientHeight", this.aiChatWindowRef.current.clientHeight);
// if (blockIndex >= 0 && blockIndex < this.codeSelectBlockRefArray.length) {
// this.codeSelectSelectedIndex.set(blockIndex);
// const currentRef = this.codeSelectBlockRefArray[blockIndex].current;
// if (currentRef != null && this.aiChatWindowRef?.current != null) {
// const chatWindowTop = scrollTop;
// const chatWindowBottom = chatWindowTop + this.aiChatWindowRef.current.clientHeight - 100;
// const elemTop = currentRef.offsetTop;
// let elemBottom = elemTop - currentRef.offsetHeight;
// const elementIsInView = elemBottom < chatWindowBottom && elemTop > chatWindowTop;
// if (!elementIsInView) {
// console.log(
// "elemBottom - this.aiChatWindowRef.current.clientHeight / 3",
// elemBottom - this.aiChatWindowRef.current.clientHeight / 3
// );
// viewport.scrollTo({
// behavior: "auto",
// top: elemBottom - this.aiChatWindowRef.current.clientHeight / 3,
// });
// // this.aiChatWindowRef.current.scrollTop = elemBottom - this.aiChatWindowRef.current.clientHeight / 3;
// }
// }
// }
// this.codeSelectBlockRefArray = [];
// this.setActiveAuxView(appconst.InputAuxView_AIChat);
// this.setAuxViewFocus(true);
// }
@mobx.action
codeSelectSelectNextNewestCodeBlock() {
// oldest code block = index 0 in array
// this decrements codeSelectSelected index
// if (this.codeSelectSelectedIndex.get() == this.codeSelectTop) {
// this.codeSelectSelectedIndex.set(this.codeSelectBottom);
// } else if (this.codeSelectSelectedIndex.get() == this.codeSelectBottom) {
// return;
// }
if (this.codeSelectSelectedIndex.get() == this.codeSelectTop) {
this.codeSelectSelectedIndex.set(this.codeSelectBottom);
} else if (this.codeSelectSelectedIndex.get() == this.codeSelectBottom) {
return;
}
const incBlockIndex = this.codeSelectSelectedIndex.get() + 1;
// if (this.codeSelectSelectedIndex.get() == this.codeSelectBlockRefArray.length - 1) {
// // this.codeSelectDeselectAll();
// // if (this.aiChatWindowRef?.current != null) {
// // this.aiChatWindowRef.current.scrollTop = this.aiChatWindowRef.current.scrollHeight;
// // }
// }
// console.log("incBlockIndex", incBlockIndex);
// console.log("this.codeSelectBlockRefArray.length", this.codeSelectBlockRefArray.length);
if (this.codeSelectSelectedIndex.get() == this.codeSelectBlockRefArray.length - 1) {
this.codeSelectDeselectAll();
if (this.aiChatWindowRef?.current != null) {
this.aiChatWindowRef.current.scrollTop = this.aiChatWindowRef.current.scrollHeight;
}
}
if (incBlockIndex >= 0 && incBlockIndex < this.codeSelectBlockRefArray.length) {
this.setCodeSelectSelectedCodeBlock(incBlockIndex);
}
@@ -686,29 +614,23 @@ class InputModel {
@mobx.action
codeSelectSelectNextOldestCodeBlock() {
if (this.codeSelectSelectedIndex.get() == null && this.codeSelectBlockRefArray.length > 0) {
console.log("triggered====== 1");
// if (this.codeSelectBlockRefArray.length > 0) {
// this.codeSelectSelectedIndex.set(this.codeSelectBlockRefArray.length - 1);
// }
this.setCodeSelectSelectedCodeBlock(this.codeSelectBlockRefArray.length - 1);
if (this.codeSelectSelectedIndex.get() == this.codeSelectBottom) {
if (this.codeSelectBlockRefArray.length > 0) {
this.codeSelectSelectedIndex.set(this.codeSelectBlockRefArray.length);
} else {
return;
}
} else if (this.codeSelectSelectedIndex.get() == this.codeSelectTop) {
return;
// } else if (this.codeSelectSelectedIndex.get() == this.codeSelectTop) {
// console.log("triggered====== 2");
// return;
}
const decBlockIndex = this.codeSelectSelectedIndex.get() - 1;
// if (decBlockIndex < 0) {
// console.log("triggered====== 3");
// this.codeSelectDeselectAll(this.codeSelectTop);
// if (this.aiChatWindowRef?.current != null) {
// this.aiChatWindowRef.current.scrollTop = 0;
// }
// }
if (decBlockIndex < 0) {
this.codeSelectDeselectAll(this.codeSelectTop);
if (this.aiChatWindowRef?.current != null) {
this.aiChatWindowRef.current.scrollTop = 0;
}
}
if (decBlockIndex >= 0 && decBlockIndex < this.codeSelectBlockRefArray.length) {
console.log("triggered====== 4");
this.setCodeSelectSelectedCodeBlock(decBlockIndex);
}
}
@@ -725,7 +647,7 @@ class InputModel {
return blockIndex == this.codeSelectSelectedIndex.get();
}
codeSelectDeselectAll(direction: number) {
codeSelectDeselectAll(direction: number = this.codeSelectBottom) {
if (this.codeSelectSelectedIndex.get() == direction) {
return;
}
@@ -737,7 +659,6 @@ class InputModel {
@mobx.action
openAIAssistantChat(): void {
console.log("openAIAssistantChat");
this.setActiveAuxView(appconst.InputAuxView_AIChat);
this.setAuxViewFocus(true);
this.globalModel.sendActivity("aichat-open");
@@ -854,7 +775,6 @@ class InputModel {
}
set curLine(val: string) {
console.log("triggered set curLine");
this.lastCurLine = this.curLine;
const hidx = this.historyIndex.get();
mobx.action(() => {

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