mirror of
https://github.com/wavetermdev/backup.git
synced 2026-04-22 15:26:58 -07:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7d9f429ee1 | |||
| bcf6e91f48 | |||
| 4758b7351d | |||
| c6207970ee | |||
| de271d3873 | |||
| 8aaea9f1c8 | |||
| c93b6e3d34 | |||
| 8a22e73e60 | |||
| 35a5f1645d | |||
| 34837aabae | |||
| 918ff98ea1 | |||
| cc61b16cec | |||
| 4f06cd8095 | |||
| fbc7bc9688 | |||
| 67df71d1ca | |||
| d177fab6e3 | |||
| 8ea22c4c1f | |||
| af32c8f6f3 | |||
| f2e31a6483 | |||
| 8b8b7ea2b6 | |||
| dbc91d8a4e | |||
| de81464082 | |||
| 5e6cbf30e7 | |||
| 75ae8807eb | |||
| 84227a7128 | |||
| 498f91d7fe | |||
| 4d05ef9998 | |||
| 1eb7ff512e | |||
| ba5a089382 | |||
| e40f93b858 | |||
| 30b9453bcd | |||
| 2a79057314 | |||
| 268bfabec2 | |||
| 30d1e4dfad | |||
| c522d55a23 |
@@ -22,8 +22,8 @@ jobs:
|
||||
- uses: dashcamio/testdriver@main
|
||||
id: testdriver
|
||||
with:
|
||||
version: v2.12.12
|
||||
prerun: |
|
||||
version: v2.12.5
|
||||
prerun: |
|
||||
rm ~/Desktop/WITH-LOVE-FROM-AMERICA.txt
|
||||
cd ~/actions-runner/_work/testdriver/testdriver/
|
||||
brew install go
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
scripthaus run electron 1>/dev/null 2>&1 &
|
||||
echo "Electron Done"
|
||||
exit
|
||||
prompt: |
|
||||
prompt: |
|
||||
1. wait 10 seconds
|
||||
1. click "Get Started"
|
||||
1. validate that overlapping text does not appear in the application
|
||||
|
||||
@@ -285,6 +285,10 @@
|
||||
"keys": ["Ctrl:r"],
|
||||
"commandStr": ["/history"]
|
||||
},
|
||||
{
|
||||
"command": "cmdinput:openAIChat",
|
||||
"keys": ["Ctrl:Space"]
|
||||
},
|
||||
{
|
||||
"command": "history:closeHistory",
|
||||
"keys": ["Ctrl:g", "Ctrl:c"]
|
||||
@@ -328,9 +332,5 @@
|
||||
{
|
||||
"command": "codeedit:togglePreview",
|
||||
"keys": ["Cmd:p"]
|
||||
},
|
||||
{
|
||||
"command": "rightsidebar:toggle",
|
||||
"keys": ["Cmd:Shift:Space"]
|
||||
}
|
||||
]
|
||||
+3
-6
@@ -6,7 +6,7 @@
|
||||
},
|
||||
"productName": "Wave",
|
||||
"description": "An Open-Source, AI-Native, Terminal Built for Seamless Workflows",
|
||||
"version": "0.7.6",
|
||||
"version": "0.7.5",
|
||||
"main": "dist/emain.js",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
@@ -24,7 +24,6 @@
|
||||
"@table-nav/react": "^0.0.7",
|
||||
"@tanstack/match-sorter-utils": "^8.8.4",
|
||||
"@tanstack/react-table": "^8.10.3",
|
||||
"@withfig/autocomplete": "^2.652.3",
|
||||
"autobind-decorator": "^2.4.0",
|
||||
"base64-js": "^1.5.1",
|
||||
"clsx": "^2.1.1",
|
||||
@@ -39,7 +38,7 @@
|
||||
"monaco-editor": "0.48.0",
|
||||
"mustache": "^4.2.0",
|
||||
"node-fetch": "^3.2.10",
|
||||
"overlayscrollbars": "^2.6.1",
|
||||
"overlayscrollbars": "^2.7.3",
|
||||
"overlayscrollbars-react": "^0.5.5",
|
||||
"papaparse": "^5.4.1",
|
||||
"react": "^18.1.0",
|
||||
@@ -79,15 +78,13 @@
|
||||
"@types/semver": "^7.5.6",
|
||||
"@types/sprintf-js": "^1.1.3",
|
||||
"@types/throttle-debounce": "^5.0.1",
|
||||
"@types/tinycolor2": "^1",
|
||||
"@types/uuid": "^9.0.7",
|
||||
"@types/webpack-env": "^1.18.3",
|
||||
"@withfig/autocomplete-types": "^1.30.0",
|
||||
"babel-loader": "^9.1.3",
|
||||
"babel-plugin-jsx-control-statements": "^4.1.2",
|
||||
"copy-webpack-plugin": "^12.0.0",
|
||||
"css-loader": "^7.1.0",
|
||||
"electron": "^30.0.8",
|
||||
"electron": "^30.0.1",
|
||||
"electron-builder": "^24.13.3",
|
||||
"electron-builder-squirrel-windows": "^24.13.3",
|
||||
"file-loader": "^6.2.0",
|
||||
|
||||
@@ -170,7 +170,6 @@
|
||||
--cmdinput-button-bg-color: var(--tab-green);
|
||||
--cmdinput-disabled-bg-color: var(--app-text-bg-disabled-color);
|
||||
--cmdinput-history-bg-color: var(--app-bg-color);
|
||||
--cmdinput-ghost-text-color: rgb(145, 150, 144);
|
||||
|
||||
/* screen view color */
|
||||
--screen-view-text-caption-color: rgb(139, 145, 138);
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
--modal-header-bottom-border-color: rgba(0, 0, 0, 0.3);
|
||||
|
||||
/* cmd input */
|
||||
--cmdinput-ghost-text-color: rgb(116, 116, 116);
|
||||
|
||||
/* scroll colors */
|
||||
--scrollbar-background-color: var(--app-bg-color);
|
||||
|
||||
+9
-16
@@ -31,20 +31,12 @@ class App extends React.Component<{}, {}> {
|
||||
dcWait: OV<boolean> = mobx.observable.box(false, { name: "dcWait" });
|
||||
mainContentRef: React.RefObject<HTMLDivElement> = React.createRef();
|
||||
termThemesLoaded: OV<boolean> = mobx.observable.box(false, { name: "termThemesLoaded" });
|
||||
chatFocusTimeoutId: NodeJS.Timeout = null;
|
||||
|
||||
constructor(props: {}) {
|
||||
super(props);
|
||||
if (GlobalModel.isDev) document.body.classList.add("is-dev");
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.chatFocusTimeoutId) {
|
||||
clearTimeout(this.chatFocusTimeoutId);
|
||||
this.chatFocusTimeoutId = null;
|
||||
}
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleContextMenu(e: any) {
|
||||
let isInNonTermInput = false;
|
||||
@@ -76,15 +68,16 @@ class App extends React.Component<{}, {}> {
|
||||
|
||||
@boundMethod
|
||||
openMainSidebar() {
|
||||
GlobalModel.mainSidebarModel.setCollapsed(false);
|
||||
const mainSidebarModel = GlobalModel.mainSidebarModel;
|
||||
const width = mainSidebarModel.getWidth(true);
|
||||
mainSidebarModel.saveState(width, false);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
openRightSidebar() {
|
||||
GlobalModel.rightSidebarModel.setCollapsed(false);
|
||||
this.chatFocusTimeoutId = setTimeout(() => {
|
||||
GlobalModel.inputModel.setChatSidebarFocus();
|
||||
}, 100);
|
||||
const rightSidebarModel = GlobalModel.rightSidebarModel;
|
||||
const width = rightSidebarModel.getWidth(true);
|
||||
rightSidebarModel.saveState(width, false);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
@@ -166,13 +159,13 @@ class App extends React.Component<{}, {}> {
|
||||
</div>
|
||||
</div>
|
||||
</If>
|
||||
<If condition={rightSidebarCollapsed && activeMainView == "session"}>
|
||||
<div className="right-sidebar-triggers" title="Open Wave AI (Cmd-Shift-Space)">
|
||||
<If condition={GlobalModel.isDev && rightSidebarCollapsed && activeMainView == "session"}>
|
||||
<div className="right-sidebar-triggers">
|
||||
<Button
|
||||
className="secondary ghost right-sidebar-trigger"
|
||||
onClick={this.openRightSidebar}
|
||||
>
|
||||
<i className="fa-sharp fa-regular fa-sparkles"></i>
|
||||
<i className="fa-sharp fa-solid fa-sidebar-flip"></i>
|
||||
</Button>
|
||||
</div>
|
||||
</If>
|
||||
|
||||
@@ -72,4 +72,3 @@ export const ErrorCode_InvalidCwd = "ERRCWD";
|
||||
export const InputAuxView_History = "history";
|
||||
export const InputAuxView_Info = "info";
|
||||
export const InputAuxView_AIChat = "aichat";
|
||||
export const InputAuxView_Suggestions = "suggestions";
|
||||
|
||||
@@ -11,10 +11,10 @@ import { Toggle, InlineSettingsTextEdit, SettingsError, Dropdown } from "@/commo
|
||||
import { commandRtnHandler, isBlank } from "@/util/util";
|
||||
import { getTermThemes } from "@/util/themeutil";
|
||||
import * as appconst from "@/app/appconst";
|
||||
import { MainView } from "@/common/elements/mainview";
|
||||
import { OverlayScrollbarsComponent } from "overlayscrollbars-react";
|
||||
|
||||
import "./clientsettings.less";
|
||||
import { MainView } from "../common/elements/mainview";
|
||||
import { OverlayScrollbarsComponent } from "overlayscrollbars-react";
|
||||
|
||||
class ClientSettingsKeybindings extends React.Component<{}, {}> {
|
||||
componentDidMount() {
|
||||
@@ -110,19 +110,6 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
||||
GlobalModel.getElectronApi().changeAutoUpdate(val);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleChangeAutocompleteEnabled(val: boolean): void {
|
||||
const prtn: Promise<CommandRtnType> = GlobalCommandRunner.setAutocompleteEnabled(val);
|
||||
commandRtnHandler(prtn, this.errorMessage);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleChangeAutocompleteDebuggingEnabled(val: boolean): void {
|
||||
mobx.action(() => {
|
||||
GlobalModel.autocompleteModel.loggingEnabled = val;
|
||||
})();
|
||||
}
|
||||
|
||||
getFontSizes(): DropdownItem[] {
|
||||
const availableFontSizes: DropdownItem[] = [];
|
||||
for (let s = appconst.MinFontSize; s <= appconst.MaxFontSize; s++) {
|
||||
@@ -460,24 +447,6 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">Command Autocomplete</div>
|
||||
<div className="settings-input">
|
||||
<Toggle
|
||||
checked={cdata.clientopts.autocompleteenabled ?? false}
|
||||
onChange={this.handleChangeAutocompleteEnabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">Command Autocomplete Debugging</div>
|
||||
<div className="settings-input">
|
||||
<Toggle
|
||||
checked={GlobalModel.autocompleteModel.loggingEnabled}
|
||||
onChange={this.handleChangeAutocompleteDebuggingEnabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<SettingsError errorMessage={this.errorMessage} />
|
||||
</div>
|
||||
</MainView>
|
||||
|
||||
@@ -3,13 +3,11 @@ import { Button } from "./button";
|
||||
import { boundMethod } from "autobind-decorator";
|
||||
import * as mobxReact from "mobx-react";
|
||||
import * as mobx from "mobx";
|
||||
import { clsx } from "clsx";
|
||||
|
||||
import "./copybutton.less";
|
||||
|
||||
type CopyButtonProps = {
|
||||
title: string;
|
||||
className?: string;
|
||||
onClick: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
||||
};
|
||||
|
||||
@@ -36,14 +34,10 @@ class CopyButton extends React.Component<CopyButtonProps, {}> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { title, className } = this.props;
|
||||
const { title, onClick } = this.props;
|
||||
const isCopied = this.isCopied.get();
|
||||
return (
|
||||
<Button
|
||||
onClick={this.handleOnClick}
|
||||
className={clsx("copy-button secondary ghost", className)}
|
||||
title={title}
|
||||
>
|
||||
<Button onClick={this.handleOnClick} className="copy-button secondary ghost" title={title}>
|
||||
{isCopied ? (
|
||||
<i className="fa-sharp fa-solid fa-check"></i>
|
||||
) : (
|
||||
|
||||
@@ -19,4 +19,3 @@ export { TabIcon } from "./tabicon";
|
||||
export { DatePicker } from "./datepicker";
|
||||
export { TermStyleList } from "./termstyle";
|
||||
export { CopyButton } from "./copybutton";
|
||||
export { TypingIndicator } from "./typingindicator";
|
||||
|
||||
@@ -48,69 +48,30 @@
|
||||
|
||||
pre {
|
||||
background-color: var(--markdown-bg-color);
|
||||
margin: 4px 10px;
|
||||
padding: 0.4em 0.7em;
|
||||
margin: 4px 10px 4px 10px;
|
||||
padding: 0.7em;
|
||||
border-radius: 4px;
|
||||
position: relative;
|
||||
|
||||
code {
|
||||
line-height: 1.5;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
overflow: auto;
|
||||
overflow: hidden;
|
||||
background-color: transparent;
|
||||
padding: 0;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.codeblock-actions {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
border-radius: 4px;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
background-color: var(--line-actions-bg-color);
|
||||
backdrop-filter: blur(8px);
|
||||
|
||||
i {
|
||||
color: var(--line-actions-inactive-color);
|
||||
|
||||
&:first-child {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--line-actions-active-color);
|
||||
}
|
||||
|
||||
&.fa-check {
|
||||
color: var(--app-success-color);
|
||||
}
|
||||
|
||||
&.fa-square-terminal {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .codeblock-actions {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
code {
|
||||
color: var(--app-text-color);
|
||||
background-color: var(--markdown-bg-color);
|
||||
font-family: var(--termfontfamily);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
pre.selected {
|
||||
outline: 2px solid var(--markdown-outline-color);
|
||||
}
|
||||
|
||||
code {
|
||||
color: var(--app-text-color);
|
||||
font-family: var(--termfontfamily);
|
||||
border-radius: 4px;
|
||||
background-color: var(--markdown-bg-color);
|
||||
padding: 0.15em 0.5em;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: semibold;
|
||||
padding-top: 6px;
|
||||
@@ -140,10 +101,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.markdown.content {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.markdown > *:first-child {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@ import * as React from "react";
|
||||
import * as mobxReact from "mobx-react";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import { CopyButton } from "@/elements";
|
||||
import { clsx } from "clsx";
|
||||
import * as mobx from "mobx";
|
||||
import { If } from "tsx-control-statements/components";
|
||||
import { GlobalModel } from "@/models";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
import "./markdown.less";
|
||||
import { boundMethod } from "autobind-decorator";
|
||||
|
||||
function Link(props: any): JSX.Element {
|
||||
function LinkRenderer(props: any): any {
|
||||
let newUrl = "https://extern?" + encodeURIComponent(props.href);
|
||||
return (
|
||||
<a href={newUrl} target="_blank" rel={"noopener"}>
|
||||
@@ -21,86 +21,94 @@ function Link(props: any): JSX.Element {
|
||||
);
|
||||
}
|
||||
|
||||
function Header(props: any, hnum: number): JSX.Element {
|
||||
function HeaderRenderer(props: any, hnum: number): any {
|
||||
return <div className={clsx("title", "is-" + hnum)}>{props.children}</div>;
|
||||
}
|
||||
|
||||
function Code(props: any): JSX.Element {
|
||||
function CodeRenderer(props: any): any {
|
||||
return <code>{props.children}</code>;
|
||||
}
|
||||
|
||||
const CodeBlock = mobxReact.observer(
|
||||
(props: { children: React.ReactNode; onClickExecute?: (cmd: string) => void }): JSX.Element => {
|
||||
const copied: OV<boolean> = mobx.observable.box(false, { name: "copied" });
|
||||
@mobxReact.observer
|
||||
class CodeBlockMarkdown extends React.Component<
|
||||
{ children: React.ReactNode; codeSelectSelectedIndex?: number; uuid: string },
|
||||
{}
|
||||
> {
|
||||
blockIndex: number;
|
||||
blockRef: React.RefObject<HTMLPreElement>;
|
||||
|
||||
const getTextContent = (children: any) => {
|
||||
if (typeof children === "string") {
|
||||
return children;
|
||||
} else if (Array.isArray(children)) {
|
||||
return children.map(getTextContent).join("");
|
||||
} else if (children.props && children.props.children) {
|
||||
return getTextContent(children.props.children);
|
||||
}
|
||||
return "";
|
||||
};
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.blockRef = React.createRef();
|
||||
this.blockIndex = GlobalModel.inputModel.addCodeBlockToCodeSelect(this.blockRef, this.props.uuid);
|
||||
}
|
||||
|
||||
const handleCopy = async (e: React.MouseEvent) => {
|
||||
let textToCopy = getTextContent(props.children);
|
||||
textToCopy = textToCopy.replace(/\n$/, ""); // remove trailing newline
|
||||
await navigator.clipboard.writeText(textToCopy);
|
||||
copied.set(true);
|
||||
setTimeout(() => copied.set(false), 2000); // Reset copied state after 2 seconds
|
||||
};
|
||||
|
||||
const handleExecute = (e: React.MouseEvent) => {
|
||||
let textToCopy = getTextContent(props.children);
|
||||
textToCopy = textToCopy.replace(/\n$/, ""); // remove trailing newline
|
||||
if (props.onClickExecute) {
|
||||
props.onClickExecute(textToCopy);
|
||||
return;
|
||||
}
|
||||
};
|
||||
@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 selected = this.blockIndex == this.props.codeSelectSelectedIndex;
|
||||
return (
|
||||
<pre className="codeblock">
|
||||
{props.children}
|
||||
<div className="codeblock-actions">
|
||||
<CopyButton className="copy-button" onClick={handleCopy} title="Copy" />
|
||||
<If condition={props.onClickExecute}>
|
||||
<i className="fa-regular fa-square-terminal" onClick={handleExecute}></i>
|
||||
</If>
|
||||
</div>
|
||||
<pre ref={this.blockRef} className={clsx({ selected: selected })} onClick={this.handleClick}>
|
||||
{this.props.children}
|
||||
</pre>
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@mobxReact.observer
|
||||
class Markdown extends React.Component<
|
||||
{
|
||||
text: string;
|
||||
style?: any;
|
||||
className?: string;
|
||||
onClickExecute?: (cmd: string) => void;
|
||||
},
|
||||
{ text: string; style?: any; extraClassName?: string; codeSelect?: boolean },
|
||||
{}
|
||||
> {
|
||||
render() {
|
||||
let { text, className, onClickExecute } = this.props;
|
||||
let markdownComponents = {
|
||||
a: Link,
|
||||
h1: (props) => <Header {...props} hnum={1} />,
|
||||
h2: (props) => <Header {...props} hnum={2} />,
|
||||
h3: (props) => <Header {...props} hnum={3} />,
|
||||
h4: (props) => <Header {...props} hnum={4} />,
|
||||
h5: (props) => <Header {...props} hnum={5} />,
|
||||
h6: (props) => <Header {...props} hnum={6} />,
|
||||
code: Code,
|
||||
pre: (props) => <CodeBlock {...props} onClickExecute={onClickExecute} />,
|
||||
};
|
||||
curUuid: string;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.curUuid = uuidv4();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
codeBlockRenderer(props: any, codeSelect: boolean, codeSelectIndex: number, curUuid: string): any {
|
||||
if (codeSelect) {
|
||||
return (
|
||||
<CodeBlockMarkdown codeSelectSelectedIndex={codeSelectIndex} uuid={curUuid}>
|
||||
{props.children}
|
||||
</CodeBlockMarkdown>
|
||||
);
|
||||
} else {
|
||||
const clickHandler = (e: React.MouseEvent<HTMLElement>) => {
|
||||
let blockText = (e.target as HTMLElement).innerText;
|
||||
if (blockText) {
|
||||
blockText = blockText.replace(/\n$/, ""); // remove trailing newline
|
||||
navigator.clipboard.writeText(blockText);
|
||||
}
|
||||
};
|
||||
return <pre onClick={(event) => clickHandler(event)}>{props.children}</pre>;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let { text } = this.props;
|
||||
let codeSelect = this.props.codeSelect;
|
||||
let curCodeSelectIndex = GlobalModel.inputModel.getCodeSelectSelectedIndex();
|
||||
let markdownComponents = {
|
||||
a: LinkRenderer,
|
||||
h1: (props) => HeaderRenderer(props, 1),
|
||||
h2: (props) => HeaderRenderer(props, 2),
|
||||
h3: (props) => HeaderRenderer(props, 3),
|
||||
h4: (props) => HeaderRenderer(props, 4),
|
||||
h5: (props) => HeaderRenderer(props, 5),
|
||||
h6: (props) => HeaderRenderer(props, 6),
|
||||
code: (props) => CodeRenderer(props),
|
||||
pre: (props) => this.codeBlockRenderer(props, codeSelect, curCodeSelectIndex, this.curUuid),
|
||||
};
|
||||
return (
|
||||
<div className={clsx("markdown content", className)} style={this.props.style}>
|
||||
<div className={clsx("markdown content", this.props.extraClassName)} style={this.props.style}>
|
||||
<ReactMarkdown remarkPlugins={[remarkGfm]} components={markdownComponents}>
|
||||
{text}
|
||||
</ReactMarkdown>
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
@dot-width: 11px;
|
||||
@dot-color: var(--app-success-color);
|
||||
@speed: 1.5s;
|
||||
|
||||
.typing {
|
||||
position: relative;
|
||||
height: @dot-width;
|
||||
|
||||
span {
|
||||
content: "";
|
||||
animation: blink @speed infinite;
|
||||
animation-fill-mode: both;
|
||||
height: @dot-width;
|
||||
width: @dot-width;
|
||||
background: @dot-color;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
border-radius: 50%;
|
||||
|
||||
&:nth-child(2) {
|
||||
animation-delay: 0.2s;
|
||||
margin-left: @dot-width * 1.5;
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
animation-delay: 0.4s;
|
||||
margin-left: @dot-width * 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0% {
|
||||
opacity: 0.1;
|
||||
}
|
||||
20% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0.1;
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import React from "react";
|
||||
import { clsx } from "clsx";
|
||||
|
||||
import "./typingindicator.less";
|
||||
|
||||
type Props = {
|
||||
className?: string;
|
||||
};
|
||||
const TypingIndicator: React.FC<Props> = (props: { className?: string }) => {
|
||||
return (
|
||||
<div className={clsx("typing", props.className)}>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { TypingIndicator };
|
||||
@@ -135,12 +135,14 @@ export const StatusIndicator: React.FC<StatusIndicatorProps> = (props) => {
|
||||
*/
|
||||
React.useEffect(() => {
|
||||
if (runningCommands && !timeoutState) {
|
||||
console.log("show spinner");
|
||||
setTimeoutState(
|
||||
setTimeout(() => {
|
||||
setSpinnerVisible(true);
|
||||
}, 100)
|
||||
);
|
||||
} else if (!runningCommands) {
|
||||
console.log("clear spinner");
|
||||
clearSpinnerTimeout();
|
||||
}
|
||||
return () => {
|
||||
|
||||
@@ -114,25 +114,6 @@ class LineActions extends React.Component<{ screen: LineContainerType; line: Lin
|
||||
GlobalCommandRunner.lineRestart(line.lineid, true);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
clickChat(e: any) {
|
||||
e.stopPropagation();
|
||||
const { line, screen } = this.props;
|
||||
const termWrap = screen.getTermWrap(line.lineid);
|
||||
const cmd = screen.getCmd(line);
|
||||
if (termWrap && cmd) {
|
||||
GlobalModel.sidebarchatModel.setCmdAndOutput(
|
||||
screen.getCmd(line)?.getCmdStr(),
|
||||
termWrap?.getOutput(false),
|
||||
// multiply by 2 to get a rough estimate of the number of rows within the chatbox
|
||||
screen.getUsedRows(lineutil.getRendererContext(line), line, cmd, 300) * 2,
|
||||
cmdShouldMarkError(cmd)
|
||||
);
|
||||
GlobalModel.inputModel.setChatSidebarFocus();
|
||||
GlobalModel.sidebarchatModel.resetSelectedCodeBlockIndex();
|
||||
}
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
clickMinimize() {
|
||||
const { line } = this.props;
|
||||
@@ -173,14 +154,10 @@ class LineActions extends React.Component<{ screen: LineContainerType; line: Lin
|
||||
const { line, screen } = this.props;
|
||||
const isMinimized = line.linestate["wave:min"];
|
||||
const containerType = screen.getContainerType();
|
||||
// console.log("******************", screen.getTermWrap(line.lineid));
|
||||
return (
|
||||
<div className="line-actions">
|
||||
<Choose>
|
||||
<When condition={containerType == appconst.LineContainer_Main}>
|
||||
<div key="chat" title="Restart Command" className="line-icon" onClick={this.clickChat}>
|
||||
<i className="fa-sharp fa-regular fa-sparkles fa-fw" />
|
||||
</div>
|
||||
<div key="restart" title="Restart Command" className="line-icon" onClick={this.clickRestart}>
|
||||
<i className="fa-sharp fa-regular fa-arrows-rotate fa-fw" />
|
||||
</div>
|
||||
@@ -537,6 +514,7 @@ class LineCmd extends React.Component<
|
||||
const lastHeight = this.lastHeight;
|
||||
this.lastHeight = curHeight;
|
||||
this.props.onHeightChange(line.linenum, curHeight, lastHeight);
|
||||
// console.log("line height change: ", line.linenum, lastHeight, "=>", curHeight);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
|
||||
@@ -23,10 +23,10 @@ let MagicLayout = {
|
||||
MainSidebarDefaultWidth: 240,
|
||||
|
||||
RightSidebarMinWidth: 0,
|
||||
RightSidebarMaxWidth: 700,
|
||||
RightSidebarMaxWidth: 400,
|
||||
RightSidebarSnapThreshold: 90,
|
||||
RightSidebarDragResistance: 50,
|
||||
RightSidebarDefaultWidth: 400,
|
||||
RightSidebarDefaultWidth: 240,
|
||||
};
|
||||
|
||||
let m = MagicLayout;
|
||||
|
||||
+23
-15
@@ -1,10 +1,30 @@
|
||||
.sidebarchat {
|
||||
.sidebar-aichat {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
|
||||
> .scrollable {
|
||||
.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;
|
||||
@@ -20,24 +40,17 @@
|
||||
.filler {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
> * {
|
||||
cursor: default;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-msg {
|
||||
padding: calc(var(--termpad) * 2);
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
||||
.chat-msg-header {
|
||||
display: flex;
|
||||
margin-bottom: 2px;
|
||||
|
||||
i {
|
||||
margin-top: 2px;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
}
|
||||
@@ -60,13 +73,9 @@
|
||||
font-family: var(--markdown-font);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.typing-indicator {
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebarchat-input-wrapper {
|
||||
.chat-input {
|
||||
padding: 16px 15px 7px;
|
||||
flex: 0 0 auto;
|
||||
border-top: 1px solid var(--app-border-color);
|
||||
@@ -83,7 +92,6 @@
|
||||
font-family: var(--termfontfamily);
|
||||
font-weight: normal;
|
||||
line-height: var(--termlineheight);
|
||||
height: 21px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+176
-379
File diff suppressed because it is too large
Load Diff
@@ -24,22 +24,19 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 11px;
|
||||
padding: 0 5px;
|
||||
border-bottom: 1px solid var(--app-border-color);
|
||||
}
|
||||
|
||||
.rsb-modes {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 5px 10px;
|
||||
gap: 5px;
|
||||
|
||||
.icon-container {
|
||||
padding: 4px;
|
||||
padding: 2px;
|
||||
cursor: pointer;
|
||||
|
||||
span {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-container:hover {
|
||||
@@ -51,10 +48,6 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.close {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.keybind-debug-pane {
|
||||
padding: 10px;
|
||||
overflow: hidden;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user