mirror of
https://github.com/wavetermdev/backup.git
synced 2026-04-22 15:26:58 -07:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8af0b0b7ae | |||
| fb7f055449 | |||
| 3e4bd458b3 | |||
| 18fe3f3296 | |||
| 2839179ced | |||
| 532e65c8ab | |||
| 85f22a0733 | |||
| 94de0460b4 | |||
| 71b09cb44e | |||
| 07abaa92fa | |||
| 2a4d85430a | |||
| d319e72609 | |||
| 7a5afccab3 | |||
| efe567398a | |||
| 187509504d | |||
| 903b26bfca | |||
| e692c7c180 | |||
| b37f7f722e | |||
| ff855cf308 | |||
| bf1b556537 |
@@ -10,7 +10,7 @@
|
||||
|
||||
# Wave Terminal
|
||||
|
||||
A open-source, cross-platform, modern terminal for seamless workflows.
|
||||
A open-source, cross-platform, AI-integrated, modern terminal for seamless workflows.
|
||||
|
||||
Wave isn't just another terminal emulator; it's a rethink on how terminals are built. Wave combines command line with the power of the open web to help veteran CLI users and new developers alike.
|
||||
|
||||
@@ -18,6 +18,7 @@ Wave isn't just another terminal emulator; it's a rethink on how terminals are b
|
||||
* Persistent sessions that can restore state across network disconnections and reboots
|
||||
* Searchable contextual command history across all remote sessions (saved locally)
|
||||
* Workspaces, tabs, and command blocks to keep you organized
|
||||
* AI Integration with ChatGPT (or ChatGPT compatible APIs) to help write commands and get answers inline
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -35,6 +36,7 @@ brew install --cask wave
|
||||
* Homepage — https://www.waveterm.dev
|
||||
* Download Page — https://www.waveterm.dev/download
|
||||
* Documentation — https://docs.waveterm.dev/
|
||||
* Blog — https://blog.waveterm.dev/
|
||||
* Quick Start Guide — https://docs.waveterm.dev/quickstart/
|
||||
* Discord Community — https://discord.gg/XfvZ334gwU
|
||||
|
||||
|
||||
+3
-6
@@ -7,10 +7,9 @@ import * as mobx from "mobx";
|
||||
import { boundMethod } from "autobind-decorator";
|
||||
import { If } from "tsx-control-statements/components";
|
||||
import dayjs from "dayjs";
|
||||
import type { ContextMenuOpts } from "../types/types";
|
||||
import localizedFormat from "dayjs/plugin/localizedFormat";
|
||||
import { GlobalModel } from "../model/model";
|
||||
import { isBlank } from "../util/util";
|
||||
import { GlobalModel } from "@/models";
|
||||
import { isBlank } from "@/util/util";
|
||||
import { WorkspaceView } from "./workspace/workspaceview";
|
||||
import { PluginsView } from "./pluginsview/pluginsview";
|
||||
import { BookmarksView } from "./bookmarks/bookmarks";
|
||||
@@ -25,14 +24,12 @@ import "./app.less";
|
||||
|
||||
dayjs.extend(localizedFormat);
|
||||
|
||||
type OV<V> = mobx.IObservableValue<V>;
|
||||
|
||||
@mobxReact.observer
|
||||
class App extends React.Component<{}, {}> {
|
||||
dcWait: OV<boolean> = mobx.observable.box(false, { name: "dcWait" });
|
||||
mainContentRef: React.RefObject<HTMLDivElement> = React.createRef();
|
||||
|
||||
constructor(props: any) {
|
||||
constructor(props: {}) {
|
||||
super(props);
|
||||
if (GlobalModel.isDev) document.body.className = "is-dev";
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ export const SESSION_SETTINGS = "sessionSettings";
|
||||
export const LINE_SETTINGS = "lineSettings";
|
||||
export const CLIENT_SETTINGS = "clientSettings";
|
||||
export const TAB_SWITCHER = "tabSwitcher";
|
||||
export const USER_INPUT = "userInput";
|
||||
|
||||
export const LineContainer_Main = "main";
|
||||
export const LineContainer_History = "history";
|
||||
@@ -16,3 +17,43 @@ export const LineContainer_Sidebar = "sidebar";
|
||||
export const ConfirmKey_HideShellPrompt = "hideshellprompt";
|
||||
|
||||
export const NoStrPos = -1;
|
||||
|
||||
export const RemotePtyRows = 8; // also in main.tsx
|
||||
export const RemotePtyCols = 80;
|
||||
export const ProdServerEndpoint = "http://127.0.0.1:1619";
|
||||
export const ProdServerWsEndpoint = "ws://127.0.0.1:1623";
|
||||
export const DevServerEndpoint = "http://127.0.0.1:8090";
|
||||
export const DevServerWsEndpoint = "ws://127.0.0.1:8091";
|
||||
export const DefaultTermFontSize = 12;
|
||||
export const MinFontSize = 8;
|
||||
export const MaxFontSize = 24;
|
||||
export const InputChunkSize = 500;
|
||||
export const RemoteColors = ["red", "green", "yellow", "blue", "magenta", "cyan", "white", "orange"];
|
||||
export const TabColors = ["red", "orange", "yellow", "green", "mint", "cyan", "blue", "violet", "pink", "white"];
|
||||
export const TabIcons = [
|
||||
"sparkle",
|
||||
"fire",
|
||||
"ghost",
|
||||
"cloud",
|
||||
"compass",
|
||||
"crown",
|
||||
"droplet",
|
||||
"graduation-cap",
|
||||
"heart",
|
||||
"file",
|
||||
];
|
||||
|
||||
// @ts-ignore
|
||||
export const VERSION = __WAVETERM_VERSION__;
|
||||
// @ts-ignore
|
||||
export const BUILD = __WAVETERM_BUILD__;
|
||||
|
||||
/**
|
||||
* Levels for the screen status indicator
|
||||
*/
|
||||
export enum StatusIndicatorLevel {
|
||||
None = 0,
|
||||
Output = 1,
|
||||
Success = 2,
|
||||
Error = 3,
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import "../../app/common/themes/themes.less";
|
||||
@import "@/common/themes/themes.less";
|
||||
|
||||
.bookmarks-view {
|
||||
background-color: @background-session;
|
||||
|
||||
@@ -7,20 +7,27 @@ import * as mobx from "mobx";
|
||||
import { boundMethod } from "autobind-decorator";
|
||||
import { If, For } from "tsx-control-statements/components";
|
||||
import cn from "classnames";
|
||||
import type { BookmarkType } from "../../types/types";
|
||||
import { GlobalModel } from "../../model/model";
|
||||
import { CmdStrCode, Markdown } from "../common/elements";
|
||||
import { GlobalModel } from "@/models";
|
||||
import { CmdStrCode, Markdown } from "@/common/elements";
|
||||
|
||||
import { ReactComponent as XmarkIcon } from "../assets/icons/line/xmark.svg";
|
||||
import { ReactComponent as CopyIcon } from "../assets/icons/favourites/copy.svg";
|
||||
import { ReactComponent as PenIcon } from "../assets/icons/favourites/pen.svg";
|
||||
import { ReactComponent as TrashIcon } from "../assets/icons/favourites/trash.svg";
|
||||
import { ReactComponent as FavoritesIcon } from "../assets/icons/favourites.svg";
|
||||
import { ReactComponent as XmarkIcon } from "@/assets/icons/line/xmark.svg";
|
||||
import { ReactComponent as CopyIcon } from "@/assets/icons/favourites/copy.svg";
|
||||
import { ReactComponent as PenIcon } from "@/assets/icons/favourites/pen.svg";
|
||||
import { ReactComponent as TrashIcon } from "@/assets/icons/favourites/trash.svg";
|
||||
import { ReactComponent as FavoritesIcon } from "@/assets/icons/favourites.svg";
|
||||
|
||||
import "./bookmarks.less";
|
||||
|
||||
type BookmarkProps = {
|
||||
bookmark: BookmarkType;
|
||||
};
|
||||
|
||||
@mobxReact.observer
|
||||
class Bookmark extends React.Component<{ bookmark: BookmarkType }, {}> {
|
||||
class Bookmark extends React.Component<BookmarkProps, {}> {
|
||||
constructor(props: BookmarkProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleDeleteClick(): void {
|
||||
let { bookmark } = this.props;
|
||||
@@ -179,6 +186,10 @@ class Bookmark extends React.Component<{ bookmark: BookmarkType }, {}> {
|
||||
|
||||
@mobxReact.observer
|
||||
class BookmarksView extends React.Component<{}, {}> {
|
||||
constructor(props: {}) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
closeView(): void {
|
||||
GlobalModel.bookmarksModel.closeView();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import "../../app/common/themes/themes.less";
|
||||
@import "@/common/themes/themes.less";
|
||||
|
||||
.clientsettings-view {
|
||||
background-color: @background-session;
|
||||
|
||||
@@ -6,23 +6,18 @@ import * as mobxReact from "mobx-react";
|
||||
import * as mobx from "mobx";
|
||||
import { boundMethod } from "autobind-decorator";
|
||||
import cn from "classnames";
|
||||
import { GlobalModel, GlobalCommandRunner, MinFontSize, MaxFontSize, RemotesModel } from "../../model/model";
|
||||
import { Toggle, InlineSettingsTextEdit, SettingsError, Dropdown } from "../common/elements";
|
||||
import { CommandRtnType, ClientDataType } from "../../types/types";
|
||||
import { commandRtnHandler, isBlank } from "../../util/util";
|
||||
import { GlobalModel, GlobalCommandRunner, RemotesModel } from "@/models";
|
||||
import { Toggle, InlineSettingsTextEdit, SettingsError, Dropdown } from "@/common/elements";
|
||||
import { commandRtnHandler, isBlank } from "@/util/util";
|
||||
import * as appconst from "@/app/appconst";
|
||||
|
||||
import "./clientsettings.less";
|
||||
|
||||
type OV<V> = mobx.IObservableValue<V>;
|
||||
|
||||
// @ts-ignore
|
||||
const VERSION = __WAVETERM_VERSION__;
|
||||
// @ts-ignore
|
||||
const BUILD = __WAVETERM_BUILD__;
|
||||
|
||||
@mobxReact.observer
|
||||
class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hoveredItemId: string }> {
|
||||
fontSizeDropdownActive: OV<boolean> = mobx.observable.box(false, { name: "clientSettings-fontSizeDropdownActive" });
|
||||
fontSizeDropdownActive: OV<boolean> = mobx.observable.box(false, {
|
||||
name: "clientSettings-fontSizeDropdownActive",
|
||||
});
|
||||
errorMessage: OV<string> = mobx.observable.box(null, { name: "ClientSettings-errorMessage" });
|
||||
|
||||
@boundMethod
|
||||
@@ -34,12 +29,12 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
||||
|
||||
@boundMethod
|
||||
handleChangeFontSize(fontSize: string): void {
|
||||
let newFontSize = Number(fontSize);
|
||||
const newFontSize = Number(fontSize);
|
||||
this.fontSizeDropdownActive.set(false);
|
||||
if (GlobalModel.termFontSize.get() == newFontSize) {
|
||||
return;
|
||||
}
|
||||
let prtn = GlobalCommandRunner.setTermFontSize(newFontSize, false);
|
||||
const prtn = GlobalCommandRunner.setTermFontSize(newFontSize, false);
|
||||
commandRtnHandler(prtn, this.errorMessage);
|
||||
}
|
||||
|
||||
@@ -72,29 +67,29 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
||||
commandRtnHandler(prtn, this.errorMessage);
|
||||
}
|
||||
|
||||
getFontSizes(): any {
|
||||
let availableFontSizes: { label: string; value: number }[] = [];
|
||||
for (let s = MinFontSize; s <= MaxFontSize; s++) {
|
||||
availableFontSizes.push({ label: s + "px", value: s });
|
||||
getFontSizes(): DropdownItem[] {
|
||||
const availableFontSizes: DropdownItem[] = [];
|
||||
for (let s = appconst.MinFontSize; s <= appconst.MaxFontSize; s++) {
|
||||
availableFontSizes.push({ label: s + "px", value: String(s) });
|
||||
}
|
||||
return availableFontSizes;
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
inlineUpdateOpenAIModel(newModel: string): void {
|
||||
let prtn = GlobalCommandRunner.setClientOpenAISettings({ model: newModel });
|
||||
const prtn = GlobalCommandRunner.setClientOpenAISettings({ model: newModel });
|
||||
commandRtnHandler(prtn, this.errorMessage);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
inlineUpdateOpenAIToken(newToken: string): void {
|
||||
let prtn = GlobalCommandRunner.setClientOpenAISettings({ apitoken: newToken });
|
||||
const prtn = GlobalCommandRunner.setClientOpenAISettings({ apitoken: newToken });
|
||||
commandRtnHandler(prtn, this.errorMessage);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
inlineUpdateOpenAIMaxTokens(newMaxTokensStr: string): void {
|
||||
let prtn = GlobalCommandRunner.setClientOpenAISettings({ maxtokens: newMaxTokensStr });
|
||||
const prtn = GlobalCommandRunner.setClientOpenAISettings({ maxtokens: newMaxTokensStr });
|
||||
commandRtnHandler(prtn, this.errorMessage);
|
||||
}
|
||||
|
||||
@@ -110,19 +105,41 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
||||
GlobalModel.clientSettingsViewModel.closeView();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleChangeShortcut(newShortcut: string): void {
|
||||
const prtn = GlobalCommandRunner.setGlobalShortcut(newShortcut);
|
||||
commandRtnHandler(prtn, this.errorMessage);
|
||||
}
|
||||
|
||||
getFKeys(): DropdownItem[] {
|
||||
const opts: DropdownItem[] = [];
|
||||
opts.push({ label: "Disabled", value: "" });
|
||||
const platform = GlobalModel.getPlatform();
|
||||
for (let i = 1; i <= 12; i++) {
|
||||
const shortcut = (platform == "darwin" ? "Cmd" : "Alt") + "+F" + String(i);
|
||||
opts.push({ label: shortcut, value: shortcut });
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
|
||||
getCurrentShortcut(): string {
|
||||
const clientData = GlobalModel.clientData.get();
|
||||
return clientData?.clientopts?.globalshortcut ?? "";
|
||||
}
|
||||
|
||||
render() {
|
||||
let isHidden = GlobalModel.activeMainView.get() != "clientsettings";
|
||||
const isHidden = GlobalModel.activeMainView.get() != "clientsettings";
|
||||
if (isHidden) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let cdata: ClientDataType = GlobalModel.clientData.get();
|
||||
let openAIOpts = cdata.openaiopts ?? {};
|
||||
let apiTokenStr = isBlank(openAIOpts.apitoken) ? "(not set)" : "********";
|
||||
let maxTokensStr = String(
|
||||
const cdata: ClientDataType = GlobalModel.clientData.get();
|
||||
const openAIOpts = cdata.openaiopts ?? {};
|
||||
const apiTokenStr = isBlank(openAIOpts.apitoken) ? "(not set)" : "********";
|
||||
const maxTokensStr = String(
|
||||
openAIOpts.maxtokens == null || openAIOpts.maxtokens == 0 ? 1000 : openAIOpts.maxtokens
|
||||
);
|
||||
let curFontSize = GlobalModel.termFontSize.get();
|
||||
const curFontSize = GlobalModel.termFontSize.get();
|
||||
|
||||
return (
|
||||
<div className={cn("view clientsettings-view")}>
|
||||
@@ -151,7 +168,7 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">Client Version</div>
|
||||
<div className="settings-input">
|
||||
{VERSION} {BUILD}
|
||||
{appconst.VERSION} {appconst.BUILD}
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-field">
|
||||
@@ -212,6 +229,17 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">Global Hotkey</div>
|
||||
<div className="settings-input">
|
||||
<Dropdown
|
||||
className="hotkey-dropdown"
|
||||
options={this.getFKeys()}
|
||||
defaultValue={this.getCurrentShortcut()}
|
||||
onChange={this.handleChangeShortcut}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<SettingsError errorMessage={this.errorMessage} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import "../../../app/common/themes/themes.less";
|
||||
@import "@/common/themes/themes.less";
|
||||
|
||||
.wave-button {
|
||||
background: none;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import "../../../app/common/themes/themes.less";
|
||||
@import "@/common/themes/themes.less";
|
||||
|
||||
.checkbox {
|
||||
display: flex;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import "../../../app/common/themes/themes.less";
|
||||
@import "@/common/themes/themes.less";
|
||||
|
||||
.cmdstr-code {
|
||||
position: relative;
|
||||
|
||||
@@ -6,8 +6,8 @@ import { boundMethod } from "autobind-decorator";
|
||||
import cn from "classnames";
|
||||
import { If } from "tsx-control-statements/components";
|
||||
|
||||
import { ReactComponent as CheckIcon } from "../../assets/icons/line/check.svg";
|
||||
import { ReactComponent as CopyIcon } from "../../assets/icons/history/copy.svg";
|
||||
import { ReactComponent as CheckIcon } from "@/assets/icons/line/check.svg";
|
||||
import { ReactComponent as CopyIcon } from "@/assets/icons/history/copy.svg";
|
||||
|
||||
import "./cmdstrcode.less";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import "../../../app/common/themes/themes.less";
|
||||
@import "@/common/themes/themes.less";
|
||||
|
||||
.wave-dropdown {
|
||||
position: relative;
|
||||
|
||||
@@ -17,7 +17,7 @@ interface DropdownDecorationProps {
|
||||
|
||||
interface DropdownProps {
|
||||
label?: string;
|
||||
options: { value: string; label: string }[];
|
||||
options: DropdownItem[];
|
||||
value?: string;
|
||||
className?: string;
|
||||
onChange: (value: string) => void;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import "../../../app/common/themes/themes.less";
|
||||
@import "@/common/themes/themes.less";
|
||||
|
||||
.inline-edit {
|
||||
.icon {
|
||||
|
||||
@@ -7,12 +7,10 @@ import * as mobx from "mobx";
|
||||
import { boundMethod } from "autobind-decorator";
|
||||
import cn from "classnames";
|
||||
import { If } from "tsx-control-statements/components";
|
||||
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "../../../util/keyutil";
|
||||
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "@/util/keyutil";
|
||||
|
||||
import "./inlinesettingstextedit.less";
|
||||
|
||||
type OV<V> = mobx.IObservableValue<V>;
|
||||
|
||||
@mobxReact.observer
|
||||
class InlineSettingsTextEdit extends React.Component<
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import "../../../app/common/themes/themes.less";
|
||||
@import "@/common/themes/themes.less";
|
||||
|
||||
.wave-input-decoration {
|
||||
display: flex;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
@import "../../../app/common/themes/themes.less";
|
||||
@import "@/common/themes/themes.less";
|
||||
|
||||
.markdown {
|
||||
color: @term-white;
|
||||
margin-bottom: 10px;
|
||||
font-family: @markdown-font;
|
||||
font-size: 14px;
|
||||
overflow-wrap: break-word;
|
||||
|
||||
code {
|
||||
background-color: @markdown-highlight;
|
||||
|
||||
@@ -6,7 +6,7 @@ import * as mobxReact from "mobx-react";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import cn from "classnames";
|
||||
import { GlobalModel } from "../../../model/model";
|
||||
import { GlobalModel } from "@/models";
|
||||
|
||||
import "./markdown.less";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import "../../../app/common/themes/themes.less";
|
||||
@import "@/common/themes/themes.less";
|
||||
|
||||
.wave-modal-container {
|
||||
position: fixed;
|
||||
|
||||
@@ -10,8 +10,6 @@ import { IconButton } from "./iconbutton";
|
||||
|
||||
import "./modal.less";
|
||||
|
||||
type OV<V> = mobx.IObservableValue<V>;
|
||||
|
||||
interface ModalHeaderProps {
|
||||
onClose?: () => void;
|
||||
title: string;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user